L14-Click 1.0
STM32WLE5CC LoRaWAN Sensor Platform
Loading...
Searching...
No Matches
scd41.c
Go to the documentation of this file.
1/*
2 * hvac.c
3 *
4 * Created on: 29. 12. 2025
5 * Author: Milan
6 */
7
8
9#include "scd41.h"
10
11#ifdef SENSOR_SCD41
12
13#include "i2c.h"
14#include "utils/mydefs.h"
15#include "mymems.h"
16#include "mysensors_base.h"
17#include <stdio.h>
18
19// I2C Addresses
20#define SCD41_ADDR (0x62 << 1)
21#define SPS30_ADDR (0x69 << 1)
22
23// SCD41 Commands
24#define SCD41_CMD_START_PERIODIC 0x21b1 // reading - fast, but higher consumption
25#define SCD41_CMD_START_LOW_POWER_PERIODIC 0x21ac // slow reading, only every 30s
26#define SCD41_CMD_START_SINGLE_SHOT 0x219D
27
28#define SCD41_CMD_START SCD41_CMD_START_PERIODIC
29//#define SCD41_CMD_START SCD41_CMD_START_LOW_POWER_PERIODIC
30//#define SCD41_CMD_START SCD41_CMD_START_SINGLE_SHOT
31
32#define SCD41_CMD_STOP_PERIODIC 0x3f86
33#define SCD41_CMD_SET_ALTITUDE 0x2427
34#define SCD41_CMD_READ_MEAS 0xec05
35#define SCD41_CMD_GET_DATA_READY 0xe4b8
36#define SCD41_CMD_REINIT 0x3646
37
38// default settings
40scd41_t _bck_scd41Data = {}; // backup
41
42static int8_t _isScd41 = 0;
43
44// Internal Helper: Send 16-bit command + 16-bit data + CRC
45static HAL_StatusTypeDef scd41_WriteWithCRC(I2C_HandleTypeDef *hi2c, uint16_t cmd, uint16_t val)
46{
47 uint8_t tx[5];
48 tx[0] = (uint8_t) (cmd >> 8);
49 tx[1] = (uint8_t) (cmd & 0xFF);
50 tx[2] = (uint8_t) (val >> 8);
51 tx[3] = (uint8_t) (val & 0xFF);
52 tx[4] = systemParams_CalculateCrc(&tx[2], 2);
53 return HAL_I2C_Master_Transmit(hi2c, SCD41_ADDR, tx, 5, 100);
54}
55
56static HAL_StatusTypeDef scd41_onOff(I2C_HandleTypeDef *hi2c, uint16_t onOff)
57{
58 HAL_StatusTypeDef status = HAL_ERROR;
59
60 uint8_t cmd[2];
61 cmd[0] = (onOff >> 8);
62 cmd[1] = (onOff & 0xFF);
63 status = HAL_I2C_Master_Transmit(hi2c, SCD41_ADDR, cmd, 2, HAL_MAX_DELAY);
64// if (status == HAL_OK)
65// HAL_Delay(500); // Wait for sensor to process start
66 _isScd41 = (status == HAL_OK);
67 return status;
68}
69
70int8_t scd41_Is(I2C_HandleTypeDef *hi2c, int8_t tryInit)
71{
72 if (!_isScd41 && tryInit)
73 scd41_Init(hi2c);
74 return _isScd41;
75}
76
77HAL_StatusTypeDef scd41_On(I2C_HandleTypeDef *hi2c)
78{
79 HAL_StatusTypeDef status = HAL_ERROR;
80
81 if (_isScd41)
82 {
83 status = scd41_onOff(hi2c, SCD41_CMD_START);
84 _scd41Data.IsDataValid = 0;
85 if (status == HAL_OK)
86 {
87 _memsMainBlock.Sens_SCD41Start++;
89 }
90 }
91 return status;
92}
93
94HAL_StatusTypeDef scd41_Off(I2C_HandleTypeDef *hi2c)
95{
97}
98
99HAL_StatusTypeDef scd41_Init(I2C_HandleTypeDef *hi2c)
100{
101 HAL_StatusTypeDef ret = I2C_IsDeviceReadyMT(hi2c, SCD41_ADDR, 2, 2); // first check
102
103 if (ret == HAL_OK)
104 {
105 uint8_t cmd[2];
106 do
107 {
108 // 1. Send Stop Periodic Measurement (ensure it's idle)
109 scd41_Off(hi2c);
110
111 cmd[0] = (SCD41_CMD_REINIT >> 8);
112 cmd[1] = (SCD41_CMD_REINIT & 0xFF);
113 if ((ret = HAL_I2C_Master_Transmit(hi2c, SCD41_ADDR, cmd, 2, HAL_MAX_DELAY)) != HAL_OK)
114 break;
115 HAL_Delay(30);
116
117 // 2. altitude setting
118 if (_systemParams.SensAltitude > 0)
119 if ((ret = scd41_WriteWithCRC(hi2c, SCD41_CMD_SET_ALTITUDE, _systemParams.SensAltitude)) != HAL_OK)
120 break;
121
122 // 3. Set Temp Offset (e.g., 2.5 degrees)
123 //SCD41_SetTempOffset(hi2c, 2.5f);
124 //HAL_Delay(10);
125
126 // 4. Start Periodic Measurement
127 //cmd[0] = (SCD41_CMD_START >> 8);
128 //cmd[1] = (SCD41_CMD_START & 0xFF);
129 //if ((ret = HAL_I2C_Master_Transmit(hi2c, SCD41_ADDR, cmd, 2, HAL_MAX_DELAY)) != HAL_OK)
130 // break;
131 //if ((ret = scd41_Start(hi2c)) != HAL_OK)
132 // break;
133 } while (0);
134 }
135 _isScd41 = (ret==HAL_OK);
136 return ret;
137}
138
139/**
140 * @brief check if data is available
141 * @retval HAL_OK - data is available, can be read, HAL_BUSY - data not yet available, HAL_ERROR - error
142 */
143HAL_StatusTypeDef scd41_IsDataReady(I2C_HandleTypeDef *hi2c)
144{
145 HAL_StatusTypeDef status = HAL_ERROR;
146
147 if (_isScd41)
148 {
149 uint8_t cmd[2] =
151 uint8_t buf[3] = {};
152
153 do
154 {
155 // Send command
156
157 if ((status = HAL_I2C_Master_Transmit(hi2c, SCD41_ADDR, cmd, 2, 100)) != HAL_OK)
158 break;
159 HAL_Delay(2); // Small processing time
160
161 // Read 3 bytes (Word + CRC)
162 if ((status = HAL_I2C_Master_Receive(hi2c, SCD41_ADDR, buf, 3, 100)) != HAL_OK)
163 return HAL_ERROR; // I2C Error
164
165 //if ((status = HAL_I2C_Mem_Read(hi2c, SCD41_ADDR, SCD41_CMD_GET_DATA_READY, I2C_MEMADD_SIZE_16BIT, buf, 3, 100)) != HAL_OK)
166 // break;
167
168 // Optional: Verify CRC
169 if (systemParams_CalculateCrc(buf, 2) != buf[2])
170 {
171 status = HAL_ERROR; // CRC Error
172 break;
173 }
174 // Combine bytes to 16-bit status
175 uint16_t dataReady; // = (uint16_t) ((buf[0] << 8) | buf[1]);
176
177 dataReady = buf[0];
178 dataReady <<= 8;
179 dataReady |= buf[1];
180 // If the least significant 11 bits are 0, data is not ready.
181 // (status & 0x07FF) will be non-zero if data is ready.
182 status = ((dataReady & 0x07FF) != 0) ? HAL_OK : HAL_BUSY;
183 //if (!dataReady)
184 // scd41_Init(hi2c);
185 } while (0);
186 }
187 return status;
188}
189
190HAL_StatusTypeDef scd41_Read(I2C_HandleTypeDef *hi2c)
191{
192 HAL_StatusTypeDef status = scd41_IsDataReady(hi2c);
193
194 if (status == HAL_OK)
195 {
196 uint8_t cmd[2] =
197 { (SCD41_CMD_READ_MEAS >> 8), (SCD41_CMD_READ_MEAS & 0xFF) };
198 uint8_t buf[9] = {};
199
200 do
201 {
202
203 if ((status = HAL_I2C_Master_Transmit(hi2c, SCD41_ADDR, cmd, 2, HAL_MAX_DELAY)) != HAL_OK)
204 break;
205 HAL_Delay(1);
206
207 if ((status = HAL_I2C_Master_Receive(hi2c, SCD41_ADDR, buf, 9, HAL_MAX_DELAY)) != HAL_OK)
208 break;
209
210 //status = HAL_I2C_Mem_Read(hi2c, SCD41_ADDR, SCD41_CMD_READ_MEAS,
211 //I2C_MEMADD_SIZE_16BIT, buf, 9, 500);
212
213 if (systemParams_CalculateCrc(&buf[0], 2) != buf[2] || systemParams_CalculateCrc(&buf[3], 2) != buf[5] || systemParams_CalculateCrc(&buf[6], 2) != buf[8])
214 {
215 status = HAL_ERROR;
216 break;
217 }
218
219 _scd41Data.Co2 = (float) ((uint16_t) ((buf[0] << 8) | buf[1]));
220 _scd41Data.Temperature = -45.0f + 175.0f * (float) ((buf[3] << 8) | buf[4]) / 65536.0f;
221 _scd41Data.Humidity = 100.0f * (float) ((buf[6] << 8) | buf[7]) / 65536.0f;
222 _scd41Data.IsDataValid = 1;
223 } while (0);
224 }
225 return status;
226}
227
228void scd41_LogData(char *buf)
229{
230 if (buf != NULL)
231 sprintf(buf, "|scd41 co2:%d temp:" PRIf_02 " hum:" PRIf_02 " ", (int) _scd41Data.Co2, PRIf_02D(_scd41Data.Temperature), PRIf_02D(_scd41Data.Humidity));
232}
233
234#endif
This file contains all the function prototypes for the i2c.c file.
HAL_StatusTypeDef I2C_IsDeviceReadyMT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Trials, uint32_t Timeout)
Wrapper around HAL_I2C_IsDeviceReady() that recovers from a busy bus. If the HAL I2C bus is in a BUSY...
Definition i2c.c:158
#define PRIf_02D(fData)
Expands to integer and fractional arguments for use with PRIf_02. Splits a float/double into the inte...
Definition mydefs.h:38
#define PRIf_02
printf format string for printing a float/double as integer with 2 decimal places....
Definition mydefs.h:30
mems_MainBlock_t _memsMainBlock
Global instance of the main flash control block; loaded by mems_ReadMainBlock().
Definition mymems.c:27
HAL_StatusTypeDef mems_WriteMainBlock()
writing the main block on flash. The main block is stored on address 0
Definition mymems.c:117
systemParams_t _systemParams
uint8_t systemParams_CalculateCrc(uint8_t *data, uint8_t len)
Calculate a CRC-8 checksum (Sensirion polynomial) over a byte buffer. Used to validate sensor I2C res...
#define SCD41_CMD_STOP_PERIODIC
Definition scd41.c:32
#define SCD41_CMD_REINIT
Definition scd41.c:36
HAL_StatusTypeDef scd41_IsDataReady(I2C_HandleTypeDef *hi2c)
check if data is available
Definition scd41.c:143
#define SCD41_CMD_START
Definition scd41.c:28
#define SCD41_CMD_READ_MEAS
Definition scd41.c:34
#define SCD41_ADDR
Definition scd41.c:20
static HAL_StatusTypeDef scd41_onOff(I2C_HandleTypeDef *hi2c, uint16_t onOff)
Definition scd41.c:56
#define SCD41_CMD_SET_ALTITUDE
Definition scd41.c:33
#define SCD41_CMD_GET_DATA_READY
Definition scd41.c:35
HAL_StatusTypeDef scd41_Off(I2C_HandleTypeDef *hi2c)
stop reading
Definition scd41.c:94
void scd41_LogData(char *buf)
log data to buffer
Definition scd41.c:228
HAL_StatusTypeDef scd41_Init(I2C_HandleTypeDef *hi2c)
initialization of sensor sdc41
Definition scd41.c:99
HAL_StatusTypeDef scd41_Read(I2C_HandleTypeDef *hi2c)
read value from sensor
Definition scd41.c:190
static HAL_StatusTypeDef scd41_WriteWithCRC(I2C_HandleTypeDef *hi2c, uint16_t cmd, uint16_t val)
Definition scd41.c:45
HAL_StatusTypeDef scd41_On(I2C_HandleTypeDef *hi2c)
start reading - turn on sensor, reading mode can be: SCD41_CMD_START_PERIODIC - every 5s - this is pr...
Definition scd41.c:77
int8_t scd41_Is(I2C_HandleTypeDef *hi2c, int8_t tryInit)
check if CO2 sensor is present
Definition scd41.c:70
static int8_t _isScd41
Definition scd41.c:42
scd41_t _scd41Data
Live measurement data from the SCD41 sensor; updated by scd41_Read().
Definition scd41.c:39
scd41_t _bck_scd41Data
Snapshot copy of the last completed measurement; used for LoRaWAN transmission.
Definition scd41.c:40
Measurement data produced by the SCD41 CO2 / temperature / humidity sensor. Populated by scd41_Read()...
Definition scd41.h:36
void HAL_Delay(__IO uint32_t Delay)
Definition sys_app.c:369