Skip to content

Commit 455a41c

Browse files
authored
Merge pull request #10 from dgoffredo/pico-cleanup
Revise the Raspberry Pi Pico sample implementation
2 parents 7d01aec + 33cdddf commit 455a41c

File tree

5 files changed

+131
-123
lines changed

5 files changed

+131
-123
lines changed

sample-implementations/RaspberryPi_Pico/cMakeLists.txt renamed to sample-implementations/RaspberryPi_Pico/CMakeLists.txt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,21 @@ pico_sdk_init()
66

77
set(CMAKE_C_STANDARD 11)
88
set(CMAKE_CXX_STANDARD 17)
9+
add_compile_options(-Wall -Wextra -Werror)
910
add_executable(main
1011
main.c
11-
sensirion_i2c.c
12-
sensirion_i2c.hal.c
13-
scd4x_i2c.c
14-
sensirion_common.c)
12+
../../sensirion_i2c.c
13+
sensirion_i2c_hal.c
14+
../../scd4x_i2c.c
15+
../../sensirion_common.c)
1516

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

20+
# use USB for stdin/stdout, rather than using UART
1921
pico_enable_stdio_usb(main 1)
20-
2122
pico_enable_stdio_uart(main 0)
2223

2324
# create map/bin/hex file etc.
2425
pico_add_extra_outputs(main)
25-
26+
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
SCD4x on the Raspberry Pi Pico
2+
==============================
3+
<img alt="Pico W with an SCD41 connected" src="hardware.jpg" height="400"/>
4+
5+
In this example, an SCD41 is connected to a Raspberry Pi Pico W on GPIO pins 12
6+
(I2C0 SDA) and 13 (I2C0 SCL). The same code will work for any variant of the
7+
Pico.
8+
9+
The following shell session is from an Ubuntu machine that had the Pico plugged
10+
in to USB in boot select mode.
11+
12+
```console
13+
$ ls
14+
CMakeLists.txt hardware.jpg main.c README.md sensirion_i2c_hal.c
15+
16+
$ mkdir build
17+
18+
$ cd build
19+
20+
$ cmake -DPICO_SDK_PATH=$HOME/src/pico-sdk ..
21+
[...]
22+
23+
$ make -j
24+
[...]
25+
26+
$ ls
27+
CMakeCache.txt cmake_install.cmake generated main.dis main.elf.map main.uf2 pico-sdk
28+
CMakeFiles elf2uf2 main.bin main.elf main.hex Makefile pioasm
29+
30+
$ cp main.uf2 /media/$USER/RPI-RP2
31+
32+
$ screen /dev/ttyACM0
33+
The I2C baudrate is 399361 Hz
34+
Sensor serial number is: 0x8a7e 0xbb07 0x3ba0
35+
CO2: 1111 ppm, Temperature: 28.4 C (83.1 F), Humidity: 60.4%
36+
CO2: 1080 ppm, Temperature: 28.5 C (83.2 F), Humidity: 61.1%
37+
CO2: 1070 ppm, Temperature: 28.4 C (83.1 F), Humidity: 61.7%
38+
[...]
39+
```
Loading
Lines changed: 69 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,89 @@
1+
#include "../../scd4x_i2c.h"
12

3+
#include <hardware/i2c.h>
4+
#include <pico/stdlib.h>
5+
#include <pico/time.h>
26

3-
#include "hardware/i2c.h"
4-
#include "pico/binary_info.h"
5-
#include "pico/stdlib.h"
6-
#include "scd4x_i2c.h"
77
#include <stdio.h>
88

