博世BMP390读数异常:
/*****************************************************************************
Copyright (C)
2021 Philipp Garn
2021-2022 Frank Reifegerste
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*****************************************************************************/
#include "bmp390.h"
#include "stm32_lpm.h"
#include "stm32_timer.h"
#include "stm32_seq.h"
#include "utilities_def.h"
#include "sys_sensors.h"
#include "pins.h"
#define SET_IDLE
extern I2C_HandleTypeDef hi2c1;
extern RTC_HandleTypeDef hrtc;
double bmp390_T, bmp390_P; // Results from BMP390
static uint16_t T1, T2; // calibration data
static int8_t T3;
static int64_t Tf; // calibration t_fine data
static int16_t P1, P2, P9;
static int8_t P3, P4;
static uint16_t P5, P6;
static int8_t P7, P8, P10, P11;
static UTIL_TIMER_Object_t MeasurementTimer; // TimerObject for TIMER_UTIL
static void ( *bmp390_callback )(void) = NULL; // Callback to be called when measurement is done
#ifdef BME390_FLOATSUPPORT
static double DT1, DT2, DT3, DTlin;
static double DP1, DP2, DP3, DP4, DP5, DP6, DP7, DP8, DP9, DP10, DP11;
#endif // FLOATSUPPORT
//static BMP390_ST_AVG AvgFilter[2];
static void CompensateT(uint32_t T);
static void CompensateP(uint32_t P);
static void enterStop(uint32_t delay);
void onTimer_MeasurementReady(void *context);
void task_readMeasurement();
//static void CalAvgValue(uint8_t *Index, int32_t *AvgBuffer, int32_t InputVal, int32_t *OutputVal);
// uint32_t cy, cy2; // benchmark time points
// cy = DWT->CYCCNT; // Benchmark
// cy2 = DWT->CYCCNT; // Benchmark
// printf("DP %lu\r\n", cy2-cy);
//----------------------------------------------------------------------------
// Sensor initialization
//----------------------------------------------------------------------------
uint8_t bmp390_init() {
// Activate VDD_P and I2C Pullups
HAL_GPIO_WritePin(EN_I2C_GPIO_Port, EN_I2C_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(EN_VDD_P_N_GPIO_Port, EN_VDD_P_N_Pin, GPIO_PIN_SET);
// Register read task so that timer event will be process in main loop
UTIL_SEQ_RegTask((1 << CFG_SEQ_Task_BMP390_ReadMeasurement),
UTIL_SEQ_RFU, task_readMeasurement);
uint8_t value = 0;
// get sensor status, abort if busy
uint8_t status = HAL_I2C_Mem_Read(&hi2c1, BMP390_I2C_ADDR,
BMP390_REG_STATUS,
I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);
uint32_t error = HAL_I2C_GetError(&hi2c1);
SENSOR_LOG("BMP390 Status: %i, Error %i\r\n", status, error);
if (!value)
return false;
value = BMP390_CMD_SOFTRESET;
HAL_I2C_Mem_Write(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_CMD,
I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);
HAL_Delay(2); // Duration softreset 2 ms
// test if command execution failed
HAL_I2C_Mem_Read(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_ERR,
I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);
if (value & BMP390_CMD_ERR)
return false;
// test chip ID
HAL_I2C_Mem_Read(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_CHIP_ID,
I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);
if (value != BMP390_CHIP_ID)
return false;
bmp390_calibrate();
// set ODR to 25/2Hz -> 80ms sampling period
//value = BMP390_ODR_12P5;
//HAL_I2C_Mem_Write(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_ODR, I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);
// x32 oversampling for pressure and temperature
// BMP390_REG_OSR, BMP390_PSMPL_X32 | BMP390_TSMPL_X32 max. Resolution
value = BMP390_PSMPL_X32 | BMP390_TSMPL_X32;
HAL_I2C_Mem_Write(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_OSR,
I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);
// switch off IIR filter
// BMP390_REG_CFG, BMP390_IIR_CF127 127 tap IIR
value = BMP390_IIR_CF0;
HAL_I2C_Mem_Write(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_CFG,
I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);
/*
// enable normal mode
value = BMP390_P_EN | BMP390_T_EN | BMP390_MODE_NORMAL;
HAL_I2C_Mem_Write(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_PWR_CTRL, I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);
*/
// energy saving: enter sleep mode
value = BMP390_MODE_SLEEP;
HAL_I2C_Mem_Write(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_PWR_CTRL,
I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);
return true;
}
void task_readMeasurement() {
// VDD_P and I2C Pullups should be active because of CFG_LPM_Flag_BMP390Active flag
HAL_GPIO_WritePin(EN_I2C_GPIO_Port, EN_I2C_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(EN_VDD_P_N_GPIO_Port, EN_VDD_P_N_Pin, GPIO_PIN_SET);
uint32_t T, P;
uint8_t m[6];
uint8_t value = 0;
uint32_t tick_start = HAL_GetTick();
//while (value != (BMP390_CMD_RDY | BMP390_T_RDY | BMP390_P_RDY)) // measurement is running
while ((value & (BMP390_CMD_RDY | BMP390_T_RDY | BMP390_P_RDY))
!= (BMP390_CMD_RDY | BMP390_T_RDY | BMP390_P_RDY))
{
HAL_I2C_Mem_Read(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_STATUS,
I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);
int diff_ticks = HAL_GetTick() - tick_start;
if (diff_ticks > 1000) {
break;
}
}
HAL_I2C_Mem_Read(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_PRESS_7_0,
I2C_MEMADD_SIZE_8BIT, &m[0], 6, 0x10);
#ifdef SET_IDLE
value = BMP390_MODE_SLEEP;
HAL_I2C_Mem_Write(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_PWR_CTRL,
I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);
#endif
// energy saving: disable Sensors
P = (m[2] << 16) | (m[1] << 8) | m[0];
T = (m[5] << 16) | (m[4] << 8) | m[3];
CompensateT(T);
CompensateP(P); // Tf is needed here!
SENSOR_LOG("BMP390 temperature: %.3f\r\n", bmp390_T);
SENSOR_LOG("BMP390 pressure: %.3f\r\n", bmp390_P);
// MeasurementTimer done, can be switched off during STOP
UTIL_LPM_SetFlag(CFG_LPM_Flag_BMP390Active, UTIL_LPM_DISABLE);
if (bmp390_callback != NULL) {
bmp390_callback();
}
}
void onTimer_MeasurementReady(void *context) {
UTIL_SEQ_SetTask((1 << CFG_SEQ_Task_BMP390_ReadMeasurement),
CFG_SEQ_Prio_0);
// task_readMeasurement();
}
uint8_t bmp390_calibrate() {
uint8_t m[21];
// read calibration data
HAL_I2C_Mem_Read(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_T1_LSB,
I2C_MEMADD_SIZE_8BIT, &m[0], 21, 0x10);
T1 = (m[1] << 8) | m[0];
T2 = (m[3] << 8) | m[2];
T3 = m[4];
P1 = ((m[6] << 8) | m[5]) - 16384;
P2 = ((m[8] << 8) | m[7]) - 16384;
P3 = m[9];
P4 = m[10];
P5 = (m[12] << 8) | m[11];
P6 = (m[14] << 8) | m[13];
P7 = m[15];
P8 = m[16];
P9 = (m[18] << 8) | m[17];
P10 = m[19];
P11 = m[20];
#ifdef BME390_FLOATSUPPORT
// 1 / 2^8
// DT1 = (double)T1 / (double)0.00390625f; // * 256
DT1 = (double)T1 * (double)256.0f; // * 256
DT2 = (double)T2 / (double)1073741824.0f; // / 2^30
DT3 = (double)T3 / (double)281474976710656.0f; // / 2^48
DP1 = (double)P1 / (double)1048576.0f; // / 2^20
DP2 = (double)P2 / (double)536870912.0f; // / 2^29
DP3 = (double)P3 / (double)4294967296.0f; // / 2^32
DP4 = (double)P4 / (double)137438953472.0f; // / 2^37
// 1/2^3
// DP5 = (double)P5 / (double)0.125f; // * 8
DP5 = (double)P5 * (double)8.0f; // * 8
DP6 = (double)P6 / (double)64.0f; // / 2^6
DP7 = (double)P7 / (double)256.0f; // / 2^8
DP8 = (double)P8 / (double)32768.0f; // / 2^15
DP9 = (double)P9 / (double)281474976710656.0f; // / 2^48
DP10 = (double)P10 / (double)281474976710656.0f; // / 2^48
DP11 = (double)P11 / (double)36893488147419103232.0f; // / 2^65
#endif // FLOATSUPPORT
}
//----------------------------------------------------------------------------
// get the raw temperature and pressure data from the temperature and pressure register
//----------------------------------------------------------------------------
void bmp390_getsensordata(void) {
HAL_GPIO_WritePin(EN_I2C_GPIO_Port, EN_I2C_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(EN_VDD_P_N_GPIO_Port, EN_VDD_P_N_Pin, GPIO_PIN_SET);
// Needs to be active when MeasurementTimer is running
UTIL_LPM_SetFlag(CFG_LPM_Flag_BMP390Active, UTIL_LPM_ENABLE);
// start single measurement
uint8_t value = BMP390_MODE_FORCED2 | BMP390_T_EN | BMP390_P_EN;
HAL_I2C_Mem_Write(&hi2c1, BMP390_I2C_ADDR, BMP390_REG_PWR_CTRL,
I2C_MEMADD_SIZE_8BIT, &value, 1, 0x10);
UTIL_TIMER_Create(&MeasurementTimer, 0xFFFFFFFFU, UTIL_TIMER_ONESHOT,
onTimer_MeasurementReady,
NULL);
UTIL_TIMER_SetPeriod(&MeasurementTimer, 500); // estimated time for x32 oversampling -> less I2C traffic for polling
UTIL_TIMER_Start(&MeasurementTimer);
}
#ifdef BME390_FLOATSUPPORT
//----------------------------------------------------------------------------
// Korrekturpolynom Temperatur, Fließkommaversion
// Fließkommavariante: 436 CLKs
//----------------------------------------------------------------------------
void CompensateT(uint32_t T) {
double v1, v2;
v1 = (double)T - DT1;
v2 = v1 * DT2;
bmp390_T = v2 + v1*v1*DT3;
DTlin = bmp390_T;
}
//----------------------------------------------------------------------------
// Korrekturpolynom Druck, Fließkommaversion
// Fließkommavariante: 2117 CLKs
//----------------------------------------------------------------------------
void CompensateP(uint32_t Pin) {
double po1, po2, po3, p;
p = (double)Pin;
po1 = DP5 + DP6 * DTlin + DP7 * DTlin*DTlin + DP8 * DTlin*DTlin*DTlin;
po2 = p * (DP1 + DP2 * DTlin + DP3 * DTlin*DTlin + DP4 * DTlin*DTlin*DTlin);
po3 = p*p * (DP9 + DP10 * DTlin) + p*p*p * DP11;
bmp390_P = po1 + po2 + po3;
}
#else
//----------------------------------------------------------------------------
//calculation of the temperature compensate value using of the calibration data (data sheet)
// Multiplikationen: 66 CLKs
// Multiplikationen durch shifts: 31 CLKs
//----------------------------------------------------------------------------
void CompensateT(uint32_t T) {
/* int64_t v1, v2, v3, v4, v5, v6, Tc;
v1 = (int64_t)(T - ((int64_t)256 * T1));
v2 = (int64_t)(T2 * v1);
v3 = (int64_t)(v1 * v1);
v4 = (int64_t)v3 * T3;
v5 = (int64_t)((int64_t)(v2 * 262144) + v4);
v6 = (int64_t)(v5 / 4294967296);
T_fine = v6;
Tc = (v6 * 25) / 16384; */
uint64_t v1, v2;
int64_t v3, Tc;
v1 = (uint64_t) T - ((uint64_t) T1 << 8);
v2 = v1 * (uint64_t) T2;
v3 = v1 * v1 * (int64_t) T3;
Tf = (((int64_t) v2 << 18) + v3) >> 32;
Tc = (Tf * 25) >> 14;
bmp390_T = (double) Tc / 100.0;
}
//----------------------------------------------------------------------------
// calculation of the pressure compensate value using of the calibration data (data sheet)
// P = P5 + P6*T + P7*T^2 + P8*T^3 + P*(P2*T + P3*T^2 + P4*T^3) + P^2*(P9 + P10*T) + P^3*P11
// Multiplikationen durch shifts: 188 CLKs
//----------------------------------------------------------------------------
void CompensateP(uint32_t P) {
int64_t v1, v2, v3, v4, v5, v6;
int64_t offset, sensitivity;
uint64_t Pc;
v1 = Tf * Tf;
v2 = v1 >> 6;
v3 = (v2 * Tf) >> 8;
v4 = ((int64_t) P8 * v3) >> 5;
v5 = ((int64_t) P7 * v1) >> 4;
v6 = ((int64_t) P6 * Tf) << 22;
offset = ((int64_t) P5 * ((uint64_t) 1 << 47)) + v4 + v5 + v6; // no bitwise op on signed int
v2 = ((int64_t) P4 * v3) >> 5;
v4 = ((int64_t) P3 * v1) << 2;
v5 = ((int64_t) P2 * Tf) << 21;
sensitivity = ((int64_t) P1 * ((uint64_t) 1 << 46)) + v2 + v4 + v5;
v1 = (sensitivity >> 24) * P;
v2 = (int64_t) P10 * Tf;
v3 = v2 + ((int64_t) P9 << 16);
v4 = (v3 * P) >> 13;
v5 = (v4 * P) >> 9;
v2 = ((int64_t) P11 * P * P) >> 16;
v3 = (v2 * P) >> 7;
v4 = (offset >> 2) + v1 + v5 + v3;
Pc = ((int64_t) v4 * 25) / ((uint64_t) 1 << 40);
bmp390_P = (double) Pc / 10000.0;
}
#endif // FLOATSUPPORT
void enterStop(uint32_t delay) {
HAL_SuspendTick();
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, delay,
RTC_WAKEUPCLOCK_RTCCLK_DIV16);
// HAL_PWR_EnterSTANDBYMode();
HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);
HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
SystemClock_Config();
HAL_ResumeTick();
}
void bmp390_onReadyCallback(void ( *Callback )()) {
bmp390_callback = Callback;
}
//----------------------------------------------------------------------------
//calculation of the average value
// filter of the temperature and pressure data and get an output data
// CalAvgValue(&(AvgFilter[0].Index), AvgFilter[0].AvgBuffer, TemperatureIn, TemperatureOut);
// CalAvgValue(&(AvgFilter[1].Index), AvgFilter[1].AvgBuffer, PressureIn, PressureOut);
//----------------------------------------------------------------------------
/*void CalAvgValue(uint8_t *Index, int32_t *AvgBuffer, int32_t InputVal, int32_t *OutputVal) {
uint8_t i;
*(AvgBuffer + ((*Index)++)) = InputVal;
*Index &= 0x07;
*OutputVal = 0;
for (i = 0; i < 8; i++) {
*OutputVal += *(AvgBuffer + i);
}
*OutputVal >>= 3;
}*/
代码为BMP390在以STM32L0单片机为基础的LORAWAN工程的实现。当机器通电第一次读取数据正常,从第二次开始读取数据为0.求解决方案。