From 5f1141399f95792e1795362bd2ec2240f7e282c752de1a79330067886f64f287 Mon Sep 17 00:00:00 2001 From: localhorst Date: Sun, 9 Nov 2025 17:58:54 +0100 Subject: [PATCH] get battery reference voltage --- main.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/main.c b/main.c index d7f6aee..b9cb86b 100644 --- a/main.c +++ b/main.c @@ -76,13 +76,13 @@ int main(void) PORTA.PIN0CTRL = PORT_PULLUPEN_bm; // Pull-up enabled leds_off(); // Ensure all LEDs off at startup - battery_level_indicator(); // TODO: Implement bool bLedEnabledOld = bLedEnabled; eModeCurrent = ANIMATION_BLINK; // Set the mode to start with while (true) { + battery_level_indicator(); bBtnPressed = handleSwitch(); // Check switch state // Light LEDs while button is pressed @@ -162,6 +162,7 @@ static inline void switchMode(void) */ static void configureLowPower(void) { + return; // Set unused pins as outputs LOW to prevent floating inputs // Floating inputs can cause extra current consumption PORTA.DIRSET = PIN4_bm | PIN5_bm; // Set PA4, PA5 as outputs if unused @@ -248,15 +249,72 @@ static inline void leds_on(void) setPWM_PA2(255U); } +/** + * @brief Read battery voltage using internal 1.1V reference + * @return Estimated battery voltage in millivolts + */ +uint16_t readBatteryVoltage(void) +{ + // Enable ADC + ADC0.CTRLA = ADC_ENABLE_bm; + + // Select internal voltage reference as input + ADC0.MUXPOS = ADC_MUXPOS_INTREF_gc; + + // Use VCC as reference (default) + ADC0.CTRLC = ADC_PRESC_DIV4_gc; // Prescaler for 5MHz/4 = 1.25MHz ADC clock + + // Start conversion + ADC0.COMMAND = ADC_STCONV_bm; + + // Wait for conversion complete + while (!(ADC0.INTFLAGS & ADC_RESRDY_bm)) + ; + + uint16_t adcResult = ADC0.RES; + + // Disable ADC to save power + ADC0.CTRLA = !ADC_ENABLE_bm; + + // Calculate VCC voltage + // V_battery = 1.1V × 1023 / ADC_result + // Result in millivolts: 1100 × 1023 / ADC_result + uint32_t voltage_mv = (1100UL * 1023UL) / adcResult; + + return (uint16_t)voltage_mv; +} + /** * @brief Battery monitoring */ static void battery_level_indicator(void) { - // TODO: Implement - VPORTA.OUT |= (PA6_SET_MASK | PA7_SET_MASK); // green + red OFF -} + uint16_t voltage = readBatteryVoltage(); + // 1S LiPo voltage ranges: + // Good: >=3700mV + // Low: >=3500mV + + // VPORTA.OUT &= ~(PA6_SET_MASK | PA7_SET_MASK); // Turn off both LEDs first + + if (voltage >= 3700) + { + // Green ON, Red OFF - Good battery + VPORTA.OUT &= ~PA6_SET_MASK; // Green ON (active low) + } + else if (voltage >= 3500) + { + // Both ON (yellow/orange) - Medium battery + VPORTA.OUT &= ~(PA6_SET_MASK | PA7_SET_MASK); + } + else + { + // Green OFF, Red ON - Low battery + VPORTA.OUT &= ~PA7_SET_MASK; // Red ON (active low) + } + + VPORTA.OUT &= ~(PA6_SET_MASK | PA7_SET_MASK); +} /** * @brief Handle momentary switch input on PA0 *