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

          Line data    Source code
       1             : #include "AP_BattMonitor_AD7091R5.h"
       2             : 
       3             : /**
       4             :  * @brief You can use it to Read Current and voltage of 1-3 batteries from a ADC extender IC over I2C.
       5             :  * AD7091R5 is a ADC extender and we are using it to read current and voltage of multiple batteries.
       6             :  * Examples of Pin combination:
       7             :  *  1)Pin 50 = Voltage 51,52,53 =  Current. For 3 battery combination Voltage will be same accross.
       8             :  *  2)Pin 50,51 = Voltage and Current Battery 1 -   Pin 52,53 = Voltage and Current Battery 2
       9             :  * Only the First instance of Battery Monitor will be reading the values from IC over I2C.
      10             :  * Make sure you understand the method of calculation used in this driver before using it.
      11             :  * e.g. using pin 1 on IC to read voltage of 2 batteries and pin 2 and 3 to read current from individual battery.
      12             :  * Pin number represents 50 = pin 1, 51 = pin 2 and so on 52, 53
      13             :  * BATT2_Monitor  = 24 ,  BATT3_Monitor  = 24
      14             :  * BATT2_VOLT_PIN = 50 ,  BATT3_VOLT_PIN = 50
      15             :  * BATT2_CURR_PIN = 51 ,  BATT3_CURR_PIN = 52
      16             :  *
      17             :  *
      18             :  */
      19             : 
      20             : #if AP_BATTERY_AD7091R5_ENABLED
      21             : 
      22             : #include <AP_HAL/AP_HAL.h>
      23             : #include <AP_Common/AP_Common.h>
      24             : #include <AP_Math/AP_Math.h>
      25             : 
      26             : //macro defines
      27             : #define AD7091R5_I2C_ADDR        0x2F // A0 and A1 tied to GND
      28             : #define AD7091R5_I2C_BUS         0
      29             : #define AD7091R5_RESET           0x02
      30             : #define AD7091R5_RESULT_ADDR     0x00
      31             : #define AD7091R5_CHAN_ADDR       0x01
      32             : #define AD7091R5_CONF_ADDR       0x02
      33             : #define AD7091R5_CH_ID(x)        ((x >> 5) & 0x03)
      34             : #define AD7091R5_RES_MASK        0x0F
      35             : #define AD7091R5_REF             3.3f
      36             : #define AD7091R5_RESOLUTION      (float)4096
      37             : #define AD7091R5_PERIOD_USEC     100000
      38             : #define AD7091R5_BASE_PIN        50
      39             : 
      40             : 
      41             : extern const AP_HAL::HAL& hal;
      42             : const AP_Param::GroupInfo AP_BattMonitor_AD7091R5::var_info[] = {
      43             : 
      44             :     // @Param: VOLT_PIN
      45             :     // @DisplayName: Battery Voltage sensing pin on the AD7091R5 Ic
      46             :     // @Description: Sets the analog input pin that should be used for voltage monitoring on AD7091R5.
      47             :     // @Values: -1:Disabled
      48             :     // @Range: -1 127
      49             :     // @User: Standard
      50             :     // @RebootRequired: True
      51             :     AP_GROUPINFO("VOLT_PIN", 56, AP_BattMonitor_AD7091R5, _volt_pin, 0),
      52             : 
      53             :     // @Param: CURR_PIN
      54             :     // @DisplayName: Battery Current sensing pin
      55             :     // @Description: Sets the analog input pin that should be used for Current monitoring on AD7091R5.
      56             :     // @Values: -1:Disabled
      57             :     // @Range: -1 127
      58             :     // @User: Standard
      59             :     // @RebootRequired: True
      60             :     AP_GROUPINFO("CURR_PIN", 57, AP_BattMonitor_AD7091R5, _curr_pin, 0),
      61             : 
      62             :     // @Param: VOLT_MULT
      63             :     // @DisplayName: Voltage Multiplier
      64             :     // @Description: Used to convert the voltage of the voltage sensing pin (@PREFIX@VOLT_PIN) to the actual battery's voltage (pin_voltage * VOLT_MULT).
      65             :     // @User: Advanced
      66             :     AP_GROUPINFO("VOLT_MULT", 58, AP_BattMonitor_AD7091R5, _volt_multiplier, 0),
      67             : 
      68             :     // @Param: AMP_PERVLT
      69             :     // @DisplayName: Amps per volt
      70             :     // @Description: Number of amps that a 1V reading on the current sensor corresponds to.
      71             :     // @Units: A/V
      72             :     // @User: Standard
      73             :     AP_GROUPINFO("AMP_PERVLT", 59, AP_BattMonitor_AD7091R5, _curr_amp_per_volt, 0),
      74             : 
      75             :     // @Param: AMP_OFFSET
      76             :     // @DisplayName: AMP offset
      77             :     // @Description: Voltage offset at zero current on current sensor
      78             :     // @Units: V
      79             :     // @User: Standard
      80             :     AP_GROUPINFO("AMP_OFFSET", 60, AP_BattMonitor_AD7091R5, _curr_amp_offset, 0),
      81             : 
      82             :     // @Param: VLT_OFFSET
      83             :     // @DisplayName: Volage offset
      84             :     // @Description: Voltage offset on voltage pin. This allows for an offset due to a diode. This voltage is subtracted before the scaling is applied
      85             :     // @Units: V
      86             :     // @User: Advanced
      87             :     AP_GROUPINFO("VLT_OFFSET", 61, AP_BattMonitor_AD7091R5, _volt_offset, 0),
      88             : 
      89             :     // CHECK/UPDATE INDEX TABLE IN AP_BattMonitor_Backend.cpp WHEN CHANGING OR ADDING PARAMETERS
      90             : 
      91             :     AP_GROUPEND
      92             : };
      93             : 
      94             : 
      95             : //Variable initialised to read from first instance.
      96             : AP_BattMonitor_AD7091R5::AnalogData AP_BattMonitor_AD7091R5::_analog_data[AD7091R5_NO_OF_CHANNELS];
      97             : bool AP_BattMonitor_AD7091R5::_first = true;
      98             : bool AP_BattMonitor_AD7091R5::_health = false;
      99             : 
     100             : /**
     101             :  * @brief Construct a new ap battmonitor ad7091r5::ap battmonitor ad7091r5 object
     102             :  *
     103             :  * @param mon
     104             :  * @param mon_state
     105             :  * @param params
     106             :  */
     107           0 : AP_BattMonitor_AD7091R5::AP_BattMonitor_AD7091R5(AP_BattMonitor &mon,
     108             :         AP_BattMonitor::BattMonitor_State &mon_state,
     109           0 :         AP_BattMonitor_Params &params) :
     110           0 :     AP_BattMonitor_Backend(mon, mon_state, params)
     111             : {
     112           0 :     AP_Param::setup_object_defaults(this, var_info);
     113           0 :     _state.var_info = var_info;
     114           0 : }
     115             : 
     116             : /**
     117             :  * @brief probe and initialize the sensor and register call back
     118             :  *
     119             :  */
     120           0 : void AP_BattMonitor_AD7091R5::init()
     121             : {
     122             :     // voltage and current pins from params and check if there are in range
     123           0 :     if (_volt_pin.get() >= AD7091R5_BASE_PIN && _volt_pin.get() <= AD7091R5_BASE_PIN + AD7091R5_NO_OF_CHANNELS && 
     124           0 :     _curr_pin.get() >= AD7091R5_BASE_PIN && _curr_pin.get() <= AD7091R5_BASE_PIN + AD7091R5_NO_OF_CHANNELS) {
     125           0 :         volt_buff_pt = _volt_pin.get() - AD7091R5_BASE_PIN;
     126           0 :         curr_buff_pt = _curr_pin.get() - AD7091R5_BASE_PIN;
     127             :     }
     128             :     else{
     129           0 :         return; //pin values are out of range
     130             :     }
     131             : 
     132             :     // only the first instance read the i2c device
     133           0 :     if (_first) {
     134           0 :         _first = false;
     135             :         // probe i2c device
     136           0 :         _dev = hal.i2c_mgr->get_device_ptr(AD7091R5_I2C_BUS, AD7091R5_I2C_ADDR);
     137             : 
     138           0 :         if (_dev) {
     139           0 :             WITH_SEMAPHORE(_dev->get_semaphore());
     140           0 :             _dev->set_retries(10); // lots of retries during probe
     141             :             //Reset and config device
     142           0 :             if (_initialize()) {
     143           0 :                 _dev->set_retries(2); // drop to 2 retries for runtime
     144           0 :                 _dev->register_periodic_callback(AD7091R5_PERIOD_USEC, FUNCTOR_BIND_MEMBER(&AP_BattMonitor_AD7091R5::_read_adc, void));
     145             :             }
     146           0 :         }
     147             :     }
     148             : }
     149             : 
     150             : /**
     151             :  * @brief read - read the voltage and curren
     152             :  *
     153             :  */
     154           0 : void AP_BattMonitor_AD7091R5::read()
     155             : {
     156             : 
     157           0 :     WITH_SEMAPHORE(sem);
     158             :     //copy global health status to all instances
     159           0 :     _state.healthy = _health;
     160             : 
     161             :     //return if system not healthy
     162           0 :     if (!_state.healthy) {
     163           0 :         return;
     164             :     }
     165             : 
     166             :     //voltage conversion
     167           0 :     _state.voltage = (_data_to_volt(_analog_data[volt_buff_pt].data) - _volt_offset) * _volt_multiplier;
     168             : 
     169             :     //current amps conversion
     170           0 :     _state.current_amps = (_data_to_volt(_analog_data[curr_buff_pt].data) - _curr_amp_offset) * _curr_amp_per_volt;
     171             : 
     172             :     // calculate time since last current read
     173           0 :     uint32_t tnow = AP_HAL::micros();
     174           0 :     uint32_t dt_us = tnow - _state.last_time_micros;
     175             : 
     176             :     // update total current drawn since startup
     177           0 :     update_consumed(_state, dt_us);
     178             : 
     179             :     // record time
     180           0 :     _state.last_time_micros = tnow;
     181           0 : }
     182             : 
     183             : /**
     184             :  * @brief read all four channels and store the results
     185             :  *
     186             :  */
     187           0 : void AP_BattMonitor_AD7091R5::_read_adc()
     188             : {
     189             :     uint8_t data[AD7091R5_NO_OF_CHANNELS*2];
     190             :     //reset and reconfigure IC if health status is not good.
     191           0 :     if (!_state.healthy) {
     192           0 :         _initialize();
     193             :     }
     194             :     //read value
     195           0 :     bool ret = _dev->transfer(nullptr, 0, data, sizeof(data));
     196           0 :     WITH_SEMAPHORE(sem);
     197           0 :     if (ret) {
     198           0 :         for (int i=0; i<AD7091R5_NO_OF_CHANNELS; i++) {
     199           0 :             uint8_t chan = AD7091R5_CH_ID(data[2*i]);
     200           0 :             _analog_data[chan].data = ((uint16_t)(data[2*i]&AD7091R5_RES_MASK)<<8) | data[2*i+1];
     201             :         }
     202           0 :         _health = true;
     203             :     } else {
     204           0 :         _health = false;
     205             :     }
     206           0 : }
     207             : 
     208             : /**
     209             :  * @brief config the adc
     210             :  *
     211             :  * @return true
     212             :  * @return false
     213             :  */
     214           0 : bool AP_BattMonitor_AD7091R5::_initialize()
     215             : {
     216             :     //reset the device
     217           0 :     uint8_t data[3] = {AD7091R5_CONF_ADDR, AD7091R5_CONF_CMD | AD7091R5_RESET, AD7091R5_CONF_PDOWN0};
     218             : 
     219           0 :     if(_dev->transfer(data, sizeof(data), nullptr, 0)){
     220             :         //command mode, use external 3.3 reference, all channels enabled, set address pointer register to read the adc results
     221           0 :         uint8_t data_2[6] = {AD7091R5_CONF_ADDR, AD7091R5_CONF_CMD, AD7091R5_CONF_PDOWN0, AD7091R5_CHAN_ADDR, AD7091R5_CHAN_ALL, AD7091R5_RESULT_ADDR};
     222           0 :         return _dev->transfer(data_2, sizeof(data_2), nullptr, 0);
     223             :     }
     224           0 :     return false;
     225             : }
     226             : 
     227             : /**
     228             :  * @brief convert binary reading to volts
     229             :  *
     230             :  * @param data
     231             :  * @return float
     232             :  */
     233           0 : float AP_BattMonitor_AD7091R5::_data_to_volt(uint32_t data)
     234             : {
     235           0 :     return (AD7091R5_REF/AD7091R5_RESOLUTION)*data;
     236             : }
     237             : 
     238             : #endif // AP_BATTERY_AD7091R5_ENABLED

Generated by: LCOV version 1.14