Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/libraries/AP_Baro/AP_Baro_BMP388.cpp
Views: 1798
/*1This program is free software: you can redistribute it and/or modify2it under the terms of the GNU General Public License as published by3the Free Software Foundation, either version 3 of the License, or4(at your option) any later version.56This program is distributed in the hope that it will be useful,7but WITHOUT ANY WARRANTY; without even the implied warranty of8MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9GNU General Public License for more details.1011You should have received a copy of the GNU General Public License12along with this program. If not, see <http://www.gnu.org/licenses/>.13*/14#include "AP_Baro_BMP388.h"1516#if AP_BARO_BMP388_ENABLED1718#include <utility>19#include <AP_Math/AP_Math.h>2021extern const AP_HAL::HAL &hal;2223#define BMP388_MODE_SLEEP 024#define BMP388_MODE_FORCED 125#define BMP388_MODE_NORMAL 326#define BMP388_MODE BMP388_MODE_NORMAL2728#define BMP388_ID 0x5029#define BMP390_ID 0x603031#define BMP388_REG_ID 0x0032#define BMP388_REV_ID_ADDR 0x0133#define BMP388_REG_ERR 0x0234#define BMP388_REG_STATUS 0x0335#define BMP388_REG_PRESS 0x04 // 24 bit36#define BMP388_REG_TEMP 0x07 // 24 bit37#define BMP388_REG_TIME 0x0C // 24 bit38#define BMP388_REG_EVENT 0x1039#define BMP388_REG_INT_STS 0x1140#define BMP388_REG_FIFO_LEN 0x12 // 9 bit41#define BMP388_REG_FIFO_DATA 0x1442#define BMP388_REG_FIFO_WTMK 0x15 // 9 bit43#define BMP388_REG_FIFO_CNF1 0x1744#define BMP388_REG_FIFO_CNF2 0x1845#define BMP388_REG_INT_CTRL 0x1946#define BMP388_REG_PWR_CTRL 0x1B47#define BMP388_REG_OSR 0x1C48#define BMP388_REG_ODR 0x1D49#define BMP388_REG_CONFIG 0x1F50#define BMP388_REG_CMD 0x7E5152#define BMP388_REG_CAL_P 0x3653#define BMP388_REG_CAL_T 0x315455AP_Baro_BMP388::AP_Baro_BMP388(AP_Baro &baro, AP_HAL::OwnPtr<AP_HAL::Device> _dev)56: AP_Baro_Backend(baro)57, dev(std::move(_dev))58{59}6061AP_Baro_Backend *AP_Baro_BMP388::probe(AP_Baro &baro,62AP_HAL::OwnPtr<AP_HAL::Device> _dev)63{64if (!_dev) {65return nullptr;66}6768AP_Baro_BMP388 *sensor = NEW_NOTHROW AP_Baro_BMP388(baro, std::move(_dev));69if (!sensor || !sensor->init()) {70delete sensor;71return nullptr;72}73return sensor;74}7576bool AP_Baro_BMP388::init()77{78if (!dev) {79return false;80}81WITH_SEMAPHORE(dev->get_semaphore());8283dev->set_speed(AP_HAL::Device::SPEED_HIGH);8485// setup to allow reads on SPI86if (dev->bus_type() == AP_HAL::Device::BUS_TYPE_SPI) {87dev->set_read_flag(0x80);88}8990// normal mode, temp and pressure91dev->write_register(BMP388_REG_PWR_CTRL, 0x33, true);9293uint8_t whoami;94if (!read_registers(BMP388_REG_ID, &whoami, 1)) {95return false;96}9798switch (whoami) {99case BMP388_ID:100dev->set_device_type(DEVTYPE_BARO_BMP388);101break;102case BMP390_ID:103dev->set_device_type(DEVTYPE_BARO_BMP390);104break;105default:106return false;107}108109// read the calibration data110read_registers(BMP388_REG_CAL_P, (uint8_t *)&calib_p, sizeof(calib_p));111read_registers(BMP388_REG_CAL_T, (uint8_t *)&calib_t, sizeof(calib_t));112113scale_calibration_data();114115dev->setup_checked_registers(4);116117// normal mode, temp and pressure118dev->write_register(BMP388_REG_PWR_CTRL, 0x33, true);119120instance = _frontend.register_sensor();121122set_bus_id(instance, dev->get_bus_id());123124// request 50Hz update125dev->register_periodic_callback(20 * AP_USEC_PER_MSEC, FUNCTOR_BIND_MEMBER(&AP_Baro_BMP388::timer, void));126127return true;128}129130131132// accumulate a new sensor reading133void AP_Baro_BMP388::timer(void)134{135uint8_t buf[7];136137if (!read_registers(BMP388_REG_STATUS, buf, sizeof(buf))) {138return;139}140const uint8_t status = buf[0];141if ((status & 0x20) != 0) {142// we have pressure data143update_pressure((buf[3] << 16) | (buf[2] << 8) | buf[1]);144}145if ((status & 0x40) != 0) {146// we have temperature data147update_temperature((buf[6] << 16) | (buf[5] << 8) | buf[4]);148}149150dev->check_next_register();151}152153// transfer data to the frontend154void AP_Baro_BMP388::update(void)155{156WITH_SEMAPHORE(_sem);157158if (pressure_count == 0) {159return;160}161162_copy_to_frontend(instance,163pressure_sum/pressure_count,164temperature);165166pressure_sum = 0;167pressure_count = 0;168}169170/*171convert calibration data from NVM values to values ready for172compensation calculations173*/174void AP_Baro_BMP388::scale_calibration_data(void)175{176// note that this assumes little-endian MCU177calib.par_t1 = calib_t.nvm_par_t1 * 256.0;178calib.par_t2 = calib_t.nvm_par_t2 / 1073741824.0f;179calib.par_t3 = calib_t.nvm_par_t3 / 281474976710656.0f;180181calib.par_p1 = (calib_p.nvm_par_p1 - 16384) / 1048576.0f;182calib.par_p2 = (calib_p.nvm_par_p2 - 16384) / 536870912.0f;183calib.par_p3 = calib_p.nvm_par_p3 / 4294967296.0f;184calib.par_p4 = calib_p.nvm_par_p4 / 137438953472.0;185calib.par_p5 = calib_p.nvm_par_p5 * 8.0f;186calib.par_p6 = calib_p.nvm_par_p6 / 64.0;187calib.par_p7 = calib_p.nvm_par_p7 / 256.0f;188calib.par_p8 = calib_p.nvm_par_p8 / 32768.0f;189calib.par_p9 = calib_p.nvm_par_p9 / 281474976710656.0f;190calib.par_p10 = calib_p.nvm_par_p10 / 281474976710656.0f;191calib.par_p11 = calib_p.nvm_par_p11 / 36893488147419103232.0f;192}193194/*195update temperature from raw sample196*/197void AP_Baro_BMP388::update_temperature(uint32_t data)198{199float partial1 = data - calib.par_t1;200float partial2 = partial1 * calib.par_t2;201202WITH_SEMAPHORE(_sem);203temperature = partial2 + sq(partial1) * calib.par_t3;204}205206/*207update pressure from raw pressure data208*/209void AP_Baro_BMP388::update_pressure(uint32_t data)210{211float partial1 = calib.par_p6 * temperature;212float partial2 = calib.par_p7 * powf(temperature, 2);213float partial3 = calib.par_p8 * powf(temperature, 3);214float partial_out1 = calib.par_p5 + partial1 + partial2 + partial3;215216partial1 = calib.par_p2 * temperature;217partial2 = calib.par_p3 * powf(temperature, 2);218partial3 = calib.par_p4 * powf(temperature, 3);219float partial_out2 = data * (calib.par_p1 + partial1 + partial2 + partial3);220221partial1 = powf(data, 2);222partial2 = calib.par_p9 + calib.par_p10 * temperature;223partial3 = partial1 * partial2;224float partial4 = partial3 + powf(data, 3) * calib.par_p11;225float press = partial_out1 + partial_out2 + partial4;226227WITH_SEMAPHORE(_sem);228229pressure_sum += press;230pressure_count++;231}232233/*234read registers, special SPI handling needed235*/236bool AP_Baro_BMP388::read_registers(uint8_t reg, uint8_t *data, uint8_t len)237{238// when on I2C we just read normally239if (dev->bus_type() != AP_HAL::Device::BUS_TYPE_SPI) {240return dev->read_registers(reg, data, len);241}242// for SPI we need to discard the first returned byte. See243// datasheet for explanation244uint8_t b[len+2];245b[0] = reg | 0x80;246memset(&b[1], 0, len+1);247if (!dev->transfer(b, len+2, b, len+2)) {248return false;249}250memcpy(data, &b[2], len);251return true;252}253254#endif // AP_BARO_BMP388_ENABLED255256257