LCOV - code coverage report
Current view: top level - AP_Baro - AP_Baro_DPS280.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 145 0.0 %
Date: 2026-09-09 11:02:08 Functions: 0 13 0.0 %

          Line data    Source code
       1             : /*
       2             :    This program is free software: you can redistribute it and/or modify
       3             :    it under the terms of the GNU General Public License as published by
       4             :    the Free Software Foundation, either version 3 of the License, or
       5             :    (at your option) any later version.
       6             : 
       7             :    This program is distributed in the hope that it will be useful,
       8             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
       9             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      10             :    GNU General Public License for more details.
      11             : 
      12             :    You should have received a copy of the GNU General Public License
      13             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      14             :  */
      15             : /*
      16             :   DPS280 barometer driver
      17             :  */
      18             : 
      19             : #include "AP_Baro_DPS280.h"
      20             : 
      21             : #if AP_BARO_DPS280_ENABLED
      22             : 
      23             : #include <stdio.h>
      24             : #include <AP_Math/definitions.h>
      25             : 
      26             : extern const AP_HAL::HAL &hal;
      27             : 
      28             : #define DPS280_REG_PRESS  0x00
      29             : #define DPS280_REG_TEMP   0x03
      30             : #define DPS280_REG_PCONF  0x06
      31             : #define DPS280_REG_TCONF  0x07
      32             : #define DPS280_REG_MCONF  0x08
      33             : #define DPS280_REG_CREG   0x09
      34             : #define DPS280_REG_ISTS   0x0A
      35             : #define DPS280_REG_FSTS   0x0B
      36             : #define DPS280_REG_RESET  0x0C
      37             : #define DPS280_REG_PID    0x0D
      38             : #define DPS280_REG_COEF   0x10
      39             : #define DPS280_REG_CSRC   0x28
      40             : 
      41             : #define DPS280_WHOAMI 0x10
      42             : 
      43             : #define TEMPERATURE_LIMIT_C 120
      44             : 
      45           0 : AP_Baro_DPS280::AP_Baro_DPS280(AP_Baro &baro, AP_HAL::Device &_dev)
      46             :     : AP_Baro_Backend(baro)
      47           0 :     , dev(&_dev)
      48             : {
      49           0 : }
      50             : 
      51           0 : AP_Baro_Backend *AP_Baro_DPS280::probe(AP_Baro &baro,
      52             :                                        AP_HAL::Device &_dev)
      53             : {
      54           0 :     AP_Baro_DPS280 *sensor = NEW_NOTHROW AP_Baro_DPS280(baro, _dev);
      55           0 :     if (!sensor || !sensor->init()) {
      56           0 :         delete sensor;
      57           0 :         return nullptr;
      58             :     }
      59           0 :     return sensor;
      60             : }
      61             : 
      62           0 : AP_Baro_Backend *AP_Baro_DPS310::probe(AP_Baro &baro, AP_HAL::Device &_dev)
      63             : {
      64           0 :     auto *sensor = NEW_NOTHROW AP_Baro_DPS310(baro, _dev);
      65           0 :     if (!sensor || !sensor->init()) {
      66           0 :         delete sensor;
      67           0 :         return nullptr;
      68             :     }
      69           0 :     return sensor;
      70             : }
      71             : 
      72             : /*
      73             :   handle bit width for 16 bit config registers
      74             :  */
      75           0 : void AP_Baro_DPS280::fix_config_bits16(int16_t &v, uint8_t bits) const
      76             : {
      77           0 :     if (v > int16_t((1U<<(bits-1))-1)) {
      78           0 :         v = v - (1U<<bits);
      79             :     }
      80           0 : }
      81             : 
      82             : /*
      83             :   handle bit width for 32 bit config registers
      84             :  */
      85           0 : void AP_Baro_DPS280::fix_config_bits32(int32_t &v, uint8_t bits) const
      86             : {
      87           0 :     if (v > int32_t((1U<<(bits-1))-1)) {
      88           0 :         v = v - (1U<<bits);
      89             :     }
      90           0 : }
      91             : 
      92             : /*
      93             :   read calibration data
      94             :  */
      95           0 : bool AP_Baro_DPS280::read_calibration(void)
      96             : {
      97             :     uint8_t buf[18];
      98             : 
      99           0 :     if (!dev->read_registers(DPS280_REG_COEF, buf, 18)) {
     100           0 :         return false;
     101             :     }
     102             : 
     103           0 :     calibration.C0  = (buf[0] << 4) + ((buf[1] >>4) & 0x0F);
     104           0 :     calibration.C1  = (buf[2] + ((buf[1] & 0x0F)<<8));
     105           0 :     calibration.C00 = ((buf[4]<<4) + (buf[3]<<12)) + ((buf[5]>>4) & 0x0F);
     106           0 :     calibration.C10 = ((buf[5] & 0x0F)<<16) + buf[7] + (buf[6]<<8);
     107           0 :     calibration.C01 = (buf[9] + (buf[8]<<8));
     108           0 :     calibration.C11 = (buf[11] + (buf[10]<<8));
     109           0 :     calibration.C20 = (buf[13] + (buf[12]<<8));
     110           0 :     calibration.C21 = (buf[15] + (buf[14]<<8));
     111           0 :     calibration.C30 = (buf[17] + (buf[16]<<8));
     112             : 
     113           0 :     fix_config_bits16(calibration.C0, 12);
     114           0 :     fix_config_bits16(calibration.C1, 12);
     115           0 :     fix_config_bits32(calibration.C00, 20);
     116           0 :     fix_config_bits32(calibration.C10, 20);
     117           0 :     fix_config_bits16(calibration.C01, 16);
     118           0 :     fix_config_bits16(calibration.C11, 16);
     119           0 :     fix_config_bits16(calibration.C20, 16);
     120           0 :     fix_config_bits16(calibration.C21, 16);
     121           0 :     fix_config_bits16(calibration.C30, 16);
     122             : 
     123             :     /* get calibration source */
     124           0 :     if (!dev->read_registers(DPS280_REG_CSRC, &calibration.temp_source, 1)) {
     125           0 :         return false;
     126             :     }
     127           0 :     calibration.temp_source &= 0x80;
     128             : 
     129           0 :     return true;
     130             : }
     131             : 
     132           0 : void AP_Baro_DPS280::set_config_registers(void)
     133             : {
     134           0 :     dev->write_register(DPS280_REG_CREG, 0x0C, true); // shift for 16x oversampling
     135           0 :     dev->write_register(DPS280_REG_PCONF, 0x54, true); // 32 Hz, 16x oversample
     136           0 :     dev->write_register(DPS280_REG_TCONF, 0x54 | calibration.temp_source, true); // 32 Hz, 16x oversample
     137           0 :     dev->write_register(DPS280_REG_MCONF, 0x07); // continuous temp and pressure.
     138           0 : }
     139             : 
     140           0 : void AP_Baro_DPS310::set_config_registers(void)
     141             : {
     142           0 :         AP_Baro_DPS280::set_config_registers();
     143             : 
     144             :         // work around broken temperature handling on some sensors
     145             :         // using undocumented register writes
     146             :         // see https://github.com/infineon/DPS310-Pressure-Sensor/blob/dps310/src/DpsClass.cpp#L442
     147           0 :         dev->write_register(0x0E, 0xA5);
     148           0 :         dev->write_register(0x0F, 0x96);
     149           0 :         dev->write_register(0x62, 0x02);
     150           0 :         dev->write_register(0x0E, 0x00);
     151           0 :         dev->write_register(0x0F, 0x00);
     152           0 : }
     153             : 
     154           0 : bool AP_Baro_DPS280::init()
     155             : {
     156           0 :     if (!dev) {
     157           0 :         return false;
     158             :     }
     159           0 :     dev->get_semaphore()->take_blocking();
     160             : 
     161             :     // setup to allow reads on SPI
     162           0 :     if (dev->bus_type() == AP_HAL::Device::BUS_TYPE_SPI) {
     163           0 :         dev->set_read_flag(0x80);
     164             :     }
     165             : 
     166           0 :     dev->set_speed(AP_HAL::Device::SPEED_HIGH);
     167             : 
     168             :     // the DPS310 can get into a state on boot where the whoami is not
     169             :     // read correctly at startup. Toggling the CS line gets its out of
     170             :     // this state
     171           0 :     dev->set_chip_select(true);
     172           0 :     dev->set_chip_select(false);
     173             : 
     174           0 :     uint8_t whoami=0;
     175           0 :     if (!dev->read_registers(DPS280_REG_PID, &whoami, 1) ||
     176           0 :         whoami != DPS280_WHOAMI) {
     177           0 :         dev->get_semaphore()->give();
     178           0 :         return false;
     179             :     }
     180             : 
     181           0 :     if (!read_calibration()) {
     182           0 :         dev->get_semaphore()->give();
     183           0 :         return false;
     184             :     }
     185             : 
     186           0 :     dev->setup_checked_registers(4, 20);
     187             : 
     188           0 :     set_config_registers();
     189             : 
     190           0 :     instance = _frontend.register_sensor();
     191             : 
     192           0 :     dev->set_device_type(device_type());
     193           0 :     set_bus_id(instance, dev->get_bus_id());
     194             :     
     195           0 :     dev->get_semaphore()->give();
     196             : 
     197             :     // request 64Hz update. New data will be available at 32Hz
     198           0 :     dev->register_periodic_callback((1000 / 64) * AP_USEC_PER_MSEC, FUNCTOR_BIND_MEMBER(&AP_Baro_DPS280::timer, void));
     199             : 
     200           0 :     return true;
     201             : }
     202             : 
     203             : /*
     204             :   calculate corrected pressure and temperature
     205             :  */
     206           0 : void AP_Baro_DPS280::calculate_PT(int32_t UT, int32_t UP, float &pressure, float &temperature)
     207             : {
     208           0 :     const struct dps280_cal &cal = calibration;
     209             :     // scaling for 16x oversampling
     210           0 :     const float scaling_16 = 1.0f/253952;
     211             : 
     212             :     float temp_scaled;
     213             :     float press_scaled;
     214             : 
     215           0 :     temp_scaled = float(UT) * scaling_16;
     216           0 :     temperature = cal.C0 * 0.5f + cal.C1 * temp_scaled;
     217             : 
     218           0 :     press_scaled = float(UP) * scaling_16;
     219             : 
     220           0 :     pressure = cal.C00;
     221           0 :     pressure += press_scaled * (cal.C10 + press_scaled * (cal.C20 + press_scaled * cal.C30));
     222           0 :     pressure += temp_scaled * cal.C01;
     223           0 :     pressure += temp_scaled * press_scaled * (cal.C11 + press_scaled * cal.C21);
     224           0 : }
     225             : 
     226             : /*
     227             :   check health and possibly reset
     228             :  */
     229           0 : void AP_Baro_DPS280::check_health(void)
     230             : {
     231           0 :     dev->check_next_register();
     232             : 
     233           0 :     if (fabsf(last_temperature) > TEMPERATURE_LIMIT_C) {
     234           0 :         err_count++;
     235             :     }
     236           0 :     if (err_count > 16) {
     237           0 :         err_count = 0;
     238           0 :         dev->write_register(DPS280_REG_RESET, 0x09);
     239           0 :         set_config_registers();
     240           0 :         pending_reset = true;
     241             :     }
     242           0 : }
     243             : 
     244             : //  accumulate a new sensor reading
     245           0 : void AP_Baro_DPS280::timer(void)
     246             : {
     247             :     uint8_t buf[6];
     248             :     uint8_t ready;
     249             : 
     250           0 :     if (pending_reset) {
     251             :         // reset registers after software reset from check_health()
     252           0 :         pending_reset = false;
     253           0 :         set_config_registers();
     254           0 :         return;
     255             :     }
     256             : 
     257           0 :     if (!dev->read_registers(DPS280_REG_MCONF, &ready, 1) ||
     258           0 :         !(ready & (1U<<4)) ||
     259           0 :         !dev->read_registers(DPS280_REG_PRESS, buf, 3) ||
     260           0 :         !dev->read_registers(DPS280_REG_TEMP, &buf[3], 3)) {
     261             :         // data not ready
     262           0 :         err_count++;
     263           0 :         check_health();
     264           0 :         return;
     265             :     }
     266             : 
     267           0 :     int32_t press = (buf[2]) + (buf[1]<<8) + (buf[0]<<16);
     268           0 :     int32_t temp  = (buf[5]) + (buf[4]<<8) + (buf[3]<<16);
     269           0 :     fix_config_bits32(press, 24);
     270           0 :     fix_config_bits32(temp, 24);
     271             : 
     272             :     float pressure, temperature;
     273             : 
     274           0 :     calculate_PT(temp, press, pressure, temperature);
     275             : 
     276           0 :     last_temperature = temperature;
     277             : 
     278           0 :     if (!pressure_ok(pressure)) {
     279           0 :         return;
     280             :     }
     281             : 
     282           0 :     check_health();
     283             : 
     284           0 :     if (fabsf(last_temperature) <= TEMPERATURE_LIMIT_C) {
     285           0 :         err_count = 0;
     286             :     }
     287             :     
     288           0 :     WITH_SEMAPHORE(_sem);
     289             : 
     290           0 :     pressure_sum += pressure;
     291           0 :     temperature_sum += temperature;
     292           0 :     count++;
     293           0 : }
     294             : 
     295             : // transfer data to the frontend
     296           0 : void AP_Baro_DPS280::update(void)
     297             : {
     298           0 :     if (count == 0) {
     299           0 :         return;
     300             :     }
     301             : 
     302           0 :     WITH_SEMAPHORE(_sem);
     303             : 
     304           0 :     _copy_to_frontend(instance, pressure_sum/count, temperature_sum/count);
     305           0 :     pressure_sum = 0;
     306           0 :     temperature_sum = 0;
     307           0 :     count=0;
     308           0 : }
     309             : 
     310             : #endif  // AP_BARO_DPS280_ENABLED

Generated by: LCOV version 1.14