2 * This file is part of Cleanflight.
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/>.
17 ******************************************************************************
18 * @brief contains definitions from the ST MEMS team
19 * @author MEMS Application Team
21 * @date 11-February-2015
22 ******************************************************************************
25 * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
33 #include "build/build_config.h"
34 #include "build/debug.h"
35 #include "common/utils.h"
37 #include "drivers/time.h"
38 #include "drivers/io.h"
39 #include "drivers/bus.h"
40 #include "drivers/barometer/barometer.h"
41 #include "drivers/barometer/barometer_lps25h.h"
43 #if defined(USE_BARO_LPS25H)
45 #define LPS25HB_WHO_AM_I_ADDR 0x0F
46 #define LPS25HB_RES_CONF_ADDR 0x10
47 #define LPS25HB_CTRL_REG1_ADDR 0x20
48 #define LPS25HB_CTRL_REG2_ADDR 0x21
49 #define LPS25HB_STATUS_REG_ADDR 0x27
50 #define LPS25HB_PRESS_POUT_XL_ADDR 0x28
51 #define LPS25HB_PRESS_OUT_L_ADDR 0x29
52 #define LPS25HB_PRESS_OUT_H_ADDR 0x2A
53 #define LPS25HB_TEMP_OUT_L_ADDR 0x2B
54 #define LPS25HB_TEMP_OUT_H_ADDR 0x2C
56 #define LPS25HB_I2C_MULTIPLEBYTE_CMD 0x80
57 #define LPS25HB_SPI_MULTIPLEBYTE_CMD 0x40
59 #define TEMPERATURE_READY_MASK (1 << 0)
60 #define PRESSURE_READY_MASK (1 << 1)
62 #define I_AM_LPS25HB 0xBD
64 #define LPS25HB_MODE_MASK 0x80
65 #define LPS25HB_MODE_POWERDOWN 0x00
66 #define LPS25HB_MODE_ACTIVE 0x80
68 #define LPS25HB_ODR_MASK 0x70
69 #define LPS25HB_ODR_ONE_SHOT 0x00
70 #define LPS25HB_ODR_1Hz 0x10
71 #define LPS25HB_ODR_7Hz 0x20
72 #define LPS25HB_ODR_12_5Hz 0x30
73 #define LPS25HB_ODR_25Hz 0x40
75 #define LPS25HB_DIFF_EN_MASK 0x08
76 #define LPS25HB_DIFF_DISABLE 0x00
77 #define LPS25HB_DIFF_ENABLE 0x08
79 #define LPS25HB_BDU_MASK 0x04
80 #define LPS25HB_BDU_CONT 0x00
81 #define LPS25HB_BDU_READ 0x04
84 #define LPS25HB_RESET_MEMORY_MASK 0x80
85 #define LPS25HB_NORMAL_MODE 0x00
86 #define LPS25HB_RESET_MEMORY 0x80
89 #define LPS25HB_P_RES_MASK 0x03
90 #define LPS25HB_P_RES_AVG_8 0x00
91 #define LPS25HB_P_RES_AVG_32 0x01
92 #define LPS25HB_P_RES_AVG_128 0x02
93 #define LPS25HB_P_RES_AVG_512 0x03
95 #define LPS25HB_T_RES_MASK 0x0C
96 #define LPS25HB_T_RES_AVG_8 0x00
97 #define LPS25HB_T_RES_AVG_16 0x04
98 #define LPS25HB_T_RES_AVG_32 0x08
99 #define LPS25HB_T_RES_AVG_64 0x0C
101 #define LPS25H_CHIP_ID 0xBD
103 static int32_t pressureRaw
;
104 static int32_t temperatureRaw
;
106 static bool lps25hbRebootCmd(baroDev_t
* baro
)
110 /* Read CTRL_REG5 register */
111 bool ack
= busRead(baro
->busDev
, LPS25HB_CTRL_REG2_ADDR
, &tmpreg
);
116 /* Enable or Disable the reboot memory */
117 tmpreg
|= LPS25HB_RESET_MEMORY
;
119 /* Write value to MEMS CTRL_REG5 regsister */
120 ack
= busWrite(baro
->busDev
, LPS25HB_CTRL_REG2_ADDR
, tmpreg
);
128 static bool lps25hbPower(baroDev_t
* baro
, bool enable
)
132 /* Read the register content */
133 bool ack
= busRead(baro
->busDev
, LPS25HB_CTRL_REG1_ADDR
, &tmpreg
);
138 tmpreg
&= ~LPS25HB_MODE_MASK
;
141 tmpreg
|= LPS25HB_MODE_ACTIVE
;
144 tmpreg
|= LPS25HB_MODE_POWERDOWN
;
148 ack
= busWrite(baro
->busDev
, LPS25HB_CTRL_REG1_ADDR
, tmpreg
);
156 static bool lps25hbInit(baroDev_t
* baro
)
160 /* Configure the low level interface ---------------------------------------*/
161 if (!lps25hbRebootCmd(baro
)) {
167 if (!lps25hbPower(baro
, false)) {
171 bool ack
= busRead(baro
->busDev
, LPS25HB_CTRL_REG1_ADDR
, &tmp1
);
176 /* Output Data Rate selection */
177 tmp1
= (tmp1
& (~(LPS25HB_ODR_MASK
))) | LPS25HB_ODR_25Hz
;
179 /* Interrupt circuit selection */
180 tmp1
= (tmp1
& (~(LPS25HB_DIFF_EN_MASK
))) | LPS25HB_DIFF_ENABLE
;
182 /* Block Data Update selection - continuous mode */
183 tmp1
= (tmp1
& (~(LPS25HB_BDU_MASK
))) | LPS25HB_BDU_CONT
;
185 ack
= busWrite(baro
->busDev
, LPS25HB_CTRL_REG1_ADDR
, tmp1
);
191 ack
= busRead(baro
->busDev
, LPS25HB_RES_CONF_ADDR
, &tmp1
);
196 // PressureResolution
197 tmp1
= (tmp1
& (~(LPS25HB_P_RES_MASK
))) | LPS25HB_P_RES_AVG_512
;
199 // TemperatureResolution
200 tmp1
= (tmp1
& (~(LPS25HB_T_RES_MASK
))) | LPS25HB_T_RES_AVG_32
;
202 ack
= busWrite(baro
->busDev
, LPS25HB_RES_CONF_ADDR
, tmp1
);
207 if (!lps25hbPower(baro
, true)) {
215 // check the status register bit to be present
216 static bool isDataReady(baroDev_t
* baro
, uint8_t bitMask
)
220 bool ack
= busRead(baro
->busDev
, LPS25HB_STATUS_REG_ADDR
, &tmp
);
225 return (tmp
& bitMask
);
228 static bool lps25h_start_up(baroDev_t
* baro
)
234 static bool lps25h_get_up(baroDev_t
* baro
)
236 uint8_t buffer
[3] = {0};
238 if (isDataReady(baro
, PRESSURE_READY_MASK
)) {
239 if (baro
->busDev
->busType
== BUSTYPE_SPI
) {
240 busReadBuf(baro
->busDev
, LPS25HB_SPI_MULTIPLEBYTE_CMD
| LPS25HB_PRESS_POUT_XL_ADDR
, buffer
, sizeof(buffer
));
243 busReadBuf(baro
->busDev
, LPS25HB_I2C_MULTIPLEBYTE_CMD
| LPS25HB_PRESS_POUT_XL_ADDR
, buffer
, sizeof(buffer
));
246 pressureRaw
= (int32_t)((uint32_t)buffer
[2] << 16 | (uint32_t)buffer
[1] << 8 | (uint32_t)buffer
[0]);
252 static bool lps25h_start_ut(baroDev_t
* baro
)
258 static bool lps25h_get_ut(baroDev_t
* baro
)
260 uint8_t data
[2] = {0};
262 if (isDataReady(baro
, TEMPERATURE_READY_MASK
)) {
263 if (baro
->busDev
->busType
== BUSTYPE_SPI
) {
264 busReadBuf(baro
->busDev
, LPS25HB_SPI_MULTIPLEBYTE_CMD
| LPS25HB_TEMP_OUT_L_ADDR
, data
, sizeof(data
));
267 busReadBuf(baro
->busDev
, LPS25HB_I2C_MULTIPLEBYTE_CMD
| LPS25HB_TEMP_OUT_L_ADDR
, data
, sizeof(data
));
270 temperatureRaw
= (int16_t)((uint16_t)data
[1] << 8 | (uint16_t)data
[0]);
276 #define DETECTION_MAX_RETRY_COUNT 5
277 static bool deviceDetect(busDevice_t
* busDev
)
279 for (int retry
= 0; retry
< DETECTION_MAX_RETRY_COUNT
; retry
++) {
284 bool ack
= busRead(busDev
, LPS25HB_WHO_AM_I_ADDR
, &chipId
);
285 // verified: id is 189 (0xBD)
287 if (ack
&& chipId
== LPS25H_CHIP_ID
) {
295 STATIC_UNIT_TESTED
bool lps25h_calculate(baroDev_t
* baro
, int32_t * pressure
, int32_t * temperature
)
300 // Pout(hPa) = PRESS_OUT / 4096
301 // Pout(Pa) = Pout(hPa) * 100
302 *pressure
= pressureRaw
* 100 / 4096;
306 // We need temperature in 0.01 degC
307 *temperature
= 4250 + temperatureRaw
* 100 / 480;
313 bool lps25hDetect(baroDev_t
*baro
)
315 baro
->busDev
= busDeviceInit(BUSTYPE_ANY
, DEVHW_LPS25H
, 0, OWNER_BARO
);
316 if (baro
->busDev
== NULL
) {
320 busSetSpeed(baro
->busDev
, BUS_SPEED_STANDARD
);
322 if (!deviceDetect(baro
->busDev
)) {
323 busDeviceDeInit(baro
->busDev
);
330 baro
->get_ut
= lps25h_get_ut
;
331 baro
->start_ut
= lps25h_start_ut
;
333 baro
->up_delay
= 1000;
334 baro
->start_up
= lps25h_start_up
;
335 baro
->get_up
= lps25h_get_up
;
337 baro
->calculate
= lps25h_calculate
;