17#define SPS30_I2C_ADDR (0x69 << 1)
20#define SPS30_CMD_START_MEAS 0x0010
21#define SPS30_CMD_STOP_MEAS 0x0104
22#define SPS30_CMD_READ_DRDY 0x0202
23#define SPS30_CMD_READ_MEAS 0x0300
24#define SPS30_CMD_SOFT_RESET 0xD304
25#define SPS30_CMD_START_CLEAN 0x5607
26#define SPS30_CMD_SLEEP 0x1001
27#define SPS30_CMD_WAKEUP 0x1103
28#define SPS30_CMD_CLEAN_INTERVAL 0x8004
38sps30_t _sps30Data = {};
39sps30_t _bck_sps30Data = {};
41static uint8_t _isSps30 = 0;
42static const uint8_t _cleaningInterval = 100;
44static clearing_t _isClearing = CLR_NONE;
47AQI_Level_t sps30_ClassifyPM25(
char **label)
49 float pm2_5 = _sps30Data.Mass_pm2_5;
56 else if (pm2_5 <= 35.4f)
61 else if (pm2_5 <= 55.4f)
63 *label =
"Unhealthy for Sensitive Groups";
64 return AQI_UNHEALTHY_SENSITIVE;
66 else if (pm2_5 <= 150.4f)
71 else if (pm2_5 <= 250.4f)
73 *label =
"Very Unhealthy";
74 return AQI_VERY_UNHEALTHY;
83int8_t sps30_Is(I2C_HandleTypeDef *hi2c, int8_t tryInit)
85 if (!_isSps30 && tryInit)
90HAL_StatusTypeDef sps30_Init(I2C_HandleTypeDef *hi2c)
93 HAL_StatusTypeDef status;
95 _isClearing = CLR_NONE;
98 cmd[0] = (SPS30_CMD_WAKEUP >> 8);
99 cmd[1] = (SPS30_CMD_WAKEUP & 0xFF);
100 status = HAL_I2C_Master_Transmit(hi2c, SPS30_I2C_ADDR, cmd, 2, 100);
105 if (status == HAL_OK)
108 { (SPS30_CMD_SOFT_RESET >> 8), (SPS30_CMD_SOFT_RESET & 0xFF) };
112 if ((status = HAL_I2C_Master_Transmit(hi2c, SPS30_I2C_ADDR, cmd, 2, 100)) != HAL_OK)
117 cmd[0] = (SPS30_CMD_SLEEP >> 8);
118 cmd[1] = (SPS30_CMD_SLEEP & 0xFF);
119 if ((status = HAL_I2C_Master_Transmit(hi2c, SPS30_I2C_ADDR, cmd, 2, 100)) != HAL_OK)
124 _isSps30 = (status == HAL_OK);
128HAL_StatusTypeDef sps30_On(I2C_HandleTypeDef *hi2c)
130 HAL_StatusTypeDef status = HAL_ERROR;
132 _sps30Data.IsDataValid = 0;
141 cmd[0] = (SPS30_CMD_WAKEUP >> 8);
142 cmd[1] = (SPS30_CMD_WAKEUP & 0xFF);
143 while (wakeUp-- > 0 && (status = HAL_I2C_Master_Transmit(hi2c, SPS30_I2C_ADDR, cmd, 2, 100)) != HAL_OK)
146 if (status != HAL_OK)
151 cmd[0] = (SPS30_CMD_START_MEAS >> 8);
152 cmd[1] = (SPS30_CMD_START_MEAS & 0xFF);
157 if ((status = HAL_I2C_Master_Transmit(hi2c, SPS30_I2C_ADDR, cmd, 5, 100)) != HAL_OK)
162 if (_isClearing == CLR_NONE)
167 _isClearing = CLR_START;
170 _isSps30 = (status == HAL_OK);
175HAL_StatusTypeDef sps30_Off(I2C_HandleTypeDef *hi2c)
177 HAL_StatusTypeDef status = HAL_ERROR;
182 { (SPS30_CMD_STOP_MEAS >> 8), (SPS30_CMD_STOP_MEAS & 0xFF) };
186 if ((status = HAL_I2C_Master_Transmit(hi2c, SPS30_I2C_ADDR, cmd, 2, 100)) != HAL_OK)
190 cmd[0] = (SPS30_CMD_SLEEP >> 8);
191 cmd[1] = (SPS30_CMD_SLEEP & 0xFF);
192 if ((status = HAL_I2C_Master_Transmit(hi2c, SPS30_I2C_ADDR, cmd, 2, 100)) != HAL_OK)
201HAL_StatusTypeDef sps30_IsDataReady(I2C_HandleTypeDef *hi2c)
203 HAL_StatusTypeDef status = HAL_ERROR;
208 { (SPS30_CMD_READ_DRDY >> 8), (SPS30_CMD_READ_DRDY & 0xFF) };
213 if ((status = HAL_I2C_Master_Transmit(hi2c, SPS30_I2C_ADDR, cmd, 2, 100)) != HAL_OK)
215 if ((status = HAL_I2C_Master_Receive(hi2c, SPS30_I2C_ADDR, data, 3, 100)) != HAL_OK)
218 status = (data[1] == 1) ? HAL_OK : HAL_BUSY;
224HAL_StatusTypeDef sps30_Read(I2C_HandleTypeDef *hi2c)
226 HAL_StatusTypeDef status = sps30_IsDataReady(hi2c);
228 if (status == HAL_OK)
231 { (SPS30_CMD_READ_MEAS >> 8), (SPS30_CMD_READ_MEAS & 0xFF) };
235 if ((status = HAL_I2C_Master_Transmit(hi2c, SPS30_I2C_ADDR, cmd, 2, 100)) != HAL_OK)
238 if ((status = HAL_I2C_Master_Receive(hi2c, SPS30_I2C_ADDR, buffer, 60, 500)) != HAL_OK)
241 float *f_ptr = (
float*) &_sps30Data;
242 for (
int i = 0; i < 10; i++)
244 uint8_t raw_float[4];
247 if (
calculateCrc(&buffer[b_idx], 2) != buffer[b_idx + 2] ||
248 calculateCrc(&buffer[b_idx + 3], 2) != buffer[b_idx + 5])
251 _sps30Data.IsDataValid = 0;
256 raw_float[3] = buffer[b_idx];
257 raw_float[2] = buffer[b_idx + 1];
259 raw_float[1] = buffer[b_idx + 3];
260 raw_float[0] = buffer[b_idx + 4];
263 memcpy(&f_ptr[i], raw_float, 4);
264 _sps30Data.IsDataValid = 1;
271HAL_StatusTypeDef sps30_IsOnOff(I2C_HandleTypeDef *hi2c, uint8_t *onOff)
277 HAL_StatusTypeDef status = sps30_IsDataReady(hi2c);
279 if (status == HAL_OK || status == HAL_BUSY)
282 *onOff = (status == HAL_OK);
288HAL_StatusTypeDef sps30_StartCleaning(I2C_HandleTypeDef *hi2c)
290 HAL_StatusTypeDef status = HAL_ERROR;
292 { (SPS30_CMD_START_CLEAN >> 8), (SPS30_CMD_START_CLEAN & 0xFF) };
296 status = HAL_I2C_Master_Transmit(hi2c, SPS30_I2C_ADDR, cmd, 2, 100);
300HAL_StatusTypeDef sps30_GetAutoCleanInterval(I2C_HandleTypeDef *hi2c, uint32_t *interval_sec)
302 HAL_StatusTypeDef status = HAL_ERROR;
307 { (SPS30_CMD_CLEAN_INTERVAL >> 8), (SPS30_CMD_CLEAN_INTERVAL & 0xFF) };
312 if ((status = HAL_I2C_Master_Transmit(hi2c, SPS30_I2C_ADDR, cmd, 2, 100)) != HAL_OK)
314 if ((status = HAL_I2C_Master_Receive(hi2c, SPS30_I2C_ADDR, buffer, 6, 100)) != HAL_OK)
323 *interval_sec = ((uint32_t) buffer[0] << 24) | ((uint32_t) buffer[1] << 16) | ((uint32_t) buffer[3] << 8) | (uint32_t) buffer[4];
329HAL_StatusTypeDef sps30_SetAutoCleanInterval(I2C_HandleTypeDef *hi2c, uint32_t interval_sec)
331 HAL_StatusTypeDef status = HAL_ERROR;
338 cmd[0] = (SPS30_CMD_CLEAN_INTERVAL >> 8);
339 cmd[1] = (SPS30_CMD_CLEAN_INTERVAL & 0xFF);
342 cmd[2] = (uint8_t) (interval_sec >> 24);
343 cmd[3] = (uint8_t) (interval_sec >> 16);
346 cmd[5] = (uint8_t) (interval_sec >> 8);
347 cmd[6] = (uint8_t) (interval_sec & 0xFF);
349 if ((status = HAL_I2C_Master_Transmit(hi2c, SPS30_I2C_ADDR, cmd, 8, 100)) != HAL_OK)
356void sps30_LogData(
char *buf)
362 sps30_ClassifyPM25(&txt);
363 sprintf(buf,
"|sps30: pm1_0:" PRIf_02 " pm2_5:" PRIf_02 " %s ",
PRIf_02D(_sps30Data.Mass_pm1_0),
PRIf_02D(_sps30Data.Mass_pm2_5), ((txt != NULL) ? txt :
"(none)"));
367int8_t sps30_Service(I2C_HandleTypeDef *hi2c)
369 HAL_StatusTypeDef status;
374 status = sps30_On(hi2c);
375 writeLog(
"sps30 clearing start, status:%d", (
int) status);
376 if (status == HAL_OK)
378 status = sps30_StartCleaning(hi2c);
379 writeLog(
"sps30 clearing process, status:%d", (
int) status);
381 if (status == HAL_OK)
383 _isClearing = CLR_PROCESS;
387 _isClearing = CLR_STOP;
391 _isClearing = CLR_STOP;
394 status = sps30_Off(hi2c);
395 _isClearing = CLR_NONE;
396 writeLog(
"sps30 clearing stop, status:%d", (
int) status);
400 return _isClearing != CLR_NONE;
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...
void writeLog(const char *format,...)
Format and send a log message over UART (printf-style). Available only when WRITELOG is defined; comp...
#define PRIf_02D(fData)
Expands to integer and fractional arguments for use with PRIf_02. Splits a float/double into the inte...
#define PRIf_02
printf format string for printing a float/double as integer with 2 decimal places....
mems_MainBlock_t _memsMainBlock
Global instance of the main flash control block; loaded by mems_ReadMainBlock().
HAL_StatusTypeDef mems_WriteMainBlock()
writing the main block on flash. The main block is stored on address 0
Non-blocking timer utility – similar to HAL_Delay but without CPU blocking.
void HAL_Delay(__IO uint32_t Delay)
uint8_t calculateCrc(uint8_t *data, uint8_t len)
Calculate a CRC-8 checksum (Sensirion polynomial) over a byte buffer. Used to validate sensor I2C res...
void sleeper_Init(sleeper_t *v, uint32_t sleepMS)
Initialise the sleeper and start timing from now.
int sleeper_IsElapsed(const sleeper_t *v)
Check whether the configured time interval has elapsed.