Paparazzi UAS v7.1_unstable
Paparazzi is a free software Unmanned Aircraft System.
Loading...
Searching...
No Matches
dps310_i2c.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2026 OpenUAS
3 *
4 * This file is part of paparazzi.
5 *
6 * paparazzi is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * paparazzi is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with paparazzi; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
39#include "mcu_periph/sys_time.h"
40
41/* Reliability limits */
42#define DPS310_BROKEN_RETRY_US 5000000
43#define DPS310_MAX_ERROR_CNT 10
44#define DPS310_PRESSURE_MIN_PA 30000.0f
45#define DPS310_PRESSURE_MAX_PA 120000.0f
46
47/* Compensation scale factors for 16x oversampling (datasheet table "Compensation Scale Factors").
48 * Tied to the PM_PRC/TMP_PRC settings written in DPS310_STATUS_CONFIGURE_REGS: change them together. */
49#define DPS310_SCALE_FACTOR_KT 253952.0f
50#define DPS310_SCALE_FACTOR_KP 253952.0f
51
52/* The 18-byte calibration read must fit in the I2C transaction buffer */
53#if I2C_BUF_LEN < 18
54#error "DPS310: I2C_BUF_LEN is too small for the 18 byte calibration coefficient read"
55#endif
56
66static const uint8_t dps310_temp_fix_seq[][2] = {
67 { 0x0E, 0xA5 },
68 { 0x0F, 0x96 },
69 { 0x62, 0x02 },
70 { 0x0E, 0x00 },
71 { 0x0F, 0x00 }
72};
73
74#define DPS310_TEMP_FIX_SEQ_LEN (sizeof(dps310_temp_fix_seq) / sizeof(dps310_temp_fix_seq[0]))
75
83{
84 if (raw & ((uint32_t)1 << (length - 1))) {
85 return ((int32_t)raw) - ((int32_t)1 << length);
86 }
87 return raw;
88}
89
97static void parse_calib_data(struct Dps310_I2c *dps)
98{
99 // Keep the volatile qualifier of the live transaction buffer instead of casting it away
100 volatile uint8_t *coef = dps->i2c_trans.buf;
101
102 dps->calib.c0 = getTwosComplement(((uint32_t)coef[0] << 4) | (((uint32_t)coef[1] >> 4) & 0x0F), 12);
103 dps->calib.c1 = getTwosComplement((((uint32_t)coef[1] & 0x0F) << 8) | (uint32_t)coef[2], 12);
104 dps->calib.c00 = getTwosComplement(((uint32_t)coef[3] << 12) | ((uint32_t)coef[4] << 4) | (((
105 uint32_t)coef[5] >> 4) & 0x0F), 20);
106 dps->calib.c10 = getTwosComplement((((uint32_t)coef[5] & 0x0F) << 16) | ((uint32_t)coef[6] << 8) | (uint32_t)coef[7],
107 20);
108 dps->calib.c01 = getTwosComplement(((uint32_t)coef[8] << 8) | (uint32_t)coef[9], 16);
109 dps->calib.c11 = getTwosComplement(((uint32_t)coef[10] << 8) | (uint32_t)coef[11], 16);
110 dps->calib.c20 = getTwosComplement(((uint32_t)coef[12] << 8) | (uint32_t)coef[13], 16);
111 dps->calib.c21 = getTwosComplement(((uint32_t)coef[14] << 8) | (uint32_t)coef[15], 16);
112 dps->calib.c30 = getTwosComplement(((uint32_t)coef[16] << 8) | (uint32_t)coef[17], 16);
113
114 // DPS310 ignores c31 and c40 (only used on SPL07_003)
115 dps->calib.c31 = 0;
116 dps->calib.c40 = 0;
117}
118
124static void parse_sensor_data(struct Dps310_I2c *dps)
125{
128
129 // Registers 0x00 to 0x02 for pressure
130 data_msb = (uint32_t)dps->i2c_trans.buf[0] << 16;
131 data_lsb = (uint32_t)dps->i2c_trans.buf[1] << 8;
132 data_xlsb = (uint32_t)dps->i2c_trans.buf[2];
134 dps->raw_pressure = getTwosComplement(prs_raw, 24);
135
136 // Registers 0x03 to 0x05 for temperature
137 data_msb = (uint32_t)dps->i2c_trans.buf[3] << 16;
138 data_lsb = (uint32_t)dps->i2c_trans.buf[4] << 8;
139 data_xlsb = (uint32_t)dps->i2c_trans.buf[5];
141 dps->raw_temperature = getTwosComplement(tmp_raw, 24);
142}
143
153static void compensate_sensor(struct Dps310_I2c *dps)
154{
155 float Traw_sc = (float)dps->raw_temperature / DPS310_SCALE_FACTOR_KT;
156 float Praw_sc = (float)dps->raw_pressure / DPS310_SCALE_FACTOR_KP;
157
158 struct dps310_reg_calib_data *c = &dps->calib;
159
160 dps->temperature = (c->c0 * 0.5f) + (c->c1 * Traw_sc);
161 dps->pressure = c->c00 + Praw_sc * (c->c10 + Praw_sc * (c->c20 + Praw_sc * c->c30)) +
162 Traw_sc * c->c01 + Traw_sc * Praw_sc * (c->c11 + Praw_sc * c->c21);
163}
164
174void dps310_i2c_init(struct Dps310_I2c *dps, struct i2c_periph *i2c_p, uint8_t addr)
175{
176 dps->i2c_p = i2c_p;
177 dps->i2c_trans.slave_addr = addr;
178 dps->i2c_trans.status = I2CTransDone;
179 dps->data_available = false;
180 dps->initialized = false;
181 dps->is_broken = false;
182 dps->init_error_cnt = 0;
183 dps->timer = 0;
184 dps->status = DPS310_STATUS_UNINIT;
185 dps->temp_coef_srce = 0;
186 dps->temp_fix_step = 0;
187}
188
200{
201 if (dps->is_broken) {
202 // Back off, but periodically retry a full re-detection instead of giving up forever.
203 // Unsigned arithmetic handles a wrap-around of the time counter.
205 return;
206 }
207 dps->is_broken = false;
208 dps->init_error_cnt = 0;
209 dps->status = DPS310_STATUS_UNINIT;
210 }
211
212 if (dps->i2c_trans.status != I2CTransDone) {
213 return;
214 }
215
216 switch (dps->status) {
218 dps->data_available = false;
219 dps->initialized = false;
220 dps->temp_fix_step = 0;
221 dps->status = DPS310_STATUS_GET_ID;
222 break;
223
225 dps->i2c_trans.buf[0] = DPS310_REG_ID;
226 i2c_transceive(dps->i2c_p, &dps->i2c_trans, dps->i2c_trans.slave_addr, 1, 1);
227 break;
228
230 dps->i2c_trans.buf[0] = dps310_temp_fix_seq[dps->temp_fix_step][0];
231 dps->i2c_trans.buf[1] = dps310_temp_fix_seq[dps->temp_fix_step][1];
232 i2c_transmit(dps->i2c_p, &dps->i2c_trans, dps->i2c_trans.slave_addr, 2);
233 break;
234
236 dps->i2c_trans.buf[0] = DPS310_REG_MEAS_CFG;
237 i2c_transceive(dps->i2c_p, &dps->i2c_trans, dps->i2c_trans.slave_addr, 1, 1);
238 break;
239
241 dps->i2c_trans.buf[0] = DPS310_REG_COEF_SRCE;
242 i2c_transceive(dps->i2c_p, &dps->i2c_trans, dps->i2c_trans.slave_addr, 1, 1);
243 break;
244
246 dps->i2c_trans.buf[0] = DPS310_REG_COEF;
247 i2c_transceive(dps->i2c_p, &dps->i2c_trans, dps->i2c_trans.slave_addr, 1, 18);
248 break;
249
251 dps->i2c_trans.buf[0] = DPS310_REG_PRS_CFG;
252 // Sensor-internal background rates, decoupled from the (e.g. 50Hz) periodic polling rate.
253 // Datasheet budget: total conversion time < 1s/s. At 16x oversampling (27.6ms/conversion),
254 // 16Hz P + 16Hz T = 883ms/s, so 16Hz is the maximum working rate for both channels.
255 // Note: 16x oversampling requires P_SHIFT/T_SHIFT below and kT=kP=253952 in compensate_sensor().
257 dps->i2c_trans.buf[2] = DPS310_TMP_CFG_TMP_RATE_16HZ | DPS310_TMP_CFG_TMP_PRC_16 | dps->temp_coef_srce;
258 dps->i2c_trans.buf[3] = 0x00; // Idle MEAS_CFG initially until CFG_REG is correctly established below!
260 i2c_transmit(dps->i2c_p, &dps->i2c_trans, dps->i2c_trans.slave_addr, 5);
261 break;
262
264 // Explicitly enable continuous measurements AFTER CFG_REG is written to avoid start-up timing bugs
265 dps->i2c_trans.buf[0] = DPS310_REG_MEAS_CFG;
266 dps->i2c_trans.buf[1] = DPS310_MEAS_CTRL_CONT;
267 i2c_transmit(dps->i2c_p, &dps->i2c_trans, dps->i2c_trans.slave_addr, 2);
268 break;
269
271 dps->i2c_trans.buf[0] = DPS310_REG_PSR_B2;
272 i2c_transceive(dps->i2c_p, &dps->i2c_trans, dps->i2c_trans.slave_addr, 1, 6);
273 break;
274
275 default:
276 break;
277 }
278}
279
291{
292 if (dps->i2c_trans.status == I2CTransSuccess) {
293 switch (dps->status) {
295 // Apply the temperature errata fix only on genuine DPS310 silicon.
296 // Register-compatible parts (e.g. SPL07-003, ID 0x11) skip it.
297 if (dps->i2c_trans.buf[0] == DPS310_CHIP_ID) {
298 dps->temp_fix_step = 0;
299 dps->status = DPS310_STATUS_TEMP_FIX;
300 } else {
301 dps->status = DPS310_STATUS_WAIT_RDY;
302 }
303 break;
304
306 dps->temp_fix_step++;
307 if (dps->temp_fix_step >= DPS310_TEMP_FIX_SEQ_LEN) {
308 dps->status = DPS310_STATUS_WAIT_RDY;
309 }
310 break;
311
313 // Only proceed once the sensor is ready and, crucially, the calibration
314 // coefficients are valid (~40ms after power-up). Reading them too early
315 // would silently corrupt every pressure value computed afterwards.
316 if ((dps->i2c_trans.buf[0] & (DPS310_MEAS_CFG_COEF_RDY | DPS310_MEAS_CFG_SENSOR_RDY))
319 }
320 break;
321
323 // Isolate the bit handling internal/external temperature sensor src logic
324 dps->temp_coef_srce = dps->i2c_trans.buf[0] & DPS310_COEF_SRCE_BIT_TMP_COEF_SRCE;
326 break;
327
331 break;
332
335 break;
336
339 dps->initialized = true;
340 dps->init_error_cnt = 0;
341 break;
342
346 dps->init_error_cnt = 0; // successful transaction, reset the consecutive failure counter
347 // Only publish values within the specified measurement range of the sensor,
348 // anything outside means the data got corrupted on its way here
349 if ((dps->pressure >= DPS310_PRESSURE_MIN_PA) && (dps->pressure <= DPS310_PRESSURE_MAX_PA)) {
350 dps->data_available = true;
351 }
352 break;
353
354 default:
355 break;
356 }
357 dps->i2c_trans.status = I2CTransDone;
358 } else if (dps->i2c_trans.status == I2CTransFailed) {
359 dps->init_error_cnt++;
360 if (!dps->initialized) {
361 /* Failure during initialization: count and eventually back off */
362 if (dps->init_error_cnt >= DPS310_MAX_ERROR_CNT) {
363 dps->is_broken = true; // Back off, retried after DPS310_BROKEN_RETRY_US
364 dps->timer = get_sys_time_usec();
365 }
366 dps->status = DPS310_STATUS_UNINIT;
367 } else if (dps->init_error_cnt >= DPS310_MAX_ERROR_CNT) {
368 /* Too many consecutive failures during measurements: full re-initialization */
369 dps->initialized = false;
370 dps->data_available = false;
371 dps->init_error_cnt = 0;
372 dps->status = DPS310_STATUS_UNINIT;
373 }
374 /* Otherwise a transient failure simply retries the current read on the next periodic tick */
375 dps->i2c_trans.status = I2CTransDone;
376 }
377}
uint32_t get_sys_time_usec(void)
Get the time in microseconds since startup.
#define DPS310_SCALE_FACTOR_KP
pressure, 16x oversampling
Definition dps310_i2c.c:50
#define DPS310_SCALE_FACTOR_KT
temperature, 16x oversampling
Definition dps310_i2c.c:49
#define DPS310_TEMP_FIX_SEQ_LEN
Definition dps310_i2c.c:74
static void parse_sensor_data(struct Dps310_I2c *dps)
Extract the raw 24-bit pressure and temperature measurements.
Definition dps310_i2c.c:124
static void parse_calib_data(struct Dps310_I2c *dps)
Unpack the 18 calibration coefficient bytes (registers 0x10-0x21)
Definition dps310_i2c.c:97
#define DPS310_MAX_ERROR_CNT
consecutive transaction failures before escalating
Definition dps310_i2c.c:43
static const uint8_t dps310_temp_fix_seq[][2]
DPS310 temperature errata fix sequence.
Definition dps310_i2c.c:66
void dps310_i2c_event(struct Dps310_I2c *dps)
Consume finished I2C transactions and advance the state machine.
Definition dps310_i2c.c:290
#define DPS310_PRESSURE_MIN_PA
specified measurement range is 300-1200 hPa,
Definition dps310_i2c.c:44
#define DPS310_PRESSURE_MAX_PA
anything outside means the data got corrupted
Definition dps310_i2c.c:45
static int32_t getTwosComplement(uint32_t raw, uint8_t length)
Sign-extend a raw two's complement value of arbitrary bit length.
Definition dps310_i2c.c:82
static void compensate_sensor(struct Dps310_I2c *dps)
Convert raw measurements into pressure [Pa] and temperature [deg C].
Definition dps310_i2c.c:153
void dps310_i2c_periodic(struct Dps310_I2c *dps)
Run the driver state machine, submitting at most one I2C transaction.
Definition dps310_i2c.c:199
void dps310_i2c_init(struct Dps310_I2c *dps, struct i2c_periph *i2c_p, uint8_t addr)
Initialize the driver instance (no bus traffic yet)
Definition dps310_i2c.c:174
#define DPS310_BROKEN_RETRY_US
retry a failed/absent sensor every 5s instead of giving up forever
Definition dps310_i2c.c:42
Driver for the Infineon DPS310 barometer (I2C)
@ DPS310_STATUS_CONFIGURE_REGS
write PRS_CFG, TMP_CFG, MEAS_CFG (idle) and CFG_REG in one burst
Definition dps310_i2c.h:46
@ DPS310_STATUS_READ_DATA
operational: poll the 6 result registers
Definition dps310_i2c.h:48
@ DPS310_STATUS_GET_COEF_SRCE
read which temperature sensor the factory calibration used
Definition dps310_i2c.h:44
@ DPS310_STATUS_WAIT_RDY
wait for SENSOR_RDY and COEF_RDY (~40ms after power-up)
Definition dps310_i2c.h:43
@ DPS310_STATUS_CONFIGURE_MEAS
enable continuous pressure + temperature measurements
Definition dps310_i2c.h:47
@ DPS310_STATUS_TEMP_FIX
apply the 5-write temperature errata fix (genuine DPS310 only)
Definition dps310_i2c.h:42
@ DPS310_STATUS_GET_ID
read the product/revision ID register
Definition dps310_i2c.h:41
@ DPS310_STATUS_UNINIT
restart point: reset driver state, then detect the sensor
Definition dps310_i2c.h:40
@ DPS310_STATUS_GET_CALIB
read the 18 calibration coefficient bytes
Definition dps310_i2c.h:45
#define DPS310_MEAS_CTRL_CONT
Definition dps310_regs.h:79
#define DPS310_CHIP_ID
Definition dps310_regs.h:37
#define DPS310_REG_MEAS_CFG
Definition dps310_regs.h:48
#define DPS310_COEF_SRCE_BIT_TMP_COEF_SRCE
Definition dps310_regs.h:80
#define DPS310_REG_COEF_SRCE
Definition dps310_regs.h:56
#define DPS310_MEAS_CFG_COEF_RDY
Definition dps310_regs.h:60
#define DPS310_PRS_CFG_PM_PRC_16
Definition dps310_regs.h:69
#define DPS310_TMP_CFG_TMP_RATE_16HZ
Definition dps310_regs.h:72
#define DPS310_MEAS_CFG_SENSOR_RDY
Definition dps310_regs.h:61
#define DPS310_TMP_CFG_TMP_PRC_16
Definition dps310_regs.h:74
#define DPS310_REG_PSR_B2
Definition dps310_regs.h:40
#define DPS310_REG_PRS_CFG
Definition dps310_regs.h:46
#define DPS310_REG_ID
Definition dps310_regs.h:53
#define DPS310_PRS_CFG_PM_RATE_16HZ
Definition dps310_regs.h:67
#define DPS310_CFG_REG_P_SHIFT
Definition dps310_regs.h:76
#define DPS310_REG_COEF
Definition dps310_regs.h:55
#define DPS310_CFG_REG_T_SHIFT
Definition dps310_regs.h:77
enum I2CStatus status
Definition i2c.h:160
bool i2c_transmit(struct i2c_periph *p, struct i2c_transaction *t, uint8_t s_addr, uint8_t len)
Submit a write only transaction.
Definition i2c.c:202
bool i2c_transceive(struct i2c_periph *p, struct i2c_transaction *t, uint8_t s_addr, uint8_t len_w, uint16_t len_r)
Submit a write/read transaction.
Definition i2c.c:222
@ I2CTransSuccess
transaction successfully finished by I2C driver
Definition i2c.h:58
@ I2CTransFailed
transaction failed
Definition i2c.h:59
@ I2CTransDone
transaction set to done by user level
Definition i2c.h:60
uint16_t foo
Definition main_demo5.c:58
Architecture independent timing functions.
int int32_t
Typedef defining 32 bit int type.
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.