1 #include "devAnalogVbat.h"
9 // Sample 5x samples over 500ms (unless SlowUpdate)
10 #define VBAT_SMOOTH_CNT 5
11 #if defined(DEBUG_VBAT_ADC)
12 #define VBAT_SAMPLE_INTERVAL 20U // faster updates in debug mode
14 #define VBAT_SAMPLE_INTERVAL 100U
17 typedef uint16_t vbatAnalogStorage_t
;
18 static MedianAvgFilter
<vbatAnalogStorage_t
, VBAT_SMOOTH_CNT
>vbatSmooth
;
19 static uint8_t vbatUpdateScale
;
21 #if defined(PLATFORM_ESP32)
22 #include "esp_adc_cal.h"
23 static esp_adc_cal_characteristics_t
*vbatAdcUnitCharacterics
;
26 /* Shameful externs */
27 extern Telemetry telemetry
;
30 * @brief: Enable SlowUpdate mode to reduce the frequency Vbat telemetry is sent
32 void Vbat_enableSlowUpdate(bool enable
)
34 vbatUpdateScale
= enable
? 2 : 1;
37 static bool initialize()
39 return GPIO_ANALOG_VBAT
!= UNDEF_PIN
;
45 #if defined(PLATFORM_ESP32)
46 analogReadResolution(12);
48 int atten
= hardware_int(HARDWARE_vbat_atten
);
51 // if the configured value is higher than the max item (11dB, it indicates to use cal_characterize)
52 bool useCal
= atten
> ADC_11db
;
55 atten
-= (ADC_11db
+ 1);
57 vbatAdcUnitCharacterics
= new esp_adc_cal_characteristics_t();
58 int8_t channel
= digitalPinToAnalogChannel(GPIO_ANALOG_VBAT
);
59 adc_unit_t unit
= (channel
> (SOC_ADC_MAX_CHANNEL_NUM
- 1)) ? ADC_UNIT_2
: ADC_UNIT_1
;
60 esp_adc_cal_characterize(unit
, (adc_atten_t
)atten
, ADC_WIDTH_BIT_12
, 3300, vbatAdcUnitCharacterics
);
62 analogSetPinAttenuation(GPIO_ANALOG_VBAT
, (adc_attenuation_t
)atten
);
66 return VBAT_SAMPLE_INTERVAL
;
69 static void reportVbat()
71 uint32_t adc
= vbatSmooth
.calc();
72 #if defined(PLATFORM_ESP32) && !defined(DEBUG_VBAT_ADC)
73 if (vbatAdcUnitCharacterics
)
74 adc
= esp_adc_cal_raw_to_voltage(adc
, vbatAdcUnitCharacterics
);
78 // For negative offsets, anything between abs(OFFSET) and 0 is considered 0
79 if (ANALOG_VBAT_OFFSET
< 0 && adc
<= -ANALOG_VBAT_OFFSET
)
82 vbat
= ((int32_t)adc
- ANALOG_VBAT_OFFSET
) * 100 / ANALOG_VBAT_SCALE
;
84 CRSF_MK_FRAME_T(crsf_sensor_battery_t
) crsfbatt
= { 0 };
85 // Values are MSB first (BigEndian)
86 crsfbatt
.p
.voltage
= htobe16((uint16_t)vbat
);
87 // No sensors for current, capacity, or remaining available
89 CRSF::SetHeaderAndCrc((uint8_t *)&crsfbatt
, CRSF_FRAMETYPE_BATTERY_SENSOR
, CRSF_FRAME_SIZE(sizeof(crsf_sensor_battery_t
)), CRSF_ADDRESS_CRSF_TRANSMITTER
);
90 telemetry
.AppendTelemetryPackage((uint8_t *)&crsfbatt
);
95 if (telemetry
.GetCrsfBatterySensorDetected())
97 return DURATION_NEVER
;
100 uint32_t adc
= analogRead(GPIO_ANALOG_VBAT
);
101 #if defined(PLATFORM_ESP32) && defined(DEBUG_VBAT_ADC)
102 // When doing DEBUG_VBAT_ADC, every value is adjusted (for logging)
103 // in normal mode only the final value is adjusted to save CPU cycles
104 if (vbatAdcUnitCharacterics
)
105 adc
= esp_adc_cal_raw_to_voltage(adc
, vbatAdcUnitCharacterics
);
106 DBGLN("$ADC,%u", adc
);
109 unsigned int idx
= vbatSmooth
.add(adc
);
110 if (idx
== 0 && connectionState
== connected
)
113 return VBAT_SAMPLE_INTERVAL
* vbatUpdateScale
;
116 device_t AnalogVbat_device
= {
117 .initialize
= initialize
,
121 .subscribe
= EVENT_NONE