2 * This file is part of INAV.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
23 #include "build/build_config.h"
24 #include "common/utils.h"
26 #include "drivers/time.h"
27 #include "drivers/io.h"
28 #include "drivers/bus.h"
29 #include "drivers/barometer/barometer.h"
30 #include "drivers/barometer/barometer_spl06.h"
32 #if defined(USE_BARO_SPL06)
34 // SPL06, address 0x76
49 spl06_coeffs_t spl06_cal
;
50 // uncompensated pressure and temperature
51 static int32_t spl06_pressure_raw
= 0;
52 static int32_t spl06_temperature_raw
= 0;
54 static int8_t spl06_samples_to_cfg_reg_value(uint8_t sample_rate
)
66 default: return -1; // invalid
70 static int32_t spl06_raw_value_scale_factor(uint8_t oversampling_rate
)
72 switch(oversampling_rate
)
74 case 1: return 524288;
75 case 2: return 1572864;
76 case 4: return 3670016;
77 case 8: return 7864320;
78 case 16: return 253952;
79 case 32: return 516096;
80 case 64: return 1040384;
81 case 128: return 2088960;
82 default: return -1; // invalid
86 static bool spl06_start_temperature_measurement(baroDev_t
* baro
)
88 return busWrite(baro
->busDev
, SPL06_MODE_AND_STATUS_REG
, SPL06_MEAS_TEMPERATURE
);
91 static bool spl06_read_temperature(baroDev_t
* baro
)
93 uint8_t data
[SPL06_TEMPERATURE_LEN
];
94 int32_t spl06_temperature
;
96 bool ack
= busReadBuf(baro
->busDev
, SPL06_TEMPERATURE_START_REG
, data
, SPL06_TEMPERATURE_LEN
);
99 spl06_temperature
= (int32_t)((data
[0] & 0x80 ? 0xFF000000 : 0) | (((uint32_t)(data
[0])) << 16) | (((uint32_t)(data
[1])) << 8) | ((uint32_t)data
[2]));
100 spl06_temperature_raw
= spl06_temperature
;
106 static bool spl06_start_pressure_measurement(baroDev_t
* baro
)
108 return busWrite(baro
->busDev
, SPL06_MODE_AND_STATUS_REG
, SPL06_MEAS_PRESSURE
);
111 static bool spl06_read_pressure(baroDev_t
* baro
)
113 uint8_t data
[SPL06_PRESSURE_LEN
];
114 int32_t spl06_pressure
;
116 bool ack
= busReadBuf(baro
->busDev
, SPL06_PRESSURE_START_REG
, data
, SPL06_PRESSURE_LEN
);
119 spl06_pressure
= (int32_t)((data
[0] & 0x80 ? 0xFF000000 : 0) | (((uint32_t)(data
[0])) << 16) | (((uint32_t)(data
[1])) << 8) | ((uint32_t)data
[2]));
120 spl06_pressure_raw
= spl06_pressure
;
126 // Returns temperature in degrees centigrade
127 static float spl06_compensate_temperature(int32_t temperature_raw
)
129 const float t_raw_sc
= (float)temperature_raw
/ spl06_raw_value_scale_factor(SPL06_TEMPERATURE_OVERSAMPLING
);
130 const float temp_comp
= (float)spl06_cal
.c0
/ 2 + t_raw_sc
* spl06_cal
.c1
;
134 // Returns pressure in Pascal
135 static float spl06_compensate_pressure(int32_t pressure_raw
, int32_t temperature_raw
)
137 const float p_raw_sc
= (float)pressure_raw
/ spl06_raw_value_scale_factor(SPL06_PRESSURE_OVERSAMPLING
);
138 const float t_raw_sc
= (float)temperature_raw
/ spl06_raw_value_scale_factor(SPL06_TEMPERATURE_OVERSAMPLING
);
140 const float pressure_cal
= (float)spl06_cal
.c00
+ p_raw_sc
* ((float)spl06_cal
.c10
+ p_raw_sc
* ((float)spl06_cal
.c20
+ p_raw_sc
* spl06_cal
.c30
));
141 const float p_temp_comp
= t_raw_sc
* ((float)spl06_cal
.c01
+ p_raw_sc
* ((float)spl06_cal
.c11
+ p_raw_sc
* spl06_cal
.c21
));
143 return pressure_cal
+ p_temp_comp
;
146 bool spl06_calculate(baroDev_t
* baro
, int32_t * pressure
, int32_t * temperature
)
151 *pressure
= lrintf(spl06_compensate_pressure(spl06_pressure_raw
, spl06_temperature_raw
));
155 *temperature
= lrintf(spl06_compensate_temperature(spl06_temperature_raw
) * 100);
161 #define DETECTION_MAX_RETRY_COUNT 5
162 static bool deviceDetect(busDevice_t
* busDev
)
165 for (int retry
= 0; retry
< DETECTION_MAX_RETRY_COUNT
; retry
++) {
167 bool ack
= busRead(busDev
, SPL06_CHIP_ID_REG
, &chipId
);
168 if (ack
&& chipId
== SPL06_DEFAULT_CHIP_ID
) {
176 static bool read_calibration_coefficients(baroDev_t
*baro
) {
178 if (!(busRead(baro
->busDev
, SPL06_MODE_AND_STATUS_REG
, &sstatus
) && (sstatus
& SPL06_MEAS_CFG_COEFFS_RDY
)))
179 return false; // error reading status or coefficients not ready
181 uint8_t caldata
[SPL06_CALIB_COEFFS_LEN
];
183 if (!busReadBuf(baro
->busDev
, SPL06_CALIB_COEFFS_START
, (uint8_t *)&caldata
, SPL06_CALIB_COEFFS_LEN
)) {
187 spl06_cal
.c0
= (caldata
[0] & 0x80 ? 0xF000 : 0) | ((uint16_t)caldata
[0] << 4) | (((uint16_t)caldata
[1] & 0xF0) >> 4);
188 spl06_cal
.c1
= ((caldata
[1] & 0x8 ? 0xF000 : 0) | ((uint16_t)caldata
[1] & 0x0F) << 8) | (uint16_t)caldata
[2];
189 spl06_cal
.c00
= (caldata
[3] & 0x80 ? 0xFFF00000 : 0) | ((uint32_t)caldata
[3] << 12) | ((uint32_t)caldata
[4] << 4) | (((uint32_t)caldata
[5] & 0xF0) >> 4);
190 spl06_cal
.c10
= (caldata
[5] & 0x8 ? 0xFFF00000 : 0) | (((uint32_t)caldata
[5] & 0x0F) << 16) | ((uint32_t)caldata
[6] << 8) | (uint32_t)caldata
[7];
191 spl06_cal
.c01
= ((uint16_t)caldata
[8] << 8) | ((uint16_t)caldata
[9]);
192 spl06_cal
.c11
= ((uint16_t)caldata
[10] << 8) | (uint16_t)caldata
[11];
193 spl06_cal
.c20
= ((uint16_t)caldata
[12] << 8) | (uint16_t)caldata
[13];
194 spl06_cal
.c21
= ((uint16_t)caldata
[14] << 8) | (uint16_t)caldata
[15];
195 spl06_cal
.c30
= ((uint16_t)caldata
[16] << 8) | (uint16_t)caldata
[17];
200 static bool spl06_configure_measurements(baroDev_t
*baro
)
204 reg_value
= SPL06_TEMP_USE_EXT_SENSOR
| spl06_samples_to_cfg_reg_value(SPL06_TEMPERATURE_OVERSAMPLING
);
205 if (!busWrite(baro
->busDev
, SPL06_TEMPERATURE_CFG_REG
, reg_value
)) {
209 reg_value
= spl06_samples_to_cfg_reg_value(SPL06_PRESSURE_OVERSAMPLING
);
210 if (!busWrite(baro
->busDev
, SPL06_PRESSURE_CFG_REG
, reg_value
)) {
215 if (SPL06_TEMPERATURE_OVERSAMPLING
> 8) {
216 reg_value
|= SPL06_TEMPERATURE_RESULT_BIT_SHIFT
;
218 if (SPL06_PRESSURE_OVERSAMPLING
> 8) {
219 reg_value
|= SPL06_PRESSURE_RESULT_BIT_SHIFT
;
221 if (!busWrite(baro
->busDev
, SPL06_INT_AND_FIFO_CFG_REG
, reg_value
)) {
228 bool spl06Detect(baroDev_t
*baro
)
230 baro
->busDev
= busDeviceInit(BUSTYPE_ANY
, DEVHW_SPL06
, 0, OWNER_BARO
);
231 if (baro
->busDev
== NULL
) {
235 busSetSpeed(baro
->busDev
, BUS_SPEED_STANDARD
);
237 if (!(deviceDetect(baro
->busDev
) && read_calibration_coefficients(baro
) && spl06_configure_measurements(baro
))) {
238 busDeviceDeInit(baro
->busDev
);
242 baro
->ut_delay
= SPL06_MEASUREMENT_TIME(SPL06_TEMPERATURE_OVERSAMPLING
) * 1000;
243 baro
->get_ut
= spl06_read_temperature
;
244 baro
->start_ut
= spl06_start_temperature_measurement
;
246 baro
->up_delay
= SPL06_MEASUREMENT_TIME(SPL06_PRESSURE_OVERSAMPLING
) * 1000;
247 baro
->start_up
= spl06_start_pressure_measurement
;
248 baro
->get_up
= spl06_read_pressure
;
250 baro
->calculate
= spl06_calculate
;