Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revise the Raspberry Pi Pico sample implementation #10

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,21 @@ pico_sdk_init()

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
add_compile_options(-Wall -Wextra -Werror)
add_executable(main
main.c
sensirion_i2c.c
sensirion_i2c.hal.c
scd4x_i2c.c
sensirion_common.c)
../../sensirion_i2c.c
sensirion_i2c_hal.c
../../scd4x_i2c.c
../../sensirion_common.c)

# pull in common dependencies and additional i2c hardware support
target_link_libraries(main pico_stdlib hardware_i2c)

# use USB for stdin/stdout, rather than using UART
pico_enable_stdio_usb(main 1)

pico_enable_stdio_uart(main 0)

# create map/bin/hex file etc.
pico_add_extra_outputs(main)

39 changes: 39 additions & 0 deletions sample-implementations/RaspberryPi_Pico/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
SCD4x on the Raspberry Pi Pico
==============================
<img alt="Pico W with an SCD41 connected" src="hardware.jpg" height="400"/>

In this example, an SCD41 is connected to a Raspberry Pi Pico W on GPIO pins 12
(I2C0 SDA) and 13 (I2C0 SCL). The same code will work for any variant of the
Pico.

The following shell session is from an Ubuntu machine that had the Pico plugged
in to USB in boot select mode.

```console
$ ls
CMakeLists.txt hardware.jpg main.c README.md sensirion_i2c_hal.c

$ mkdir build

$ cd build

$ cmake -DPICO_SDK_PATH=$HOME/src/pico-sdk ..
[...]

$ make -j
[...]

$ ls
CMakeCache.txt cmake_install.cmake generated main.dis main.elf.map main.uf2 pico-sdk
CMakeFiles elf2uf2 main.bin main.elf main.hex Makefile pioasm

$ cp main.uf2 /media/$USER/RPI-RP2

$ screen /dev/ttyACM0
The I2C baudrate is 399361 Hz
Sensor serial number is: 0x8a7e 0xbb07 0x3ba0
CO2: 1111 ppm, Temperature: 28.4 C (83.1 F), Humidity: 60.4%
CO2: 1080 ppm, Temperature: 28.5 C (83.2 F), Humidity: 61.1%
CO2: 1070 ppm, Temperature: 28.4 C (83.1 F), Humidity: 61.7%
[...]
```
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
116 changes: 62 additions & 54 deletions sample-implementations/RaspberryPi_Pico/main.c
Original file line number Diff line number Diff line change
@@ -1,77 +1,85 @@
#include "../../scd4x_i2c.h"

#include <hardware/i2c.h>
#include <pico/stdlib.h>
#include <pico/time.h>

#include "hardware/i2c.h"
#include "pico/binary_info.h"
#include "pico/stdlib.h"
#include "scd4x_i2c.h"
#include <stdio.h>

/// I2C address
static int addr = 0x62;

// I2C Pins
static uint sda_pin = 16;
static uint scl_pin = 17;

