Path: blob/master/libraries/AP_Baro/AP_Baro_DPS280.cpp
9552 views
/*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/*15DPS280 barometer driver16*/1718#include "AP_Baro_DPS280.h"1920#if AP_BARO_DPS280_ENABLED2122#include <stdio.h>23#include <AP_Math/definitions.h>2425extern const AP_HAL::HAL &hal;2627#define DPS280_REG_PRESS 0x0028#define DPS280_REG_TEMP 0x0329#define DPS280_REG_PCONF 0x0630#define DPS280_REG_TCONF 0x0731#define DPS280_REG_MCONF 0x0832#define DPS280_REG_CREG 0x0933#define DPS280_REG_ISTS 0x0A34#define DPS280_REG_FSTS 0x0B35#define DPS280_REG_RESET 0x0C36#define DPS280_REG_PID 0x0D37#define DPS280_REG_COEF 0x1038#define DPS280_REG_CSRC 0x283940#define DPS280_WHOAMI 0x104142#define TEMPERATURE_LIMIT_C 1204344AP_Baro_DPS280::AP_Baro_DPS280(AP_Baro &baro, AP_HAL::Device &_dev)45: AP_Baro_Backend(baro)46, dev(&_dev)47{48}4950AP_Baro_Backend *AP_Baro_DPS280::probe(AP_Baro &baro,51AP_HAL::Device &_dev,52bool _is_dps310)53{54AP_Baro_DPS280 *sensor = NEW_NOTHROW AP_Baro_DPS280(baro, _dev);55if (sensor) {56sensor->is_dps310 = _is_dps310;57}58if (!sensor || !sensor->init(_is_dps310)) {59delete sensor;60return nullptr;61}62return sensor;63}6465AP_Baro_Backend *AP_Baro_DPS310::probe(AP_Baro &baro, AP_HAL::Device &_dev)66{67// same as DPS280 but with is_dps310 set for temperature fix68return AP_Baro_DPS280::probe(baro, _dev, true);69}7071/*72handle bit width for 16 bit config registers73*/74void AP_Baro_DPS280::fix_config_bits16(int16_t &v, uint8_t bits) const75{76if (v > int16_t((1U<<(bits-1))-1)) {77v = v - (1U<<bits);78}79}8081/*82handle bit width for 32 bit config registers83*/84void AP_Baro_DPS280::fix_config_bits32(int32_t &v, uint8_t bits) const85{86if (v > int32_t((1U<<(bits-1))-1)) {87v = v - (1U<<bits);88}89}9091/*92read calibration data93*/94bool AP_Baro_DPS280::read_calibration(void)95{96uint8_t buf[18];9798if (!dev->read_registers(DPS280_REG_COEF, buf, 18)) {99return false;100}101102calibration.C0 = (buf[0] << 4) + ((buf[1] >>4) & 0x0F);103calibration.C1 = (buf[2] + ((buf[1] & 0x0F)<<8));104calibration.C00 = ((buf[4]<<4) + (buf[3]<<12)) + ((buf[5]>>4) & 0x0F);105calibration.C10 = ((buf[5] & 0x0F)<<16) + buf[7] + (buf[6]<<8);106calibration.C01 = (buf[9] + (buf[8]<<8));107calibration.C11 = (buf[11] + (buf[10]<<8));108calibration.C20 = (buf[13] + (buf[12]<<8));109calibration.C21 = (buf[15] + (buf[14]<<8));110calibration.C30 = (buf[17] + (buf[16]<<8));111112fix_config_bits16(calibration.C0, 12);113fix_config_bits16(calibration.C1, 12);114fix_config_bits32(calibration.C00, 20);115fix_config_bits32(calibration.C10, 20);116fix_config_bits16(calibration.C01, 16);117fix_config_bits16(calibration.C11, 16);118fix_config_bits16(calibration.C20, 16);119fix_config_bits16(calibration.C21, 16);120fix_config_bits16(calibration.C30, 16);121122/* get calibration source */123if (!dev->read_registers(DPS280_REG_CSRC, &calibration.temp_source, 1)) {124return false;125}126calibration.temp_source &= 0x80;127128return true;129}130131void AP_Baro_DPS280::set_config_registers(void)132{133dev->write_register(DPS280_REG_CREG, 0x0C, true); // shift for 16x oversampling134dev->write_register(DPS280_REG_PCONF, 0x54, true); // 32 Hz, 16x oversample135dev->write_register(DPS280_REG_TCONF, 0x54 | calibration.temp_source, true); // 32 Hz, 16x oversample136dev->write_register(DPS280_REG_MCONF, 0x07); // continuous temp and pressure.137138if (is_dps310) {139// work around broken temperature handling on some sensors140// using undocumented register writes141// see https://github.com/infineon/DPS310-Pressure-Sensor/blob/dps310/src/DpsClass.cpp#L442142dev->write_register(0x0E, 0xA5);143dev->write_register(0x0F, 0x96);144dev->write_register(0x62, 0x02);145dev->write_register(0x0E, 0x00);146dev->write_register(0x0F, 0x00);147}148}149150bool AP_Baro_DPS280::init(bool _is_dps310)151{152if (!dev) {153return false;154}155dev->get_semaphore()->take_blocking();156157// setup to allow reads on SPI158if (dev->bus_type() == AP_HAL::Device::BUS_TYPE_SPI) {159dev->set_read_flag(0x80);160}161162dev->set_speed(AP_HAL::Device::SPEED_HIGH);163164// the DPS310 can get into a state on boot where the whoami is not165// read correctly at startup. Toggling the CS line gets its out of166// this state167dev->set_chip_select(true);168dev->set_chip_select(false);169170uint8_t whoami=0;171if (!dev->read_registers(DPS280_REG_PID, &whoami, 1) ||172whoami != DPS280_WHOAMI) {173dev->get_semaphore()->give();174return false;175}176177if (!read_calibration()) {178dev->get_semaphore()->give();179return false;180}181182dev->setup_checked_registers(4, 20);183184set_config_registers();185186instance = _frontend.register_sensor();187if(_is_dps310) {188dev->set_device_type(DEVTYPE_BARO_DPS310);189} else {190dev->set_device_type(DEVTYPE_BARO_DPS280);191}192set_bus_id(instance, dev->get_bus_id());193194dev->get_semaphore()->give();195196// request 64Hz update. New data will be available at 32Hz197dev->register_periodic_callback((1000 / 64) * AP_USEC_PER_MSEC, FUNCTOR_BIND_MEMBER(&AP_Baro_DPS280::timer, void));198199return true;200}201202/*203calculate corrected pressure and temperature204*/205void AP_Baro_DPS280::calculate_PT(int32_t UT, int32_t UP, float &pressure, float &temperature)206{207const struct dps280_cal &cal = calibration;208// scaling for 16x oversampling209const float scaling_16 = 1.0f/253952;210211float temp_scaled;212float press_scaled;213214temp_scaled = float(UT) * scaling_16;215temperature = cal.C0 * 0.5f + cal.C1 * temp_scaled;216217press_scaled = float(UP) * scaling_16;218219pressure = cal.C00;220pressure += press_scaled * (cal.C10 + press_scaled * (cal.C20 + press_scaled * cal.C30));221pressure += temp_scaled * cal.C01;222pressure += temp_scaled * press_scaled * (cal.C11 + press_scaled * cal.C21);223}224225/*226check health and possibly reset227*/228void AP_Baro_DPS280::check_health(void)229{230dev->check_next_register();231232if (fabsf(last_temperature) > TEMPERATURE_LIMIT_C) {233err_count++;234}235if (err_count > 16) {236err_count = 0;237dev->write_register(DPS280_REG_RESET, 0x09);238set_config_registers();239pending_reset = true;240}241}242243// accumulate a new sensor reading244void AP_Baro_DPS280::timer(void)245{246uint8_t buf[6];247uint8_t ready;248249if (pending_reset) {250// reset registers after software reset from check_health()251pending_reset = false;252set_config_registers();253return;254}255256if (!dev->read_registers(DPS280_REG_MCONF, &ready, 1) ||257!(ready & (1U<<4)) ||258!dev->read_registers(DPS280_REG_PRESS, buf, 3) ||259!dev->read_registers(DPS280_REG_TEMP, &buf[3], 3)) {260// data not ready261err_count++;262check_health();263return;264}265266int32_t press = (buf[2]) + (buf[1]<<8) + (buf[0]<<16);267int32_t temp = (buf[5]) + (buf[4]<<8) + (buf[3]<<16);268fix_config_bits32(press, 24);269fix_config_bits32(temp, 24);270271float pressure, temperature;272273calculate_PT(temp, press, pressure, temperature);274275last_temperature = temperature;276277if (!pressure_ok(pressure)) {278return;279}280281check_health();282283if (fabsf(last_temperature) <= TEMPERATURE_LIMIT_C) {284err_count = 0;285}286287WITH_SEMAPHORE(_sem);288289pressure_sum += pressure;290temperature_sum += temperature;291count++;292}293294// transfer data to the frontend295void AP_Baro_DPS280::update(void)296{297if (count == 0) {298return;299}300301WITH_SEMAPHORE(_sem);302303_copy_to_frontend(instance, pressure_sum/count, temperature_sum/count);304pressure_sum = 0;305temperature_sum = 0;306count=0;307}308309#endif // AP_BARO_DPS280_ENABLED310311312