Refactor missing prototypes 2 (#14170)
[betaflight.git] / src / main / drivers / barometer / barometer_lps22df.c
blobc5e773943b3de98d664bb2634ad7d705d75d792c
1 /*
2 * This file is part of Betaflight.
4 * Betaflight is free software. You can redistribute this software
5 * and/or modify this software under the terms of the GNU General
6 * Public License as published by the Free Software Foundation,
7 * either version 3 of the License, or (at your option) any later
8 * version.
10 * Betaflight is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this software.
19 * If not, see <http://www.gnu.org/licenses/>.
22 #include <stdbool.h>
23 #include <stdint.h>
25 #include "platform.h"
27 #include "build/build_config.h"
28 #include "build/debug.h"
30 #include "barometer.h"
32 #include "drivers/bus.h"
33 #include "drivers/bus_i2c.h"
34 #include "drivers/bus_i2c_busdev.h"
35 #include "drivers/bus_spi.h"
36 #include "drivers/io.h"
37 #include "drivers/time.h"
39 #include "barometer_lps22df.h"
41 // 10 MHz max SPI frequency
42 #define LPS22DF_MAX_SPI_CLK_HZ 10000000
44 #if defined(USE_BARO) && (defined(USE_BARO_LPS22DF) || defined(USE_BARO_SPI_LPS22DF))
46 /* See datasheet
48 * https://www.st.com/resource/en/datasheet/lps22df.pdf
51 // Macros to encode/decode multi-bit values
52 #define LSM6DSV_ENCODE_BITS(val, mask, shift) ((val << shift) & mask)
53 #define LSM6DSV_DECODE_BITS(val, mask, shift) ((val & mask) >> shift)
55 // RESERVED - 00-0A
57 // Interrupt mode for pressure acquisition configuration (R/W)
58 #define LPS22DF_INTERRUPT_CFG 0x0B
59 #define LPS22DF_INTERRUPT_CFG_AUTOREFP 0x80
60 #define LPS22DF_INTERRUPT_CFG_RESET_ARP 0x40
61 #define LPS22DF_INTERRUPT_CFG_AUTOZERO 0x20
62 #define LPS22DF_INTERRUPT_CFG_RESET_AZ 0x10
63 #define LPS22DF_INTERRUPT_CFG_LIR 0x04
64 #define LPS22DF_INTERRUPT_CFG_PLE 0x02
65 #define LPS22DF_INTERRUPT_CFG_PHE 0x01
67 // Threshold value for pressure interrupt event (least significant bits) (R/W)
68 #define LPS22DF_THS_P_L 0x0C
69 #define LPS22DF_THS_P_H 0x0D
71 // Interface control register (R/W)
72 #define LPS22DF_IF_CTRL 0x0E
73 #define LPS22DF_IF_CTRL_INT_EN_I3C 0x80
74 #define LPS22DF_IF_CTRL_I2C_I3C_DIS 0x40
75 #define LPS22DF_IF_CTRL_SIM 0x20
76 #define LPS22DF_IF_CTRL_SDA_PU_EN 0x10
77 #define LPS22DF_IF_CTRL_SDO_PU_EN 0x08
78 #define LPS22DF_IF_CTRL_INT_PD_DIS 0x04
79 #define LPS22DF_IF_CTRL_CS_PU_DIS 0x02
81 // Device Who am I (R)
82 #define LPS22DF_WHO_AM_I 0x0F
83 #define LPS22DF_CHIP_ID 0xB4
85 // Control register 1 (R/W)
86 #define LPS22DF_CTRL_REG1 0x10
87 #define LPS22DF_CTRL_REG1_ODR_MASK 0x78
88 #define LPS22DF_CTRL_REG1_ODR_SHIFT 3
89 #define LPS22DF_CTRL_REG1_ODR_ONE_SHOT 0
90 #define LPS22DF_CTRL_REG1_ODR_1HZ 1
91 #define LPS22DF_CTRL_REG1_ODR_4HZ 2
92 #define LPS22DF_CTRL_REG1_ODR_10HZ 3
93 #define LPS22DF_CTRL_REG1_ODR_25HZ 4
94 #define LPS22DF_CTRL_REG1_ODR_50HZ 5
95 #define LPS22DF_CTRL_REG1_ODR_75HZ 6
96 #define LPS22DF_CTRL_REG1_ODR_100HZ 7
97 #define LPS22DF_CTRL_REG1_ODR_200HZ 8
98 #define LPS22DF_CTRL_REG1_AVG_MASK 0x03
99 #define LPS22DF_CTRL_REG1_AVG_SHIFT 0
100 #define LPS22DF_CTRL_REG1_AVG_4 0
101 #define LPS22DF_CTRL_REG1_AVG_8 1
102 #define LPS22DF_CTRL_REG1_AVG_16 2
103 #define LPS22DF_CTRL_REG1_AVG_32 3
104 #define LPS22DF_CTRL_REG1_AVG_64 4
105 #define LPS22DF_CTRL_REG1_AVG_128 5
106 #define LPS22DF_CTRL_REG1_AVG_512 7
108 // Control register 2 (R/W)
109 #define LPS22DF_CTRL_REG2 0x11
110 #define LPS22DF_CTRL_REG2_BOOT 0x80
111 #define LPS22DF_CTRL_REG2_LFPF_CFG 0x20
112 #define LPS22DF_CTRL_REG2_EN_LPFP 0x10
113 #define LPS22DF_CTRL_REG2_BDU 0x08
114 #define LPS22DF_CTRL_REG2_SWRESET 0x04
115 #define LPS22DF_CTRL_REG2_ONESHOT 0x01
117 // Control register 3 (R/W)
118 #define LPS22DF_CTRL_REG3 0x12
119 #define LPS22DF_CTRL_REG3_INT_HL 0x08
120 #define LPS22DF_CTRL_REG3_PP_OD 0x02
121 #define LPS22DF_CTRL_REG3_IF_ADD_INC 0x01
123 // Control register 4 (R/W)
124 #define LPS22DF_CTRL_REG4 0x13
125 #define LPS22DF_CTRL_REG4_DRDY_PLS 0x40
126 #define LPS22DF_CTRL_REG4_DRDY 0x20
127 #define LPS22DF_CTRL_REG4_INT_EN 0x10
128 #define LPS22DF_CTRL_REG4_INT_F_FULL 0x04
129 #define LPS22DF_CTRL_REG4_INT_F_WTM 0x02
130 #define LPS22DF_CTRL_REG4_INT_F_OVR 0x01
132 //FIFO control register (R/W)
133 #define LPS22DF_FIFO_CTRL 0x14
134 #define LPS22DF_FIFO_CTRL_STOP_ON_WTM 0x08
135 #define LPS22DF_FIFO_CTRL_TRIG_MODES 0x04
136 #define LPS22DF_FIFO_CTRL_F_MODE_MASK 0x03
137 #define LPS22DF_FIFO_CTRL_F_MODE_SHIFT 0
138 #define LPS22DF_FIFO_CTRL_F_MODE_BYPASS 0
139 #define LPS22DF_FIFO_CTRL_F_MODE_FIFO_MODE 1
140 #define LPS22DF_FIFO_CTRL_F_MODE_CONT 2
141 #define LPS22DF_FIFO_CTRL_F_MODE_CONT_TO_FIFO 3
143 // FIFO threshold setting register (R/W)
144 #define LPS22DF_FIFO_WTM 0x15
146 // Reference pressure LSB data (R)
147 #define LPS22DF_REF_P_L 0x16
148 #define LPS22DF_REF_P_H 0x17
150 // RESERVED - 18
152 // Control register (R/W)
153 #define LPS22DF_I3C_IF_CTRL_ADD 0x19
154 #define LPS22DF_I3C_IF_CTRL_ADD_RESVD 0x80
155 #define LPS22DF_I3C_IF_CTRL_ADD_ASF_ON 0x20
156 #define LPS22DF_I3C_IF_CTRL_ADD_I3C_BUS_AVB_SEL_MASK 0x03
157 #define LPS22DF_I3C_IF_CTRL_ADD_I3C_BUS_AVB_SEL_SHIFT 0
158 #define LPS22DF_I3C_IF_CTRL_ADD_I3C_BUS_AVB_SEL_50US 0
159 #define LPS22DF_I3C_IF_CTRL_ADD_I3C_BUS_AVB_SEL_2US 1
160 #define LPS22DF_I3C_IF_CTRL_ADD_I3C_BUS_AVB_SEL_1MS 2
161 #define LPS22DF_I3C_IF_CTRL_ADD_I3C_BUS_AVB_SEL_25MS 3
163 // Pressure offset (R/W)
164 #define LPS22DF_RPDS_L 0x1A
165 #define LPS22DF_RPDS_H 0x1B
167 // RESERVED - 1C-23
169 // Interrupt source (R) register for differential pressure. A read at this address clears the INT_SOURCE register itself.
170 #define LPS22DF_INT_SOURCE 0x24
171 #define LPS22DF_INT_SOURCE_BOOT_ON 0x80
172 #define LPS22DF_INT_SOURCE_IA 0x04
173 #define LPS22DF_INT_SOURCE_PL 0x02
174 #define LPS22DF_INT_SOURCE_PH 0x01
176 // FIFO status register (R)
177 #define LPS22DF_FIFO_STATUS1 0x25
179 // FIFO status register (R)
180 #define LPS22DF_FIFO_STATUS2 0x26
181 #define LPS22DF_FIFO_STATUS2_WTM_IA 0x80
182 #define LPS22DF_FIFO_STATUS2_OVR_IA 0x40
183 #define LPS22DF_FIFO_STATUS2_FULL_IA 0x20
185 // Status register (R)
186 #define LPS22DF_STATUS 0x27
187 #define LPS22DF_STATUS_T_OR 0x20
188 #define LPS22DF_STATUS_P_OR 0x10
189 #define LPS22DF_STATUS_T_DA 0x02
190 #define LPS22DF_STATUS_P_DA 0x01
192 // Pressure output value (R)
193 #define LPS22DF_PRESSURE_OUT_XL 0x28
194 #define LPS22DF_PRESSURE_OUT_L 0x29
195 #define LPS22DF_PRESSURE_OUT_H 0x2A
197 // Temperature output value (R)
198 #define LPS22DF_TEMP_OUT_L 0x2B
199 #define LPS22DF_TEMP_OUT_H 0x2C
201 // RESERVED - 2D-77
203 // FIFO pressure output (R)
204 #define LPS22DF_FIFO_DATA_OUT_PRESS_XL 0x78
205 #define LPS22DF_FIFO_DATA_OUT_PRESS_L 0x79
206 #define LPS22DF_FIFO_DATA_OUT_PRESS_H 0x7A
208 #define LPS22DF_I2C_ADDR 0x5D
210 static uint8_t lps22df_chip_id = 0;
212 // uncompensated pressure and temperature
213 static int32_t lps22df_up = 0;
214 static int32_t lps22df_ut = 0;
216 // 3 bytes of pressure followed by two bytes of temperature
217 #define LPS22DF_DATA_FRAME_SIZE (LPS22DF_TEMP_OUT_H - LPS22DF_PRESSURE_OUT_XL + 1)
219 static DMA_DATA_ZERO_INIT uint8_t sensor_data[LPS22DF_DATA_FRAME_SIZE];
221 static bool lps22dfStartUT(baroDev_t *baro);
222 static bool lps22dfReadUT(baroDev_t *baro);
223 static bool lps22dfGetUT(baroDev_t *baro);
224 static bool lps22dfStartUP(baroDev_t *baro);
225 static bool lps22dfReadUP(baroDev_t *baro);
226 static bool lps22dfGetUP(baroDev_t *baro);
228 STATIC_UNIT_TESTED void lps22dfCalculate(int32_t *pressure, int32_t *temperature);
230 static void lps22dfBusInit(const extDevice_t *dev)
232 #ifdef USE_BARO_SPI_LPS22DF
233 if (dev->bus->busType == BUS_TYPE_SPI) {
234 IOHi(dev->busType_u.spi.csnPin); // Disable
235 IOInit(dev->busType_u.spi.csnPin, OWNER_BARO_CS, 0);
236 IOConfigGPIO(dev->busType_u.spi.csnPin, IOCFG_OUT_PP);
237 spiSetClkDivisor(dev, spiCalculateDivider(LPS22DF_MAX_SPI_CLK_HZ));
239 #else
240 UNUSED(dev);
241 #endif
244 static void lps22dfBusDeinit(const extDevice_t *dev)
246 #ifdef USE_BARO_SPI_LPS22DF
247 if (dev->bus->busType == BUS_TYPE_SPI) {
248 ioPreinitByIO(dev->busType_u.spi.csnPin, IOCFG_IPU, PREINIT_PIN_STATE_HIGH);
250 #else
251 UNUSED(dev);
252 #endif
255 bool lps22dfDetect(baroDev_t *baro)
257 delay(20);
259 extDevice_t *dev = &baro->dev;
260 bool defaultAddressApplied = false;
262 lps22dfBusInit(dev);
264 if ((dev->bus->busType == BUS_TYPE_I2C) && (dev->busType_u.i2c.address == 0)) {
265 // Default address for LPS22DF
266 dev->busType_u.i2c.address = LPS22DF_I2C_ADDR;
267 defaultAddressApplied = true;
270 busReadRegisterBuffer(dev, LPS22DF_WHO_AM_I, &lps22df_chip_id, 1); /* read Chip Id */
272 if ((lps22df_chip_id != LPS22DF_CHIP_ID)) {
273 lps22dfBusDeinit(dev);
274 if (defaultAddressApplied) {
275 dev->busType_u.i2c.address = 0;
277 return false;
280 busDeviceRegister(dev);
282 // Reset the device
283 busWriteRegister(dev, LPS22DF_CTRL_REG2, LPS22DF_CTRL_REG2_SWRESET);
285 // Enable one-shot ODR and averaging at 16
286 busWriteRegister(dev, LPS22DF_CTRL_REG1, LSM6DSV_ENCODE_BITS(LPS22DF_CTRL_REG1_ODR_ONE_SHOT,
287 LPS22DF_CTRL_REG1_ODR_MASK,
288 LPS22DF_CTRL_REG1_ODR_SHIFT) |
289 LSM6DSV_ENCODE_BITS(LPS22DF_CTRL_REG1_AVG_16,
290 LPS22DF_CTRL_REG1_AVG_MASK,
291 LPS22DF_CTRL_REG1_AVG_SHIFT));
293 // these are dummy as temperature is measured as part of pressure
294 baro->combined_read = true;
295 baro->ut_delay = 0;
296 baro->start_ut = lps22dfStartUT;
297 baro->get_ut = lps22dfGetUT;
298 baro->read_ut = lps22dfReadUT;
299 // only _up part is executed, and gets both temperature and pressure
300 baro->start_up = lps22dfStartUP;
301 baro->get_up = lps22dfGetUP;
302 baro->read_up = lps22dfReadUP;
303 baro->up_delay = 10000; // 10ms
304 baro->calculate = lps22dfCalculate;
306 return true;
309 static bool lps22dfStartUT(baroDev_t *baro)
311 UNUSED(baro);
312 // dummy
314 return true;
317 static bool lps22dfReadUT(baroDev_t *baro)
319 UNUSED(baro);
320 // dummy
321 return true;
324 static bool lps22dfGetUT(baroDev_t *baro)
326 UNUSED(baro);
327 // dummy
328 return true;
331 static bool lps22dfStartUP(baroDev_t *baro)
333 // start measurement
334 // Trigger one-shot enable block data update to ensure LSB/MSB are coherent
335 return busWriteRegister(&baro->dev, LPS22DF_CTRL_REG2, LPS22DF_CTRL_REG2_ONESHOT | LPS22DF_CTRL_REG2_BDU);
338 static bool lps22dfReadUP(baroDev_t *baro)
340 if (busBusy(&baro->dev, NULL)) {
341 return false;
344 // Read data from sensor
345 return busReadRegisterBufferStart(&baro->dev, LPS22DF_PRESSURE_OUT_XL, sensor_data, LPS22DF_DATA_FRAME_SIZE);
348 static bool lps22dfGetUP(baroDev_t *baro)
350 if (busBusy(&baro->dev, NULL)) {
351 return false;
354 lps22df_up = (int32_t)(sensor_data[0] | sensor_data[1] << 8 | sensor_data[2] << 16);
355 lps22df_ut = (int32_t)(sensor_data[3] | sensor_data[4] << 8);
357 return true;
360 // Returns temperature in DegC, resolution is 0.01 DegC. Output value of "5123" equals 51.23 DegC
361 // t_fine carries fine temperature as global value
362 static int32_t lps22dfCompensateTemperature(int32_t adc_T)
364 return adc_T;
367 // Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits).
368 // Output value of "24674867" represents 24674867/256 = 96386.2 Pa = 963.862 hPa
369 static uint32_t lps22dfCompensatePressure(int32_t adc_P)
371 return (uint32_t)(adc_P * 100.0f / 16);
374 STATIC_UNIT_TESTED void lps22dfCalculate(int32_t *pressure, int32_t *temperature)
376 // calculate
377 int32_t t;
378 uint32_t p;
379 t = lps22dfCompensateTemperature(lps22df_ut);
380 p = lps22dfCompensatePressure(lps22df_up);
382 if (pressure)
383 *pressure = (int32_t)(p / 256);
384 if (temperature)
385 *temperature = t;
388 #endif