watch_adc: enable ADC when checking battery; let's get rid of this footgun once and for all

This commit is contained in:
Joey Castillo 2025-05-21 08:51:39 -04:00
parent 07a085e90b
commit 310ad3d095
10 changed files with 10 additions and 17 deletions

View File

@ -109,9 +109,7 @@ bool close_enough_clock_face_loop(movement_event_t event, void *context) {
// check the battery voltage once a day...
if (date_time.unit.day != state->last_battery_check) {
state->last_battery_check = date_time.unit.day;
watch_enable_adc();
uint16_t voltage = watch_get_vcc_voltage();
watch_disable_adc();
// 2.2 volts will happen when the battery has maybe 5-10% remaining?
// we can refine this later.
state->battery_low = (voltage < 2200);

View File

@ -115,9 +115,7 @@ bool minute_repeater_decimal_face_loop(movement_event_t event, void *context) {
// check the battery voltage once a day...
if (date_time.unit.day != state->last_battery_check) {
state->last_battery_check = date_time.unit.day;
watch_enable_adc();
uint16_t voltage = watch_get_vcc_voltage();
watch_disable_adc();
// 2.2 volts will happen when the battery has maybe 5-10% remaining?
// we can refine this later.
state->battery_low = (voltage < 2200);

View File

@ -100,9 +100,7 @@ bool repetition_minute_face_loop(movement_event_t event, void *context) {
// check the battery voltage once a day...
if (date_time.unit.day != state->last_battery_check) {
state->last_battery_check = date_time.unit.day;
watch_enable_adc();
uint16_t voltage = watch_get_vcc_voltage();
watch_disable_adc();
// 2.2 volts will happen when the battery has maybe 5-10% remaining?
// we can refine this later.
state->battery_low = (voltage < 2200);

View File

@ -126,9 +126,7 @@ bool simple_clock_bin_led_face_loop(movement_event_t event, void *context) {
// check the battery voltage once a day...
if (date_time.unit.day != state->last_battery_check) {
state->last_battery_check = date_time.unit.day;
watch_enable_adc();
uint16_t voltage = watch_get_vcc_voltage();
watch_disable_adc();
// 2.2 volts will happen when the battery has maybe 5-10% remaining?
// we can refine this later.
state->battery_low = (voltage < 2200);

View File

@ -82,9 +82,7 @@ bool weeknumber_clock_face_loop(movement_event_t event, void *context) {
// check the battery voltage once a day...
if (date_time.unit.day != state->last_battery_check) {
state->last_battery_check = date_time.unit.day;
watch_enable_adc();
uint16_t voltage = watch_get_vcc_voltage();
watch_disable_adc();
// 2.2 volts will happen when the battery has maybe 5-10% remaining?
// we can refine this later.
state->battery_low = (voltage < 2200);

View File

@ -98,9 +98,7 @@ static void clock_check_battery_periodically(clock_state_t *state, watch_date_ti
state->last_battery_check = date_time.unit.day;
watch_enable_adc();
uint16_t voltage = watch_get_vcc_voltage();
watch_disable_adc();
state->battery_low = voltage < CLOCK_FACE_LOW_BATTERY_VOLTAGE_THRESHOLD;

View File

@ -28,9 +28,7 @@
#include "watch.h"
static void _voltage_face_update_display(void) {
watch_enable_adc();
float voltage = (float)watch_get_vcc_voltage() / 1000.0;
watch_disable_adc();
watch_display_text_with_fallback(WATCH_POSITION_TOP_LEFT, "BAT", "BA");
watch_display_float_with_best_effort(voltage, " V");

View File

@ -67,6 +67,11 @@ void _watch_set_analog_reference_voltage(uint8_t reference) {
uint16_t watch_get_vcc_voltage(void) {
// stash the previous reference so we can restore it when we're done.
uint8_t oldref = ADC->REFCTRL.bit.REFSEL;
// same with the previous state of the ADC
bool adc_was_disabled = !adc_is_enabled();
// enable the ADC if needed
if (adc_was_disabled) watch_enable_adc();
// if we weren't already using the internal reference voltage, select it now.
if (oldref != ADC_REFCTRL_REFSEL_INTREF_Val) _watch_set_analog_reference_voltage(ADC_REFCTRL_REFSEL_INTREF_Val);
@ -77,6 +82,9 @@ uint16_t watch_get_vcc_voltage(void) {
// restore the old reference, if needed.
if (oldref != ADC_REFCTRL_REFSEL_INTREF_Val) _watch_set_analog_reference_voltage(oldref);
// and restore the ADC to its previous state
if (adc_was_disabled) watch_disable_adc();
return (uint16_t)((raw_val * 1000) / (1024 * 1 << ADC->AVGCTRL.bit.SAMPLENUM));
}

View File

@ -51,9 +51,7 @@ void _watch_init(void) {
while(!SUPC->STATUS.bit.VREGRDY); // wait for voltage regulator to become ready
// check the battery voltage...
watch_enable_adc();
uint16_t battery_voltage = watch_get_vcc_voltage();
watch_disable_adc();
// ...because we can enable the more efficient low power regulator if the system voltage is > 2.5V
// still, enable LPEFF only if the battery voltage is comfortably above this threshold.
if (battery_voltage >= 2700) {

View File

@ -53,7 +53,8 @@ void watch_enable_analog_input(const uint16_t pin);
uint16_t watch_get_analog_pin_level(const uint16_t pin);
/** @brief Returns the voltage of the VCC supply in millivolts (i.e. 3000 mV == 3.0 V). If running on
* a coin cell, this will be the battery voltage.
* a coin cell, this will be the battery voltage. If the ADC is not running when this function
* is called, it enabled the ADC briefly, and returns it to the off state.
* @details Unlike other ADC functions, this function does not return a raw value from the ADC, but
* rather scales it to an actual number of millivolts. This is because the ADC doesn't let
* us measure VCC per se; it instead lets us measure VCC / 4, and we choose to measure it