From 57a75bf43a1bb5ff7a21d1eb73838a93923cf1a5 Mon Sep 17 00:00:00 2001 From: Joey Pongallo Date: Sat, 3 Sep 2022 01:28:14 -0400 Subject: [PATCH 1/4] Added Sample Implementations for Raspberry Pi Pico --- .../RaspberryPi_Pico/cMakeLists.txt | 25 ++++ .../RaspberryPi_Pico/main.c | 79 +++++++++++ .../RaspberryPi_Pico/sensirion_i2c_hal.c | 126 ++++++++++++++++++ 3 files changed, 230 insertions(+) create mode 100644 sample-implementations/RaspberryPi_Pico/cMakeLists.txt create mode 100644 sample-implementations/RaspberryPi_Pico/main.c create mode 100644 sample-implementations/RaspberryPi_Pico/sensirion_i2c_hal.c diff --git a/sample-implementations/RaspberryPi_Pico/cMakeLists.txt b/sample-implementations/RaspberryPi_Pico/cMakeLists.txt new file mode 100644 index 0000000..4a9c75a --- /dev/null +++ b/sample-implementations/RaspberryPi_Pico/cMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.12) +include(${PICO_SDK_PATH}/pico_sdk_init.cmake) + +project(SCD4XSensor C CXX ASM) +pico_sdk_init() + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +add_executable(main + main.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) + +pico_enable_stdio_usb(main 1) + +pico_enable_stdio_uart(main 0) + +# create map/bin/hex file etc. +pico_add_extra_outputs(main) + diff --git a/sample-implementations/RaspberryPi_Pico/main.c b/sample-implementations/RaspberryPi_Pico/main.c new file mode 100644 index 0000000..b144d94 --- /dev/null +++ b/sample-implementations/RaspberryPi_Pico/main.c @@ -0,0 +1,79 @@ + + +#include "hardware/i2c.h" +#include "pico/binary_info.h" +#include "pico/stdlib.h" +#include "scd4x_i2c.h" +#include + +/// 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() { + + 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); + + // 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. + + int status = 0; + + // Stop any readings if occuring + status = scd4x_stop_periodic_measurement(); + + // 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; + + scd4x_get_serial_number(&one, &two, &three); + + // Start the readings. + status1 = scd4x_start_periodic_measurement(); + + while (1) { + + // Check if data is ready to read + bool dataReady; + while (dataReady == false) { + + status1 = scd4x_get_data_ready_flag(&dataReady); + } + + // 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); + + // Sleep for 5 seconds. + sleep_ms(5000); + } +} + + \ No newline at end of file diff --git a/sample-implementations/RaspberryPi_Pico/sensirion_i2c_hal.c b/sample-implementations/RaspberryPi_Pico/sensirion_i2c_hal.c new file mode 100644 index 0000000..46116e8 --- /dev/null +++ b/sample-implementations/RaspberryPi_Pico/sensirion_i2c_hal.c @@ -0,0 +1,126 @@ +#include +/* + * Copyright (c) 2018, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * 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 */ +} + +/** + * 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 */ +} + +/** + * Execute one read transaction on the I2C bus, reading a given number of bytes. + * If the device does not acknowledge the read command, an error shall be + * returned. + * + * @param address 7-bit I2C address to read from + * @param data pointer to the buffer where the data is to be stored + * @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; +} + +/** + * Execute one write transaction on the I2C bus, sending a given number of + * bytes. The bytes in the supplied buffer must be sent to the given address. If + * the slave device does not acknowledge any of the bytes, an error shall be + * returned. + * + * @param address 7-bit I2C address to write to + * @param data pointer to the buffer containing the data to write + * @param count number of bytes to read from the buffer and send over I2C + * @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; +} + +/** + * Sleep for a given number of microseconds. The function should delay the + * execution for at least the given time, but may also sleep longer. + * + * Despite the unit, a <10 millisecond precision is sufficient. + * + * @param useconds the sleep time in microseconds + */ +void sensirion_i2c_hal_sleep_usec(uint32_t useconds) { + sleep_ms(useconds / 1000); +} From 25221a5be515b3038fb4f5ed5fff0b1b76f2725c Mon Sep 17 00:00:00 2001 From: exzile Date: Sat, 3 Sep 2022 01:33:22 -0400 Subject: [PATCH 2/4] Update README.md --- README.md | 105 +----------------------------------------------------- 1 file changed, 1 insertion(+), 104 deletions(-) diff --git a/README.md b/README.md index 6586695..ee93469 100644 --- a/README.md +++ b/README.md @@ -1,104 +1 @@ -# Sensirion Embedded I2C SCD4x Driver - -This is a generic embedded driver for the [Sensirion SCD4x Carbon Dioxide Sensor](https://www.sensirion.com/scd4x/). -It enables developers to communicate with the SCD4x sensor on different hardware platforms by only adapting the I2C communication related source files. - -[
](https://sensirion.com/my-scd-ek) - -# Getting started - -## Implement the I2C Interface - -So we need to adjust two files according to your platform. - -### Edit `sensirion_i2c_hal.c` - -This file contains the implementation of the sensor communication -(how to send requests to the sensor). Therefore, how this is done depends on your -hardware platform. Therefore we can only provide function stubs in which you -can implement the logic yourself. -There are sample implementations available for some platforms: [`sample-implementations`](sample-implementations). -If you are using a Linux based platform like Raspberry Pi -you can just replace the unimplemented HAL template with the provided -implementation in `sample-implementations/linux_user_space/`: - -``` -cp sample-implementations/linux_user_space/sensirion_i2c_hal.c ./ -``` - -### Edit `sensirion_config.h` - -If you are on a Linux based platform you can skip this part since -everything is already correctly setup for you. - -Otherwise you need to check if the libraries `` and -`` are provided by your toolchain, compiler or system. -If you have no idea on how to do that you can skip this -step for now and come back when you get errors related to these names when -compiling the driver. -The features we use out of those libraries are standard integer sizes -from `` and `NULL` from ``. If they are not available -you need to specify the following integer types yourself: - -* `int64_t` = signed 64bit integer -* `uint64_t` = unsigned 64bit integer -* `int32_t` = signed 32bit integer -* `uint32_t` = unsigned 32bit integer -* `int16_t` = signed 16bit integer -* `uint16_t` = unsigned 16bit integer -* `int8_t` = signed 8bit integer -* `uint8_t` = unsigned 8bit integer - -In addition to that you will need to specify `NULL`. -For both we have a detailed template where you just need to fill in -your system specific values. - -Now we are ready to compile and run the example usage for your sensor. - -## Compile and Run - -Take the `.c` and `.h` files directly in this folder pass them to your -favorite C compiler and run the resulting binary. -This step may vary, depending on your platform. Here we demonstrate the -procedure for Linux based platforms: - -1. Open up a terminal. -2. Navigate to the directory where this README is located. -3. Run `make` (this compiles all the code here to one binary). -4. Run `./scd4x_i2c_example_usage` (This will run your newly compiled binary). -5. Now you should see the first measurement values appear in your terminal. - As a next step you can adjust the example usage file or write your own - main function to use the sensor. - -# Background - -## Files - -### sensirion\_i2c.[ch] - -In these files you can find the implementation of the I2C protocol used by Sensirion -sensors. The functions in these files are used by the embedded driver to build the -correct frame out of data to be sent to the sensor or receive a frame of data from -the sensor and convert it back to data readable by your machine. The functions in -here calculate and check CRCs, reorder bytes for different byte orders and build the -correct formatted frame for your sensor. - -### sensirion\_i2c\_hal.[ch] - -In these files you can find the implementation of the hardware abstraction layer used -by Sensirion's I2C embedded drivers. This part of the code is specific to the underlying -hardware platform. This is an unimplemented template for the user to implement. -In the `sample-implementations/` folder we provide implementations for the most common -platforms. - -### sensirion\_config.h - -In this file we keep all the included libraries for our drivers and global defines. -Next to `sensirion_i2c_hal.c` *it's the only file you should need to edit to get your -driver working.* - -### sensirion\_common.[ch] - -In these files you can find some helper functions used by Sensirion's embedded drivers. -It mostly contains byte order conversions for different variable types. These functions -are also used by the UART embedded drivers therefore they are kept in their own file. +This a fork that can be used for the Raspberry Pi Pico. The files are in the implementation folder to get started. From aa01802942b9a7f6035f519465d00384f835d653 Mon Sep 17 00:00:00 2001 From: exzile Date: Sat, 3 Sep 2022 01:36:41 -0400 Subject: [PATCH 3/4] Update README.md --- README.md | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ee93469..6586695 100644 --- a/README.md +++ b/README.md @@ -1 +1,104 @@ -This a fork that can be used for the Raspberry Pi Pico. The files are in the implementation folder to get started. +# Sensirion Embedded I2C SCD4x Driver + +This is a generic embedded driver for the [Sensirion SCD4x Carbon Dioxide Sensor](https://www.sensirion.com/scd4x/). +It enables developers to communicate with the SCD4x sensor on different hardware platforms by only adapting the I2C communication related source files. + +[
](https://sensirion.com/my-scd-ek) + +# Getting started + +## Implement the I2C Interface + +So we need to adjust two files according to your platform. + +### Edit `sensirion_i2c_hal.c` + +This file contains the implementation of the sensor communication +(how to send requests to the sensor). Therefore, how this is done depends on your +hardware platform. Therefore we can only provide function stubs in which you +can implement the logic yourself. +There are sample implementations available for some platforms: [`sample-implementations`](sample-implementations). +If you are using a Linux based platform like Raspberry Pi +you can just replace the unimplemented HAL template with the provided +implementation in `sample-implementations/linux_user_space/`: + +``` +cp sample-implementations/linux_user_space/sensirion_i2c_hal.c ./ +``` + +### Edit `sensirion_config.h` + +If you are on a Linux based platform you can skip this part since +everything is already correctly setup for you. + +Otherwise you need to check if the libraries `` and +`` are provided by your toolchain, compiler or system. +If you have no idea on how to do that you can skip this +step for now and come back when you get errors related to these names when +compiling the driver. +The features we use out of those libraries are standard integer sizes +from `` and `NULL` from ``. If they are not available +you need to specify the following integer types yourself: + +* `int64_t` = signed 64bit integer +* `uint64_t` = unsigned 64bit integer +* `int32_t` = signed 32bit integer +* `uint32_t` = unsigned 32bit integer +* `int16_t` = signed 16bit integer +* `uint16_t` = unsigned 16bit integer +* `int8_t` = signed 8bit integer +* `uint8_t` = unsigned 8bit integer + +In addition to that you will need to specify `NULL`. +For both we have a detailed template where you just need to fill in +your system specific values. + +Now we are ready to compile and run the example usage for your sensor. + +## Compile and Run + +Take the `.c` and `.h` files directly in this folder pass them to your +favorite C compiler and run the resulting binary. +This step may vary, depending on your platform. Here we demonstrate the +procedure for Linux based platforms: + +1. Open up a terminal. +2. Navigate to the directory where this README is located. +3. Run `make` (this compiles all the code here to one binary). +4. Run `./scd4x_i2c_example_usage` (This will run your newly compiled binary). +5. Now you should see the first measurement values appear in your terminal. + As a next step you can adjust the example usage file or write your own + main function to use the sensor. + +# Background + +## Files + +### sensirion\_i2c.[ch] + +In these files you can find the implementation of the I2C protocol used by Sensirion +sensors. The functions in these files are used by the embedded driver to build the +correct frame out of data to be sent to the sensor or receive a frame of data from +the sensor and convert it back to data readable by your machine. The functions in +here calculate and check CRCs, reorder bytes for different byte orders and build the +correct formatted frame for your sensor. + +### sensirion\_i2c\_hal.[ch] + +In these files you can find the implementation of the hardware abstraction layer used +by Sensirion's I2C embedded drivers. This part of the code is specific to the underlying +hardware platform. This is an unimplemented template for the user to implement. +In the `sample-implementations/` folder we provide implementations for the most common +platforms. + +### sensirion\_config.h + +In this file we keep all the included libraries for our drivers and global defines. +Next to `sensirion_i2c_hal.c` *it's the only file you should need to edit to get your +driver working.* + +### sensirion\_common.[ch] + +In these files you can find some helper functions used by Sensirion's embedded drivers. +It mostly contains byte order conversions for different variable types. These functions +are also used by the UART embedded drivers therefore they are kept in their own file. From 896ff77f9ba755f4305e4d2c96b7c2add98b330a Mon Sep 17 00:00:00 2001 From: Pascal Sachs Date: Mon, 18 Dec 2023 11:12:42 +0100 Subject: [PATCH 4/4] Fix Raspi Pic formatting --- sample-implementations/RaspberryPi_Pico/main.c | 10 ++++------ .../RaspberryPi_Pico/sensirion_i2c_hal.c | 3 ++- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/sample-implementations/RaspberryPi_Pico/main.c b/sample-implementations/RaspberryPi_Pico/main.c index b144d94..195febe 100644 --- a/sample-implementations/RaspberryPi_Pico/main.c +++ b/sample-implementations/RaspberryPi_Pico/main.c @@ -12,7 +12,6 @@ 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 @@ -50,14 +49,15 @@ int main() { while (1) { - // Check if data is ready to read + // Check if data is ready to read bool dataReady; while (dataReady == false) { status1 = scd4x_get_data_ready_flag(&dataReady); } - // Get the ticks. The scd4x_read_measurement function is giving incorrect data due to the arthimetic + // 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; @@ -70,10 +70,8 @@ int main() { // Print results to terminal (output) printf("C:%d,T:%d,H:%d", co2, tempInFarenheit, humidityPercent); - + // Sleep for 5 seconds. sleep_ms(5000); } } - - \ No newline at end of file diff --git a/sample-implementations/RaspberryPi_Pico/sensirion_i2c_hal.c b/sample-implementations/RaspberryPi_Pico/sensirion_i2c_hal.c index 46116e8..d7299ba 100644 --- a/sample-implementations/RaspberryPi_Pico/sensirion_i2c_hal.c +++ b/sample-implementations/RaspberryPi_Pico/sensirion_i2c_hal.c @@ -103,7 +103,8 @@ int8_t sensirion_i2c_hal_read(uint8_t address, uint8_t* data, uint16_t count) { * @param count number of bytes to read from the buffer and send over I2C * @returns 0 on success, error code otherwise */ -int8_t sensirion_i2c_hal_write(uint8_t address, const 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);