9-
/// I2C address
10-
static int addr = 0x62;
11-
12-
// I2C Pins
13-
static uint sda_pin = 16;
14-
static uint scl_pin = 17;
15-
16-
// This is the main entry for your c application. U
17-
// is
18-
int main() {
19-
9+
int main(void) {
2010
stdio_init_all();
2111

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

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

31-
int status = 0;
27+
// Initialize driver with i2c address
28+
scd4x_init(SCD41_I2C_ADDR_62);
3229

33-
// Stop any readings if occuring
34-
status = scd4x_stop_periodic_measurement();
30+
int status;
3531

36-
// Perform self test
37-
uint16_t* selfTest = 0;
38-
scd4x_perform_self_test(selfTest);
39-
40-
// Get Serial number 3 parts
41-
uint16_t one;
42-
uint16_t two;
43-
uint16_t three;
32+
// Stop any ongoing measurement.
33+
status = scd4x_stop_periodic_measurement();
34+
if (status) {
35+
printf("Unable to stop measurement. Error: %d\n", status);
36+
return status;
37+
}
4438

45-
scd4x_get_serial_number(&one, &two, &three);
39+
// Get serial number.
40+
uint16_t serial_number[3] = {0};
41+
status = scd4x_get_serial_number(serial_number, 3);
42+
if (status) {
43+
printf("Unable to get sensor serial number. Error: %d\n", status);
44+
return status;
45+
}
46+
printf("Sensor serial number is: 0x%x 0x%x 0x%x\n", (int)serial_number[0],
47+
(int)serial_number[1], (int)serial_number[2]);
4648

4749
// Start the readings.
48-
status1 = scd4x_start_periodic_measurement();
49-
50-
while (1) {
50+
status = scd4x_start_periodic_measurement();
51+
if (status) {
52+
printf("Unable to start periodic measurement. Error %d\n", status);
53+
return status;
54+
}
5155

52-
// Check if data is ready to read
56+
for (;;) {
57+
// Wait for the measurement to complete.
58+
sleep_ms(5000 - 10);
5359
bool dataReady;
54-
while (dataReady == false) {
55-
56-
status1 = scd4x_get_data_ready_flag(&dataReady);
60+
do {
61+
sleep_ms(10);
62+
status = scd4x_get_data_ready_status(&dataReady);
63+
if (status) {
64+
printf("Unable to get sensor readiness status. Error %d.\n",
65+
status);
66+
return status;
67+
}
68+
} while (!dataReady);
69+
70+
// Read the measurement data and convert it to common units.
71+
uint16_t co2Raw; // ppm
72+
int32_t temperatureRaw; // millicelsius
73+
int32_t humidityRaw; // millipercent
74+
status = scd4x_read_measurement(&co2Raw, &temperatureRaw, &humidityRaw);
75+
if (status) {
76+
printf("Unable to read measurement data. Error: %d\n", status);
77+
return status;
5778
}
5879

59-
// Get the ticks. The scd4x_read_measurement function is giving
60-
// incorrect data due to the arthimetic
61-
uint16_t co2;
62-
uint16_t temp;
63-
uint16_t humidity;
64-
status1 = scd4x_read_measurement_ticks(&co2, &temp, &humidity);
65-
66-
// Arithemtic to change raw data into information
67-
int tempInCelsius = -45 + 175 * temp / 65536;
68-
int tempInFarenheit = tempInCelsius * 1.8 + 32;
69-
int humidityPercent = 100 * humidity / 65536;
70-
71-
// Print results to terminal (output)
72-
printf("C:%d,T:%d,H:%d", co2, tempInFarenheit, humidityPercent);
80+
const int co2Ppm = co2Raw;
81+
const float temperatureCelsius = temperatureRaw / 1000.0f;
82+
const float temperatureFahrenheit = temperatureCelsius * 1.8f + 32;
83+
const float humidityPercent = humidityRaw / 1000.0f;
7384

74-
// Sleep for 5 seconds.
75-
sleep_ms(5000);
85+
printf("CO2: %d ppm, Temperature: %.1f C (%.1f F), Humidity: %.1f%%\n",
86+
co2Ppm, temperatureCelsius, temperatureFahrenheit,
87+
humidityPercent);
7688
}
7789
}
Lines changed: 16 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#include <hardware/i2c.h>
21
/*
32
* Copyright (c) 2018, Sensirion AG
43
* All rights reserved.
@@ -30,49 +29,12 @@
3029
* POSSIBILITY OF SUCH DAMAGE.
3130
*/
3231

33-
#include "sensirion_common.h"
34-
#include "sensirion_config.h"
35-
#include "sensirion_i2c_hal.h"
36-
37-
/*
38-
* INSTRUCTIONS
39-
* ============
40-
*
41-
* Implement all functions where they are marked as IMPLEMENT.
42-
* Follow the function specification in the comments.
43-
*/
44-
45-
/**
46-
* Select the current i2c bus by index.
47-
* All following i2c operations will be directed at that bus.
48-
*
49-
* THE IMPLEMENTATION IS OPTIONAL ON SINGLE-BUS SETUPS (all sensors on the same
50-
* bus)
51-
*
52-
* @param bus_idx Bus index to select
53-
* @returns 0 on success, an error code otherwise
54-
*/
55-
int16_t sensirion_i2c_hal_select_bus(uint8_t bus_idx) {
56-
/* TODO:IMPLEMENT or leave empty if all sensors are located on one single
57-
* bus
58-
*/
59-
return NOT_IMPLEMENTED_ERROR;
60-
}
61-
62-
/**
63-
* Initialize all hard- and software components that are needed for the I2C
64-
* communication.
65-
*/
66-
void sensirion_i2c_hal_init(void) {
67-
/* TODO:IMPLEMENT */
68-
}
32+
#include "../../sensirion_i2c_hal.h"
33+
#include "../../sensirion_common.h"
34+
#include "../../sensirion_config.h"
6935

70-
/**
71-
* Release all resources initialized by sensirion_i2c_hal_init().
72-
*/
73-
void sensirion_i2c_hal_free(void) {
74-
/* TODO:IMPLEMENT or leave empty if no resources need to be freed */
75-
}
36+
#include <hardware/i2c.h>
37+
#include <pico/time.h>
7638

7739
/**
7840
* Execute one read transaction on the I2C bus, reading a given number of bytes.
@@ -84,12 +46,10 @@ void sensirion_i2c_hal_free(void) {
8446
* @param count number of bytes to read from I2C and store in the buffer
8547
* @returns 0 on success, error code otherwise
8648
*/
87-
int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
88-
int status = i2c_read_blocking(i2c_default, address, data, count, false);
89-
if (status == 0)
90-
return 1;
91-
else
92-
return 0;
49+
int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint8_t count) {
50+
const bool nostop =
51+
true; // master retains control of the bus after the read
52+
return !i2c_read_blocking(i2c_default, address, data, count, nostop);
9353
}
9454

9555
/**
@@ -104,14 +64,10 @@ int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) {
10464
* @returns 0 on success, error code otherwise
10565
*/
10666
int8_t sensirion_i2c_hal_write(uint8_t address, const uint8_t* data,
107-
uint16_t count) {
108-
// I2C Default is used (I2C0).
109-
int status = i2c_write_blocking(i2c_default, address, data, count, true);
110-
111-
if (status == 0)
112-
return 1;
113-
else
114-
return 0;
67+
uint8_t count) {
68+
const bool nostop =
69+
true; // master retains control of the bus after the write
70+
return !i2c_write_blocking(i2c_default, address, data, count, nostop);
11571
}
11672

11773
/**
@@ -120,8 +76,8 @@ int8_t sensirion_i2c_hal_write(uint8_t address, const uint8_t* data,
12076
*
12177
* Despite the unit, a <10 millisecond precision is sufficient.
12278
*
123-
* @param useconds the sleep time in microseconds
79+
* @param microseconds the sleep time in microseconds
12480
*/
125-
void sensirion_i2c_hal_sleep_usec(uint32_t useconds) {
126-
sleep_ms(useconds / 1000);
81+
void sensirion_i2c_hal_sleep_usec(uint32_t microseconds) {
82+
sleep_us(microseconds);
12783
}

0 commit comments

Comments
 (0)