diff options
| -rw-r--r-- | fsm/ramping.c | 5 | ||||
| -rw-r--r-- | fsm/ramping.h | 3 | ||||
| -rw-r--r-- | hw/hank/emisar-d3aa/hwdef.c | 64 | ||||
| -rw-r--r-- | hw/hank/emisar-d3aa/hwdef.h | 9 | ||||
| -rw-r--r-- | ui/anduril/anduril.c | 12 |
5 files changed, 91 insertions, 2 deletions
diff --git a/fsm/ramping.c b/fsm/ramping.c index adc8acb..63ab399 100644 --- a/fsm/ramping.c +++ b/fsm/ramping.c @@ -57,6 +57,11 @@ inline void set_level_aux_rgb_leds(uint8_t level) { void set_level(uint8_t level) { + #ifdef USE_RAMP_LEVEL_HARD_LIMIT + if (level > ramp_level_hard_limit) + level = ramp_level_hard_limit; + #endif + #ifdef USE_JUMP_START // maybe "jump start" the engine, if it's prone to slow starts // (pulse the output high for a moment to wake up the power regulator) diff --git a/fsm/ramping.h b/fsm/ramping.h index c4b7d48..6fe87fe 100644 --- a/fsm/ramping.h +++ b/fsm/ramping.h @@ -10,6 +10,9 @@ uint8_t actual_level = 0; // the level used before actual uint8_t prev_level = 0; +#ifdef USE_RAMP_LEVEL_HARD_LIMIT +uint8_t ramp_level_hard_limit = RAMP_SIZE; +#endif void set_level(uint8_t level); //void set_level_smooth(uint8_t level); diff --git a/hw/hank/emisar-d3aa/hwdef.c b/hw/hank/emisar-d3aa/hwdef.c index e2fd315..f6cf94e 100644 --- a/hw/hank/emisar-d3aa/hwdef.c +++ b/hw/hank/emisar-d3aa/hwdef.c @@ -4,6 +4,8 @@ #pragma once #include "fsm/chan-rgbaux.c" +#include "fsm/ramping.h" +#include "ui/anduril/misc.h" void set_level_zero(); @@ -110,3 +112,65 @@ uint8_t voltage_raw2cooked(uint16_t measurement) { } #endif +#ifdef USE_WEAK_BATTERY_PROTECTION +uint8_t quick_volt_measurement() { + // take the average of a few samples + // (assumes the ADC is in voltage mode and running continuously) + uint16_t total = 0; + for (uint8_t i=0; i<8; i++) { + uint16_t m = adc_raw[0]; + total += voltage_raw2cooked(m); + delay_zero(); + } + uint8_t v = total / 8; + return v; +} + +void detect_weak_battery() { + // guess at the cell strength with a load test... + // - measure voltage while LEDs off + // - measure again with LEDs on + // - determine how much to limit power + // - blink to indicate weak battery mode, if active + + uint16_t resting, loaded; + + set_level(0); + resting = quick_volt_measurement(); + + set_level(WEAK_BATTERY_CHECK_LEVEL); + loaded = quick_volt_measurement(); + set_level(0); + + int16_t diff = resting - loaded; + uint8_t extra_blinks = 0; + + if (loaded <= DUAL_VOLTAGE_LOW_LOW) { + // weak or empty AA battery has a low limit + ramp_level_hard_limit = WEAK_BATTERY_LOWEST_LIMIT; + extra_blinks = 2; + } else if (loaded >= VOLTAGE_RED) { + // reasonably strong li-ion battery + ramp_level_hard_limit = WEAK_BATTERY_HIGHEST_LIMIT; + } else if (diff <= (-5 * 4)) { + // marginal battery, dropped a lot under mild load + ramp_level_hard_limit = WEAK_BATTERY_MEDIUM_LIMIT; + extra_blinks = 1; + } + + for (uint8_t i=0; i<extra_blinks; i++) { + delay_4ms(300/4); + blink_once(); + } + + voltage = resting; + battcheck(); + + voltage = loaded; + battcheck(); + + //if (diff < 0) + // blink_num(-diff); +} +#endif + diff --git a/hw/hank/emisar-d3aa/hwdef.h b/hw/hank/emisar-d3aa/hwdef.h index 56dd061..1e677b6 100644 --- a/hw/hank/emisar-d3aa/hwdef.h +++ b/hw/hank/emisar-d3aa/hwdef.h @@ -114,6 +114,15 @@ enum CHANNEL_MODES { #define USE_VOLTAGE_VDDIO2 #endif +// Alkaline AA can't handle the power this light wants, +// so try to detect it and limit the maximum power +#define USE_RAMP_LEVEL_HARD_LIMIT +#define USE_WEAK_BATTERY_PROTECTION +#define WEAK_BATTERY_HIGHEST_LIMIT RAMP_SIZE +#define WEAK_BATTERY_MEDIUM_LIMIT (RAMP_SIZE*2/3) +#define WEAK_BATTERY_LOWEST_LIMIT (RAMP_SIZE*1/3) +#define WEAK_BATTERY_CHECK_LEVEL (RAMP_SIZE*2/3) + // average drop across diode on this hardware #ifndef VOLTAGE_FUDGE_FACTOR #define VOLTAGE_FUDGE_FACTOR 0 // using a PFET so no appreciable drop diff --git a/ui/anduril/anduril.c b/ui/anduril/anduril.c index 1cdb8d0..f50f8d2 100644 --- a/ui/anduril/anduril.c +++ b/ui/anduril/anduril.c @@ -225,8 +225,16 @@ void setup() { // regular e-switch light, no hard clicky power button - // blink at power-on to let user know power is connected - blink_once(); + #ifdef USE_WEAK_BATTERY_PROTECTION + // try to measure the battery strength + // (must be done *before* factory reset, + // because reset tries to use full power, + // and a weak battery can't do that) + detect_weak_battery(); + #else + // blink at power-on to let user know power is connected + blink_once(); + #endif #ifdef USE_FACTORY_RESET if (button_is_pressed()) |
