aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/attiny1616.c125
-rw-r--r--arch/attiny1616.h20
-rw-r--r--arch/avr32dd20.c37
-rw-r--r--arch/avr32dd20.h4
-rw-r--r--fsm/adc.c47
-rw-r--r--fsm/adc.h4
-rw-r--r--hw/sofirn/sp10-pro/hwdef.h4
-rw-r--r--hw/thefreeman/avr32dd20-devkit/hwdef.c16
-rw-r--r--hw/thefreeman/avr32dd20-devkit/hwdef.h6
-rw-r--r--hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/hwdef.h17
-rw-r--r--ui/anduril/anduril.c1
-rw-r--r--ui/anduril/aux-leds.c34
-rw-r--r--ui/anduril/config-default.h4
13 files changed, 207 insertions, 112 deletions
diff --git a/arch/attiny1616.c b/arch/attiny1616.c
index a3ead7e..330c809 100644
--- a/arch/attiny1616.c
+++ b/arch/attiny1616.c
@@ -7,36 +7,60 @@
////////// clock speed / delay stuff //////////
+inline void mcu_clock_speed() {
+ // TODO: allow hwdef to define a base clock speed
+ // set up the system clock to run at 10 MHz instead of the default 3.33 MHz
+ _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB,
+ CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm );
+}
+
///// clock dividers
// this should work, but needs further validation
inline void clock_prescale_set(uint8_t n) {
cli();
- CCP = CCP_IOREG_gc; // temporarily disable clock change protection
- CLKCTRL.MCLKCTRLB = n; // Set the prescaler
+ _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, n); // Set the prescaler
while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm) {} // wait for clock change to finish
sei();
}
+
////////// ADC voltage / temperature //////////
inline void mcu_set_admux_therm() {
+ // put the ADC in temperature mode
+ // attiny1616 datasheet section 30.3.2.6
+ VREF.CTRLA = (VREF.CTRLA & (~VREF_ADC0REFSEL_gm))
+ | VREF_ADC0REFSEL_1V1_gc; // Set Vbg ref to 1.1V
ADC0.MUXPOS = ADC_MUXPOS_TEMPSENSE_gc; // read temperature
+ ADC0.CTRLB = ADC_SAMPNUM_ACC4_gc; // 10-bit result + 4x oversampling
ADC0.CTRLC = ADC_SAMPCAP_bm
- | ADC_PRESC_DIV64_gc
+ | ADC_PRESC_DIV16_gc
| ADC_REFSEL_INTREF_gc; // Internal ADC reference
}
inline void mcu_set_admux_voltage() {
- #ifdef USE_VOLTAGE_DIVIDER // 1.1V / ADC input pin
- // verify that this is correct!!! untested
+ // Enabled, free-running (aka, auto-retrigger), run in standby
+ ADC0.CTRLA = ADC_ENABLE_bm | ADC_FREERUN_bm | ADC_RUNSTBY_bm;
+ // set a INITDLY value because the AVR manual says so (section 30.3.5)
+ // (delay 1st reading until Vref is stable)
+ ADC0.CTRLD |= ADC_INITDLY_DLY16_gc;
+ #ifdef USE_VOLTAGE_DIVIDER // measure an arbitrary pin
+ // result = resolution * Vdiv / 1.1V
+ VREF.CTRLA = (VREF.CTRLA & (~VREF_ADC0REFSEL_gm))
+ | VREF_ADC0REFSEL_1V1_gc; // Set Vbg ref to 1.1V
ADC0.MUXPOS = ADMUX_VOLTAGE_DIVIDER; // read the requested ADC pin
+ ADC0.CTRLB = ADC_SAMPNUM_ACC4_gc; // 12-bit result, 4x oversampling
ADC0.CTRLC = ADC_SAMPCAP_bm
- | ADC_PRESC_DIV64_gc
+ | ADC_PRESC_DIV16_gc
| ADC_REFSEL_INTREF_gc; // Use internal ADC reference
- #else // VCC / 1.1V reference
+ #else // measure VDD pin
+ // result = resolution * 1.5V / Vbat
+ VREF.CTRLA = (VREF.CTRLA & (~VREF_ADC0REFSEL_gm))
+ | VREF_ADC0REFSEL_1V5_gc; // Set Vbg ref to 1.5V
ADC0.MUXPOS = ADC_MUXPOS_INTREF_gc; // read internal reference
+ ADC0.CTRLB = ADC_SAMPNUM_ACC4_gc; // 12-bit result, 4x oversampling
ADC0.CTRLC = ADC_SAMPCAP_bm
- | ADC_PRESC_DIV64_gc
+ | ADC_PRESC_DIV16_gc
| ADC_REFSEL_VDDREF_gc; // Vdd (Vcc) be ADC reference
#endif
}
@@ -47,9 +71,10 @@ inline void mcu_adc_sleep_mode() {
inline void mcu_adc_start_measurement() {
ADC0.INTCTRL |= ADC_RESRDY_bm; // enable interrupt
- ADC0.COMMAND |= ADC_STCONV_bm; // Start the ADC conversions
+ ADC0.COMMAND |= ADC_STCONV_bm; // actually start measuring
}
+/*
inline void mcu_adc_on() {
VREF.CTRLA |= VREF_ADC0REFSEL_1V1_gc; // Set Vbg ref to 1.1V
// Enabled, free-running (aka, auto-retrigger), run in standby
@@ -59,6 +84,7 @@ inline void mcu_adc_on() {
ADC0.CTRLD |= ADC_INITDLY_DLY16_gc;
hwdef_set_admux_voltage();
}
+*/
inline void mcu_adc_off() {
ADC0.CTRLA &= ~(ADC_ENABLE_bm); // disable the ADC
@@ -69,22 +95,69 @@ inline void mcu_adc_vect_clear() {
}
inline uint16_t mcu_adc_result_temp() {
- // Use the factory calibrated values in SIGROW.TEMPSENSE0 and
- // SIGROW.TEMPSENSE1 to calculate a temperature reading in Kelvin, then
- // left-align it.
- int8_t sigrow_offset = SIGROW.TEMPSENSE1; // Read signed value from signature row
- uint8_t sigrow_gain = SIGROW.TEMPSENSE0; // Read unsigned value from signature row
- uint32_t temp = ADC0.RES - sigrow_offset;
- temp *= sigrow_gain; // Result might overflow 16 bit variable (10bit+8bit)
- temp += 0x80; // Add 1/2 to get correct rounding on division below
- //temp >>= 8; // Divide result to get Kelvin
- //return temp << 6; // left align it
- return temp >> 2; // left-aligned uint16_t
+ // just return left-aligned ADC result, don't convert to calibrated units
+ //return ADC0.RES << 6;
+ return ADC0.RES << 4;
}
inline uint16_t mcu_adc_result_volts() {
- // FIXME: set up ADC to use left-aligned values natively
- return ADC0.RES << 6; // voltage, force left-alignment
+ // ADC has no left-aligned mode, so left-align it manually
+ return ADC0.RES << 4;
+}
+
+inline uint8_t mcu_vdd_raw2cooked(uint16_t measurement) {
+ // In : 65535 * 1.5 / Vbat
+ // Out: uint8_t: Vbat * 40
+ // 1.5 = ADC Vref
+ #if 0
+ // 1024 = how much ADC resolution we're using (10 bits)
+ // (12 bits available, but it costs an extra 84 bytes of ROM to calculate)
+ uint8_t vbat40 = (uint16_t)(40 * 1.5 * 1024) / (measurement >> 6);
+ #else
+ // ... spend the extra 84 bytes of ROM for better precision
+ // 4096 = how much ADC resolution we're using (12 bits)
+ uint8_t vbat40 = (uint32_t)(40 * 1.5 * 4096) / (measurement >> 4);
+ #endif
+ return vbat40;
+}
+
+#if 0 // fine voltage, 0 to 10.24V in 1/6400th V steps
+inline uint16_t mcu_vdd_raw2fine(uint16_t measurement) {
+ // In : 65535 * 1.5 / Vbat
+ // Out: 65535 * (Vbat / 10) / 1.024V
+ uint16_t voltage = ((uint32_t)(1.5 * 4096 * 100 * 64 * 16) / measurement;
+ return voltage;
+}
+#endif
+
+#ifdef USE_VOLTAGE_DIVIDER
+inline uint8_t mcu_vdivider_raw2cooked(uint16_t measurement) {
+ // In : 4095 * Vdiv / 1.1V
+ // Out: uint8_t: Vbat * 40
+ // Vdiv = Vbat / 4.3 (typically)
+ // 1.1 = ADC Vref
+ const uint16_t adc_per_volt =
+ (((uint16_t)ADC_44 << 4) - ((uint16_t)ADC_22 << 4))
+ / (4 * (44-22));
+ uint8_t result = measurement / adc_per_volt;
+ return result;
+}
+#endif
+
+inline uint16_t mcu_temp_raw2cooked(uint16_t measurement) {
+ // convert raw ADC values to calibrated temperature
+ // In: ADC raw temperature (16-bit, or 12-bit left-aligned)
+ // Out: Kelvin << 6
+ // Precision: 1/64th Kelvin (but noisy)
+ // attiny1616 datasheet section 30.3.2.6
+ uint8_t sigrow_gain = SIGROW.TEMPSENSE0; // factory calibration data
+ int8_t sigrow_offset = SIGROW.TEMPSENSE1;
+ const uint32_t scaling_factor = 65536; // use all 16 bits of ADC data
+ uint32_t temp = measurement - (sigrow_offset << 6);
+ temp *= sigrow_gain; // 24-bit result
+ temp += scaling_factor / 8; // Add 1/8th K to get correct rounding on later divisions
+ temp = temp >> 8; // change (K << 14) to (K << 6)
+ return temp; // left-aligned uint16_t, 0 to 1023.98 Kelvin
}
inline uint8_t mcu_adc_lsb() {
@@ -98,13 +171,15 @@ inline uint8_t mcu_adc_lsb() {
inline void mcu_wdt_active() {
RTC.PITINTCTRL = RTC_PI_bm; // enable the Periodic Interrupt
while (RTC.PITSTATUS > 0) {} // make sure the register is ready to be updated
- RTC.PITCTRLA = RTC_PERIOD_CYC512_gc | RTC_PITEN_bm; // Period = 16ms, enable the PI Timer
+ // Period = 16ms (64 Hz), enable the PI Timer
+ RTC.PITCTRLA = RTC_PERIOD_CYC512_gc | RTC_PITEN_bm;
}
inline void mcu_wdt_standby() {
RTC.PITINTCTRL = RTC_PI_bm; // enable the Periodic Interrupt
while (RTC.PITSTATUS > 0) {} // make sure the register is ready to be updated
- RTC.PITCTRLA = (1<<6) | (STANDBY_TICK_SPEED<<3) | RTC_PITEN_bm; // Set period, enable the PI Timer
+ // Set period (64 Hz / STANDBY_TICK_SPEED = 8 Hz), enable the PI Timer
+ RTC.PITCTRLA = (1<<6) | (STANDBY_TICK_SPEED<<3) | RTC_PITEN_bm;
}
inline void mcu_wdt_stop() {
@@ -148,6 +223,6 @@ void reboot() {
inline void prevent_reboot_loop() {
// prevent WDT from rebooting MCU again
RSTCTRL.RSTFR &= ~(RSTCTRL_WDRF_bm); // reset status flag
- wdt_disable();
+ wdt_disable(); // from avr/wdt.h
}
diff --git a/arch/attiny1616.h b/arch/attiny1616.h
index b4e17fc..57b0023 100644
--- a/arch/attiny1616.h
+++ b/arch/attiny1616.h
@@ -9,9 +9,11 @@
////////// clock speed / delay stuff //////////
#define F_CPU 10000000UL
-#define BOGOMIPS (F_CPU/4700)
+#define BOGOMIPS (F_CPU/4350)
#define DELAY_ZERO_TIME 1020
+inline void mcu_clock_speed();
+
///// clock dividers
// this should work, but needs further validation
inline void clock_prescale_set(uint8_t n);
@@ -44,20 +46,30 @@ inline void mcu_adc_sleep_mode();
inline void mcu_adc_start_measurement();
-inline void mcu_adc_on();
+//inline void mcu_adc_on();
inline void mcu_adc_off();
#define ADC_vect ADC0_RESRDY_vect
inline void mcu_adc_vect_clear();
+//// both readings are left-aligned
+//inline uint16_t mcu_adc_result();
+
// read ADC differently for temperature and voltage
#define MCU_ADC_RESULT_PER_TYPE
-
inline uint16_t mcu_adc_result_temp();
-
inline uint16_t mcu_adc_result_volts();
+// return Volts * 40, range 0 to 6.375V
+#define voltage_raw2cooked mcu_vdd_raw2cooked
+inline uint8_t mcu_vdd_raw2cooked(uint16_t measurement);
+inline uint8_t mcu_vdivider_raw2cooked(uint16_t measurement);
+
+// return (temp in Kelvin << 6)
+#define temp_raw2cooked mcu_temp_raw2cooked
+inline uint16_t mcu_temp_raw2cooked(uint16_t measurement);
+
inline uint8_t mcu_adc_lsb();
diff --git a/arch/avr32dd20.c b/arch/avr32dd20.c
index 998e9f6..2ac3526 100644
--- a/arch/avr32dd20.c
+++ b/arch/avr32dd20.c
@@ -1,8 +1,10 @@
-// arch/avr32dd20.h: avr32dd20 support header
+// arch/avr32dd20.h: avr32dd20 support functions
// Copyright (C) 2023 Selene ToyKeeper
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
+#include "arch/avr32dd20.h"
+
////////// clock speed / delay stuff //////////
inline void mcu_clock_speed() {
@@ -137,12 +139,22 @@ inline uint16_t mcu_adc_result() {
return ADC0.RES;
}
-inline uint16_t mcu_vdd_raw2cooked(uint16_t measurement) {
+inline uint8_t mcu_vdd_raw2cooked(uint16_t measurement) {
+ // In : 65535 * (Vbat / 10) / 1.024V
+ // Out: uint8_t: Vbat * 40
+ // (add 80 to round up near a boundary)
+ uint8_t vbat40 = (uint16_t)(measurement + 80) / 160;
+ return vbat40;
+}
+
+#if 0
+inline uint16_t mcu_vdd_raw2fine(uint16_t measurement) {
// In : 65535 * (Vbat / 10) / 1.024V
// Out: 65535 * (Vbat / 10) / 1.024V
// This MCU's native format is already correct
return measurement;
}
+#endif
inline uint16_t mcu_temp_raw2cooked(uint16_t measurement) {
// convert raw ADC values to calibrated temperature
@@ -164,29 +176,10 @@ inline uint16_t mcu_temp_raw2cooked(uint16_t measurement) {
}
inline uint8_t mcu_adc_lsb() {
- // temp is right-aligned, voltage is 16-bit, both have a useful LSB
+ // volts and temp are both 16-bit, so the LSB is useful as-is
return ADC0_RESL;
}
-#ifdef USE_VOLTAGE_VDD
-uint8_t calc_voltage(uint16_t measurement) {
- // calculate actual voltage: volts * 10
- // FIXME
- // ADC = 1.1 * 1024 / volts
- // volts = 1.1 * 1024 / ADC
- result = ((uint16_t)(2*1.1*1024*10)/(measurement>>6)
- + VOLTAGE_FUDGE_FACTOR
- #ifdef USE_VOLTAGE_CORRECTION
- + VOLT_CORR - 7
- #endif
- ) >> 1;
- return result;
-}
-#elif defined(USE_VOLTAGE_VDDIO2)
-#elif defined(USE_VOLTAGE_VDDIO2)
-#else
-// hwdef must supply its own function
-#endif
////////// WDT //////////
// this uses the RTC PIT interrupt instead of WDT,
diff --git a/arch/avr32dd20.h b/arch/avr32dd20.h
index 3ebb05a..82951de 100644
--- a/arch/avr32dd20.h
+++ b/arch/avr32dd20.h
@@ -58,9 +58,9 @@ inline uint16_t mcu_adc_result();
//inline uint16_t mcu_adc_result_temp();
//inline uint16_t mcu_adc_result_volts();
-// return (centiVolts << 6), range 0 to 10.24V
+// return Volts * 40, range 0 to 6.375V
#define voltage_raw2cooked mcu_vdd_raw2cooked
-inline uint16_t mcu_vdd_raw2cooked(uint16_t measurement);
+inline uint8_t mcu_vdd_raw2cooked(uint16_t measurement);
// return (temp in Kelvin << 6)
#define temp_raw2cooked mcu_temp_raw2cooked
diff --git a/fsm/adc.c b/fsm/adc.c
index 73e282d..97dfc93 100644
--- a/fsm/adc.c
+++ b/fsm/adc.c
@@ -209,10 +209,16 @@ static inline void ADC_voltage_handler() {
#endif
else measurement = adc_smooth[0];
- // convert raw ADC value to FSM voltage units: (V * 100) << 6
- // 0 .. 65535 = 0.0V .. 10.24V
- measurement = voltage_raw2cooked(measurement) / (10 << 5);
-
+ // convert raw ADC value to FSM voltage units: Volts * 40
+ // 0 .. 200 = 0.0V .. 5.0V
+ voltage = voltage_raw2cooked(measurement)
+ + (VOLTAGE_FUDGE_FACTOR << 1)
+ #ifdef USE_VOLTAGE_CORRECTION
+ + ((VOLT_CORR - 7) << 1)
+ #endif
+ ;
+
+ /*
// calculate actual voltage: volts * 10
// TODO: should be (volts * 40) for extra precision
voltage = (measurement + VOLTAGE_FUDGE_FACTOR
@@ -220,6 +226,7 @@ static inline void ADC_voltage_handler() {
+ VOLT_CORR - 7
#endif
) >> 1;
+ */
#if 0
// values stair-step between intervals of 64, with random variations
@@ -433,33 +440,37 @@ static inline void ADC_temperature_handler() {
#ifdef USE_BATTCHECK
#ifdef BATTCHECK_4bars
PROGMEM const uint8_t voltage_blinks[] = {
- 30, 35, 38, 40, 42, 99,
+ 4*30, 4*35, 4*38, 4*40, 4*42, 255,
};
#endif
#ifdef BATTCHECK_6bars
PROGMEM const uint8_t voltage_blinks[] = {
- 30, 34, 36, 38, 40, 41, 43, 99,
+ 4*30, 4*34, 4*36, 4*38, 4*40, 4*41, 4*43, 255,
};
#endif
#ifdef BATTCHECK_8bars
PROGMEM const uint8_t voltage_blinks[] = {
- 30, 33, 35, 37, 38, 39, 40, 41, 42, 99,
+ 4*30, 4*33, 4*35, 4*37, 4*38, 4*39, 4*40, 4*41, 4*42, 255,
};
#endif
void battcheck() {
#ifdef BATTCHECK_VpT
- blink_num(voltage);
- #else
- uint8_t i;
- for(i=0;
- voltage >= pgm_read_byte(voltage_blinks + i);
- i++) {}
- #ifdef DONT_DELAY_AFTER_BATTCHECK
- blink_digit(i);
+ blink_num(voltage / 4);
+ #ifdef USE_EXTRA_BATTCHECK_DIGIT
+ // 0 1 2 3 --> 0 2 5 7, representing x.x00 x.x25 x.x50 x.x75
+ blink_num(((voltage % 4)<<1) + ((voltage % 4)>>1));
+ #endif
#else
- if (blink_digit(i))
- nice_delay_ms(1000);
- #endif
+ uint8_t i;
+ for(i=0;
+ voltage >= pgm_read_byte(voltage_blinks + i);
+ i++) {}
+ #ifdef DONT_DELAY_AFTER_BATTCHECK
+ blink_digit(i);
+ #else
+ if (blink_digit(i))
+ nice_delay_ms(1000);
+ #endif
#endif
}
#endif
diff --git a/fsm/adc.h b/fsm/adc.h
index 65d7d6c..0c0a9e5 100644
--- a/fsm/adc.h
+++ b/fsm/adc.h
@@ -17,11 +17,11 @@ volatile uint8_t adc_reset = 2;
#endif
// low-battery threshold in volts * 10
#ifndef VOLTAGE_LOW
-#define VOLTAGE_LOW 29
+#define VOLTAGE_LOW (4*29)
#endif
// battery is low but not critical
#ifndef VOLTAGE_RED
-#define VOLTAGE_RED 33
+#define VOLTAGE_RED (4*33)
#endif
// MCU sees voltage 0.X volts lower than actual, add X/2 to readings
#ifndef VOLTAGE_FUDGE_FACTOR
diff --git a/hw/sofirn/sp10-pro/hwdef.h b/hw/sofirn/sp10-pro/hwdef.h
index cb1271d..047758b 100644
--- a/hw/sofirn/sp10-pro/hwdef.h
+++ b/hw/sofirn/sp10-pro/hwdef.h
@@ -62,8 +62,8 @@ enum CHANNEL_MODES {
// Voltage divider battLVL
#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is regulated
-#define DUAL_VOLTAGE_FLOOR 21 // for AA/14500 boost drivers, don't indicate low voltage if below this level
-#define DUAL_VOLTAGE_LOW_LOW 7 // the lower voltage range's danger zone 0.7 volts (NiMH)
+#define DUAL_VOLTAGE_FLOOR (4*21) // for AA/14500 boost drivers, don't indicate low voltage if below this level
+#define DUAL_VOLTAGE_LOW_LOW (4*7) // the lower voltage range's danger zone 0.7 volts (NiMH)
#define ADMUX_VOLTAGE_DIVIDER ADC_MUXPOS_AIN9_gc // which ADC channel to read
// Raw ADC readings at 4.4V and 2.2V
diff --git a/hw/thefreeman/avr32dd20-devkit/hwdef.c b/hw/thefreeman/avr32dd20-devkit/hwdef.c
index 133baca..3e5dd79 100644
--- a/hw/thefreeman/avr32dd20-devkit/hwdef.c
+++ b/hw/thefreeman/avr32dd20-devkit/hwdef.c
@@ -104,15 +104,15 @@ bool gradual_tick_main(uint8_t gt) {
}
-uint16_t voltage_raw2cooked(uint16_t measurement) {
- // In : 65535 * BATTLVL pin / 1.024 Vref
- // Out: 65535 * (Vbat / 10) / 1.024V (i.e. FSM Volt units)
+uint8_t voltage_raw2cooked(uint16_t measurement) {
+ // In : 65535 * BATTLVL / 1.024V
+ // Out: uint8_t: Vbat * 40
// BATTLVL = Vbat * (100.0/(330+100)) = Vbat / 4.3
- // So, Out = In * 4.3 / 10.24
- // (plus 1.5% based on measured hardware)
- // (plus a fudge factor of +0.04V to round up to nearest 1/10th Volt)
- uint16_t result = ((uint32_t)measurement * 436 / 1024)
- + (65535 * 4 / 1024);
+ // So, Out = In * 4.3 / 1600
+ // (plus a bit of fudging to fix the slope and offset,
+ // based on measuring actual hardware)
+ uint8_t result = (uint32_t)(measurement + (65535 * 4 / 1024))
+ * 43 / 16128;
return result;
}
diff --git a/hw/thefreeman/avr32dd20-devkit/hwdef.h b/hw/thefreeman/avr32dd20-devkit/hwdef.h
index 7e1ad3d..a5b37a9 100644
--- a/hw/thefreeman/avr32dd20-devkit/hwdef.h
+++ b/hw/thefreeman/avr32dd20-devkit/hwdef.h
@@ -111,11 +111,11 @@ enum CHANNEL_MODES {
// AVR datasheet table 3.1 I/O Multiplexing, PA6 ADC0 = AIN26
#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is regulated
#define ADMUX_VOLTAGE_DIVIDER ADC_MUXPOS_AIN26_gc
-#define DUAL_VOLTAGE_FLOOR 21 // for AA/14500 boost drivers, don't indicate low voltage if below this level
-#define DUAL_VOLTAGE_LOW_LOW 7 // the lower voltage range's danger zone 0.7 volts (NiMH)
+#define DUAL_VOLTAGE_FLOOR (4*21) // for AA/14500 boost drivers, don't indicate low voltage if below this level
+#define DUAL_VOLTAGE_LOW_LOW (4*7) // the lower voltage range's danger zone 0.7 volts (NiMH)
// convert BATT LVL pin readings to FSM volt units
#undef voltage_raw2cooked
-uint16_t voltage_raw2cooked(uint16_t measurement);
+uint8_t voltage_raw2cooked(uint16_t measurement);
// average drop across diode on this hardware
diff --git a/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/hwdef.h b/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/hwdef.h
index 095aea0..45c02de 100644
--- a/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/hwdef.h
+++ b/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/hwdef.h
@@ -103,21 +103,20 @@ enum CHANNEL_MODES {
// Voltage divider battLVL
#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is regulated
-#define DUAL_VOLTAGE_FLOOR 21 // for AA/14500 boost drivers, don't indicate low voltage if below this level
-#define DUAL_VOLTAGE_LOW_LOW 7 // the lower voltage range's danger zone 0.7 volts (NiMH)
+#define DUAL_VOLTAGE_FLOOR (4*21) // for AA/14500 boost drivers, don't indicate low voltage if below this level
+#define DUAL_VOLTAGE_LOW_LOW (4*7) // the lower voltage range's danger zone 0.7 volts (NiMH)
#define ADMUX_VOLTAGE_DIVIDER ADC_MUXPOS_AIN2_gc // which ADC channel to read
+#undef voltage_raw2cooked
+#define voltage_raw2cooked mcu_vdivider_raw2cooked
+
// Raw ADC readings at 4.4V and 2.2V
// calibrate the voltage readout here
// estimated / calculated values are:
-// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1)
+// (voltage - D1) * (R2/(R2+R1) * 4096 / 1.1)
// Resistors are 330k and 100k
-#ifndef ADC_44
-#define ADC_44 951 // raw value at 4.40V
-#endif
-#ifndef ADC_22
-#define ADC_22 476 // raw value at 2.20V
-#endif
+#define ADC_44 3810 // raw value at 4.40V
+#define ADC_22 1905 // raw value at 2.20V
// this driver allows for aux LEDs under the optic
#define AUXLED_R_PIN PIN3_bp
diff --git a/ui/anduril/anduril.c b/ui/anduril/anduril.c
index c434518..1cdb8d0 100644
--- a/ui/anduril/anduril.c
+++ b/ui/anduril/anduril.c
@@ -316,6 +316,7 @@ void loop() {
#ifdef USE_BATTCHECK
else if (state == battcheck_state) {
+ nice_delay_ms(1000); // wait a moment for a more accurate reading
battcheck();
#ifdef USE_SIMPLE_UI
// in simple mode, turn off after one readout
diff --git a/ui/anduril/aux-leds.c b/ui/anduril/aux-leds.c
index dce8d26..fd184fc 100644
--- a/ui/anduril/aux-leds.c
+++ b/ui/anduril/aux-leds.c
@@ -58,27 +58,27 @@ void indicator_led_update(uint8_t mode, uint8_t tick) {
uint8_t voltage_to_rgb() {
static const uint8_t levels[] = {
// voltage, color
- 0, 0, // black
+ 0, 0, // black
#ifdef DUAL_VOLTAGE_FLOOR
// AA / NiMH voltages
- 9, 1, // R
- 10, 2, // R+G
- 11, 3, // G
- 12, 4, // G+B
- 13, 5, // B
- 14, 6, // R + B
- 16, 7, // R+G+B
- 20, 0, // black
+ 4* 9, 1, // R
+ 4*10, 2, // R+G
+ 4*11, 3, // G
+ 4*12, 4, // G+B
+ 4*13, 5, // B
+ 4*14, 6, // R + B
+ 4*16, 7, // R+G+B
+ 4*20, 0, // black
#endif
// li-ion voltages
- 29, 1, // R
- 33, 2, // R+G
- 35, 3, // G
- 37, 4, // G+B
- 39, 5, // B
- 41, 6, // R + B
- 44, 7, // R+G+B // skip; looks too similar to G+B
- 255, 7, // R+G+B
+ 4*29, 1, // R
+ 4*33, 2, // R+G
+ 4*35, 3, // G
+ 4*37, 4, // G+B
+ 4*39, 5, // B
+ 4*41, 6, // R + B
+ 4*44, 7, // R+G+B // skip; looks too similar to G+B
+ 255, 7, // R+G+B
};
uint8_t volts = voltage;
//if (volts < VOLTAGE_LOW) return 0;
diff --git a/ui/anduril/config-default.h b/ui/anduril/config-default.h
index cd25b52..1b34e8c 100644
--- a/ui/anduril/config-default.h
+++ b/ui/anduril/config-default.h
@@ -143,6 +143,10 @@
#define BATTCHECK_VpT
//#define BATTCHECK_8bars // FIXME: breaks build
//#define BATTCHECK_4bars // FIXME: breaks build
+#if ROM_SIZE > 10000
+ // battcheck displays 1.25V instead of 1.2V
+ #define USE_EXTRA_BATTCHECK_DIGIT
+#endif
// allow the user to calibrate the voltage readings?
// (adjust in 0.05V increments from -0.30V to +0.30V)
// (1 = -0.30V, 2 = -0.25V, ... 7 = 0V, ... 13 = +0.30V)