Skip to content

Commit

Permalink
Merge pull request #10 from dgoffredo/pico-cleanup
Browse files Browse the repository at this point in the history
Revise the Raspberry Pi Pico sample implementation
  • Loading branch information
LeonieFierz authored Feb 10, 2025
2 parents 7d01aec + 33cdddf commit 455a41c
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 123 deletions.
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.
126 changes: 69 additions & 57 deletions sample-implementations/RaspberryPi_Pico/main.c
Original file line number Diff line number Diff line change
@@ -1,77 +1,89 @@
#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;
// Initialize driver with i2c address
scd4x_init(SCD41_I2C_ADDR_62);

// Stop any readings if occuring
status = scd4x_stop_periodic_measurement();
int status;

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

// Get Serial number 3 parts
uint16_t one;
uint16_t two;
uint16_t three;
// Stop any ongoing measurement.
status = scd4x_stop_periodic_measurement();
if (status) {
printf("Unable to stop measurement. Error: %d\n", status);
return status;
}

scd4x_get_serial_number(&one, &two, &three);
// Get serial number.
uint16_t serial_number[3] = {0};
status = scd4x_get_serial_number(serial_number, 3);
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)serial_number[0],
(int)serial_number[1], (int)serial_number[2]);

// 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_status(&dataReady);
if (status) {
printf("Unable to get sensor readiness status. 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);
}
}
76 changes: 16 additions & 60 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_i2c_hal.h"
#include "../../sensirion_common.h"
#include "../../sensirion_config.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 @@ -84,12 +46,10 @@ void sensirion_i2c_hal_free(void) {
* @param count number of bytes to read from I2C and store in the buffer
* @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;
int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint8_t count) {
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 @@ -104,14 +64,10 @@ int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
* @returns 0 on success, error code otherwise
*/
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;
uint8_t count) {
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 +76,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);
}

0 comments on commit 455a41c

Please sign in to comment.