// This is the main entry for your c application. U
// is
int main() {

int main(void) {
stdio_init_all();

// Setup I2c using pins 16 & 17
i2c_init(i2c_default, 400 * 1000);
gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
// Give us a few seconds to start viewing the output if we're plugged into
// the computer over USB.
sleep_ms(3000);

// This variable will hold the return status of the function calls.
// You can separate each function call result into their own variable or re
// - use this.
// Setup I2C using GPIO pins 12 & 13.
const uint desired_clock_hz = 400 * 1000;
const uint actual_baudrate = i2c_init(i2c_default, desired_clock_hz);
printf("The I2C baudrate is %u Hz\n", actual_baudrate);
const uint sda_pin = 12;
const uint scl_pin = 13;
gpio_set_function(sda_pin, GPIO_FUNC_I2C);
gpio_set_function(scl_pin, GPIO_FUNC_I2C);
gpio_pull_up(sda_pin);
gpio_pull_up(scl_pin);

int status = 0;
int status;

// Stop any readings if occuring
// Stop any ongoing measurement.
status = scd4x_stop_periodic_measurement();
if (status) {
printf("Unable to stop measurement. Error: %d\n", status);
return status;
}

// Perform self test
uint16_t* selfTest = 0;
scd4x_perform_self_test(selfTest);

// Get Serial number 3 parts
// Get serial number.
uint16_t one;
uint16_t two;
uint16_t three;

scd4x_get_serial_number(&one, &two, &three);
status = scd4x_get_serial_number(&one, &two, &three);
if (status) {
printf("Unable to get sensor serial number. Error: %d\n", status);
return status;
}
printf("Sensor serial number is: 0x%x 0x%x 0x%x\n", (int)one, (int)two, (int)three);

// Start the readings.
status1 = scd4x_start_periodic_measurement();

while (1) {
status = scd4x_start_periodic_measurement();
if (status) {
printf("Unable to start periodic measurement. Error %d\n", status);
return status;
}

// Check if data is ready to read
for (;;) {
// Wait for the measurement to complete.
sleep_ms(5000 - 10);
bool dataReady;
while (dataReady == false) {

status1 = scd4x_get_data_ready_flag(&dataReady);
do {
sleep_ms(10);
status = scd4x_get_data_ready_flag(&dataReady);
if (status) {
printf("Unable to get sensor readiness flag. Error %d.\n", status);
return status;
}
} while (!dataReady);

// Read the measurement data and convert it to common units.
uint16_t co2Raw; // ppm
int32_t temperatureRaw; // millicelsius
int32_t humidityRaw; // millipercent
status = scd4x_read_measurement(&co2Raw, &temperatureRaw, &humidityRaw);
if (status) {
printf("Unable to read measurement data. Error: %d\n", status);
return status;
}

// Get the ticks. The scd4x_read_measurement function is giving
// incorrect data due to the arthimetic
uint16_t co2;
uint16_t temp;
uint16_t humidity;
status1 = scd4x_read_measurement_ticks(&co2, &temp, &humidity);

// Arithemtic to change raw data into information
int tempInCelsius = -45 + 175 * temp / 65536;
int tempInFarenheit = tempInCelsius * 1.8 + 32;
int humidityPercent = 100 * humidity / 65536;

// Print results to terminal (output)
printf("C:%d,T:%d,H:%d", co2, tempInFarenheit, humidityPercent);
const int co2Ppm = co2Raw;
const float temperatureCelsius = temperatureRaw / 1000.0f;
const float temperatureFahrenheit = temperatureCelsius * 1.8f + 32;
const float humidityPercent = humidityRaw / 1000.0f;

// Sleep for 5 seconds.
sleep_ms(5000);
printf("CO2: %d ppm, Temperature: %.1f C (%.1f F), Humidity: %.1f%%\n",
co2Ppm, temperatureCelsius, temperatureFahrenheit, humidityPercent);
}
}
70 changes: 12 additions & 58 deletions sample-implementations/RaspberryPi_Pico/sensirion_i2c_hal.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#include <hardware/i2c.h>
/*
* Copyright (c) 2018, Sensirion AG
* All rights reserved.
Expand Down Expand Up @@ -30,49 +29,12 @@
* POSSIBILITY OF SUCH DAMAGE.
*/

#include "sensirion_common.h"
#include "sensirion_config.h"
#include "sensirion_i2c_hal.h"

/*
* INSTRUCTIONS
* ============
*
* Implement all functions where they are marked as IMPLEMENT.
* Follow the function specification in the comments.
*/

/**
* Select the current i2c bus by index.
* All following i2c operations will be directed at that bus.
*
* THE IMPLEMENTATION IS OPTIONAL ON SINGLE-BUS SETUPS (all sensors on the same
* bus)
*
* @param bus_idx Bus index to select
* @returns 0 on success, an error code otherwise
*/
int16_t sensirion_i2c_hal_select_bus(uint8_t bus_idx) {
/* TODO:IMPLEMENT or leave empty if all sensors are located on one single
* bus
*/
return NOT_IMPLEMENTED_ERROR;
}

/**
* Initialize all hard- and software components that are needed for the I2C
* communication.
*/
void sensirion_i2c_hal_init(void) {
/* TODO:IMPLEMENT */
}
#include "../../sensirion_common.h"
#include "../../sensirion_config.h"
#include "../../sensirion_i2c_hal.h"

/**
* Release all resources initialized by sensirion_i2c_hal_init().
*/
void sensirion_i2c_hal_free(void) {
/* TODO:IMPLEMENT or leave empty if no resources need to be freed */
}
#include <hardware/i2c.h>
#include <pico/time.h>

/**
* Execute one read transaction on the I2C bus, reading a given number of bytes.
Expand All @@ -85,11 +47,8 @@ void sensirion_i2c_hal_free(void) {
* @returns 0 on success, error code otherwise
*/
int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
int status = i2c_read_blocking(i2c_default, address, data, count, false);
if (status == 0)
return 1;
else
return 0;
const bool nostop = true; // master retains control of the bus after the read
return !i2c_read_blocking(i2c_default, address, data, count, nostop);
}

/**
Expand All @@ -105,13 +64,8 @@ int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
*/
int8_t sensirion_i2c_hal_write(uint8_t address, const uint8_t* data,
uint16_t count) {
// I2C Default is used (I2C0).
int status = i2c_write_blocking(i2c_default, address, data, count, true);

if (status == 0)
return 1;
else
return 0;
const bool nostop = true; // master retains control of the bus after the write
return !i2c_write_blocking(i2c_default, address, data, count, nostop);
}

/**
Expand All @@ -120,8 +74,8 @@ int8_t sensirion_i2c_hal_write(uint8_t address, const uint8_t* data,
*
* Despite the unit, a <10 millisecond precision is sufficient.
*
* @param useconds the sleep time in microseconds
* @param microseconds the sleep time in microseconds
*/
void sensirion_i2c_hal_sleep_usec(uint32_t useconds) {
sleep_ms(useconds / 1000);
void sensirion_i2c_hal_sleep_usec(uint32_t microseconds) {
sleep_us(microseconds);
}