diff --git a/.github/workflows/check_and_build.yml b/.github/workflows/check_and_build.yml index 50429b4..73dcf4e 100644 --- a/.github/workflows/check_and_build.yml +++ b/.github/workflows/check_and_build.yml @@ -28,6 +28,14 @@ jobs: export PATH=$PATH:$CLI_PATH curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=$CLI_PATH sh - - name: build sketch + - name: build arduino r4 sketch run: | - ${CLI_PATH}/arduino-cli compile --profile arduino-uno-r4 ./differentI2cBusesExample \ No newline at end of file + ${CLI_PATH}/arduino-cli compile --profile arduino-uno-r4 ./exampleArduinoUnoR4 + + - name: build ESP32 DevKit sketch + run: | + ${CLI_PATH}/arduino-cli compile --profile esp32-devkitC-v4 ./exampleESP32DevKitCV4 + + - name: build Nucleo sketch + run: | + ${CLI_PATH}/arduino-cli compile --profile stm32-nucleo64 ./exampleSTM32Nucleo64 \ No newline at end of file diff --git a/README.md b/README.md index 21b9311..761ba07 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,8 @@ I2C bus B. ### Pull-up resistors -Having pull-up resistors in place on the I2C data (SDA) and clock (SCL) lines is important to have a good signal quality and robust communication. You can read more about it on [I2C Pull-Up Resistors Intro](i2c-pull-up-resistors-intro.md) +Having pull-up resistors in place on the I2C data (SDA) and clock (SCL) lines is important to have a good signal quality and robust communication. +You can read more about it on [I2C Pull-Up Resistors Intro](i2c-pull-up-resistors-intro.md) The ESP32 DevKitC Board ensures that GPIO lines are automatically pulled to a high state. Therefore, there is no need to manually wire or configure pull-up resistors for the pins you intend to use. @@ -42,15 +43,17 @@ For this example, the wiring should be carried out as follows: ![Wiring diagram SEK SCD41 to ESP32 DevKitC](images/wiringTwoSCD41ToESP.png) -- SEK-SCD41 A - Pin 1 to ESP32 Pin 22 (SCL, yellow cable) -- SEK-SCD41 A - Pin 2 to ESP32 GND (Ground, black cable) -- SEK-SCD41 A - Pin 3 to ESP32 3V3 (Sensor supply voltage, red cable) -- SEK-SCD41 A - Pin 4 to ESP32 Pin 21 (SDA, green cable) -- SEK-SCD41 B - Pin 1 to ESP32 Pin 17 (SCL, yellow cable) -- SEK-SCD41 B - Pin 2 to ESP32 GND (Ground, black cable) -- SEK-SCD41 B - Pin 3 to ESP32 5V (Sensor supply voltage, red cable) -- SEK-SCD41 B - Pin 4 to ESP32 Pin 16 (SDA, green cable) +| Sensor board | ESP32 | Cable color | Description | +|---------------------|--------|-------------|-------------| +| SEK-SCD41 A - Pin 1 | Pin 22 | yellow | SCL | +| SEK-SCD41 A - Pin 2 | GND | black | Ground | +| SEK-SCD41 A - Pin 3 | 3V3 | red | Sensor supply voltage 3-5V | +| SEK-SCD41 A - Pin 4 | Pin 21 | green | SDA | +| SEK-SCD41 B - Pin 1 | Pin 17 | yellow | SCL | +| SEK-SCD41 B - Pin 2 | GND | black | Ground | +| SEK-SCD41 B - Pin 3 | 5V | red | Sensor supply voltage 3-5V | +| SEK-SCD41 B - Pin 4 | Pin 16 | green | SDA | When configuring the software later on, it is important to remember the pins allocated for the second I2C bus. Specifically, we used pin 17 for the I2C clock (SCL) and pin 16 for the I2C data (SDA). @@ -112,8 +115,7 @@ You can find more details and options how to configure several I2C buses on the ## Example sketch -You find a complete example under [differentI2cBusesExample.ino](differentI2cBusesExample/differentI2cBusesExample.ino). -Make sure to only have the define for your board `#define ESP32_DEVKITC_V4 1` uncommented, which you find at the beginning of the sketch. +You find a complete example under [exampleESP32DevKitCV4](exampleESP32DevKitCV4/exampleESP32DevKitCV4.ino) # STM32 Nucleo 64 Board @@ -123,6 +125,10 @@ The STM32 Nucleo 64 board has pre-defined I2C pins. We use I2C1 (SDA on pin 14, I2C2 (SDA on pin 3, SCL on pin 6). ### Pull Ups + +Having pull-up resistors in place on the I2C data (SDA) and clock (SCL) lines is important to have a good signal quality and robust communication. +You can read more about it on [I2C Pull-Up Resistors Intro](i2c-pull-up-resistors-intro.md) + The Nucleo board nor the development kit board has pull-up resistors built in. Thus, we need to wire a resistor into each of the I2C communication lines. Four 8.26kOhm resistors were used in this example and the wiring was done using a bread board so that no soldering was needed. @@ -132,23 +138,24 @@ this example and the wiring was done using a bread board so that no soldering wa Names R.1 to R.4 stand for resistors with a value of 8.26kOhm. -- SEK-SCD41 A Pin 1 to R.1 (SCL, yellow) -- R.1 to Nucleo Pin 15 (SCL, yellow) -- R.1 to Nucleo 3V3 -- SEK-SCD41 A Pin 2 to Nucleo GND -- SEK-SCD41 A Pin 3 to Nucleo 3V3 -- SEK-SCD41 A Pin 4 to R.2 (SDA, green) -- R.2 to Nucleo Pin 14 (SDA, green) -- R.2 to Nucleo 3V3 - -- SEK-SCD41 B Pin 1 to R.3 (SCL, yellow) -- R.3 to Nucleo Pin 6 (SCL, yellow) -- R.3 to Nucleo 3V3 -- SEK-SCD41 B Pin 2 to Nucleo GND (Ground, black cable) -- SEK-SCD41 B Pin 3 to Nucleo 5V (Sensor supply voltage, red cable) -- SEK-SCD41 B Pin 4 to R.4 (SDA, green) -- R.4 to Nucleo Pin 3 (SDA, green) -- R.4 to Nucleo 3V3 +| Sensor Board / Resistor | STM32 Nucleo 64 / Resistor | Cable color | Description | +|--------------------------------|----------------------------|-------------|-------------| +| SEK-SCD41 A Pin 1 | R.1 | yellow | SCL | +| R.1 | Nucleo Pin 15 | yellow | SCL | +| R.1 | Nucleo 3V3 | | Reference Voltage | +| SEK-SCD41 A Pin 2 | Nucleo GND | black |Ground | +| SEK-SCD41 A Pin 3 | Nucleo 3V3 | red | Sensor Supply Voltage 3-5V | +| SEK-SCD41 A Pin 4 | R.2 | green | SDA | +| R.2 | Nucleo Pin 14 | green | SDA | +| R.2 | Nucleo 3V3 | | Reference Voltage | +| SEK-SCD41 B Pin 1 | R.3 | yellow | SCL | +| R.3 | Nucleo Pin 6 | yellow | SCL | +| R.3 | Nucleo 3V3 | | Reference Voltage | +| SEK-SCD41 B Pin 2 | Nucleo GND | black | Ground | +| SEK-SCD41 B Pin 3 | Nucleo 5V | red | Sensor supply voltage 3-5V | +| SEK-SCD41 B Pin 4 | R.4 | green | SDA | +| R.4 | Nucleo Pin 3 | green | SDA| +| R.4 | Nucleo 3V3 | | Reference Voltage | What we have to remember for the configuration in the software later is the pins we used for the I2C buses. @@ -203,8 +210,7 @@ sensorB.startMeasurement(); ## Example sketch -You find a complete example under [differentI2cBusesExample.ino](differentI2cBusesExample/differentI2cBusesExample.ino). -Make sure to only have the define for your board `#define STM32_NUCLEO_64 1` uncommented, which you find at the beginning of the sketch. +You find a complete example under [exampleSTM32Nucleo64](exampleSTM32Nucleo64/exampleSTM32Nucleo64.ino). # Arduino Uno R4 WIFI @@ -219,6 +225,9 @@ The board includes 10K pull-up on SDA and SCL. ### Pull Ups +Having pull-up resistors in place on the I2C data (SDA) and clock (SCL) lines is important to have a good signal quality and robust communication. +You can read more about it on [I2C Pull-Up Resistors Intro](i2c-pull-up-resistors-intro.md) + The Arduino Uno R4 WIFI provides no pull-ups on the board. The SEK SCD41 board we are going to connect to the I2C Bus on the pin header has no pull-up resistors built in. @@ -234,16 +243,17 @@ no pull-up resistors have to be wired into this connection, for which a Qwiic ca The list below describes the wiring, where R.1 and R.2 are resistors with a value of 8.26kOhm. -- SEK-SCD41 Pin 1 to R.1 (SCL, yellow) -- R.1 to Arduino Pin SCL (yellow) -- R.1 to Arduino 3V3 -- SEK-SCD41 Pin 2 to Arduino GND -- SEK-SCD41 Pin 3 to Arduino 3V3 -- SEK-SCD41 Pin 4 to R.2 (SDA, green) -- R.2 to Arduino Pin 14 (green) -- R.2 to Arduino 3V3 - -- Adafruit SCD41 to Arduino Qwiic +| Sensor board / Resistor | Arduino / Resistor | Cable color | Description | +|-------------------------|---------------------|-------------|-------------| +| SEK-SCD41 Pin 1 | R.1 | yellow | SCL | +| R.1 | Arduino Pin SCL |yellow | SCL | +| R.1 | Arduino 3V3 | | I2C reference voltage | +| SEK-SCD41 Pin 2 | Arduino GND | Ground | +| SEK-SCD41 Pin 3 | Arduino 3V3 | Sensor supply voltage 3-5V | +| SEK-SCD41 Pin 4 | R.2 | green | SDA | +| R.2 | Arduino Pin 14 | green | SDA | +| R.2 | Arduino 3V3 | | I2C reference voltage | +| Adafruit SCD41 (includes Pull-Ups) | Arduino Qwiic connector | | Qwiic cable with SCL, GND, VDD, SDA lines | ## Software setup @@ -293,8 +303,7 @@ sensorOnQwiic.startMeasurement(); ## Example sketch -You find a complete example under [differentI2cBusesExample.ino](differentI2cBusesExample/differentI2cBusesExample.ino). -Make sure to only have the define for your board `#define ARDUINO_UNO_R4_WIFI 1` uncommented, which you find at the beginning of the sketch. +You find a complete example under [exampleArduinoUnoR4](exampleArduinoUnoR4/exampleArduinoUnoR4.ino). # Other Arduino Boards diff --git a/exampleArduinoUnoR4/exampleArduinoUnoR4.ino b/exampleArduinoUnoR4/exampleArduinoUnoR4.ino new file mode 100644 index 0000000..7bc8db1 --- /dev/null +++ b/exampleArduinoUnoR4/exampleArduinoUnoR4.ino @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2025, 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 +#include +#include + +// macro definitions +// make sure that we use the proper definition of NO_ERROR +#ifdef NO_ERROR +#undef NO_ERROR +#endif +#define NO_ERROR 0 + +static char errorMessage[64]; +static int16_t error; + +SensirionI2cScd4x sensorA; +SensirionI2cScd4x sensorB; + +bool sensorAOk; +bool sensorBOk; + +void PrintUint64(uint64_t& value) { + Serial.print("0x"); + Serial.print((uint32_t)(value >> 32), HEX); + Serial.print((uint32_t)(value & 0xFFFFFFFF), HEX); +} + +bool initSensor(SensirionI2cScd4x sensor) { + uint64_t serialNumber = 0; + delay(30); + // Ensure sensor is in clean state + error = sensor.wakeUp(); + if (error != NO_ERROR) { + Serial.print("Error trying to execute wakeUp(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + } + error = sensor.stopPeriodicMeasurement(); + if (error != NO_ERROR) { + Serial.print("Error trying to execute stopPeriodicMeasurement(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + } + + error = sensor.reinit(); + if (error != NO_ERROR) { + Serial.print("Error trying to execute reinit(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + } + // Read out information about the sensor + error = sensor.getSerialNumber(serialNumber); + if (error != NO_ERROR) { + Serial.print("Error trying to execute getSerialNumber(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + return false; + } + Serial.print("serial number: "); + PrintUint64(serialNumber); + Serial.println(); + return true; +} + +bool startMeasurement(SensirionI2cScd4x sensor) { + error = sensor.startPeriodicMeasurement(); + if (error != NO_ERROR) { + Serial.print("Error trying to execute startPeriodicMeasurement(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + return false; + } + return true; +} + +// Read measurements from the sensor and print to the console +// The method blocks until measurements are ready +void readAndPrintMeasurement(SensirionI2cScd4x sensor) { + bool dataReady = false; + uint16_t co2Concentration = 0; + float temperature = 0.0; + float relativeHumidity = 0.0; + + error = sensor.getDataReadyStatus(dataReady); + if (error != NO_ERROR) { + Serial.print("Error trying to execute getDataReadyStatus(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + return; + } + while (!dataReady) { + delay(100); + error = sensor.getDataReadyStatus(dataReady); + if (error != NO_ERROR) { + Serial.print("Error trying to execute getDataReadyStatus(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + return; + } + } + error = + sensor.readMeasurement(co2Concentration, temperature, relativeHumidity); + if (error != NO_ERROR) { + Serial.print("Error trying to execute readMeasurement(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + return; + } + // + // Print results in physical units. + Serial.print("CO2 concentration [ppm]: "); + Serial.print(co2Concentration); + Serial.println(); + Serial.print("Temperature [°C]: "); + Serial.print(temperature); + Serial.println(); + Serial.print("Relative Humidity [RH]: "); + Serial.print(relativeHumidity); + Serial.println(); +} + +void initI2c() { + // initialize the first sensor (SEK-SCD41) on default I2C pins SDA (D18), SCL (D19) + Wire.begin(); + sensorA.begin(Wire, SCD41_I2C_ADDR_62); + + // initialize the second sensor (Adafruit SCD41 breakout board) on QWIIC connector + Wire1.begin(); + sensorB.begin(Wire1, SCD41_I2C_ADDR_62); + + Serial.println("I2C Buses configured for Arduino Uno R4 WIFI."); + Serial.print("I2C Bus A on pins SDA (D18), SCL (D19); I2C Bus B Qwiic Connector."); +} + + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(100); + } + + initI2c(); + + Serial.println("----SENSOR A-----"); + sensorAOk = initSensor(sensorA); + if (sensorAOk) { + sensorAOk = startMeasurement(sensorA); + } + + Serial.println("----SENSOR B-----"); + sensorBOk = initSensor(sensorB); + if (sensorBOk) { + sensorBOk = startMeasurement(sensorB); + } +} + +void loop() { + // + // Slow down the sampling to 0.2Hz. + // + delay(5000); + + if (sensorAOk) { + Serial.println("----SENSOR A-----"); + readAndPrintMeasurement(sensorA); + } + if (sensorBOk) { + Serial.println("----SENSOR B-----"); + readAndPrintMeasurement(sensorB); + } +} \ No newline at end of file diff --git a/differentI2cBusesExample/sketch.yaml b/exampleArduinoUnoR4/sketch.yaml similarity index 85% rename from differentI2cBusesExample/sketch.yaml rename to exampleArduinoUnoR4/sketch.yaml index 2deb4a2..9105bdc 100644 --- a/differentI2cBusesExample/sketch.yaml +++ b/exampleArduinoUnoR4/sketch.yaml @@ -5,4 +5,4 @@ profiles: - platform: arduino:renesas_uno (1.4.1) libraries: - Sensirion I2C SCD4x (1.0.0) - - Sensirion Core (0.7.0) \ No newline at end of file + - Sensirion Core (0.7.0) diff --git a/differentI2cBusesExample/differentI2cBusesExample.ino b/exampleESP32DevKitCV4/exampleESP32DevKitCV4.ino similarity index 83% rename from differentI2cBusesExample/differentI2cBusesExample.ino rename to exampleESP32DevKitCV4/exampleESP32DevKitCV4.ino index ea59abd..4337bf6 100644 --- a/differentI2cBusesExample/differentI2cBusesExample.ino +++ b/exampleESP32DevKitCV4/exampleESP32DevKitCV4.ino @@ -39,24 +39,6 @@ #endif #define NO_ERROR 0 - -// CHOOSE YOUR BOARD HERE - -//#define ESP32_DEVKITC_V4 1 -//#define STM32_NUCLEO_64 1 -#define ARDUINO_UNO_R4_WIFI 1 - -#if STM32_NUCLEO_64 - // I2C Bus on Pins 14 (SDA) / 15 (SCL) - const int sda_A = 14; - const int scl_A = 15; - TwoWire i2cBusA(sda_A, scl_A); - // I2C Bus on Pins 3 (SDA) / 6 (SCL) - const int sda_B = 3; - const int scl_B = 6; - TwoWire i2cBusB(sda_B, scl_B); -#endif - static char errorMessage[64]; static int16_t error; @@ -167,8 +149,6 @@ void readAndPrintMeasurement(SensirionI2cScd4x sensor) { } void initI2c() { - #if ESP32_DEVKITC_V4 - // initialize the first sensor on default I2C pins SDA Pin 21, SCL Pin 22 Wire.begin(); sensorA.begin(Wire, SCD41_I2C_ADDR_62); @@ -182,31 +162,6 @@ void initI2c() { Serial.println("I2C Buses configured for ESP32 DevKitC V4 Board."); Serial.printf("I2C Bus A SDA Pin 21, SCL Pin 22; I2C Bus B SDA Pin %i, SCL PIN %i\n", sda_B, scl_B); - - #elif STM32_NUCLEO_64 - - i2cBusA.begin(); - sensorA.begin(i2cBusA, SCD41_I2C_ADDR_62); - - i2cBusB.begin(); - sensorB.begin(i2cBusB, SCD41_I2C_ADDR_62); - - Serial.println("I2C Buses configured for STM32 Nucleo 64 Board."); - Serial.printf("I2C Bus A SDA Pin %i, SCL Pin %i; I2C Bus B SDA Pin %i, SCL PIN %i\n", sda_A, scl_A, sda_B, scl_B); - - #elif ARDUINO_UNO_R4_WIFI - // initialize the first sensor (SEK-SCD41) on default I2C pins SDA (D18), SCL (D19) - Wire.begin(); - sensorA.begin(Wire, SCD41_I2C_ADDR_62); - - // initialize the second sensor (Adafruit SCD41 breakout board) on QWIIC connector - Wire1.begin(); - sensorB.begin(Wire1, SCD41_I2C_ADDR_62); - - Serial.println("I2C Buses configured for Arduino Uno R4 WIFI."); - Serial.print("I2C Bus A on pins SDA (D18), SCL (D19); I2C Bus B Qwiic Connector."); - - #endif } @@ -216,8 +171,6 @@ void setup() { delay(100); } - // CONFIGURE YOUR BOARD AT THE BEGINNING OF THIS FILE - initI2c(); Serial.println("----SENSOR A-----"); diff --git a/exampleESP32DevKitCV4/sketch.yaml b/exampleESP32DevKitCV4/sketch.yaml new file mode 100644 index 0000000..17d7ab0 --- /dev/null +++ b/exampleESP32DevKitCV4/sketch.yaml @@ -0,0 +1,8 @@ +profiles: + esp32-devkitC-v4: + fqbn: esp32:esp32:esp32doit-devkit-v1 + platforms: + - platform: esp32:esp32 (3.1.3) + libraries: + - Sensirion I2C SCD4x (1.0.0) + - Sensirion Core (0.7.0) diff --git a/exampleSTM32Nucleo64/exampleSTM32Nucleo64.ino b/exampleSTM32Nucleo64/exampleSTM32Nucleo64.ino new file mode 100644 index 0000000..5aa3fcf --- /dev/null +++ b/exampleSTM32Nucleo64/exampleSTM32Nucleo64.ino @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2025, 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 +#include +#include + +// macro definitions +// make sure that we use the proper definition of NO_ERROR +#ifdef NO_ERROR +#undef NO_ERROR +#endif +#define NO_ERROR 0 + + +// Prepare I2C buses +// I2C Bus A on Pins 14 (SDA) / 15 (SCL) +const int sda_A = 14; +const int scl_A = 15; +TwoWire i2cBusA(sda_A, scl_A); +// I2C Bus B on Pins 3 (SDA) / 6 (SCL) +const int sda_B = 3; +const int scl_B = 6; +TwoWire i2cBusB(sda_B, scl_B); + + +static char errorMessage[64]; +static int16_t error; + +SensirionI2cScd4x sensorA; +SensirionI2cScd4x sensorB; + +bool sensorAOk; +bool sensorBOk; + +void PrintUint64(uint64_t& value) { + Serial.print("0x"); + Serial.print((uint32_t)(value >> 32), HEX); + Serial.print((uint32_t)(value & 0xFFFFFFFF), HEX); +} + +bool initSensor(SensirionI2cScd4x sensor) { + uint64_t serialNumber = 0; + delay(30); + // Ensure sensor is in clean state + error = sensor.wakeUp(); + if (error != NO_ERROR) { + Serial.print("Error trying to execute wakeUp(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + } + error = sensor.stopPeriodicMeasurement(); + if (error != NO_ERROR) { + Serial.print("Error trying to execute stopPeriodicMeasurement(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + } + + error = sensor.reinit(); + if (error != NO_ERROR) { + Serial.print("Error trying to execute reinit(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + } + // Read out information about the sensor + error = sensor.getSerialNumber(serialNumber); + if (error != NO_ERROR) { + Serial.print("Error trying to execute getSerialNumber(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + return false; + } + Serial.print("serial number: "); + PrintUint64(serialNumber); + Serial.println(); + return true; +} + +bool startMeasurement(SensirionI2cScd4x sensor) { + error = sensor.startPeriodicMeasurement(); + if (error != NO_ERROR) { + Serial.print("Error trying to execute startPeriodicMeasurement(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + return false; + } + return true; +} + +// Read measurements from the sensor and print to the console +// The method blocks until measurements are ready +void readAndPrintMeasurement(SensirionI2cScd4x sensor) { + bool dataReady = false; + uint16_t co2Concentration = 0; + float temperature = 0.0; + float relativeHumidity = 0.0; + + error = sensor.getDataReadyStatus(dataReady); + if (error != NO_ERROR) { + Serial.print("Error trying to execute getDataReadyStatus(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + return; + } + while (!dataReady) { + delay(100); + error = sensor.getDataReadyStatus(dataReady); + if (error != NO_ERROR) { + Serial.print("Error trying to execute getDataReadyStatus(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + return; + } + } + error = + sensor.readMeasurement(co2Concentration, temperature, relativeHumidity); + if (error != NO_ERROR) { + Serial.print("Error trying to execute readMeasurement(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + return; + } + // + // Print results in physical units. + Serial.print("CO2 concentration [ppm]: "); + Serial.print(co2Concentration); + Serial.println(); + Serial.print("Temperature [°C]: "); + Serial.print(temperature); + Serial.println(); + Serial.print("Relative Humidity [RH]: "); + Serial.print(relativeHumidity); + Serial.println(); +} + +void initI2c() { + i2cBusA.begin(); + sensorA.begin(i2cBusA, SCD41_I2C_ADDR_62); + + i2cBusB.begin(); + sensorB.begin(i2cBusB, SCD41_I2C_ADDR_62); + + Serial.println("I2C Buses configured for STM32 Nucleo 64 Board."); + Serial.printf("I2C Bus A SDA Pin %i, SCL Pin %i; I2C Bus B SDA Pin %i, SCL PIN %i\n", sda_A, scl_A, sda_B, scl_B); +} + + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(100); + } + + initI2c(); + + Serial.println("----SENSOR A-----"); + sensorAOk = initSensor(sensorA); + if (sensorAOk) { + sensorAOk = startMeasurement(sensorA); + } + + Serial.println("----SENSOR B-----"); + sensorBOk = initSensor(sensorB); + if (sensorBOk) { + sensorBOk = startMeasurement(sensorB); + } +} + +void loop() { + // + // Slow down the sampling to 0.2Hz. + // + delay(5000); + + if (sensorAOk) { + Serial.println("----SENSOR A-----"); + readAndPrintMeasurement(sensorA); + } + if (sensorBOk) { + Serial.println("----SENSOR B-----"); + readAndPrintMeasurement(sensorB); + } +} \ No newline at end of file diff --git a/exampleSTM32Nucleo64/sketch.yaml b/exampleSTM32Nucleo64/sketch.yaml new file mode 100644 index 0000000..dbdf81c --- /dev/null +++ b/exampleSTM32Nucleo64/sketch.yaml @@ -0,0 +1,9 @@ +profiles: + stm32-nucleo64: + fqbn: STMicroelectronics:stm32:Nucleo_64:pnum=NUCLEO_F401RE + platforms: + - platform: STMicroelectronics:stm32 (2.10.1) + platform_index_url: https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json + libraries: + - Sensirion I2C SCD4x (1.0.0) + - Sensirion Core (0.7.0) diff --git a/images/wiringTwoSCD41ToArduinoUnoR4.fzz b/images/wiringTwoSCD41ToArduinoUnoR4.fzz index 36fe505..537b0aa 100644 Binary files a/images/wiringTwoSCD41ToArduinoUnoR4.fzz and b/images/wiringTwoSCD41ToArduinoUnoR4.fzz differ diff --git a/images/wiringTwoSCD41ToArduinoUnoR4.png b/images/wiringTwoSCD41ToArduinoUnoR4.png index c6f19ac..e13168c 100644 Binary files a/images/wiringTwoSCD41ToArduinoUnoR4.png and b/images/wiringTwoSCD41ToArduinoUnoR4.png differ