From 3d12b7066d27b591e0283e20ed066bc66e29fbe4 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 10 Nov 2023 21:34:40 -0700 Subject: refactor checkpoint: splitting MCU-specific code into arch/$MCU.[ch] Phew, that's a lot of changes! And there's still a lot more to do... --- arch/attiny1616.c | 147 ++++++++++++++++++ arch/attiny1616.h | 96 ++++++++++++ arch/attiny1634.c | 125 +++++++++++++++ arch/attiny1634.h | 98 ++++++++++++ arch/attiny85.c | 167 +++++++++++++++++++++ arch/attiny85.h | 91 +++++++++++ arch/mcu.c | 10 ++ arch/mcu.h | 147 ++---------------- bin/detect-mcu.sh | 4 +- fsm/adc.c | 159 +++----------------- fsm/adc.h | 12 +- fsm/main.c | 62 +------- fsm/misc.c | 22 --- fsm/misc.h | 4 - fsm/pcint.c | 54 +------ fsm/pcint.h | 6 +- fsm/spaghetti-monster.h | 9 +- fsm/wdt.c | 78 +--------- fsm/wdt.h | 7 +- hw/gchart/fet1-t1616/hwdef.h | 4 +- hw/hank/emisar-2ch/fet/hwdef.h | 6 +- hw/hank/emisar-2ch/hwdef.h | 6 +- hw/hank/emisar-d18/hwdef.h | 4 +- hw/hank/emisar-d4/hwdef.h | 4 +- hw/hank/emisar-d4k-3ch/hwdef.h | 6 +- hw/hank/emisar-d4sv2/hwdef.h | 6 +- hw/hank/emisar-d4v2/hwdef.h | 8 +- hw/hank/emisar-d4v2/nofet/anduril.h | 2 +- hw/hank/noctigon-dm11/boost/hwdef.h | 6 +- hw/hank/noctigon-dm11/hwdef.h | 8 +- hw/hank/noctigon-dm11/nofet/anduril.h | 2 +- hw/hank/noctigon-k1/boost/hwdef.h | 6 +- hw/hank/noctigon-k1/hwdef.h | 8 +- hw/hank/noctigon-k1/sbt90/hwdef.h | 6 +- hw/hank/noctigon-kr4/2ch/hwdef.h | 4 +- hw/hank/noctigon-kr4/boost/hwdef.h | 4 +- hw/hank/noctigon-kr4/hwdef.h | 8 +- hw/hank/noctigon-kr4/nofet/anduril.h | 2 +- hw/hank/noctigon-m44/hwdef.h | 6 +- hw/lumintop/blf-gt/hwdef.h | 4 +- hw/lumintop/fw3a/hwdef.h | 4 +- hw/lumintop/fw3x-lume1/hwdef.h | 6 +- hw/mateminco/mf01-mini/hwdef.h | 4 +- hw/mateminco/mf01s/hwdef.h | 4 +- hw/mateminco/mt35-mini/hwdef.h | 4 +- hw/sofirn/blf-lt1-t1616/hwdef.h | 4 +- hw/sofirn/blf-lt1/hwdef.h | 4 +- hw/sofirn/blf-q8-t1616/hwdef.h | 4 +- hw/sofirn/lt1s-pro/hwdef.h | 4 +- hw/sofirn/sp10-pro/hwdef.h | 6 +- .../boost-fwaa-mp3432-hdr-dac-rgb/hwdef.h | 6 +- hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h | 6 +- hw/thefreeman/lin16dac/hwdef.h | 4 +- hw/wurkkos/ts10/hwdef.h | 6 +- hw/wurkkos/ts25/hwdef.h | 6 +- ui/anduril/anduril.c | 18 ++- ui/anduril/config-default.h | 6 +- 57 files changed, 862 insertions(+), 642 deletions(-) create mode 100644 arch/attiny1616.c create mode 100644 arch/attiny1616.h create mode 100644 arch/attiny1634.c create mode 100644 arch/attiny1634.h create mode 100644 arch/attiny85.c create mode 100644 arch/attiny85.h create mode 100644 arch/mcu.c diff --git a/arch/attiny1616.c b/arch/attiny1616.c new file mode 100644 index 0000000..3b170bb --- /dev/null +++ b/arch/attiny1616.c @@ -0,0 +1,147 @@ +// arch/attiny1616.c: attiny1616 support functions +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +#include "arch/attiny1616.h" + +////////// clock speed / delay stuff ////////// + +///// 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 + while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm) {} // wait for clock change to finish + sei(); +} + +////////// ADC voltage / temperature ////////// + +inline void mcu_set_admux_therm() { + ADC0.MUXPOS = ADC_MUXPOS_TEMPSENSE_gc; // read temperature + ADC0.CTRLC = ADC_SAMPCAP_bm + | ADC_PRESC_DIV64_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 + ADC0.MUXPOS = ADMUX_VOLTAGE_DIVIDER; // read the requested ADC pin + ADC0.CTRLC = ADC_SAMPCAP_bm + | ADC_PRESC_DIV64_gc + | ADC_REFSEL_INTREF_gc; // Use internal ADC reference + #else // VCC / 1.1V reference + ADC0.MUXPOS = ADC_MUXPOS_INTREF_gc; // read internal reference + ADC0.CTRLC = ADC_SAMPCAP_bm + | ADC_PRESC_DIV64_gc + | ADC_REFSEL_VDDREF_gc; // Vdd (Vcc) be ADC reference + #endif +} + +inline void mcu_adc_sleep_mode() { + set_sleep_mode(SLEEP_MODE_STANDBY); +} + +inline void mcu_adc_start_measurement() { + ADC0.INTCTRL |= ADC_RESRDY_bm; // enable interrupt + ADC0.COMMAND |= ADC_STCONV_bm; // Start the ADC conversions +} + +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 + 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; + hwdef_set_admux_voltage(); +} + +inline void mcu_adc_off() { + ADC0.CTRLA &= ~(ADC_ENABLE_bm); // disable the ADC +} + +inline void mcu_adc_vect_clear() { + ADC0.INTFLAGS = ADC_RESRDY_bm; // clear the interrupt +} + +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 +} + +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 +} + +inline uint8_t mcu_adc_lsb() { + //return (ADCL >> 6) + (ADCH << 2); + return ADC0.RESL; // right aligned, not left... so should be equivalent? +} + + +////////// WDT ////////// + +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 +} + +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 +} + +inline void mcu_wdt_stop() { + while (RTC.PITSTATUS > 0) {} // make sure the register is ready to be updated + RTC.PITCTRLA = 0; // Disable the PI Timer +} + +inline void mcu_wdt_vect_clear() { + RTC.PITINTFLAGS = RTC_PI_bm; // clear the PIT interrupt flag +} + + +////////// PCINT - pin change interrupt (e-switch) ////////// + +inline void mcu_switch_vect_clear() { + // Write a '1' to clear the interrupt flag + SWITCH_INTFLG |= (1 << SWITCH_PIN); +} + +inline void mcu_pcint_on() { + SWITCH_ISC_REG |= PORT_ISC_BOTHEDGES_gc; +} + +inline void mcu_pcint_off() { + SWITCH_ISC_REG &= ~(PORT_ISC_gm); +} + + +////////// misc ////////// + +void reboot() { + // put the WDT in hard reset mode, then trigger it + cli(); + CCP = CCP_IOREG_gc; // temporarily disable change protection + WDT.CTRLA = WDT_PERIOD_8CLK_gc; // Enable, timeout 8ms + sei(); + wdt_reset(); + while (1) {} +} + diff --git a/arch/attiny1616.h b/arch/attiny1616.h new file mode 100644 index 0000000..5989785 --- /dev/null +++ b/arch/attiny1616.h @@ -0,0 +1,96 @@ +// arch/attiny1616.h: attiny1616 support header +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +// FIXME: remove this +#define AVRXMEGA3 + +////////// clock speed / delay stuff ////////// + +#define F_CPU 10000000UL +#define BOGOMIPS (F_CPU/4700) +#define DELAY_ZERO_TIME 1020 + +///// clock dividers +// this should work, but needs further validation +inline void clock_prescale_set(uint8_t n); + +typedef enum +{ + // Actual clock is 20 MHz, but assume that 10 MHz is the top speed and work from there + // TODO: measure PWM speed and power use at 1.25/2.5/5/10 MHz, to determine which speeds are optimal + clock_div_1 = (CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm), // 10 MHz + clock_div_2 = (CLKCTRL_PDIV_4X_gc | CLKCTRL_PEN_bm), // 5 MHz + clock_div_4 = (CLKCTRL_PDIV_8X_gc | CLKCTRL_PEN_bm), // 2.5 MHz + clock_div_8 = (CLKCTRL_PDIV_16X_gc | CLKCTRL_PEN_bm), // 1.25 MHz + clock_div_16 = (CLKCTRL_PDIV_32X_gc | CLKCTRL_PEN_bm), // 625 kHz + clock_div_32 = (CLKCTRL_PDIV_64X_gc | CLKCTRL_PEN_bm), // 312 kHz, max without changing to the 32 kHz ULP + clock_div_64 = (CLKCTRL_PDIV_64X_gc | CLKCTRL_PEN_bm), // 312 kHz + clock_div_128 = (CLKCTRL_PDIV_64X_gc | CLKCTRL_PEN_bm), // 312 kHz + clock_div_256 = (CLKCTRL_PDIV_64X_gc | CLKCTRL_PEN_bm) // 312 kHz +} clock_div_t; + + +////////// ADC voltage / temperature ////////// + +#define hwdef_set_admux_therm mcu_set_admux_therm +inline void mcu_set_admux_therm(); + +#define hwdef_set_admux_voltage mcu_set_admux_voltage +inline void mcu_set_admux_voltage(); + +inline void mcu_adc_sleep_mode(); + +inline void mcu_adc_start_measurement(); + +inline void mcu_adc_on(); + +inline void mcu_adc_off(); + +#define ADC_vect ADC0_RESRDY_vect +inline void mcu_adc_vect_clear(); + +// 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(); + +inline uint8_t mcu_adc_lsb(); + + +////////// WDT ////////// + +inline void mcu_wdt_active(); + +inline void mcu_wdt_standby(); + +inline void mcu_wdt_stop(); + +// *** Note for the AVRXMEGA3 (1-Series, eg 816 and 817), the WDT +// is not used for time-based interrupts. A new peripheral, the +// Periodic Interrupt Timer ("PIT") is used for this purpose. + +#define WDT_vect RTC_PIT_vect +inline void mcu_wdt_vect_clear(); + + +////////// PCINT - pin change interrupt (e-switch) ////////// + +// set these in hwdef +//#define SWITCH_PORT PINA +//#define SWITCH_VECT PCINT0_vect + +inline void mcu_switch_vect_clear(); + +inline void mcu_pcint_on(); + +inline void mcu_pcint_off(); + + +////////// misc ////////// + +void reboot(); + diff --git a/arch/attiny1634.c b/arch/attiny1634.c new file mode 100644 index 0000000..d4b3767 --- /dev/null +++ b/arch/attiny1634.c @@ -0,0 +1,125 @@ +// arch/attiny1634.c: attiny85 support functions +// Copyright (C) 2014-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +#include "arch/attiny1634.h" + +////////// clock speed / delay stuff ////////// + +///// clock dividers +// make it a NOP for now +// FIXME +//#define clock_prescale_set(x) ((void)0) +//#define clock_prescale_set(n) {cli(); CCP = 0xD8; CLKPR = n; sei();} +//#define clock_prescale_set(n) {cli(); CCP = 0xD8; CLKPR = n; sei();} +inline void clock_prescale_set(uint8_t n) { + cli(); + CCP = 0xD8; + CLKPR = n; + sei(); +} + +////////// default hw_setup() ////////// + + +////////// ADC voltage / temperature ////////// + +inline void mcu_set_admux_therm() { + ADMUX = ADMUX_THERM; +} + +inline void mcu_set_admux_voltage() { + #ifdef USE_VOLTAGE_DIVIDER // 1.1V / pin7 + ADMUX = ADMUX_VOLTAGE_DIVIDER; + #else // VCC / 1.1V reference + ADMUX = ADMUX_VCC; + #endif +} + +inline void mcu_adc_sleep_mode() { + set_sleep_mode(SLEEP_MODE_ADC); +} + +inline void mcu_adc_start_measurement() { + ADCSRA |= (1 << ADSC) | (1 << ADIE); +} + +inline void mcu_adc_on() { + hwdef_set_admux_voltage(); + #ifdef USE_VOLTAGE_DIVIDER + // disable digital input on divider pin to reduce power consumption + VOLTAGE_ADC_DIDR |= (1 << VOLTAGE_ADC); + #else + // disable digital input on VCC pin to reduce power consumption + //VOLTAGE_ADC_DIDR |= (1 << VOLTAGE_ADC); // FIXME: unsure how to handle for VCC pin + #endif + //ACSRA |= (1 << ACD); // turn off analog comparator to save power + ADCSRB |= (1 << ADLAR); // left-adjust flag is here instead of ADMUX + // enable, start, auto-retrigger, prescale + ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | ADC_PRSCL; +} + +inline void mcu_adc_off() { + ADCSRA &= ~(1<> 6) + (ADCH << 2); } + + +////////// WDT ////////// + +inline void mcu_wdt_active() { + wdt_reset(); // Reset the WDT + WDTCSR = (1<= 1 + DDRB |= (1 << PWM1_PIN); + TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...) + TCCR0A = PHASE; + #if (PWM1_PIN == PB4) // Second PWM counter is ... weird + TCCR1 = _BV (CS10); + GTCCR = _BV (COM1B1) | _BV (PWM1B); + OCR1C = 255; // Set ceiling value to maximum + #endif + #endif + // tint ramping needs second channel enabled, + // despite PWM_CHANNELS being only 1 + #if (PWM_CHANNELS >= 2) || defined(USE_TINT_RAMPING) + DDRB |= (1 << PWM2_PIN); + #if (PWM2_PIN == PB4) // Second PWM counter is ... weird + TCCR1 = _BV (CS10); + GTCCR = _BV (COM1B1) | _BV (PWM1B); + OCR1C = 255; // Set ceiling value to maximum + #endif + #endif + #if PWM_CHANNELS >= 3 + DDRB |= (1 << PWM3_PIN); + #if (PWM3_PIN == PB4) // Second PWM counter is ... weird + TCCR1 = _BV (CS10); + GTCCR = _BV (COM1B1) | _BV (PWM1B); + OCR1C = 255; // Set ceiling value to maximum + #endif + #endif + #if PWM_CHANNELS >= 4 + // 4th PWM channel is ... not actually supported in hardware :( + DDRB |= (1 << PWM4_PIN); + //OCR1C = 255; // Set ceiling value to maximum + TCCR1 = 1<> 6) + (ADCH << 2); } + + +////////// WDT ////////// + +inline void mcu_wdt_active() { + // interrupt every 16ms + //cli(); // Disable interrupts + wdt_reset(); // Reset the WDT + WDTCR |= (1< #include +#include +#include +#include +#include -/******************** I/O pin and register layout ************************/ -#ifdef HWDEFFILE -#include "fsm/tk.h" -#include incfile(HWDEFFILE) -#endif - -#if 0 // placeholder - -#elif defined(NANJG_LAYOUT) -#include "hwdef-nanjg.h" -#elif defined(FET_7135_LAYOUT) -#include "hwdef-FET_7135.h" +// for consistency, ROM_SIZE + EEPROM_SIZE +#define ROM_SIZE PROGMEM_SIZE -#elif defined(TRIPLEDOWN_LAYOUT) -#include "hwdef-Tripledown.h" - -#elif defined(FERRERO_ROCHER_LAYOUT) -#include "hwdef-Ferrero_Rocher.h" - -#endif // no more recognized driver types - -#ifndef LAYOUT_DEFINED -#error Hey, you need to define an I/O pin layout. -#endif - -#if (ATTINY==13) - // no changes needed -#elif (ATTINY==25) || (ATTINY==45) || (ATTINY==85) - // use clock_prescale_set(n) instead; it's safer - //#define CLOCK_DIVIDER_SET(n) {CLKPR = 1<>= 8; // Divide result to get Kelvin - m = (temp << 6); // left align it - } - else { m = (ADC0.RES << 6); } // voltage, force left-alignment - + #ifdef MCU_ADC_RESULT_PER_TYPE + // thermal, convert ADC reading to left-aligned Kelvin + if (channel) m = mcu_adc_result_temp(); + else m = mcu_adc_result_volts(); #else - m = ADC; + m = mcu_adc_result(); #endif adc_raw[channel] = m; @@ -235,11 +118,7 @@ void adc_deferred() { // real-world entropy makes this a true random, not pseudo // Why here instead of the ISR? Because it makes the time-critical ISR // code a few cycles faster and we don't need crypto-grade randomness. - #ifdef AVRXMEGA3 // ATTINY816, 817, etc - pseudo_rand_seed += ADC0.RESL; // right aligned, not left... so should be equivalent? - #else - pseudo_rand_seed += (ADCL >> 6) + (ADCH << 2); - #endif + pseudo_rand_seed += mcu_adc_lsb(); #endif // the ADC triggers repeatedly when it's on, but we only need to run the @@ -373,9 +252,9 @@ static inline void ADC_voltage_handler() { if (lvp_timer) { lvp_timer --; } else { // it has been long enough since the last warning - #ifdef DUAL_VOLTAGE_FLOOR - if (((voltage < VOLTAGE_LOW) && (voltage > DUAL_VOLTAGE_FLOOR)) || (voltage < DUAL_VOLTAGE_LOW_LOW)) { - #else + #ifdef DUAL_VOLTAGE_FLOOR + if (((voltage < VOLTAGE_LOW) && (voltage > DUAL_VOLTAGE_FLOOR)) || (voltage < DUAL_VOLTAGE_LOW_LOW)) { + #else if (voltage < VOLTAGE_LOW) { #endif // send out a warning @@ -440,6 +319,8 @@ static inline void ADC_temperature_handler() { // let the UI see the current temperature in C // Convert ADC units to Celsius (ish) + // FIXME: call something in arch/$mcu.h or hwdef.h + // instead of calculating this here #ifndef USE_EXTERNAL_TEMP_SENSOR // onboard sensor for attiny25/45/85/1634 temperature = (measurement>>1) + THERM_CAL_OFFSET + (int16_t)TH_CAL - 275; diff --git a/fsm/adc.h b/fsm/adc.h index 1bb67ed..e4046a4 100644 --- a/fsm/adc.h +++ b/fsm/adc.h @@ -102,11 +102,15 @@ static inline void ADC_temperature_handler(); #endif // ifdef USE_THERMAL_REGULATION -inline void ADC_on(); -inline void ADC_off(); -inline void ADC_start_measurement(); +//inline void ADC_on(); +#define ADC_on mcu_adc_on +//inline void ADC_off(); +#define ADC_off mcu_adc_off +//inline void ADC_start_measurement(); +#define ADC_start_measurement mcu_adc_start_measurement #ifdef TICK_DURING_STANDBY -inline void adc_sleep_mode(); + //inline void adc_sleep_mode(); + #define adc_sleep_mode mcu_adc_sleep_mode #endif diff --git a/fsm/main.c b/fsm/main.c index 0524115..1c01878 100644 --- a/fsm/main.c +++ b/fsm/main.c @@ -23,66 +23,6 @@ ISR(TIMER1_COMPA_vect) { } #endif -// FIXME: hw_setup() shouldn't be here ... move it entirely to hwdef files -#if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) -static inline void hw_setup() { - #if !defined(USE_GENERIC_HWDEF_SETUP) - hwdef_setup(); - #else - // configure PWM channels - #if PWM_CHANNELS >= 1 - DDRB |= (1 << PWM1_PIN); - TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...) - TCCR0A = PHASE; - #if (PWM1_PIN == PB4) // Second PWM counter is ... weird - TCCR1 = _BV (CS10); - GTCCR = _BV (COM1B1) | _BV (PWM1B); - OCR1C = 255; // Set ceiling value to maximum - #endif - #endif - // tint ramping needs second channel enabled, - // despite PWM_CHANNELS being only 1 - #if (PWM_CHANNELS >= 2) || defined(USE_TINT_RAMPING) - DDRB |= (1 << PWM2_PIN); - #if (PWM2_PIN == PB4) // Second PWM counter is ... weird - TCCR1 = _BV (CS10); - GTCCR = _BV (COM1B1) | _BV (PWM1B); - OCR1C = 255; // Set ceiling value to maximum - #endif - #endif - #if PWM_CHANNELS >= 3 - DDRB |= (1 << PWM3_PIN); - #if (PWM3_PIN == PB4) // Second PWM counter is ... weird - TCCR1 = _BV (CS10); - GTCCR = _BV (COM1B1) | _BV (PWM1B); - OCR1C = 255; // Set ceiling value to maximum - #endif - #endif - #if PWM_CHANNELS >= 4 - // 4th PWM channel is ... not actually supported in hardware :( - DDRB |= (1 << PWM4_PIN); - //OCR1C = 255; // Set ceiling value to maximum - TCCR1 = 1< -#include +#include "arch/mcu.h" // include project definitions to help with recognizing symbols #include "fsm/events.h" @@ -39,6 +38,10 @@ #include "arch/delay.h" #endif +////////// include all the .c files ////////// + +#include "arch/mcu.c" + #ifdef USE_DEBUG_BLINK #define DEBUG_FLASH PWM1_LVL = 64; delay_4ms(2); PWM1_LVL = 0; void debug_blink(uint8_t num) { diff --git a/fsm/wdt.c b/fsm/wdt.c index 64f006e..1095d44 100644 --- a/fsm/wdt.c +++ b/fsm/wdt.c @@ -7,85 +7,9 @@ #include #include -// *** Note for the AVRXMEGA3 (1-Series, eg 816 and 817), the WDT -// is not used for time-based interrupts. A new peripheral, the -// Periodic Interrupt Timer ("PIT") is used for this purpose. - -void WDT_on() -{ - #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) - // interrupt every 16ms - //cli(); // Disable interrupts - wdt_reset(); // Reset the WDT - WDTCR |= (1< 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 - #else - #error Unrecognized MCU type - #endif -} - -#ifdef TICK_DURING_STANDBY -inline void WDT_slow() -{ - #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) - // interrupt slower - //cli(); // Disable interrupts - wdt_reset(); // Reset the WDT - WDTCR |= (1< 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 - #else - #error Unrecognized MCU type - #endif -} -#endif - -inline void WDT_off() -{ - #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) - //cli(); // Disable interrupts - wdt_reset(); // Reset the WDT - MCUSR &= ~(1< 0) {} // make sure the register is ready to be updated - RTC.PITCTRLA = 0; // Disable the PI Timer - #else - #error Unrecognized MCU type - #endif -} - // clock tick -- this runs every 16ms (62.5 fps) -#ifdef AVRXMEGA3 // ATTINY816, 817, etc -ISR(RTC_PIT_vect) { - RTC.PITINTFLAGS = RTC_PI_bm; // clear the PIT interrupt flag -#else ISR(WDT_vect) { -#endif + mcu_wdt_vect_clear(); irq_wdt = 1; // WDT event happened } diff --git a/fsm/wdt.h b/fsm/wdt.h index abf34c5..98eaf25 100644 --- a/fsm/wdt.h +++ b/fsm/wdt.h @@ -6,8 +6,11 @@ #define TICKS_PER_SECOND 62 -void WDT_on(); -inline void WDT_off(); +//void WDT_on(); +//inline void WDT_off(); +#define WDT_on mcu_wdt_active +#define WDT_slow mcu_wdt_standby +#define WDT_off mcu_wdt_stop volatile uint8_t irq_wdt = 0; // WDT interrupt happened? diff --git a/hw/gchart/fet1-t1616/hwdef.h b/hw/gchart/fet1-t1616/hwdef.h index ac4fd53..40083fc 100644 --- a/hw/gchart/fet1-t1616/hwdef.h +++ b/hw/gchart/fet1-t1616/hwdef.h @@ -11,11 +11,9 @@ * Read voltage from VCC pin, has diode with ~0.4v drop */ -#include - // nearly all t1616-based FET+1 drivers work pretty much the same // (this one has single-color aux like the TS10) -#define HWDEF_C_FILE wurkkos/ts10/hwdef.c +#define HWDEF_C wurkkos/ts10/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-aux.h" diff --git a/hw/hank/emisar-2ch/fet/hwdef.h b/hw/hank/emisar-2ch/fet/hwdef.h index 0778e10..06dfeb8 100644 --- a/hw/hank/emisar-2ch/fet/hwdef.h +++ b/hw/hank/emisar-2ch/fet/hwdef.h @@ -32,9 +32,7 @@ * The first channel also has a direct-drive FET for turbo. */ -#include - -#define HWDEF_C_FILE hank/emisar-2ch/fet/hwdef.c +#define HWDEF_C hank/emisar-2ch/fet/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -106,7 +104,7 @@ enum channel_modes_e { #define SWITCH_PCMSK PCMSK0 // PCMSK1 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] +#define SWITCH_VECT PCINT0_vect // ISR for PCINT[7:0] #endif #define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened diff --git a/hw/hank/emisar-2ch/hwdef.h b/hw/hank/emisar-2ch/hwdef.h index e3707c7..7fbac8e 100644 --- a/hw/hank/emisar-2ch/hwdef.h +++ b/hw/hank/emisar-2ch/hwdef.h @@ -31,9 +31,7 @@ * and one pin to control the Opamp power level. */ -#include - -#define HWDEF_C_FILE hank/emisar-2ch/hwdef.c +#define HWDEF_C hank/emisar-2ch/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -103,7 +101,7 @@ enum channel_modes_e { #define SWITCH_PCMSK PCMSK0 // PCMSK1 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] +#define SWITCH_VECT PCINT0_vect // ISR for PCINT[7:0] #endif #define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened diff --git a/hw/hank/emisar-d18/hwdef.h b/hw/hank/emisar-d18/hwdef.h index 86c97c2..a0d3cd0 100644 --- a/hw/hank/emisar-d18/hwdef.h +++ b/hw/hank/emisar-d18/hwdef.h @@ -12,9 +12,7 @@ * ---- */ -#include - -#define HWDEF_C_FILE lumintop/fw3a/hwdef.c +#define HWDEF_C lumintop/fw3a/hwdef.c // channel modes // * 0. FET+N+1 stacked diff --git a/hw/hank/emisar-d4/hwdef.h b/hw/hank/emisar-d4/hwdef.h index 55ef72e..6257ddb 100644 --- a/hw/hank/emisar-d4/hwdef.h +++ b/hw/hank/emisar-d4/hwdef.h @@ -12,9 +12,7 @@ * ---- */ -#include - -#define HWDEF_C_FILE hank/emisar-d4/hwdef.c +#define HWDEF_C hank/emisar-d4/hwdef.c // allow using aux LEDs as extra channel modes (when they exist) //#ifdef AUXLED_PIN diff --git a/hw/hank/emisar-d4k-3ch/hwdef.h b/hw/hank/emisar-d4k-3ch/hwdef.h index 7cfe699..002804c 100644 --- a/hw/hank/emisar-d4k-3ch/hwdef.h +++ b/hw/hank/emisar-d4k-3ch/hwdef.h @@ -35,9 +35,7 @@ * So this code should support both wire layouts. */ -#include - -#define HWDEF_C_FILE hank/emisar-d4k-3ch/hwdef.c +#define HWDEF_C hank/emisar-d4k-3ch/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -132,7 +130,7 @@ uint8_t led4_pwm, led4_dsm; #define SWITCH_PCMSK PCMSK0 // PCMSK1 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] +#define SWITCH_VECT PCINT0_vect // ISR for PCINT[7:0] #endif #define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened diff --git a/hw/hank/emisar-d4sv2/hwdef.h b/hw/hank/emisar-d4sv2/hwdef.h index d1e0452..121593a 100644 --- a/hw/hank/emisar-d4sv2/hwdef.h +++ b/hw/hank/emisar-d4sv2/hwdef.h @@ -30,9 +30,7 @@ * ADC12 thermal sensor */ -#include - -#define HWDEF_C_FILE hank/emisar-d4sv2/hwdef.c +#define HWDEF_C hank/emisar-d4sv2/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -89,7 +87,7 @@ enum CHANNEL_MODES { #define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] +#define SWITCH_VECT PCINT0_vect // ISR for PCINT[7:0] #define ADC_PRSCL 0x07 // clk/128 diff --git a/hw/hank/emisar-d4v2/hwdef.h b/hw/hank/emisar-d4v2/hwdef.h index 9e3f755..1c10004 100644 --- a/hw/hank/emisar-d4v2/hwdef.h +++ b/hw/hank/emisar-d4v2/hwdef.h @@ -28,10 +28,8 @@ * ADC12 thermal sensor */ -#include - -#ifndef HWDEF_C_FILE -#define HWDEF_C_FILE hank/emisar-d4v2/hwdef.c +#ifndef HWDEF_C +#define HWDEF_C hank/emisar-d4v2/hwdef.c #endif // allow using aux LEDs as extra channel modes @@ -84,7 +82,7 @@ enum CHANNEL_MODES { #define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] +#define SWITCH_VECT PCINT0_vect // ISR for PCINT[7:0] #define ADC_PRSCL 0x07 // clk/128 diff --git a/hw/hank/emisar-d4v2/nofet/anduril.h b/hw/hank/emisar-d4v2/nofet/anduril.h index b5f9304..e05fb2e 100644 --- a/hw/hank/emisar-d4v2/nofet/anduril.h +++ b/hw/hank/emisar-d4v2/nofet/anduril.h @@ -4,7 +4,7 @@ #pragma once // switch to 1-channel support functions -#define HWDEF_C_FILE hank/emisar-d4v2/nofet/hwdef.c +#define HWDEF_C hank/emisar-d4v2/nofet/hwdef.c #include "hank/emisar-d4v2/anduril.h" diff --git a/hw/hank/noctigon-dm11/boost/hwdef.h b/hw/hank/noctigon-dm11/boost/hwdef.h index 5ac2daf..bef409f 100644 --- a/hw/hank/noctigon-dm11/boost/hwdef.h +++ b/hw/hank/noctigon-dm11/boost/hwdef.h @@ -36,9 +36,7 @@ * not to change brightness. */ -#include - -#define HWDEF_C_FILE hank/noctigon-dm11/boost/hwdef.c +#define HWDEF_C hank/noctigon-dm11/boost/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -101,7 +99,7 @@ uint8_t ch1_pwm, ch1_dsm; #define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] +#define SWITCH_VECT PCINT0_vect // ISR for PCINT[7:0] #define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened #define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 diff --git a/hw/hank/noctigon-dm11/hwdef.h b/hw/hank/noctigon-dm11/hwdef.h index cd21eae..11cf3a0 100644 --- a/hw/hank/noctigon-dm11/hwdef.h +++ b/hw/hank/noctigon-dm11/hwdef.h @@ -37,10 +37,8 @@ * Some models also have a direct-drive FET for turbo. */ -#include - -#ifndef HWDEF_C_FILE -#define HWDEF_C_FILE hank/noctigon-kr4/hwdef.c +#ifndef HWDEF_C +#define HWDEF_C hank/noctigon-kr4/hwdef.c #endif // allow using aux LEDs as extra channel modes @@ -95,7 +93,7 @@ enum CHANNEL_MODES { #define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] +#define SWITCH_VECT PCINT0_vect // ISR for PCINT[7:0] #define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened diff --git a/hw/hank/noctigon-dm11/nofet/anduril.h b/hw/hank/noctigon-dm11/nofet/anduril.h index 12336f1..c13f4ab 100644 --- a/hw/hank/noctigon-dm11/nofet/anduril.h +++ b/hw/hank/noctigon-dm11/nofet/anduril.h @@ -4,7 +4,7 @@ #pragma once // same support functions as a KR4 -#define HWDEF_C_FILE hank/noctigon-kr4/nofet/hwdef.c +#define HWDEF_C hank/noctigon-kr4/nofet/hwdef.c #include "hank/noctigon-dm11/anduril.h" // turn off the DD FET diff --git a/hw/hank/noctigon-k1/boost/hwdef.h b/hw/hank/noctigon-k1/boost/hwdef.h index 951932a..e0a314c 100644 --- a/hw/hank/noctigon-k1/boost/hwdef.h +++ b/hw/hank/noctigon-k1/boost/hwdef.h @@ -34,9 +34,7 @@ * not to change brightness. */ -#include - -#define HWDEF_C_FILE hank/noctigon-dm11/boost/hwdef.c +#define HWDEF_C hank/noctigon-dm11/boost/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -99,7 +97,7 @@ uint8_t ch1_pwm, ch1_dsm; #define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] +#define SWITCH_VECT PCINT0_vect // ISR for PCINT[7:0] #define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened #define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 diff --git a/hw/hank/noctigon-k1/hwdef.h b/hw/hank/noctigon-k1/hwdef.h index 9a68401..822b959 100644 --- a/hw/hank/noctigon-k1/hwdef.h +++ b/hw/hank/noctigon-k1/hwdef.h @@ -36,10 +36,8 @@ * not to change brightness. */ -#include - -#ifndef HWDEF_C_FILE -#define HWDEF_C_FILE hank/noctigon-k1/hwdef.c +#ifndef HWDEF_C +#define HWDEF_C hank/noctigon-k1/hwdef.c #endif // allow using aux LEDs as extra channel modes @@ -88,7 +86,7 @@ enum CHANNEL_MODES { #define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] +#define SWITCH_VECT PCINT0_vect // ISR for PCINT[7:0] #define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened diff --git a/hw/hank/noctigon-k1/sbt90/hwdef.h b/hw/hank/noctigon-k1/sbt90/hwdef.h index 8186b49..4c56bc0 100644 --- a/hw/hank/noctigon-k1/sbt90/hwdef.h +++ b/hw/hank/noctigon-k1/sbt90/hwdef.h @@ -37,9 +37,7 @@ * Also has a direct-drive FET for turbo. */ -#include - -#define HWDEF_C_FILE hank/noctigon-kr4/hwdef.c +#define HWDEF_C hank/noctigon-kr4/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -93,7 +91,7 @@ enum CHANNEL_MODES { #define SWITCH_PCMSK PCMSK1 // PCMSK1 is for PCINT[11:8] #define SWITCH_PORT PINB // PINA or PINB or PINC #define SWITCH_PUE PUEB // pullup group B -#define PCINT_vect PCINT1_vect // ISR for PCINT[11:8] +#define SWITCH_VECT PCINT1_vect // ISR for PCINT[11:8] #define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened #define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 diff --git a/hw/hank/noctigon-kr4/2ch/hwdef.h b/hw/hank/noctigon-kr4/2ch/hwdef.h index b23c7cc..28a686d 100644 --- a/hw/hank/noctigon-kr4/2ch/hwdef.h +++ b/hw/hank/noctigon-kr4/2ch/hwdef.h @@ -30,8 +30,6 @@ * ADC12 thermal sensor */ -#include - // move the switch to a different pin #define SWITCH_PIN PB2 // pin 17 #define SWITCH_PCINT PCINT10 // pin 17 pin change interrupt @@ -39,7 +37,7 @@ #define SWITCH_PCMSK PCMSK1 // PCMSK1 is for PCINT[11:8] #define SWITCH_PORT PINB // PINA or PINB or PINC #define SWITCH_PUE PUEB // pullup group B -#define PCINT_vect PCINT1_vect // ISR for PCINT[11:8] +#define SWITCH_VECT PCINT1_vect // ISR for PCINT[11:8] // the rest of the config is the same as the generic Emisar 2ch build #include "hank/emisar-2ch/hwdef.h" diff --git a/hw/hank/noctigon-kr4/boost/hwdef.h b/hw/hank/noctigon-kr4/boost/hwdef.h index f17d263..b923b30 100644 --- a/hw/hank/noctigon-kr4/boost/hwdef.h +++ b/hw/hank/noctigon-kr4/boost/hwdef.h @@ -46,12 +46,12 @@ #undef SWITCH_PCMSK #undef SWITCH_PORT #undef SWITCH_PUE -#undef PCINT_vect +#undef SWITCH_VECT #define SWITCH_PIN PB2 // pin 17 #define SWITCH_PCINT PCINT10 // pin 17 pin change interrupt #define SWITCH_PCIE PCIE1 // PCIE1 is for PCINT[11:8] #define SWITCH_PCMSK PCMSK1 // PCMSK1 is for PCINT[11:8] #define SWITCH_PORT PINB // PINA or PINB or PINC #define SWITCH_PUE PUEB // pullup group B -#define PCINT_vect PCINT1_vect // ISR for PCINT[11:8] +#define SWITCH_VECT PCINT1_vect // ISR for PCINT[11:8] diff --git a/hw/hank/noctigon-kr4/hwdef.h b/hw/hank/noctigon-kr4/hwdef.h index 586f848..be165bd 100644 --- a/hw/hank/noctigon-kr4/hwdef.h +++ b/hw/hank/noctigon-kr4/hwdef.h @@ -35,10 +35,8 @@ * Some models also have a direct-drive FET for turbo. */ -#include - -#ifndef HWDEF_C_FILE -#define HWDEF_C_FILE hank/noctigon-kr4/hwdef.c +#ifndef HWDEF_C +#define HWDEF_C hank/noctigon-kr4/hwdef.c #endif // allow using aux LEDs as extra channel modes @@ -93,7 +91,7 @@ enum CHANNEL_MODES { #define SWITCH_PCMSK PCMSK1 // PCMSK1 is for PCINT[11:8] #define SWITCH_PORT PINB // PINA or PINB or PINC #define SWITCH_PUE PUEB // pullup group B -#define PCINT_vect PCINT1_vect // ISR for PCINT[11:8] +#define SWITCH_VECT PCINT1_vect // ISR for PCINT[11:8] // the button tends to short out the voltage divider, // so ignore voltage while the button is being held diff --git a/hw/hank/noctigon-kr4/nofet/anduril.h b/hw/hank/noctigon-kr4/nofet/anduril.h index 4522cde..ad3f012 100644 --- a/hw/hank/noctigon-kr4/nofet/anduril.h +++ b/hw/hank/noctigon-kr4/nofet/anduril.h @@ -5,7 +5,7 @@ // (and Noctigon KR1) // (and Emisar D4v2 E21A, a.k.a. "D4v2.5") -#define HWDEF_C_FILE hank/noctigon-kr4/nofet/hwdef.c +#define HWDEF_C hank/noctigon-kr4/nofet/hwdef.c #include "hank/noctigon-kr4/anduril.h" // brightness w/ SST-20 4000K LEDs: diff --git a/hw/hank/noctigon-m44/hwdef.h b/hw/hank/noctigon-m44/hwdef.h index af942d9..6bdcef2 100644 --- a/hw/hank/noctigon-m44/hwdef.h +++ b/hw/hank/noctigon-m44/hwdef.h @@ -28,9 +28,7 @@ * ADC12 thermal sensor */ -#include - -#define HWDEF_C_FILE hank/noctigon-m44/hwdef.c +#define HWDEF_C hank/noctigon-m44/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -110,7 +108,7 @@ uint8_t ch2_pwm, ch2_dsm; #define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] +#define SWITCH_VECT PCINT0_vect // ISR for PCINT[7:0] #define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened #define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 diff --git a/hw/lumintop/blf-gt/hwdef.h b/hw/lumintop/blf-gt/hwdef.h index bf3790d..dbaf18e 100644 --- a/hw/lumintop/blf-gt/hwdef.h +++ b/hw/lumintop/blf-gt/hwdef.h @@ -16,9 +16,7 @@ * and its output gets PWM'd by pin 5. */ -#include - -#define HWDEF_C_FILE hank/emisar-d4/hwdef.c +#define HWDEF_C hank/emisar-d4/hwdef.c // channel modes // * 0. main LEDs diff --git a/hw/lumintop/fw3a/hwdef.h b/hw/lumintop/fw3a/hwdef.h index 649dc19..7809fa9 100644 --- a/hw/lumintop/fw3a/hwdef.h +++ b/hw/lumintop/fw3a/hwdef.h @@ -12,9 +12,7 @@ * ---- */ -#include - -#define HWDEF_C_FILE lumintop/fw3a/hwdef.c +#define HWDEF_C lumintop/fw3a/hwdef.c // channel modes // * 0. FET+7+1 stacked diff --git a/hw/lumintop/fw3x-lume1/hwdef.h b/hw/lumintop/fw3x-lume1/hwdef.h index 943921f..ca412cc 100644 --- a/hw/lumintop/fw3x-lume1/hwdef.h +++ b/hw/lumintop/fw3x-lume1/hwdef.h @@ -34,9 +34,7 @@ * Another pin is used for DD FET control. */ -#include - -#define HWDEF_C_FILE lumintop/fw3x-lume1/hwdef.c +#define HWDEF_C lumintop/fw3x-lume1/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -95,7 +93,7 @@ enum CHANNEL_MODES { #define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] +#define SWITCH_VECT PCINT0_vect // ISR for PCINT[7:0] #define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened #define VOLTAGE_PIN PB0 // Pin 19 PB0 ADC5 diff --git a/hw/mateminco/mf01-mini/hwdef.h b/hw/mateminco/mf01-mini/hwdef.h index f245042..82dafb2 100644 --- a/hw/mateminco/mf01-mini/hwdef.h +++ b/hw/mateminco/mf01-mini/hwdef.h @@ -12,9 +12,7 @@ * ---- */ -#include - -#define HWDEF_C_FILE lumintop/fw3a/hwdef.c +#define HWDEF_C lumintop/fw3a/hwdef.c // channel modes // * 0. FET+N+1 stacked diff --git a/hw/mateminco/mf01s/hwdef.h b/hw/mateminco/mf01s/hwdef.h index 12451d7..fef5050 100644 --- a/hw/mateminco/mf01s/hwdef.h +++ b/hw/mateminco/mf01s/hwdef.h @@ -12,9 +12,7 @@ * ---- */ -#include - -#define HWDEF_C_FILE hank/emisar-d4/hwdef.c +#define HWDEF_C hank/emisar-d4/hwdef.c // channel modes // * 0. small FET + big FET stacked diff --git a/hw/mateminco/mt35-mini/hwdef.h b/hw/mateminco/mt35-mini/hwdef.h index aec4eaf..ac7bf07 100644 --- a/hw/mateminco/mt35-mini/hwdef.h +++ b/hw/mateminco/mt35-mini/hwdef.h @@ -12,9 +12,7 @@ * ---- */ -#include - -#define HWDEF_C_FILE hank/emisar-d4/hwdef.c +#define HWDEF_C hank/emisar-d4/hwdef.c // channel modes // * 0. FET+7135 stacked diff --git a/hw/sofirn/blf-lt1-t1616/hwdef.h b/hw/sofirn/blf-lt1-t1616/hwdef.h index 66575de..c9ae1ea 100644 --- a/hw/sofirn/blf-lt1-t1616/hwdef.h +++ b/hw/sofirn/blf-lt1-t1616/hwdef.h @@ -12,9 +12,7 @@ * Voltage: VCC */ -#include - -#define HWDEF_C_FILE sofirn/blf-lt1-t1616/hwdef.c +#define HWDEF_C sofirn/blf-lt1-t1616/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-aux.h" diff --git a/hw/sofirn/blf-lt1/hwdef.h b/hw/sofirn/blf-lt1/hwdef.h index 03f3568..a57b1c4 100644 --- a/hw/sofirn/blf-lt1/hwdef.h +++ b/hw/sofirn/blf-lt1/hwdef.h @@ -12,9 +12,7 @@ * ---- */ -#include - -#define HWDEF_C_FILE sofirn/blf-lt1/hwdef.c +#define HWDEF_C sofirn/blf-lt1/hwdef.c // channel modes: // * 0. channel 1 only diff --git a/hw/sofirn/blf-q8-t1616/hwdef.h b/hw/sofirn/blf-q8-t1616/hwdef.h index 29c2ffa..638a2c1 100644 --- a/hw/sofirn/blf-q8-t1616/hwdef.h +++ b/hw/sofirn/blf-q8-t1616/hwdef.h @@ -15,11 +15,9 @@ * Voltage: VCC */ -#include - // nearly all t1616-based FET+1 drivers work pretty much the same // (this one has single-color aux like the TS10) -#define HWDEF_C_FILE wurkkos/ts10/hwdef.c +#define HWDEF_C wurkkos/ts10/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-aux.h" diff --git a/hw/sofirn/lt1s-pro/hwdef.h b/hw/sofirn/lt1s-pro/hwdef.h index cd4dd4e..7708631 100644 --- a/hw/sofirn/lt1s-pro/hwdef.h +++ b/hw/sofirn/lt1s-pro/hwdef.h @@ -13,9 +13,7 @@ * Voltage: VCC */ -#include - -#define HWDEF_C_FILE sofirn/lt1s-pro/hwdef.c +#define HWDEF_C sofirn/lt1s-pro/hwdef.c // channel modes: // * 0. warm/cool white blend diff --git a/hw/sofirn/sp10-pro/hwdef.h b/hw/sofirn/sp10-pro/hwdef.h index a52166d..cb1271d 100644 --- a/hw/sofirn/sp10-pro/hwdef.h +++ b/hw/sofirn/sp10-pro/hwdef.h @@ -12,9 +12,7 @@ * PA1 : Boost Enable */ -#include - -#define HWDEF_C_FILE sofirn/sp10-pro/hwdef.c +#define HWDEF_C sofirn/sp10-pro/hwdef.c // channel modes: // * 0. low+high PWM stacked @@ -61,8 +59,6 @@ enum CHANNEL_MODES { #define SWITCH_ISC_REG PORTB.PIN3CTRL #define SWITCH_VECT PORTB_PORT_vect #define SWITCH_INTFLG VPORTB.INTFLAGS -#define SWITCH_PCINT PCINT0 -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] // Voltage divider battLVL #define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is regulated 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 cd883fa..90fede3 100644 --- a/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/hwdef.h +++ b/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/hwdef.h @@ -36,9 +36,7 @@ * IN- NFET : pull up after BST enable to eliminate startup flash, pull down otherwise */ -#include - -#define HWDEF_C_FILE thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.c +#define HWDEF_C thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -99,8 +97,6 @@ enum CHANNEL_MODES { #define SWITCH_ISC_REG PORTC.PIN3CTRL #define SWITCH_VECT PORTC_PORT_vect #define SWITCH_INTFLG VPORTC.INTFLAGS -#define SWITCH_PCINT PCINT0 -#define PCINT_vect PCINT0_vect #endif // Voltage divider battLVL diff --git a/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h b/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h index 3f64287..72aa7b0 100644 --- a/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h +++ b/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h @@ -37,9 +37,7 @@ * IN- NFET : pull up after BST enable to eliminate startup flash, pull down otherwise */ -#include - -#define HWDEF_C_FILE thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.c +#define HWDEF_C thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -100,8 +98,6 @@ enum CHANNEL_MODES { #define SWITCH_ISC_REG PORTC.PIN2CTRL #define SWITCH_VECT PORTC_PORT_vect #define SWITCH_INTFLG VPORTC.INTFLAGS -#define SWITCH_PCINT PCINT0 -#define PCINT_vect PCINT0_vect #endif // average drop across diode on this hardware diff --git a/hw/thefreeman/lin16dac/hwdef.h b/hw/thefreeman/lin16dac/hwdef.h index 2066d04..dc4377a 100644 --- a/hw/thefreeman/lin16dac/hwdef.h +++ b/hw/thefreeman/lin16dac/hwdef.h @@ -12,9 +12,7 @@ * Read voltage from VCC pin, has PFET so no drop */ -#include - -#define HWDEF_C_FILE thefreeman/lin16dac/hwdef.c +#define HWDEF_C thefreeman/lin16dac/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-aux.h" diff --git a/hw/wurkkos/ts10/hwdef.h b/hw/wurkkos/ts10/hwdef.h index b1239b8..92898fb 100644 --- a/hw/wurkkos/ts10/hwdef.h +++ b/hw/wurkkos/ts10/hwdef.h @@ -13,9 +13,7 @@ * Voltage: VCC */ -#include - -#define HWDEF_C_FILE wurkkos/ts10/hwdef.c +#define HWDEF_C wurkkos/ts10/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-aux.h" @@ -60,12 +58,10 @@ enum CHANNEL_MODES { // e-switch #define SWITCH_PIN PIN5_bp -//#define SWITCH_PCINT PCINT0 #define SWITCH_PORT VPORTA.IN #define SWITCH_ISC_REG PORTA.PIN2CTRL #define SWITCH_VECT PORTA_PORT_vect #define SWITCH_INTFLG VPORTA.INTFLAGS -//#define PCINT_vect PCINT0_vect // average drop across diode on this hardware #ifndef VOLTAGE_FUDGE_FACTOR diff --git a/hw/wurkkos/ts25/hwdef.h b/hw/wurkkos/ts25/hwdef.h index 024a18d..ac1e574 100644 --- a/hw/wurkkos/ts25/hwdef.h +++ b/hw/wurkkos/ts25/hwdef.h @@ -14,9 +14,7 @@ * Aux Blue: PC1 */ -#include - -#define HWDEF_C_FILE wurkkos/ts25/hwdef.c +#define HWDEF_C wurkkos/ts25/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -61,12 +59,10 @@ enum CHANNEL_MODES { // e-switch #define SWITCH_PIN PIN5_bp -//#define SWITCH_PCINT PCINT0 #define SWITCH_PORT VPORTA.IN #define SWITCH_ISC_REG PORTA.PIN2CTRL #define SWITCH_VECT PORTA_PORT_vect #define SWITCH_INTFLG VPORTA.INTFLAGS -//#define PCINT_vect PCINT0_vect // average drop across diode on this hardware #ifndef VOLTAGE_FUDGE_FACTOR diff --git a/ui/anduril/anduril.c b/ui/anduril/anduril.c index e72c3b5..c434518 100644 --- a/ui/anduril/anduril.c +++ b/ui/anduril/anduril.c @@ -34,16 +34,19 @@ * as possible. These are mostly "USE" flags. */ +/********* load up MCU info, like ROM size and such *********/ +#include "arch/mcu.h" + /********* User-configurable options *********/ #include "anduril/config-default.h" /********* specific settings for known driver types *********/ -// Anduril config file name (set it here or define it at the gcc command line) -//#define CFG_H cfg-blf-q8.h -#include "fsm/tk.h" #include incfile(CFG_H) +#ifdef HWDEF_H +#include incfile(HWDEF_H) +#endif /********* Include headers which need to be before FSM *********/ @@ -77,11 +80,12 @@ #include "fsm/spaghetti-monster.h" /********* does this build target have special code to include? *********/ -#ifdef HWDEF_C_FILE -#include incfile(HWDEF_C_FILE) +#ifdef CFG_C +#include incfile(CFG_C) #endif -#ifdef CFG_C_FILE -#include incfile(CFG_C_FILE) + +#ifdef HWDEF_C +#include incfile(HWDEF_C) #endif diff --git a/ui/anduril/config-default.h b/ui/anduril/config-default.h index 899bc4a..04fc956 100644 --- a/ui/anduril/config-default.h +++ b/ui/anduril/config-default.h @@ -20,7 +20,7 @@ // overheat protection #define USE_THERMAL_REGULATION -#if (ATTINY==85) || (ATTINY==1634) +#if (MCU==0x85) || (MCU==0x1634) // sloppy temperature sensor needs bigger error margin #define DEFAULT_THERM_CEIL 45 // try not to get hotter than this (in C) #else @@ -185,7 +185,7 @@ // if the aux LEDs oscillate between "full battery" and "empty battery" // while in "voltage" mode, enable this to reduce the amplitude of // those oscillations -#if (ATTINY==1616) || (ATTINY==1634) +#if (ROM_SIZE > 10000) #define USE_LOWPASS_WHILE_ASLEEP #endif @@ -195,7 +195,7 @@ // Use "smooth steps" to soften on/off and step changes // on MCUs with enough room for extra stuff like this -#if (ATTINY==1616) || (ATTINY==1634) +#if (ROM_SIZE > 10000) #define USE_SMOOTH_STEPS #endif // 0 = none, 1 = smooth, 2+ = undefined -- cgit v1.2.3 From a4d96f08a017ce9d475b2575c597e741c6e8af1e Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 19 Nov 2023 01:42:33 -0700 Subject: version check: allow hex digits --- ui/anduril/version-check-mode.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ui/anduril/version-check-mode.c b/ui/anduril/version-check-mode.c index eebe59b..1cd6968 100644 --- a/ui/anduril/version-check-mode.c +++ b/ui/anduril/version-check-mode.c @@ -15,7 +15,10 @@ uint8_t version_check_state(Event event, uint16_t arg) { inline void version_check_iter() { for (uint8_t i=0; i ? + if (digit < 16) blink_digit(digit); else { // "buzz" for non-numeric characters for(uint8_t frame=0; frame<25; frame++) { set_level((frame&1) << 5); -- cgit v1.2.3 From 95d931dc167ae01d6af1973ea68496584fe03541 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 19 Nov 2023 01:44:35 -0700 Subject: ramp-mode: allow hwdef to adjust gradual tick speed The gradual tick frequency was written for 8-bit PWM, but it can be too slow on hardware with more bits. The hwdef can compensate by using larger steps, but that makes adjustments more visible... So this provides an option to increase speed without visibility. --- ui/anduril/config-default.h | 6 ++++++ ui/anduril/ramp-mode.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ui/anduril/config-default.h b/ui/anduril/config-default.h index 04fc956..cd25b52 100644 --- a/ui/anduril/config-default.h +++ b/ui/anduril/config-default.h @@ -113,6 +113,12 @@ // timer is available in regular ramp mode and candle mode #define USE_SUNSET_TIMER +// optionally make gradual ticks happen faster +// Affects: thermal regulation speed, sunset mode, maybe other features +// (default is calibrated for 8-bit PWM, +// but 10-bit should set this value to 4 instead of 1) +#define GRADUAL_ADJUST_SPEED 1 + ///// What to do when power is connected ///// // factory reset function erases user's runtime configuration in eeprom diff --git a/ui/anduril/ramp-mode.c b/ui/anduril/ramp-mode.c index 9e19025..4c535b4 100644 --- a/ui/anduril/ramp-mode.c +++ b/ui/anduril/ramp-mode.c @@ -287,7 +287,7 @@ uint8_t steady_state(Event event, uint16_t arg) { static uint16_t ticks_since_adjust = 0; ticks_since_adjust++; if (diff) { - uint16_t ticks_per_adjust = 256; + uint16_t ticks_per_adjust = 256 / GRADUAL_ADJUST_SPEED; if (diff < 0) { //diff = -diff; if (actual_level > THERM_FASTER_LEVEL) { -- cgit v1.2.3 From ed5e1dde6181ce71da96d7e920950830c0b869cb Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 19 Nov 2023 01:45:13 -0700 Subject: missed a "include -> HWDEF_H" conversion earlier --- hw/wurkkos/ts25/anduril.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/wurkkos/ts25/anduril.h b/hw/wurkkos/ts25/anduril.h index 722bc5d..ecf0db1 100644 --- a/hw/wurkkos/ts25/anduril.h +++ b/hw/wurkkos/ts25/anduril.h @@ -3,7 +3,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later #pragma once -#include "wurkkos/ts25/hwdef.h" +//#include "wurkkos/ts25/hwdef.h" +#define HWDEF_H wurkkos/ts25/hwdef.h #include "wurkkos/anduril.h" // this light has three aux LED channels: R, G, B -- cgit v1.2.3 From 66b15ad887c2ae74bc7019c006549ac451557a6d Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 19 Nov 2023 01:46:34 -0700 Subject: temporary fix for aux LEDs on avrdd; needs proper refactoring --- fsm/misc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fsm/misc.c b/fsm/misc.c index 5d58f52..fa8ddd7 100644 --- a/fsm/misc.c +++ b/fsm/misc.c @@ -118,7 +118,8 @@ uint8_t blink_num(uint8_t num) { #ifdef USE_INDICATOR_LED void indicator_led(uint8_t lvl) { switch (lvl) { - #ifdef AVRXMEGA3 // ATTINY816, 817, etc + // FIXME: move this logic to arch/* + #if (MCU==0x1616) || (MCU==0x32dd20) // ATTINY816, 817, etc case 0: // indicator off AUXLED_PORT.DIRSET = (1 << AUXLED_PIN); // set as output @@ -192,7 +193,8 @@ void indicator_led_auto() { void button_led_set(uint8_t lvl) { switch (lvl) { - #ifdef AVRXMEGA3 // ATTINY816, 817, etc + // FIXME: move this logic to arch/* + #if (MCU==0x1616) || (MCU==0x32dd20) // ATTINY816, 817, etc case 0: // LED off BUTTON_LED_PORT.DIRSET = (1 << BUTTON_LED_PIN); // set as output @@ -240,7 +242,8 @@ void rgb_led_set(uint8_t value) { uint8_t pin = pins[i]; switch (lvl) { - #ifdef AVRXMEGA3 // ATTINY816, 817, etc + // FIXME: move this logic to arch/* + #if (MCU==0x1616) || (MCU==0x32dd20) // ATTINY816, 817, etc case 0: // LED off AUXLED_RGB_PORT.DIRSET = (1 << pin); // set as output -- cgit v1.2.3 From e6909adcb1d44797e097dcf93ee7459276a4516a Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 19 Nov 2023 01:47:40 -0700 Subject: moved prevent_reboot_loop() and some other junk out of fsm/main.c --- arch/attiny1616.c | 6 ++++++ arch/attiny1616.h | 2 ++ arch/attiny1634.c | 6 ++++++ arch/attiny1634.h | 2 ++ arch/attiny85.c | 21 +++++++++++++++++++++ arch/attiny85.h | 2 ++ fsm/main.c | 50 +++----------------------------------------------- 7 files changed, 42 insertions(+), 47 deletions(-) diff --git a/arch/attiny1616.c b/arch/attiny1616.c index 3b170bb..a3ead7e 100644 --- a/arch/attiny1616.c +++ b/arch/attiny1616.c @@ -145,3 +145,9 @@ void reboot() { while (1) {} } +inline void prevent_reboot_loop() { + // prevent WDT from rebooting MCU again + RSTCTRL.RSTFR &= ~(RSTCTRL_WDRF_bm); // reset status flag + wdt_disable(); +} + diff --git a/arch/attiny1616.h b/arch/attiny1616.h index 5989785..b4e17fc 100644 --- a/arch/attiny1616.h +++ b/arch/attiny1616.h @@ -94,3 +94,5 @@ inline void mcu_pcint_off(); void reboot(); +inline void prevent_reboot_loop(); + diff --git a/arch/attiny1634.c b/arch/attiny1634.c index d4b3767..0737a81 100644 --- a/arch/attiny1634.c +++ b/arch/attiny1634.c @@ -123,3 +123,9 @@ void reboot() { while (1) {} } +inline void prevent_reboot_loop() { + // prevent WDT from rebooting MCU again + MCUSR &= ~(1<= 1 - PWM1_LVL = 0; - #endif - #if PWM_CHANNELS >= 2 - PWM2_LVL = 0; - #endif - #if PWM_CHANNELS >= 3 - PWM3_LVL = 0; - #endif - #if PWM_CHANNELS >= 4 - PWM4_LVL = 255; // inverted :( - #endif - #endif standby_mode(); } -- cgit v1.2.3 From 79c1d9ebfed691b1048205ebdfd91d33cfcfc8a1 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 19 Nov 2023 01:48:50 -0700 Subject: thefreeman/boost*: define Vref values more explicitly without magic numbers --- hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/anduril.h | 8 ++++---- hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/hwdef.h | 12 +++++++----- hw/thefreeman/boost21-mp3431-hdr-dac-argb/anduril.h | 8 ++++---- hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h | 12 +++++++----- 4 files changed, 22 insertions(+), 18 deletions(-) diff --git a/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/anduril.h b/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/anduril.h index eea8887..33583df 100644 --- a/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/anduril.h +++ b/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/anduril.h @@ -24,10 +24,10 @@ 14, 15, 17, 18, 19, 20, 22, 23, 25, 26, 28, 30, 32, 34, 36, 38, 40, 43, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81, 86, 90, 95, 99,104,109,114,120,126,131,138,144,150,157,164,171,179,187,195,203,212,221,230,239,249, \ 57, 59, 61, 64, 66, 69, 72, 74, 77, 80, 83, 86, 90, 93, 96,100,103,107,111,115,119,123,127,132,136,141,145,150,155,160,166,171,176,182,188,194,200,206,213,219,226,233,240,247,255 // PWM Tops: VREF selector (0.55V=16,1.1V=17, 2.5V=18, 4.3V=19, 1.5V=20) -#define PWM_TOPS 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, \ - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, \ - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, \ - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18 +#define PWM_TOPS V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05, \ + V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25, \ + V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05, \ + V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25 #define MAX_1x7135 50 #define DEFAULT_LEVEL 44 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 90fede3..095aea0 100644 --- a/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/hwdef.h +++ b/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/hwdef.h @@ -69,11 +69,13 @@ enum CHANNEL_MODES { #define DAC_VREF VREF.CTRLA // 0.55V or 2.5V #define PWM_TOP_INIT 255 // highest value used in top half of ramp (unused?) // Vref values -#define V055 16 -#define V11 17 -#define V25 18 -#define V43 19 -#define V15 20 +// (1.1V ADC + variable DAC) +#define V05 V055 +#define V055 (VREF_ADC0REFSEL_1V1_gc|VREF_DAC0REFSEL_0V55_gc) +#define V11 (VREF_ADC0REFSEL_1V1_gc|VREF_DAC0REFSEL_1V1_gc) +#define V25 (VREF_ADC0REFSEL_1V1_gc|VREF_DAC0REFSEL_2V5_gc) +#define V43 (VREF_ADC0REFSEL_1V1_gc|VREF_DAC0REFSEL_4V34_gc) +#define V15 (VREF_ADC0REFSEL_1V1_gc|VREF_DAC0REFSEL_1V5_gc) // BST enable #define BST_ENABLE_PIN PIN4_bp diff --git a/hw/thefreeman/boost21-mp3431-hdr-dac-argb/anduril.h b/hw/thefreeman/boost21-mp3431-hdr-dac-argb/anduril.h index 64da638..a6a111c 100644 --- a/hw/thefreeman/boost21-mp3431-hdr-dac-argb/anduril.h +++ b/hw/thefreeman/boost21-mp3431-hdr-dac-argb/anduril.h @@ -24,10 +24,10 @@ 8, 9, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 23, 24, 26, 27, 29, 31, 33, 35, 37, 40, 42, 45, 47, 50, 53, 56, 59, 62, 66, 69, 73, 77, 81, 85, 90, 94, 99,104,109,114,120,126,132,138,144,151,158,165,173,180,188,196,205,214,223,232,242,252, \ 57, 60, 62, 65, 67, 70, 73, 76, 78, 82, 85, 88, 91, 95, 98,102,105,109,113,117,121,126,130,135,139,144,149,154,159,164,170,175,181,187,193,199,206,212,219,225,232,240,247,255 // PWM Tops: VREF selector (0.55V=16,1.1V=17, 2.5V=18, 4.3V=19, 1.5V=20) -#define PWM_TOPS 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, \ - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, \ - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, \ - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18 +#define PWM_TOPS V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05, \ + V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25, \ + V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05, \ + V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25 #define MAX_1x7135 44 #define DEFAULT_LEVEL 44 diff --git a/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h b/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h index 72aa7b0..d030516 100644 --- a/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h +++ b/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h @@ -70,11 +70,13 @@ enum CHANNEL_MODES { #define DAC_VREF VREF.CTRLA // 0.55V or 2.5V #define PWM_TOP_INIT 255 // highest value used in top half of ramp (unused?) // Vref values -#define V055 16 -#define V11 17 -#define V25 18 -#define V43 19 -#define V15 20 +// (1.1V ADC + variable DAC) +#define V05 V055 +#define V055 (VREF_ADC0REFSEL_1V1_gc|VREF_DAC0REFSEL_0V55_gc) +#define V11 (VREF_ADC0REFSEL_1V1_gc|VREF_DAC0REFSEL_1V1_gc) +#define V25 (VREF_ADC0REFSEL_1V1_gc|VREF_DAC0REFSEL_2V5_gc) +#define V43 (VREF_ADC0REFSEL_1V1_gc|VREF_DAC0REFSEL_4V34_gc) +#define V15 (VREF_ADC0REFSEL_1V1_gc|VREF_DAC0REFSEL_1V5_gc) // BST enable #define BST_ENABLE_PIN PIN0_bp -- cgit v1.2.3 From 486dd5543653b342fe64c0e5b1fcd342f0a02dbb Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 19 Nov 2023 01:53:59 -0700 Subject: added *unfinished* support for avr32dd20, plus a build target for a dev kit ADC doesn't work yet. No voltage, no temperature. I need to do a lot of refactoring on the ADC code. :( --- arch/avr32dd20.c | 263 +++++++++++++++++++++++++++++++ arch/avr32dd20.h | 93 +++++++++++ bin/flash-avr32dd20.sh | 13 ++ hw/thefreeman/avr32dd20-devkit/anduril.h | 138 ++++++++++++++++ hw/thefreeman/avr32dd20-devkit/arch | 1 + hw/thefreeman/avr32dd20-devkit/hwdef.c | 105 ++++++++++++ hw/thefreeman/avr32dd20-devkit/hwdef.h | 208 ++++++++++++++++++++++++ hw/thefreeman/avr32dd20-devkit/model | 1 + 8 files changed, 822 insertions(+) create mode 100644 arch/avr32dd20.c create mode 100644 arch/avr32dd20.h create mode 100755 bin/flash-avr32dd20.sh create mode 100644 hw/thefreeman/avr32dd20-devkit/anduril.h create mode 100644 hw/thefreeman/avr32dd20-devkit/arch create mode 100644 hw/thefreeman/avr32dd20-devkit/hwdef.c create mode 100644 hw/thefreeman/avr32dd20-devkit/hwdef.h create mode 100644 hw/thefreeman/avr32dd20-devkit/model diff --git a/arch/avr32dd20.c b/arch/avr32dd20.c new file mode 100644 index 0000000..45923a8 --- /dev/null +++ b/arch/avr32dd20.c @@ -0,0 +1,263 @@ +// arch/avr32dd20.h: avr32dd20 support header +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +////////// clock speed / delay stuff ////////// + +inline void mcu_clock_speed() { + // TODO: allow hwdef to define a base clock speed + // run the internal clock at 12 MHz, not the default 4 MHz + _PROTECTED_WRITE( CLKCTRL.OSCHFCTRLA, + CLKCTRL_FRQSEL_12M_gc | CLKCTRL_AUTOTUNE_bm ); + // (another option is to use 20 MHz / 2, like attiny1616 does) + // divide 20 MHz to run at 10 MHz to match attiny1616 + //_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(); + _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, n); // Set the prescaler + while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm) {} // wait for clock change to finish + sei(); +} + + +////////// ADC voltage / temperature ////////// + +// ADC0.CTRLA bits: +// RUNSTDBY, -, CONVMODE, LEFTADJ, RESSEL[1:0], FREERUN, ENABLE +// CTRLB bits: -, -, -, -, -, SAMPNUM[2:0] +// CTRLC bits: -, -, -, -, PRESC[3:0] +// CTRLD bits: INITDLY[2:0], -, SAMPDLY[3:0] +// CTRLE bits: -, -, -, -, -, WINCM[2:0] +// SAMPCTRL: 8 bits +// MUXPOS, MUXNEG: 7 bits each +// COMMAND: -, -, -, -, -, -, SPCONV, STCONV + +inline void mcu_set_admux_therm() { + // ADC init: Datasheet section 33.3.2 + // Temperature mode: Datasheet section 33.3.3.8 + // measurements should be 12-bit right-adjusted single-ended conversion + // set Vref to 2.048V for temperature mode + VREF.ADC0REF = VREF_REFSEL_2V048_gc; + // set temp sensor as input + ADC0.MUXPOS = ADC_MUXPOS_TEMPSENSE_gc; + // configure init delay to >= 25 us * Fclk_adc (no sample delay needed) + ADC0.CTRLD = ADC_INITDLY_DLY32_gc | ADC_SAMPDLY_DLY0_gc; + // configure ADC sample length to >= 28 us * Fclk_adc + ADC0.SAMPCTRL = 32; + // set single-ended or differential + // set resolution to 12 bits + // set left- or right-adjust (right) + // set free-running mode or not (yes) + ADC0.CTRLA = ADC_CONVMODE_SINGLEENDED_gc + | ADC_RESSEL_12BIT_gc + //| ADC_LEFTADJ_bm // not in temperature mode + | ADC_FREERUN_bm; + // set number of samples (requires adjustment in formula too) + ADC0.CTRLB = ADC_SAMPNUM_NONE_gc; + // TODO: accumulate more samples for more resolution + // (and probably set the prescale faster too) + //ADC0.CTRLB = ADC_SAMPNUM_ACC16_gc; // 16 samples per result + // set a clock prescaler + ADC0.CTRLC = ADC_PRESC_DIV64_gc; + // enable the ADC + ADC0.CTRLA |= ADC_ENABLE_bm; + // actually start measuring (happens in another function) + //ADC0.COMMAND |= ADC_STCONV_bm; + // for each measurement: + // process according to sigrow data + formula +} + +inline void mcu_set_admux_voltage() { + // ADC init: Datasheet section 33.3.2 + // set Vref + VREF.ADC0REF = VREF_REFSEL_1V024_gc; + // set single-ended or differential + // set resolution to 12 bits + // set left- or right-adjust (right) + // set free-running mode or not (yes) + ADC0.CTRLA = ADC_CONVMODE_SINGLEENDED_gc + | ADC_RESSEL_12BIT_gc + | ADC_LEFTADJ_bm // has no effect when 16+ samples taken + | ADC_FREERUN_bm + | ADC_RUNSTBY_bm // allow voltage sense in standby mode + ; + // set number of samples + ADC0.CTRLB = ADC_SAMPNUM_ACC16_gc; // 16 samples per result + // set a clock prescaler + ADC0.CTRLC = ADC_PRESC_DIV16_gc; // not too fast, not too slow + // select the positive ADC input with MUXPOS + #ifdef USE_VOLTAGE_DIVIDER // external voltage divider + // ADC input pin / Vref + ADC0.MUXPOS = ADMUX_VOLTAGE_DIVIDER; // external pin + #elif defined (USE_VOLTAGE_VDDIO2) // internal voltage divider + // (Vbat / 10) / Vref + ADC0.MUXPOS = ADC_MUXPOS_VDDIO2DIV10_gc; + #else // measure directly on VDD/VCC pin + // (Vbat / 10) / Vref + ADC0.MUXPOS = ADC_MUXPOS_VDDDIV10_gc; + #endif + // enable the ADC + ADC0.CTRLA |= ADC_ENABLE_bm; + // actually start measuring (happens in another function) + //ADC0.COMMAND |= ADC_STCONV_bm; +} + +inline void mcu_adc_sleep_mode() { + set_sleep_mode(SLEEP_MODE_STANDBY); +} + +inline void mcu_adc_start_measurement() { + // FIXME: enable this after getting ADC stuff fixed + #if 0 + ADC0.INTCTRL |= ADC_RESRDY_bm; // enable interrupt + ADC0.COMMAND |= ADC_STCONV_bm; // actually start measuring + #endif +} + +/* +void mcu_adc_on() { + hwdef_set_admux_voltage(); + mcu_adc_start_measurement(); +} +*/ + +inline void mcu_adc_off() { + ADC0.CTRLA &= ~(ADC_ENABLE_bm); // disable the ADC +} + +inline void mcu_adc_vect_clear() { + ADC0.INTFLAGS = ADC_RESRDY_bm; // clear the interrupt +} + +inline uint16_t mcu_adc_result_temp() { + // FIXME: better math, higher precision + // 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 +} + +inline uint16_t mcu_adc_result_volts() { + // voltage is 12-bit right-aligned + 16x oversampling = 16 bits total + return ADC0.RES; +} + +inline uint8_t mcu_adc_lsb() { + // temp is right-aligned, voltage is 16-bit, both have a useful LSB + 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, +// as recommended on AVR 0/1-series and later: +// https://github.com/SpenceKonde/DxCore/blob/master/megaavr/extras/PowerSave.md#using-the-real-time-counter-rtcpit +// The PIT runs even in power-down mode, unlike RTC, +// and its cycles are relative to the AVR's internal 32768 Hz ULP oscillator +// AVR datasheet sections 26, 26.5, 26.9, 26.12, 26.13.12 + +// PIT tick speeds: +// 0 (none) +// 1 8192 Hz (CYC4) +// 2 4096 Hz +// 3 2048 Hz +// 4 1024 Hz (CYC32) +// 5 512 Hz +// 6 256 Hz +// 7 128 Hz +// 8 64 Hz (default) (CYC512) +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 + // Period = 16ms (64 Hz), enable the PI Timer + RTC.PITCTRLA = RTC_PERIOD_CYC512_gc | RTC_PITEN_bm; +} + +// STANDBY_TICK_SPEED: +// 0 64 Hz +// 1 32 Hz +// 2 16 Hz +// 3 8 Hz (default) +// 4 4 Hz +// 5 2 Hz +// 6 1 Hz +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 + // Set period (64 Hz / STANDBY_TICK_SPEED = 8 Hz), enable the PI Timer + RTC.PITCTRLA = ((8+STANDBY_TICK_SPEED)<<3) | RTC_PITEN_bm; +} + +inline void mcu_wdt_stop() { + while (RTC.PITSTATUS > 0) {} // make sure the register is ready to be updated + RTC.PITCTRLA = 0; // Disable the PI Timer +} + +inline void mcu_wdt_vect_clear() { + RTC.PITINTFLAGS = RTC_PI_bm; // clear the PIT interrupt flag +} + + +////////// PCINT - pin change interrupt (e-switch) ////////// + +inline void mcu_switch_vect_clear() { + // Write a '1' to clear the interrupt flag + SWITCH_INTFLG |= (1 << SWITCH_PIN); +} + +inline void mcu_pcint_on() { + SWITCH_ISC_REG |= PORT_ISC_BOTHEDGES_gc; +} + +inline void mcu_pcint_off() { + SWITCH_ISC_REG &= ~(PORT_ISC_gm); +} + + +////////// misc ////////// + +void reboot() { + // request a reboot (software reset) + _PROTECTED_WRITE(RSTCTRL.SWRR, RSTCTRL_SWRST_bm); +} + +inline void prevent_reboot_loop() { + // if previous reset was a crash (WDT time-out), + // prevent it from happening again immediately + //RSTCTRL.RSTFR &= ~(RSTCTRL_WDRF_bm); // reset wdt flag only + RSTCTRL.RSTFR = 0; // reset all reset status flags (maybe unneeded?) + wdt_disable(); // from avr/wdt.h +} + diff --git a/arch/avr32dd20.h b/arch/avr32dd20.h new file mode 100644 index 0000000..7a6b8f1 --- /dev/null +++ b/arch/avr32dd20.h @@ -0,0 +1,93 @@ +// arch/avr32dd20.h: avr32dd20 support header +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +////////// clock speed / delay stuff ////////// + +#define F_CPU 12000000UL +#define BOGOMIPS (F_CPU/3800) +#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); + +// TODO: allow hwdef to define a base clock speed, +// and adjust these values accordingly +typedef enum +{ + // Actual clock is 12 MHz + clock_div_1 = (0), // 12 MHz + clock_div_2 = (CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm), // 6 MHz + clock_div_4 = (CLKCTRL_PDIV_4X_gc | CLKCTRL_PEN_bm), // 3 MHz + clock_div_8 = (CLKCTRL_PDIV_8X_gc | CLKCTRL_PEN_bm), // 1.5 MHz + clock_div_16 = (CLKCTRL_PDIV_16X_gc | CLKCTRL_PEN_bm), // 0.75 MHz + clock_div_32 = (CLKCTRL_PDIV_32X_gc | CLKCTRL_PEN_bm), // 375 kHz + clock_div_64 = (CLKCTRL_PDIV_64X_gc | CLKCTRL_PEN_bm), // 187.5 kHz +} clock_div_t; + + +////////// ADC voltage / temperature ////////// + +#define hwdef_set_admux_therm mcu_set_admux_therm +inline void mcu_set_admux_therm(); + +#define hwdef_set_admux_voltage mcu_set_admux_voltage +inline void mcu_set_admux_voltage(); + +inline void mcu_adc_sleep_mode(); + +inline void mcu_adc_start_measurement(); + +//#define mcu_adc_on hwdef_set_admux_voltage +//void mcu_adc_on(); + +inline void mcu_adc_off(); + +#define ADC_vect ADC0_RESRDY_vect +inline void mcu_adc_vect_clear(); + +// 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(); + +inline uint8_t mcu_adc_lsb(); + + +////////// WDT ////////// + +inline void mcu_wdt_active(); + +inline void mcu_wdt_standby(); + +inline void mcu_wdt_stop(); + +#define WDT_vect RTC_PIT_vect +inline void mcu_wdt_vect_clear(); + + +////////// PCINT - pin change interrupt (e-switch) ////////// + +// set these in hwdef +//#define SWITCH_PORT VPORTD.IN +//#define SWITCH_VECT PORTD_PORT_vect + +inline void mcu_switch_vect_clear(); + +inline void mcu_pcint_on(); + +inline void mcu_pcint_off(); + + +////////// misc ////////// + +void reboot(); + +inline void prevent_reboot_loop(); + diff --git a/bin/flash-avr32dd20.sh b/bin/flash-avr32dd20.sh new file mode 100755 index 0000000..ef8b0f3 --- /dev/null +++ b/bin/flash-avr32dd20.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +set -e + +[[ -z "$1" ]] && echo "No .hex file specified." && exit 1 +HEX="$1" + +#pymcuprog ping -t uart -u /dev/ttyUSB2 -d avr32dd20 +#pymcuprog erase -t uart -u /dev/ttyUSB2 -d avr32dd20 +#pymcuprog write verify -t uart -u /dev/ttyUSB2 -d avr32dd20 -f "$HEX" +#pymcuprog verify -t uart -u /dev/ttyUSB2 -d avr32dd20 -f "$HEX" + +pymcuprog write --erase --verify --timing -t uart -u /dev/ttyUSB2 -d avr32dd20 -f "$HEX" diff --git a/hw/thefreeman/avr32dd20-devkit/anduril.h b/hw/thefreeman/avr32dd20-devkit/anduril.h new file mode 100644 index 0000000..97e9e10 --- /dev/null +++ b/hw/thefreeman/avr32dd20-devkit/anduril.h @@ -0,0 +1,138 @@ +// thefreeman's BST21 BST20-FWxA (no button LED) +// Copyright (C) 2023 TBD (thefreeman), Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +#define HWDEF_H thefreeman/avr32dd20-devkit/hwdef.h + +// HPRsense : 1.7+0.3+5 = 7mR (DMN22M5UFG+trace resistance+5mR) +// Vsense=42.46mV, R1= 191k +// LPRsense : 1R +// transition DAC level 8, ramp level 45 +// fifth power ramp 0.1mA to 6066mA + +#define RAMP_SIZE 150 + +// 4 ramp segments: +// - low 1.024V +// - low 2.5 V +// - high 1.024V +// - high 2.5 V +// HDR ratio: 160 +// PWM1: DAC Data +#if 1 +// level_calc.py 4.3287 1 150 7135 5 0.01 1400 --pwm 400000 +// top level for each "gear": 30 40 120 150 +#define PWM1_LEVELS \ + 6, 7, 9, 11, 14, 18, 23, 30, 37, 46, 56, 69, 83, 100, 120, 142, 168, 196, 229, 266, 307, 353, 403, 460, 522, 591, 667, 750, 840, 939, \ + 428, 476, 528, 584, 645, 710, 780, 856, 937,1023, \ + 17, 18, 20, 21, 23, 25, 27, 29, 32, 34, 37, 40, 42, 46, 49, 52, 56, 60, 64, 68, 72, 77, 81, 86, 92, 97, 103, 109, 115, 122, 128, 136, 143, 151, 159, 167, 176, 185, 194, 204, 214, 224, 235, 246, 258, 270, 283, 295, 309, 323, 337, 352, 367, 383, 399, 416, 434, 452, 470, 489, 509, 529, 550, 572, 594, 617, 640, 664, 689, 715, 741, 768, 796, 824, 854, 884, 915, 947, 979,1013, \ + 429, 443, 458, 473, 489, 505, 521, 538, 555, 572, 590, 609, 628, 647, 667, 687, 708, 729, 751, 773, 796, 819, 843, 867, 891, 917, 943, 969, 996,1023 +#define PWM2_LEVELS \ + V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, \ + V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, \ + V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, \ + V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25 +#define MAX_1x7135 40 +#define HDR_ENABLE_LEVEL_MIN 41 +#define DEFAULT_LEVEL 50 +#else +// level_calc.py 9.21 1 150 7135 5 0.2 1400 --pwm 400000 +// (plus dac-scale.py post-processing to get values for HDR+Vref ranges) +// top level for each "gear": 35 48 127 150 +#define PWM1_LEVELS \ + 5, 11, 18, 25, 33, 41, 50, 60, 71, 83, 96, 110, 125, 141, 158, 177, 198, 220, 244, 269, 297, 326, 358, 392, 429, 469, 511, 556, 605, 657, 713, 772, 836, 904, 976, \ + 431, 465, 501, 539, 580, 624, 670, 720, 772, 828, 887, 950,1017, \ + 16, 17, 18, 20, 21, 23, 24, 26, 27, 29, 31, 33, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 64, 68, 72, 76, 80, 85, 90, 95, 100, 106, 112, 118, 124, 131, 138, 145, 153, 161, 170, 179, 188, 198, 208, 219, 230, 242, 254, 266, 280, 294, 308, 323, 339, 355, 373, 391, 409, 429, 449, 470, 492, 515, 539, 564, 589, 616, 644, 673, 704, 735, 768, 802, 837, 874, 912, 952, 993, \ + 424, 442, 461, 480, 501, 522, 544, 566, 590, 614, 640, 666, 693, 721, 750, 780, 811, 844, 877, 912, 948, 985,1023 +// Vref selector (V10, V20, V25, V40 = 1.024V, 2.048V, 2.5V, 4.096V) +#define PWM2_LEVELS \ + V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, \ + V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, \ + V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, \ + V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25 + +#define MAX_1x7135 48 +#define DEFAULT_LEVEL 48 +#define HDR_ENABLE_LEVEL_MIN 49 // when HDR FET turns ON +#endif + +// no PWM, so MCU clock speed can be slow +#define HALFSPEED_LEVEL 41 +#define QUARTERSPEED_LEVEL 40 // seems to run fine at 10kHz/4, try reducing more + +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 130 // 50% / 3A / 1000 lm +// 1 22 [44] 65 87 108 130 +#define RAMP_DISCRETE_FLOOR 1 +#define RAMP_DISCRETE_CEIL 130 +#define RAMP_DISCRETE_STEPS 7 + +// 20 [45] 70 95 120 +#define SIMPLE_UI_FLOOR 20 +#define SIMPLE_UI_CEIL 120 // ~2.25A / ~750 lm +#define SIMPLE_UI_STEPS 5 + +// don't blink mid-ramp +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif + +// thermal config + +// temperature limit +#define THERM_FASTER_LEVEL 130 // stop panicking at 50%/3A +#define MIN_THERM_STEPDOWN MAX_1x7135 + + +// UI + +//#define SIMPLE_UI_ACTIVE 0 // advanced UI by default + +// allow Aux Config and Strobe Modes in Simple UI +//#define USE_EXTENDED_SIMPLE_UI + +// Allow 3C in Simple UI for switching between smooth and stepped ramping +#define USE_SIMPLE_UI_RAMPING_TOGGLE + +#define DEFAULT_2C_STYLE 1 // enable 2 click turbo + + +// AUX + +//#define USE_BUTTON_LED + +// this light has three aux LED channels: R, G, B +#define USE_AUX_RGB_LEDS + +// show each channel while it scroll by in the menu +#define USE_CONFIG_COLORS + +// blink numbers on the main LEDs by default +#define DEFAULT_BLINK_CHANNEL CM_MAIN + +// use aux red + aux blue for police strobe +#define USE_POLICE_COLOR_STROBE_MODE +#define POLICE_STROBE_USES_AUX +#define POLICE_COLOR_STROBE_CH1 CM_AUXRED +#define POLICE_COLOR_STROBE_CH2 CM_AUXBLU + +// the aux LEDs are front-facing, so turn them off while main LEDs are on +#ifdef USE_INDICATOR_LED_WHILE_RAMPING +#undef USE_INDICATOR_LED_WHILE_RAMPING +#endif + + +// Misc + +#define PARTY_STROBE_ONTIME 1 // slow down party strobe +#define STROBE_OFF_LEVEL 1 // keep the regulator chip on between pulses + +// smoother candle mode with bigger oscillations +#define CANDLE_AMPLITUDE 40 + +// enable 13H factory reset so it can be used on tail e-switch lights +#define USE_SOFT_FACTORY_RESET + +// TODO: disable lowpass while asleep; the MCU oversamples + diff --git a/hw/thefreeman/avr32dd20-devkit/arch b/hw/thefreeman/avr32dd20-devkit/arch new file mode 100644 index 0000000..bcf4552 --- /dev/null +++ b/hw/thefreeman/avr32dd20-devkit/arch @@ -0,0 +1 @@ +avr32dd20 diff --git a/hw/thefreeman/avr32dd20-devkit/hwdef.c b/hw/thefreeman/avr32dd20-devkit/hwdef.c new file mode 100644 index 0000000..e5b347f --- /dev/null +++ b/hw/thefreeman/avr32dd20-devkit/hwdef.c @@ -0,0 +1,105 @@ +// thefreeman boost driver 2.1 output helper functions +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +#include "fsm/chan-rgbaux.c" + +void set_level_zero(); + +void set_level_main(uint8_t level); +bool gradual_tick_main(uint8_t gt); + + +Channel channels[] = { + { // main LEDs + .set_level = set_level_main, + .gradual_tick = gradual_tick_main + }, + RGB_AUX_CHANNELS +}; + + +void set_level_zero() { + DAC_LVL = 0; // DAC off + DAC_VREF = V10; // low Vref + HDR_ENABLE_PORT &= ~(1 << HDR_ENABLE_PIN); // HDR off + + // prevent post-off flash + IN_NFET_ENABLE_PORT |= (1 << IN_NFET_ENABLE_PIN); + delay_4ms(IN_NFET_DELAY_TIME/4); + IN_NFET_ENABLE_PORT &= ~(1 << IN_NFET_ENABLE_PIN); + + // turn off boost last + BST_ENABLE_PORT &= ~(1 << BST_ENABLE_PIN); // BST off +} + +// single set of LEDs with 1 regulated power channel +// and low/high HDR plus low/high Vref as different "gears" +void set_level_main(uint8_t level) { + uint8_t noflash = 0; + + // when turning on from off, use IN_NFET to prevent a flash + if ((! actual_level) && (level < HDR_ENABLE_LEVEL_MIN)) { + noflash = 1; + IN_NFET_ENABLE_PORT |= (1 << IN_NFET_ENABLE_PIN); + } + + // BST on first, to give it a few extra microseconds to spin up + BST_ENABLE_PORT |= (1 << BST_ENABLE_PIN); + + // pre-load ramp data so it can be assigned faster later + // DAC level register is left-aligned + PWM1_DATATYPE dac_lvl = PWM1_GET(level) << 6; + PWM2_DATATYPE dac_vref = PWM2_GET(level); + + // enable HDR on top half of ramp + if (level >= (HDR_ENABLE_LEVEL_MIN-1)) + HDR_ENABLE_PORT |= (1 << HDR_ENABLE_PIN); + else + HDR_ENABLE_PORT &= ~(1 << HDR_ENABLE_PIN); + + // set these in successive clock cycles to avoid getting out of sync + // (minimizes ramp bumps when changing gears) + DAC_LVL = dac_lvl; + DAC_VREF = dac_vref; + + if (noflash) { + // wait for flash prevention to finish + delay_4ms(IN_NFET_DELAY_TIME/4); + IN_NFET_ENABLE_PORT &= ~(1 << IN_NFET_ENABLE_PIN); + } +} + +bool gradual_tick_main(uint8_t gt) { + // if HDR and Vref "engine gear" is the same, do a small adjustment... + // otherwise, simply jump to the next ramp level + // and let set_level() handle any gear changes + + // different gear = full adjustment + PWM2_DATATYPE vref_next = PWM2_GET(gt); + if (vref_next != DAC_VREF) return true; // let parent set_level() for us + + // same gear = small adjustment + PWM1_DATATYPE dac_now = DAC_LVL >> 6; // register is left-aligned + PWM1_DATATYPE dac_next = PWM1_GET(gt); + + // adjust multiple times based on how far until the next level + // (so it adjusts faster/coarser for big steps) + + int16_t diff = (dac_next - dac_now); + if (diff < 0) diff = -diff; + + // ~70 max DAC levels per ramp step, 1 + (70 >> 3) = max 10 + uint8_t steps; + steps = 1 + (diff >> 3); + for (uint8_t i=0; i<=steps; i++) + GRADUAL_ADJUST_SIMPLE(dac_next, dac_now); + + DAC_LVL = dac_now << 6; + + if (dac_next == dac_now) return true; // done + + return false; // not done yet +} + diff --git a/hw/thefreeman/avr32dd20-devkit/hwdef.h b/hw/thefreeman/avr32dd20-devkit/hwdef.h new file mode 100644 index 0000000..7e093f9 --- /dev/null +++ b/hw/thefreeman/avr32dd20-devkit/hwdef.h @@ -0,0 +1,208 @@ +// hwdef for thefreeman's avr32dd20 dev kit +// Copyright (C) 2023 thefreeman, Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* thefreeman’s avr32dd20 dev kit + * Boost driver based on MP3431(?) + * with high dynamic range and DAC control + aux RGB + * + * Pin Name Function + * 1 PA4 - + * 2 PA5 LVB (unused) + * 3 PA6 BATT LVL (voltage divider) + * 4 PA7 HDR: high/low Rsense range + * 5 PC1 - + * 6 PC2 - + * 7 PC3 - + * 8 VDDIO2 VCC2 (unused) + * 9 PD4 e-switch + * 10 PD5 EN: boost enable + * 11 PD6 DAC: control voltage out + * 12 PD7 IN- NFET: absorb startup flash + * 13 VDD VCC + * 14 GND GND + * 15 PF6 RESET + * 16 PF7 UPDI + * 17 PA0 R: aux red + * 18 PA1 G: aux green + * 19 PA2 B: aux blue + * 20 PA3 CH: detect charging + * + * BST EN enable the boost regulator and Op-Amp + * DAC sets the current, max current depends on Vset voltage divider and Rsense + * HDR FET switches between high value Rsense (low current range, pin low), + * and low value Rsense (high current range, pin high) + * IN- NFET : pull up after BST enable to eliminate startup flash, pull down otherwise + * CH senses the status of the onboard charger + * LVL : ??? (unused?) + * LVB is for OTSM firmware, not used here + */ + +#define HWDEF_C thefreeman/avr32dd20-devkit/hwdef.c + +// allow using aux LEDs as extra channel modes +#include "fsm/chan-rgbaux.h" + +// channel modes: +// * 0. main LEDs +// * 1+. aux RGB +#define NUM_CHANNEL_MODES (1 + NUM_RGB_AUX_CHANNEL_MODES) +enum CHANNEL_MODES { + CM_MAIN = 0, + RGB_AUX_ENUMS +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b0000000000000001 + + +#define PWM_CHANNELS 1 // old, remove this + +#undef GRADUAL_ADJUST_SPEED +#define GRADUAL_ADJUST_SPEED 4 + +#define PWM_BITS 16 // 10-bit DAC +#define PWM_DATATYPE uint16_t +#define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint16_t // main LED ramp +#define PWM1_GET(l) PWM_GET16(pwm1_levels, l) +#define PWM2_DATATYPE uint8_t // DAC Vref table +#define PWM2_GET(l) PWM_GET8(pwm2_levels, l) + +// main LED outputs +#define DAC_LVL DAC0_DATA // 0 to 255, for 0V to Vref +#define DAC_VREF VREF_DAC0REF // 1.024V, 2.048V, 4.096V, or 2.5V +//#define DAC_VREF VREF.ADC0REF // 1.024V, 2.048V, 4.096V, or 2.5V +#define PWM_TOP_INIT 255 // highest value used in top half of ramp (unused?) +// Vref values +#define V10 VREF_REFSEL_1V024_gc +#define V20 VREF_REFSEL_2V048_gc +#define V25 VREF_REFSEL_2V500_gc +#define V40 VREF_REFSEL_4V096_gc + +// BST enable +#define BST_ENABLE_PIN PIN5_bp +#define BST_ENABLE_PORT PORTD_OUT + +// HDR +// turns on HDR FET for the high current range +#define HDR_ENABLE_PIN PIN7_bp +#define HDR_ENABLE_PORT PORTA_OUT + +// IN- NFET +// pull high to force output to zero to eliminate the startup flash +#define IN_NFET_DELAY_TIME 12 // (ms) +#define IN_NFET_ENABLE_PIN PIN7_bp +#define IN_NFET_ENABLE_PORT PORTD_OUT + +// e-switch +#ifndef SWITCH_PIN +#define SWITCH_PIN PIN4_bp +#define SWITCH_PORT VPORTD.IN +#define SWITCH_ISC_REG PORTD.PIN4CTRL +#define SWITCH_VECT PORTD_PORT_vect +#define SWITCH_INTFLG VPORTD.INTFLAGS +#endif + +// TODO: define stuff for the voltage divider +// 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 + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 0 // using a PFET so no appreciable drop +#endif + +// this driver allows for aux LEDs under the optic +#define AUXLED_R_PIN PIN0_bp +#define AUXLED_G_PIN PIN1_bp +#define AUXLED_B_PIN PIN2_bp +#define AUXLED_RGB_PORT PORTA + +// this light has three aux LED channels: R, G, B +#define USE_AUX_RGB_LEDS + + +inline void hwdef_setup() { + + // TODO? for this DAC controlled-light, try to decrease the clock speed + mcu_clock_speed(); + + VPORTA.DIR = PIN0_bm // R + | PIN1_bm // G + | PIN2_bm // B + //| PIN3_bm // CH + | PIN7_bm; // HDR + VPORTD.DIR = PIN5_bm // EN + | PIN6_bm // DAC + | PIN7_bm; // IN- NFET + + // enable pullups on the unused and input pins to reduce power + //PORTA.PIN0CTRL = PORT_PULLUPEN_bm; // R + //PORTA.PIN1CTRL = PORT_PULLUPEN_bm; // G + //PORTA.PIN2CTRL = PORT_PULLUPEN_bm; // B + //PORTA.PIN3CTRL = PORT_PULLUPEN_bm; // CH + PORTA.PIN4CTRL = PORT_PULLUPEN_bm; + PORTA.PIN5CTRL = PORT_PULLUPEN_bm; + PORTA.PIN6CTRL = PORT_PULLUPEN_bm; + //PORTA.PIN7CTRL = PORT_PULLUPEN_bm; // HDR + + //PORTC.PIN0CTRL = PORT_PULLUPEN_bm; // doesn't exist + PORTC.PIN1CTRL = PORT_PULLUPEN_bm; + PORTC.PIN2CTRL = PORT_PULLUPEN_bm; + PORTC.PIN3CTRL = PORT_PULLUPEN_bm; + //PORTC.PIN4CTRL = PORT_PULLUPEN_bm; // doesn't exist + //PORTC.PIN5CTRL = PORT_PULLUPEN_bm; // doesn't exist + + //PORTD.PIN0CTRL = PORT_PULLUPEN_bm; // doesn't exist + //PORTD.PIN1CTRL = PORT_PULLUPEN_bm; // doesn't exist + //PORTD.PIN2CTRL = PORT_PULLUPEN_bm; // doesn't exist + //PORTD.PIN3CTRL = PORT_PULLUPEN_bm; // doesn't exist + PORTD.PIN4CTRL = PORT_PULLUPEN_bm + | PORT_ISC_BOTHEDGES_gc; // e-switch + //PORTD.PIN5CTRL = PORT_PULLUPEN_bm; // EN + // AVR datasheet 34.3.1 #2, DAC pin must have input disable set + PORTD.PIN6CTRL = PORT_ISC_INPUT_DISABLE_gc; // DAC + //PORTD.PIN7CTRL = PORT_PULLUPEN_bm; // IN- NFET + + // set up the DAC + // DAC ranges from 0V to (255 * Vref) / 256 + DAC_VREF = V10; + // TODO: try DAC_RUNSTDBY_bm for extra-efficient moon + DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; + DAC_LVL = 0; // set the output voltage (off at boot) + // TODO: instead of enabling the DAC at boot, pull pin down + // to generate a zero without spending power on the DAC + // (and do this in set_level_zero() too) + +} + + +// set fuses, these carry over to the ELF file +// we need this for enabling BOD in Active Mode from the factory. +// settings can be verified / dumped from the ELF file using this +// command: avr-objdump -d -S -j .fuse anduril.elf +FUSES = { + .WDTCFG = FUSE_WDTCFG_DEFAULT, // Watchdog Configuration + + // enable BOD (continuous) in active mode + .BODCFG = ACTIVE_ENABLE_gc, // BOD Configuration + + .OSCCFG = FUSE_OSCCFG_DEFAULT, // Oscillator Configuration + .SYSCFG0 = FUSE_SYSCFG0_DEFAULT, // System Configuration 0 + + // enable MVIO because VDDIO2 pin isn't connected + // set startup time to 64ms to allow power to stabilize + .SYSCFG1 = MVSYSCFG_DUAL_gc | SUT_64MS_gc, + + .CODESIZE = FUSE_CODESIZE_DEFAULT, + .BOOTSIZE = FUSE_BOOTSIZE_DEFAULT, +}; + + +#define LAYOUT_DEFINED + diff --git a/hw/thefreeman/avr32dd20-devkit/model b/hw/thefreeman/avr32dd20-devkit/model new file mode 100644 index 0000000..216403c --- /dev/null +++ b/hw/thefreeman/avr32dd20-devkit/model @@ -0,0 +1 @@ +1632==20 -- cgit v1.2.3 From 957a40fab65553842743f3c178afadcb5bb5c698 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 19 Nov 2023 01:55:01 -0700 Subject: added dac-scale.py: short script to calculate avrdd DAC+Vref values from level_calc.py ramp data --- bin/dac-scale.py | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100755 bin/dac-scale.py diff --git a/bin/dac-scale.py b/bin/dac-scale.py new file mode 100755 index 0000000..d57f8c9 --- /dev/null +++ b/bin/dac-scale.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python + +# +# Calculates DAC values and Vref values from a list of raw intensity values +# Usage: dac-scale.py 5,11,18,25,...,370474,384985,400000 +# Output: #defines suitable for use in hw/*/anduril.h +# Assumptions: +# - DAC data range is 0 to 1023 +# - DAC Vrefs are 1.024V and 2.5V +# - HDR is available and has 2 steps +# - HDR channel ratio is "highest_ramp_value / 2500" +# +# Output values thus have 4 "engine gears": +# - HDR low , 1.024V Vref +# - HDR low , 2.5 V Vref +# - HDR high, 1.024V Vref +# - HDR high, 2.5 V Vref +# + +def main(args): + max_pwm = 1023 + raw_pwm = [int(x) for x in args[0].split(',')] + ratio = raw_pwm[-1] / 2500.0 + cooked = [[]] + + def limit(p): + return min(max_pwm, int(p)) + + phase = 0 + for raw in raw_pwm: + if 0 == phase: + if raw <= 1023: + cooked[-1].append(limit(raw)) + else: + phase += 1 + cooked.append([]) + if 1 == phase: + if raw <= int(2500): + cooked[-1].append(limit(raw * 1.024 / 2.5)) + else: + phase += 1 + cooked.append([]) + if 2 == phase: + if raw <= int(1024 * ratio): + cooked[-1].append(limit(raw / ratio)) + else: + phase += 1 + cooked.append([]) + if 3 == phase: + cooked[-1].append(limit(raw * 1.024 / 2.5 / ratio)) + + # "gear change" boundaries + b1 = len(cooked[0]) + b2 = b1 + len(cooked[1]) + b3 = b2 + len(cooked[2]) + b4 = b3 + len(cooked[3]) + + #print(','.join(['%4i' % n for n in cooked])) + + def fmt_pwms(l): + return ','.join(['%4i' % n for n in l]) + + def fmt_tops(v, l): + return ','.join([' %s' % v for n in l]) + + lines = [] + + lines.append('// top level for each "gear": %i %i %i %i' % (b1, b2, b3, b4)) + + lines.append('#define PWM1_LEVELS \\') + lines.append(' ' + fmt_pwms(cooked[0]) + ', \\') + lines.append(' ' + fmt_pwms(cooked[1]) + ', \\') + lines.append(' ' + fmt_pwms(cooked[2]) + ', \\') + lines.append(' ' + fmt_pwms(cooked[3])) + lines.append('#define PWM2_LEVELS \\') + lines.append(' ' + fmt_tops('V10', cooked[0]) + ', \\') + lines.append(' ' + fmt_tops('V25', cooked[1]) + ', \\') + lines.append(' ' + fmt_tops('V10', cooked[2]) + ', \\') + lines.append(' ' + fmt_tops('V25', cooked[3])) + + lines.append('#define MAX_1x7135 %3i' % b2) + lines.append('#define HDR_ENABLE_LEVEL_MIN %3i' % (b2+1)) + + print('\n'.join(lines)) + +if __name__ == "__main__": + import sys + main(sys.argv[1:]) + -- cgit v1.2.3 From 76db685f66baa7787ad94ce91585e7cba8b94cfb Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 19 Nov 2023 01:56:17 -0700 Subject: started refactoring fsm/adc.*, but need a checkpoint before continuing --- fsm/adc.c | 23 ++++------------------- fsm/adc.h | 15 ++++++++++----- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/fsm/adc.c b/fsm/adc.c index 6d4eeb1..13a76b6 100644 --- a/fsm/adc.c +++ b/fsm/adc.c @@ -15,14 +15,14 @@ #include -static inline void set_admux_therm() { +static inline void adc_therm_mode() { hwdef_set_admux_therm(); adc_channel = 1; adc_sample_count = 0; // first result is unstable ADC_start_measurement(); } -inline void set_admux_voltage() { +void adc_voltage_mode() { hwdef_set_admux_voltage(); adc_channel = 0; adc_sample_count = 0; // first result is unstable @@ -30,21 +30,6 @@ inline void set_admux_voltage() { } -#ifdef TICK_DURING_STANDBY - // needs a special sleep mode to get accurate measurements quickly - // ... full power-down ends up using more power overall, and causes - // some weird issues when the MCU doesn't stay awake enough cycles - // to complete a reading - #define adc_sleep_mode mcu_adc_sleep_mode -#endif - -#define ADC_start_measurement mcu_adc_start_measurement - -// set up ADC for reading battery voltage -#define ADC_on mcu_adc_on -// stop the ADC -#define ADC_off mcu_adc_off - #ifdef USE_VOLTAGE_DIVIDER static inline uint8_t calc_voltage_divider(uint16_t value) { // use 9.7 fixed-point to get sufficient precision @@ -160,7 +145,7 @@ void adc_deferred() { ADC_voltage_handler(); #ifdef USE_THERMAL_REGULATION // set the correct type of measurement for next time - if (! go_to_standby) set_admux_therm(); + if (! go_to_standby) adc_therm_mode(); #endif } #endif @@ -170,7 +155,7 @@ void adc_deferred() { ADC_temperature_handler(); #ifdef USE_LVP // set the correct type of measurement for next time - set_admux_voltage(); + adc_voltage_mode(); #endif } #endif diff --git a/fsm/adc.h b/fsm/adc.h index e4046a4..65d7d6c 100644 --- a/fsm/adc.h +++ b/fsm/adc.h @@ -32,6 +32,9 @@ volatile uint8_t adc_reset = 2; #endif #endif + +void adc_voltage_mode(); + #ifdef TICK_DURING_STANDBY volatile uint8_t adc_active_now = 0; // sleep LVP needs a different sleep mode #endif @@ -103,14 +106,16 @@ static inline void ADC_temperature_handler(); //inline void ADC_on(); -#define ADC_on mcu_adc_on +#define ADC_on adc_voltage_mode //inline void ADC_off(); #define ADC_off mcu_adc_off //inline void ADC_start_measurement(); #define ADC_start_measurement mcu_adc_start_measurement -#ifdef TICK_DURING_STANDBY - //inline void adc_sleep_mode(); - #define adc_sleep_mode mcu_adc_sleep_mode -#endif +// needs a special sleep mode to get accurate measurements quickly +// ... full power-down ends up using more power overall, and causes +// some weird issues when the MCU doesn't stay awake enough cycles +// to complete a reading +//inline void adc_sleep_mode(); +#define adc_sleep_mode mcu_adc_sleep_mode -- cgit v1.2.3 From 8bc6e16569474487efcee3eaee7b6af9738585b8 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 21 Nov 2023 02:44:11 -0700 Subject: 1.55V AA battery should not show as "white" voltage color, only purple --- ui/anduril/aux-leds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/anduril/aux-leds.c b/ui/anduril/aux-leds.c index 1b30d34..dce8d26 100644 --- a/ui/anduril/aux-leds.c +++ b/ui/anduril/aux-leds.c @@ -67,7 +67,7 @@ uint8_t voltage_to_rgb() { 12, 4, // G+B 13, 5, // B 14, 6, // R + B - 15, 7, // R+G+B + 16, 7, // R+G+B 20, 0, // black #endif // li-ion voltages -- cgit v1.2.3 From fdb47b96e86924bf81852205b2b3078b8b21d040 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 21 Nov 2023 02:52:00 -0700 Subject: got ADC voltage+temp working on avrdd... but broke all other builds/MCUs This patch changes the ADC code to use two internal standard units, and everything else must convert to these units: - FSM Volts: centiVolts << 6 (range 0 to 10.24 V per cell) - FSM Kelvin: Kelvin << 6 (range 0 to 1024 K) UI-level voltage is still "Volts * 10", and temperature is still Celsius. FSM expects functions to be provided, to convert from the hardware's raw ADC measurements to these internal units: `voltage_raw2cooked()` and `temp_raw2cooked()`. Defaults will be provided by arch/*.[ch] for each MCU type, or the hwdef can make its own. Anyway, gotta go fix all the other MCUs and builds now. :( --- arch/avr32dd20.c | 60 +++++++++++++++++++--------------- arch/avr32dd20.h | 15 +++++++-- fsm/adc.c | 31 ++++++++++++++++-- hw/thefreeman/avr32dd20-devkit/hwdef.c | 13 ++++++++ hw/thefreeman/avr32dd20-devkit/hwdef.h | 12 +++++-- 5 files changed, 97 insertions(+), 34 deletions(-) diff --git a/arch/avr32dd20.c b/arch/avr32dd20.c index 45923a8..998e9f6 100644 --- a/arch/avr32dd20.c +++ b/arch/avr32dd20.c @@ -52,19 +52,19 @@ inline void mcu_set_admux_therm() { ADC0.SAMPCTRL = 32; // set single-ended or differential // set resolution to 12 bits - // set left- or right-adjust (right) + // set left- or right-adjust // set free-running mode or not (yes) ADC0.CTRLA = ADC_CONVMODE_SINGLEENDED_gc | ADC_RESSEL_12BIT_gc - //| ADC_LEFTADJ_bm // not in temperature mode + | ADC_LEFTADJ_bm | ADC_FREERUN_bm; // set number of samples (requires adjustment in formula too) ADC0.CTRLB = ADC_SAMPNUM_NONE_gc; - // TODO: accumulate more samples for more resolution - // (and probably set the prescale faster too) - //ADC0.CTRLB = ADC_SAMPNUM_ACC16_gc; // 16 samples per result + // accumulate more samples for more resolution + ADC0.CTRLB = ADC_SAMPNUM_ACC16_gc; // 16 samples per result // set a clock prescaler - ADC0.CTRLC = ADC_PRESC_DIV64_gc; + //ADC0.CTRLC = ADC_PRESC_DIV64_gc; // use this when no accumulation + ADC0.CTRLC = ADC_PRESC_DIV4_gc; // measure faster when oversampling // enable the ADC ADC0.CTRLA |= ADC_ENABLE_bm; // actually start measuring (happens in another function) @@ -90,7 +90,7 @@ inline void mcu_set_admux_voltage() { // set number of samples ADC0.CTRLB = ADC_SAMPNUM_ACC16_gc; // 16 samples per result // set a clock prescaler - ADC0.CTRLC = ADC_PRESC_DIV16_gc; // not too fast, not too slow + ADC0.CTRLC = ADC_PRESC_DIV4_gc; // measure faster when oversampling // select the positive ADC input with MUXPOS #ifdef USE_VOLTAGE_DIVIDER // external voltage divider // ADC input pin / Vref @@ -113,11 +113,8 @@ inline void mcu_adc_sleep_mode() { } inline void mcu_adc_start_measurement() { - // FIXME: enable this after getting ADC stuff fixed - #if 0 ADC0.INTCTRL |= ADC_RESRDY_bm; // enable interrupt ADC0.COMMAND |= ADC_STCONV_bm; // actually start measuring - #endif } /* @@ -135,24 +132,35 @@ inline void mcu_adc_vect_clear() { ADC0.INTFLAGS = ADC_RESRDY_bm; // clear the interrupt } -inline uint16_t mcu_adc_result_temp() { - // FIXME: better math, higher precision - // 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 +inline uint16_t mcu_adc_result() { + // value is 12-bit left-aligned + 16x oversampling = 16 bits total + return ADC0.RES; } -inline uint16_t mcu_adc_result_volts() { - // voltage is 12-bit right-aligned + 16x oversampling = 16 bits total - return ADC0.RES; +inline uint16_t mcu_vdd_raw2cooked(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; +} + +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) + // AVR DD datasheet section 33.3.3.8 + uint16_t sigrow_slope = SIGROW.TEMPSENSE0; // factory calibration data + uint16_t sigrow_offset = SIGROW.TEMPSENSE1; // 12-bit value + //const uint32_t scaling_factor = 4096; // use top 12 bits of ADC data + //uint32_t temp = sigrow_offset - (measurement >> 4); + const uint32_t scaling_factor = 65536; // use all 16 bits of ADC data + uint32_t temp = (sigrow_offset << 4) - measurement; + temp *= sigrow_slope; // 24-bit result + temp += scaling_factor / 8; // Add 1/8th K to get correct rounding on later divisions + //temp = temp >> 6; // change (K << 12) to (K << 6) + temp = temp >> 10; // change (K << 16) to (K << 6) + return temp; // left-aligned uint16_t, 0 to 1023.98 Kelvin } inline uint8_t mcu_adc_lsb() { diff --git a/arch/avr32dd20.h b/arch/avr32dd20.h index 7a6b8f1..3ebb05a 100644 --- a/arch/avr32dd20.h +++ b/arch/avr32dd20.h @@ -50,12 +50,21 @@ 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 +//#define MCU_ADC_RESULT_PER_TYPE +//inline uint16_t mcu_adc_result_temp(); +//inline uint16_t mcu_adc_result_volts(); -inline uint16_t mcu_adc_result_temp(); +// return (centiVolts << 6), range 0 to 10.24V +#define voltage_raw2cooked mcu_vdd_raw2cooked +inline uint16_t mcu_vdd_raw2cooked(uint16_t measurement); -inline uint16_t mcu_adc_result_volts(); +// 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/fsm/adc.c b/fsm/adc.c index 13a76b6..73e282d 100644 --- a/fsm/adc.c +++ b/fsm/adc.c @@ -30,6 +30,7 @@ void adc_voltage_mode() { } +#if 0 #ifdef USE_VOLTAGE_DIVIDER static inline uint8_t calc_voltage_divider(uint16_t value) { // use 9.7 fixed-point to get sufficient precision @@ -44,6 +45,7 @@ static inline uint8_t calc_voltage_divider(uint16_t value) { return result; } #endif +#endif // Each full cycle runs ~2X per second with just voltage enabled, // or ~1X per second with voltage and temperature. @@ -67,7 +69,6 @@ ISR(ADC_vect) { // update the latest value #ifdef MCU_ADC_RESULT_PER_TYPE - // thermal, convert ADC reading to left-aligned Kelvin if (channel) m = mcu_adc_result_temp(); else m = mcu_adc_result_volts(); #else @@ -208,6 +209,19 @@ 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); + + // calculate actual voltage: volts * 10 + // TODO: should be (volts * 40) for extra precision + voltage = (measurement + VOLTAGE_FUDGE_FACTOR + #ifdef USE_VOLTAGE_CORRECTION + + VOLT_CORR - 7 + #endif + ) >> 1; + + #if 0 // values stair-step between intervals of 64, with random variations // of 1 or 2 in either direction, so if we chop off the last 6 bits // it'll flap between N and N-1... but if we add half an interval, @@ -231,6 +245,7 @@ static inline void ADC_voltage_handler() { #endif ) >> 1; #endif + #endif // if low, callback EV_voltage_low / EV_voltage_critical // (but only if it has been more than N seconds since last call) @@ -290,8 +305,14 @@ static inline void ADC_temperature_handler() { } // latest 16-bit ADC reading - uint16_t measurement = adc_smooth[1]; + // convert raw ADC value to Kelvin << 6 + // 0 .. 65535 = 0 K .. 1024 K + uint16_t measurement = temp_raw2cooked(adc_smooth[1]); + // (Kelvin << 6) to Celsius + temperature = (measurement>>6) + THERM_CAL_OFFSET + (int16_t)TH_CAL - 275; + + #if 0 // values stair-step between intervals of 64, with random variations // of 1 or 2 in either direction, so if we chop off the last 6 bits // it'll flap between N and N-1... but if we add half an interval, @@ -313,6 +334,12 @@ static inline void ADC_temperature_handler() { // external sensor temperature = EXTERN_TEMP_FORMULA(measurement>>1) + THERM_CAL_OFFSET + (int16_t)TH_CAL; #endif + #endif + + // instead of (K << 6), use (K << 1) now + // TODO: use more precision, if it can be done without overflow in 16 bits + // (and still work on attiny85 without increasing ROM size) + measurement = measurement >> 5; // how much has the temperature changed between now and a few seconds ago? int16_t diff; diff --git a/hw/thefreeman/avr32dd20-devkit/hwdef.c b/hw/thefreeman/avr32dd20-devkit/hwdef.c index e5b347f..133baca 100644 --- a/hw/thefreeman/avr32dd20-devkit/hwdef.c +++ b/hw/thefreeman/avr32dd20-devkit/hwdef.c @@ -103,3 +103,16 @@ bool gradual_tick_main(uint8_t gt) { return false; // not done yet } + +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) + // 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); + return result; +} + diff --git a/hw/thefreeman/avr32dd20-devkit/hwdef.h b/hw/thefreeman/avr32dd20-devkit/hwdef.h index 7e093f9..7e1ad3d 100644 --- a/hw/thefreeman/avr32dd20-devkit/hwdef.h +++ b/hw/thefreeman/avr32dd20-devkit/hwdef.h @@ -35,7 +35,7 @@ * and low value Rsense (high current range, pin high) * IN- NFET : pull up after BST enable to eliminate startup flash, pull down otherwise * CH senses the status of the onboard charger - * LVL : ??? (unused?) + * BATT LVL : Vbat * (100.0/(330+100)) * LVB is for OTSM firmware, not used here */ @@ -109,8 +109,14 @@ enum CHANNEL_MODES { // TODO: define stuff for the voltage divider // 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 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) +// convert BATT LVL pin readings to FSM volt units +#undef voltage_raw2cooked +uint16_t voltage_raw2cooked(uint16_t measurement); + // average drop across diode on this hardware #ifndef VOLTAGE_FUDGE_FACTOR @@ -148,7 +154,7 @@ inline void hwdef_setup() { //PORTA.PIN3CTRL = PORT_PULLUPEN_bm; // CH PORTA.PIN4CTRL = PORT_PULLUPEN_bm; PORTA.PIN5CTRL = PORT_PULLUPEN_bm; - PORTA.PIN6CTRL = PORT_PULLUPEN_bm; + //PORTA.PIN6CTRL = PORT_PULLUPEN_bm; // BATT LVL //PORTA.PIN7CTRL = PORT_PULLUPEN_bm; // HDR //PORTC.PIN0CTRL = PORT_PULLUPEN_bm; // doesn't exist -- cgit v1.2.3 From baaa035cf93340b8f2c626bdba47e8066cf40067 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 22 Nov 2023 05:34:26 -0700 Subject: ADC voltage: battcheck 3 digits, fixed t1616, switched back to 8-bit internal volt unit Before this branch, `voltage` was 6 bits: Volts * 10 A couple patches ago, I upgraded it to 16 bits: 65535 * Volts / 10.24 That costs too much extra ROM on attiny85 though, for extra precision it doesn't even use... so I switched back to an 8-bit value. It's still more precise than before though: Volts * 40 ... and battcheck displays an extra digit now, on devices with ROM for it. ... and battcheck waits a second to get a more accurate measurement before displaying the first value. It has *much* less variation between first and later readings now. Also: - got t1616 builds working again (tested fc13 and thefreeman-boost-fwaa) - upgraded t1616 voltage and temp to 12-bit (10 bits + 4x oversampling) - removed expensive temp conversion from t1616 ADC interrupt - recalibrated t1616 bogomips again; runs faster after interrupt fix - increased t1616 internal VDD measurement resolution by 36% (1.5V Vref, not 1.1V) - fixed sloppy setting of Vref bits I still need to test / update other t1616 builds, and fix all the t85 + t1634 code and build targets. --- arch/attiny1616.c | 125 ++++++++++++++++----- arch/attiny1616.h | 20 +++- arch/avr32dd20.c | 37 +++--- arch/avr32dd20.h | 4 +- fsm/adc.c | 47 +++++--- fsm/adc.h | 4 +- hw/sofirn/sp10-pro/hwdef.h | 4 +- hw/thefreeman/avr32dd20-devkit/hwdef.c | 16 +-- hw/thefreeman/avr32dd20-devkit/hwdef.h | 6 +- .../boost-fwaa-mp3432-hdr-dac-rgb/hwdef.h | 17 ++- ui/anduril/anduril.c | 1 + ui/anduril/aux-leds.c | 34 +++--- ui/anduril/config-default.h | 4 + 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) -- cgit v1.2.3 From 5f8453b34550c2b26629d0e3690ff4338a967dea Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 22 Nov 2023 05:35:14 -0700 Subject: avr32dd20-devkit: make the defaults a bit more dev friendly (realtime voltage colors, and no simple UI by default) --- hw/thefreeman/avr32dd20-devkit/anduril.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hw/thefreeman/avr32dd20-devkit/anduril.h b/hw/thefreeman/avr32dd20-devkit/anduril.h index 97e9e10..ee3765a 100644 --- a/hw/thefreeman/avr32dd20-devkit/anduril.h +++ b/hw/thefreeman/avr32dd20-devkit/anduril.h @@ -87,7 +87,7 @@ // UI -//#define SIMPLE_UI_ACTIVE 0 // advanced UI by default +#define SIMPLE_UI_ACTIVE 0 // advanced UI by default, because it's a dev board // allow Aux Config and Strobe Modes in Simple UI //#define USE_EXTENDED_SIMPLE_UI @@ -104,6 +104,10 @@ // this light has three aux LED channels: R, G, B #define USE_AUX_RGB_LEDS +// turn on the aux LEDs while main LEDs are on +// because this is a dev board and it's useful to see that +#define USE_AUX_RGB_LEDS_WHILE_ON 20 +#define USE_INDICATOR_LED_WHILE_RAMPING // show each channel while it scroll by in the menu #define USE_CONFIG_COLORS -- cgit v1.2.3 From 8c237206aba74f9096d85f90209ac6b7dc238b1b Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 24 Nov 2023 06:29:56 -0700 Subject: more ADC / DAC / MCU progress... - fixed t1616 Vref values getting clobbered sometimes, wrapped setting those in a #define'd function for ease and consistency - moved some DAC definitions from hw/ to arch/ to reduce repetition - fixed thefreeman's other builds - switched from PWM_TOPS to PWM2_LEVELS (I'm trying to phase out _TOPS) --- arch/attiny1616.c | 9 ++---- arch/attiny1616.h | 24 ++++++++++++++ arch/avr32dd20.h | 13 ++++++++ hw/thefreeman/avr32dd20-devkit/anduril.h | 25 ++------------- hw/thefreeman/avr32dd20-devkit/hwdef.h | 20 ++++-------- .../boost-fwaa-mp3432-hdr-dac-rgb/anduril.h | 23 ++++++++------ .../boost-fwaa-mp3432-hdr-dac-rgb/hwdef.h | 37 ++++++++-------------- .../boost21-mp3431-hdr-dac-argb/anduril.h | 24 +++++++------- hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.c | 14 ++++---- hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h | 34 +++++++------------- hw/thefreeman/lin16dac/anduril.h | 22 +++++++------ hw/thefreeman/lin16dac/hwdef.c | 15 +++++---- hw/thefreeman/lin16dac/hwdef.h | 33 +++++++------------ 13 files changed, 136 insertions(+), 157 deletions(-) diff --git a/arch/attiny1616.c b/arch/attiny1616.c index 330c809..2770d06 100644 --- a/arch/attiny1616.c +++ b/arch/attiny1616.c @@ -29,8 +29,7 @@ inline void clock_prescale_set(uint8_t n) { 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 + mcu_set_adc0_vref(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 @@ -46,8 +45,7 @@ inline void mcu_set_admux_voltage() { 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 + mcu_set_adc0_vref(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 @@ -55,8 +53,7 @@ inline void mcu_set_admux_voltage() { | ADC_REFSEL_INTREF_gc; // Use internal ADC 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 + mcu_set_adc0_vref(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 diff --git a/arch/attiny1616.h b/arch/attiny1616.h index 57b0023..940973e 100644 --- a/arch/attiny1616.h +++ b/arch/attiny1616.h @@ -18,6 +18,8 @@ inline void mcu_clock_speed(); // this should work, but needs further validation inline void clock_prescale_set(uint8_t n); +// TODO: allow hwdef to define a base clock speed, +// and adjust these values accordingly typedef enum { // Actual clock is 20 MHz, but assume that 10 MHz is the top speed and work from there @@ -34,8 +36,30 @@ typedef enum } clock_div_t; +////////// DAC controls ////////// + +#define DAC_LVL DAC0.DATA // 0 to 255, for 0V to Vref +#define DAC_VREF VREF.CTRLA // 0.55V, 1.1V, 1.5V, 2.5V, or 4.3V + +// set only the relevant bits of the Vref register +#define mcu_set_dac_vref(x) \ + VREF.CTRLA = x | (VREF.CTRLA & (~VREF_DAC0REFSEL_gm)); + +// Vref values +// (for the DAC bits, not the ADC bits) +#define V05 V055 +#define V055 VREF_DAC0REFSEL_0V55_gc +#define V11 VREF_DAC0REFSEL_1V1_gc +#define V25 VREF_DAC0REFSEL_2V5_gc +#define V43 VREF_DAC0REFSEL_4V34_gc +#define V15 VREF_DAC0REFSEL_1V5_gc + ////////// ADC voltage / temperature ////////// +// set only the relevant bits of the Vref register +#define mcu_set_adc0_vref(x) \ + VREF.CTRLA = x | (VREF.CTRLA & (~VREF_ADC0REFSEL_gm)); + #define hwdef_set_admux_therm mcu_set_admux_therm inline void mcu_set_admux_therm(); diff --git a/arch/avr32dd20.h b/arch/avr32dd20.h index 82951de..09b4096 100644 --- a/arch/avr32dd20.h +++ b/arch/avr32dd20.h @@ -30,6 +30,19 @@ typedef enum } clock_div_t; +////////// DAC controls ////////// + +// main LED outputs +#define DAC_LVL DAC0_DATA // 0 to 1023, for 0V to Vref +#define DAC_VREF VREF_DAC0REF // 1.024V, 2.048V, 4.096V, or 2.5V + +// Vref values (suitable for DAC and ADC0) +#define V10 VREF_REFSEL_1V024_gc +#define V20 VREF_REFSEL_2V048_gc +#define V25 VREF_REFSEL_2V500_gc +#define V40 VREF_REFSEL_4V096_gc + + ////////// ADC voltage / temperature ////////// #define hwdef_set_admux_therm mcu_set_admux_therm diff --git a/hw/thefreeman/avr32dd20-devkit/anduril.h b/hw/thefreeman/avr32dd20-devkit/anduril.h index ee3765a..02d5de3 100644 --- a/hw/thefreeman/avr32dd20-devkit/anduril.h +++ b/hw/thefreeman/avr32dd20-devkit/anduril.h @@ -1,5 +1,5 @@ -// thefreeman's BST21 BST20-FWxA (no button LED) -// Copyright (C) 2023 TBD (thefreeman), Selene ToyKeeper +// thefreeman's avr32dd20 devkit board +// Copyright (C) 2023 thefreeman, Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later #pragma once @@ -20,7 +20,6 @@ // - high 2.5 V // HDR ratio: 160 // PWM1: DAC Data -#if 1 // level_calc.py 4.3287 1 150 7135 5 0.01 1400 --pwm 400000 // top level for each "gear": 30 40 120 150 #define PWM1_LEVELS \ @@ -36,26 +35,6 @@ #define MAX_1x7135 40 #define HDR_ENABLE_LEVEL_MIN 41 #define DEFAULT_LEVEL 50 -#else -// level_calc.py 9.21 1 150 7135 5 0.2 1400 --pwm 400000 -// (plus dac-scale.py post-processing to get values for HDR+Vref ranges) -// top level for each "gear": 35 48 127 150 -#define PWM1_LEVELS \ - 5, 11, 18, 25, 33, 41, 50, 60, 71, 83, 96, 110, 125, 141, 158, 177, 198, 220, 244, 269, 297, 326, 358, 392, 429, 469, 511, 556, 605, 657, 713, 772, 836, 904, 976, \ - 431, 465, 501, 539, 580, 624, 670, 720, 772, 828, 887, 950,1017, \ - 16, 17, 18, 20, 21, 23, 24, 26, 27, 29, 31, 33, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 64, 68, 72, 76, 80, 85, 90, 95, 100, 106, 112, 118, 124, 131, 138, 145, 153, 161, 170, 179, 188, 198, 208, 219, 230, 242, 254, 266, 280, 294, 308, 323, 339, 355, 373, 391, 409, 429, 449, 470, 492, 515, 539, 564, 589, 616, 644, 673, 704, 735, 768, 802, 837, 874, 912, 952, 993, \ - 424, 442, 461, 480, 501, 522, 544, 566, 590, 614, 640, 666, 693, 721, 750, 780, 811, 844, 877, 912, 948, 985,1023 -// Vref selector (V10, V20, V25, V40 = 1.024V, 2.048V, 2.5V, 4.096V) -#define PWM2_LEVELS \ - V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, \ - V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, \ - V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, \ - V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25 - -#define MAX_1x7135 48 -#define DEFAULT_LEVEL 48 -#define HDR_ENABLE_LEVEL_MIN 49 // when HDR FET turns ON -#endif // no PWM, so MCU clock speed can be slow #define HALFSPEED_LEVEL 41 diff --git a/hw/thefreeman/avr32dd20-devkit/hwdef.h b/hw/thefreeman/avr32dd20-devkit/hwdef.h index a5b37a9..f1b6095 100644 --- a/hw/thefreeman/avr32dd20-devkit/hwdef.h +++ b/hw/thefreeman/avr32dd20-devkit/hwdef.h @@ -39,7 +39,7 @@ * LVB is for OTSM firmware, not used here */ -#define HWDEF_C thefreeman/avr32dd20-devkit/hwdef.c +#define HWDEF_C thefreeman/avr32dd20-devkit/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -59,8 +59,6 @@ enum CHANNEL_MODES { #define CHANNEL_MODES_ENABLED 0b0000000000000001 -#define PWM_CHANNELS 1 // old, remove this - #undef GRADUAL_ADJUST_SPEED #define GRADUAL_ADJUST_SPEED 4 @@ -73,15 +71,7 @@ enum CHANNEL_MODES { #define PWM2_GET(l) PWM_GET8(pwm2_levels, l) // main LED outputs -#define DAC_LVL DAC0_DATA // 0 to 255, for 0V to Vref -#define DAC_VREF VREF_DAC0REF // 1.024V, 2.048V, 4.096V, or 2.5V -//#define DAC_VREF VREF.ADC0REF // 1.024V, 2.048V, 4.096V, or 2.5V -#define PWM_TOP_INIT 255 // highest value used in top half of ramp (unused?) -// Vref values -#define V10 VREF_REFSEL_1V024_gc -#define V20 VREF_REFSEL_2V048_gc -#define V25 VREF_REFSEL_2V500_gc -#define V40 VREF_REFSEL_4V096_gc +// (DAC_LVL + DAC_VREF + Vref values are defined in arch/*.h) // BST enable #define BST_ENABLE_PIN PIN5_bp @@ -113,6 +103,7 @@ enum CHANNEL_MODES { #define ADMUX_VOLTAGE_DIVIDER ADC_MUXPOS_AIN26_gc #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) +// don't use the default VDD converter // convert BATT LVL pin readings to FSM volt units #undef voltage_raw2cooked uint8_t voltage_raw2cooked(uint16_t measurement); @@ -135,7 +126,8 @@ uint8_t voltage_raw2cooked(uint16_t measurement); inline void hwdef_setup() { - // TODO? for this DAC controlled-light, try to decrease the clock speed + // TODO: for this DAC controlled-light, try to decrease the clock speed + // to reduce overall system power mcu_clock_speed(); VPORTA.DIR = PIN0_bm // R @@ -180,7 +172,7 @@ inline void hwdef_setup() { DAC_VREF = V10; // TODO: try DAC_RUNSTDBY_bm for extra-efficient moon DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; - DAC_LVL = 0; // set the output voltage (off at boot) + DAC_LVL = 0; // turn off output at boot // TODO: instead of enabling the DAC at boot, pull pin down // to generate a zero without spending power on the DAC // (and do this in set_level_zero() too) diff --git a/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/anduril.h b/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/anduril.h index 33583df..d1b1661 100644 --- a/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/anduril.h +++ b/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/anduril.h @@ -19,15 +19,17 @@ // - high 0.55V // - high 2.5V // PWM1: DAC Data -#define PWM1_LEVELS 2, 3, 4, 5, 6, 8, 9, 11, 14, 16, 19, 23, 26, 31, 35, 41, 47, 54, 61, 69, 78, 89,100,112,125,140,155,173,191,212,234, \ - 56, 62, 68, 74, 82, 89, 97,106,115,125,136,147,159,172,186,200,215,232,249, \ - 14, 15, 17, 18, 19, 20, 22, 23, 25, 26, 28, 30, 32, 34, 36, 38, 40, 43, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81, 86, 90, 95, 99,104,109,114,120,126,131,138,144,150,157,164,171,179,187,195,203,212,221,230,239,249, \ - 57, 59, 61, 64, 66, 69, 72, 74, 77, 80, 83, 86, 90, 93, 96,100,103,107,111,115,119,123,127,132,136,141,145,150,155,160,166,171,176,182,188,194,200,206,213,219,226,233,240,247,255 -// PWM Tops: VREF selector (0.55V=16,1.1V=17, 2.5V=18, 4.3V=19, 1.5V=20) -#define PWM_TOPS V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05, \ - V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25, \ - V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05, \ - V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25 +#define PWM1_LEVELS \ + 2, 3, 4, 5, 6, 8, 9, 11, 14, 16, 19, 23, 26, 31, 35, 41, 47, 54, 61, 69, 78, 89,100,112,125,140,155,173,191,212,234, \ + 56, 62, 68, 74, 82, 89, 97,106,115,125,136,147,159,172,186,200,215,232,249, \ + 14, 15, 17, 18, 19, 20, 22, 23, 25, 26, 28, 30, 32, 34, 36, 38, 40, 43, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81, 86, 90, 95, 99,104,109,114,120,126,131,138,144,150,157,164,171,179,187,195,203,212,221,230,239,249, \ + 57, 59, 61, 64, 66, 69, 72, 74, 77, 80, 83, 86, 90, 93, 96,100,103,107,111,115,119,123,127,132,136,141,145,150,155,160,166,171,176,182,188,194,200,206,213,219,226,233,240,247,255 +// PWM2: VREF selector (0.55V=16,1.1V=17, 2.5V=18, 4.3V=19, 1.5V=20) +#define PWM2_LEVELS \ + V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05, \ + V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25, \ + V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05, \ + V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25 #define MAX_1x7135 50 #define DEFAULT_LEVEL 44 @@ -39,6 +41,7 @@ #define RAMP_SMOOTH_FLOOR 1 #define RAMP_SMOOTH_CEIL 130 // ~50% power, ~??? mA / ??? lm +// 1 22 [44] 65 87 108 130 #define RAMP_DISCRETE_FLOOR 1 #define RAMP_DISCRETE_CEIL 130 #define RAMP_DISCRETE_STEPS 7 @@ -70,7 +73,7 @@ //#define SIMPLE_UI_ACTIVE 0 // advanced UI by default // allow Aux Config and Strobe Modes in Simple UI -#define USE_EXTENDED_SIMPLE_UI +//#define USE_EXTENDED_SIMPLE_UI // Allow 3C in Simple UI for switching between smooth and stepped ramping #define USE_SIMPLE_UI_RAMPING_TOGGLE 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 45c02de..bc1d9a7 100644 --- a/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/hwdef.h +++ b/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/hwdef.h @@ -56,26 +56,16 @@ enum CHANNEL_MODES { #define CHANNEL_MODES_ENABLED 0b0000000000000001 -#define PWM_CHANNELS 1 // old, remove this - #define PWM_BITS 8 // 8-bit DAC -#define PWM_GET PWM_GET8 #define PWM_DATATYPE uint8_t #define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 #define PWM1_DATATYPE uint8_t // main LED ramp +#define PWM1_GET(l) PWM_GET8(pwm1_levels, l) +#define PWM2_DATATYPE uint8_t // DAC Vref table +#define PWM2_GET(l) PWM_GET8(pwm2_levels, l) // main LED outputs -#define DAC_LVL DAC0.DATA // 0 to 255, for 0V to Vref -#define DAC_VREF VREF.CTRLA // 0.55V or 2.5V -#define PWM_TOP_INIT 255 // highest value used in top half of ramp (unused?) -// Vref values -// (1.1V ADC + variable DAC) -#define V05 V055 -#define V055 (VREF_ADC0REFSEL_1V1_gc|VREF_DAC0REFSEL_0V55_gc) -#define V11 (VREF_ADC0REFSEL_1V1_gc|VREF_DAC0REFSEL_1V1_gc) -#define V25 (VREF_ADC0REFSEL_1V1_gc|VREF_DAC0REFSEL_2V5_gc) -#define V43 (VREF_ADC0REFSEL_1V1_gc|VREF_DAC0REFSEL_4V34_gc) -#define V15 (VREF_ADC0REFSEL_1V1_gc|VREF_DAC0REFSEL_1V5_gc) +// (DAC_LVL + DAC_VREF + Vref values are defined in arch/*.h) // BST enable #define BST_ENABLE_PIN PIN4_bp @@ -103,9 +93,10 @@ enum CHANNEL_MODES { // Voltage divider battLVL #define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is regulated +#define ADMUX_VOLTAGE_DIVIDER ADC_MUXPOS_AIN2_gc // which ADC channel to read #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 +// don't use the default VDD converter #undef voltage_raw2cooked #define voltage_raw2cooked mcu_vdivider_raw2cooked @@ -130,10 +121,9 @@ enum CHANNEL_MODES { inline void hwdef_setup() { - // TODO: for this DAC controlled-light, try to decrease the clock speed or use the ULP - // set up the system clock to run at 10 MHz to match other attiny1616 lights - _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, - CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); + // TODO: for this DAC controlled-light, try to decrease the clock speed + // to reduce overall system power + mcu_clock_speed(); VPORTA.DIR = PIN4_bm // BST EN | PIN5_bm // HDR @@ -170,11 +160,10 @@ inline void hwdef_setup() { // set up the DAC // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf // DAC ranges from 0V to (255 * Vref) / 256 - // also VREF_DAC0REFSEL_0V55_gc and VREF_DAC0REFSEL_1V1_gc and VREF_DAC0REFSEL_2V5_gc - VREF.CTRLA |= VREF_DAC0REFSEL_2V5_gc; - VREF.CTRLB |= VREF_DAC0REFEN_bm; - DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; - DAC0.DATA = 255; // set the output voltage + mcu_set_dac_vref(V05); // boot at lowest Vref setting + VREF.CTRLB |= VREF_DAC0REFEN_bm; // enable DAC Vref + DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; // enable DAC + DAC_LVL = 0; // turn off output at boot } diff --git a/hw/thefreeman/boost21-mp3431-hdr-dac-argb/anduril.h b/hw/thefreeman/boost21-mp3431-hdr-dac-argb/anduril.h index a6a111c..8319d13 100644 --- a/hw/thefreeman/boost21-mp3431-hdr-dac-argb/anduril.h +++ b/hw/thefreeman/boost21-mp3431-hdr-dac-argb/anduril.h @@ -3,7 +3,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #pragma once -#include "thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h" +#define HWDEF_H thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h // HPRsense : 1.7+0.3+5 = 7mR (DMN22M5UFG+trace resistance+5mR) // Vsense=42.46mV, R1= 191k @@ -19,15 +19,17 @@ // - high 0.55V // - high 2.5V // PWM1: DAC Data -#define PWM1_LEVELS 2, 3, 4, 5, 7, 9, 11, 13, 16, 19, 23, 28, 33, 39, 45, 53, 61, 71, 81, 93,106,121,137,155,175,196,220,246, \ - 60, 67, 74, 82, 91,100,110,121,133,146,159,174,190,207,224,244, \ - 8, 9, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 23, 24, 26, 27, 29, 31, 33, 35, 37, 40, 42, 45, 47, 50, 53, 56, 59, 62, 66, 69, 73, 77, 81, 85, 90, 94, 99,104,109,114,120,126,132,138,144,151,158,165,173,180,188,196,205,214,223,232,242,252, \ - 57, 60, 62, 65, 67, 70, 73, 76, 78, 82, 85, 88, 91, 95, 98,102,105,109,113,117,121,126,130,135,139,144,149,154,159,164,170,175,181,187,193,199,206,212,219,225,232,240,247,255 -// PWM Tops: VREF selector (0.55V=16,1.1V=17, 2.5V=18, 4.3V=19, 1.5V=20) -#define PWM_TOPS V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05, \ - V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25, \ - V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05, \ - V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25 +#define PWM1_LEVELS \ + 2, 3, 4, 5, 7, 9, 11, 13, 16, 19, 23, 28, 33, 39, 45, 53, 61, 71, 81, 93,106,121,137,155,175,196,220,246, \ + 60, 67, 74, 82, 91,100,110,121,133,146,159,174,190,207,224,244, \ + 8, 9, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 23, 24, 26, 27, 29, 31, 33, 35, 37, 40, 42, 45, 47, 50, 53, 56, 59, 62, 66, 69, 73, 77, 81, 85, 90, 94, 99,104,109,114,120,126,132,138,144,151,158,165,173,180,188,196,205,214,223,232,242,252, \ + 57, 60, 62, 65, 67, 70, 73, 76, 78, 82, 85, 88, 91, 95, 98,102,105,109,113,117,121,126,130,135,139,144,149,154,159,164,170,175,181,187,193,199,206,212,219,225,232,240,247,255 +// PWM2: VREF selector (0.55V=16,1.1V=17, 2.5V=18, 4.3V=19, 1.5V=20) +#define PWM2_LEVELS \ + V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05, \ + V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25, \ + V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05, \ + V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25 #define MAX_1x7135 44 #define DEFAULT_LEVEL 44 @@ -71,7 +73,7 @@ //#define SIMPLE_UI_ACTIVE 0 // advanced UI by default // allow Aux Config and Strobe Modes in Simple UI -#define USE_EXTENDED_SIMPLE_UI +//#define USE_EXTENDED_SIMPLE_UI // Allow 3C in Simple UI for switching between smooth and stepped ramping #define USE_SIMPLE_UI_RAMPING_TOGGLE diff --git a/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.c b/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.c index 97f5fc9..573ec2f 100644 --- a/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.c +++ b/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.c @@ -22,7 +22,7 @@ Channel channels[] = { void set_level_zero() { DAC_LVL = 0; // DAC off - DAC_VREF = V055; // low Vref + mcu_set_dac_vref(V055); // low Vref HDR_ENABLE_PORT &= ~(1 << HDR_ENABLE_PIN); // HDR off // prevent post-off flash @@ -49,8 +49,8 @@ void set_level_main(uint8_t level) { BST_ENABLE_PORT |= (1 << BST_ENABLE_PIN); // pre-load ramp data so it can be assigned faster later - PWM_DATATYPE dac_lvl = PWM_GET(pwm1_levels, level); - PWM_DATATYPE dac_vref = PWM_GET(pwm_tops, level); + PWM1_DATATYPE dac_lvl = PWM1_GET(level); + PWM2_DATATYPE dac_vref = PWM2_GET(level); // enable HDR on top half of ramp if (level >= (HDR_ENABLE_LEVEL_MIN-1)) @@ -61,7 +61,7 @@ void set_level_main(uint8_t level) { // set these in successive clock cycles to avoid getting out of sync // (minimizes ramp bumps when changing gears) DAC_LVL = dac_lvl; - DAC_VREF = dac_vref; + mcu_set_dac_vref(dac_vref); if (noflash) { // wait for flash prevention to finish @@ -75,11 +75,11 @@ bool gradual_tick_main(uint8_t gt) { // otherwise, simply jump to the next ramp level // and let set_level() handle any gear changes - PWM_DATATYPE dac_next = PWM_GET(pwm1_levels, gt); - PWM_DATATYPE vref_next = PWM_GET(pwm_tops, gt); + PWM1_DATATYPE dac_next = PWM1_GET(gt); + PWM2_DATATYPE vref_next = PWM2_GET(gt); // different gear = full adjustment - if (vref_next != DAC_VREF) return true; // let parent set_level() for us + if (vref_next != (DAC_VREF & VREF_DAC0REFSEL_gm)) return true; // let parent set_level() for us // same gear = small adjustment GRADUAL_ADJUST_SIMPLE(dac_next, DAC_LVL); diff --git a/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h b/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h index d030516..d83aa46 100644 --- a/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h +++ b/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h @@ -57,26 +57,16 @@ enum CHANNEL_MODES { #define CHANNEL_MODES_ENABLED 0b0000000000000001 -#define PWM_CHANNELS 1 // old, remove this - #define PWM_BITS 8 // 8-bit DAC -#define PWM_GET PWM_GET8 #define PWM_DATATYPE uint8_t #define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 #define PWM1_DATATYPE uint8_t // main LED ramp +#define PWM1_GET(l) PWM_GET8(pwm1_levels, l) +#define PWM2_DATATYPE uint8_t // DAC Vref table +#define PWM2_GET(l) PWM_GET8(pwm2_levels, l) // main LED outputs -#define DAC_LVL DAC0.DATA // 0 to 255, for 0V to Vref -#define DAC_VREF VREF.CTRLA // 0.55V or 2.5V -#define PWM_TOP_INIT 255 // highest value used in top half of ramp (unused?) -// Vref values -// (1.1V ADC + variable DAC) -#define V05 V055 -#define V055 (VREF_ADC0REFSEL_1V1_gc|VREF_DAC0REFSEL_0V55_gc) -#define V11 (VREF_ADC0REFSEL_1V1_gc|VREF_DAC0REFSEL_1V1_gc) -#define V25 (VREF_ADC0REFSEL_1V1_gc|VREF_DAC0REFSEL_2V5_gc) -#define V43 (VREF_ADC0REFSEL_1V1_gc|VREF_DAC0REFSEL_4V34_gc) -#define V15 (VREF_ADC0REFSEL_1V1_gc|VREF_DAC0REFSEL_1V5_gc) +// (DAC_LVL + DAC_VREF + Vref values are defined in arch/*.h) // BST enable #define BST_ENABLE_PIN PIN0_bp @@ -125,10 +115,9 @@ enum CHANNEL_MODES { inline void hwdef_setup() { - // TODO: for this DAC controlled-light, try to decrease the clock speed or use the ULP - // set up the system clock to run at 10 MHz to match other attiny1616 lights - _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, - CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); + // TODO: for this DAC controlled-light, try to decrease the clock speed + // to reduce overall system power + mcu_clock_speed(); VPORTA.DIR = PIN6_bm; // DAC VPORTB.DIR = PIN1_bm // R @@ -165,11 +154,10 @@ inline void hwdef_setup() { // set up the DAC // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf // DAC ranges from 0V to (255 * Vref) / 256 - // also VREF_DAC0REFSEL_0V55_gc and VREF_DAC0REFSEL_1V1_gc and VREF_DAC0REFSEL_2V5_gc - VREF.CTRLA |= VREF_DAC0REFSEL_2V5_gc; - VREF.CTRLB |= VREF_DAC0REFEN_bm; - DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; - DAC0.DATA = 255; // set the output voltage + mcu_set_dac_vref(V05); // boot at lowest Vref setting + VREF.CTRLB |= VREF_DAC0REFEN_bm; // enable DAC Vref + DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; // enable DAC + DAC_LVL = 0; // turn off output at boot } diff --git a/hw/thefreeman/lin16dac/anduril.h b/hw/thefreeman/lin16dac/anduril.h index 8ca8b9f..8f9d6e4 100644 --- a/hw/thefreeman/lin16dac/anduril.h +++ b/hw/thefreeman/lin16dac/anduril.h @@ -3,7 +3,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #pragma once -#include "thefreeman/lin16dac/hwdef.h" +#define HWDEF_H thefreeman/lin16dac/hwdef.h // the button lights up #define USE_INDICATOR_LED @@ -24,15 +24,17 @@ // PWM1: DAC Data // FIXME: ramp stalls with 8 duplicate levels in a row // (maybe use 1.1V Vref during that part of the ramp?) -#define PWM1_LEVELS 25, 25, 33, 41, 41, 50, 58, 66, 75, 83, 92,108,117,133,150,167,192,209,234, \ - 58, 64, 71, 80, 90, 99,110,121,134,149,163,180,198,218,241, \ - 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 11, 11, 12, 13, 14, 15, 16, 18, 19, 20, 22, 23, 25, 26, 28, 30, 32, 34, 36, 39, 41, 44, 47, 50, 53, 56, 59, 63, 67, 71, 75, 79, 84, 89, 94,100,105,112,118,124,131,139,146,154,163,172,181,191,201,212,223,234,246, \ - 57, 60, 63, 66, 69, 73, 76, 80, 84, 88, 93, 97,102,107,112,117,123,129,135,141,147,154,161,169,176,184,193,201,210,220,229,239,250,255 -// PWM Tops: VREF selector (0.55V=16,1.1V=17, 2.5V=18, 4.3V=19, 1.5V=20) -#define PWM_TOPS 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, \ - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, \ - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, \ - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18 +#define PWM1_LEVELS \ + 25, 25, 33, 41, 41, 50, 58, 66, 75, 83, 92,108,117,133,150,167,192,209,234, \ + 58, 64, 71, 80, 90, 99,110,121,134,149,163,180,198,218,241, \ + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 11, 11, 12, 13, 14, 15, 16, 18, 19, 20, 22, 23, 25, 26, 28, 30, 32, 34, 36, 39, 41, 44, 47, 50, 53, 56, 59, 63, 67, 71, 75, 79, 84, 89, 94,100,105,112,118,124,131,139,146,154,163,172,181,191,201,212,223,234,246, \ + 57, 60, 63, 66, 69, 73, 76, 80, 84, 88, 93, 97,102,107,112,117,123,129,135,141,147,154,161,169,176,184,193,201,210,220,229,239,250,255 +// PWM2: VREF selector (0.55V=16,1.1V=17, 2.5V=18, 4.3V=19, 1.5V=20) +#define PWM2_LEVELS \ + V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05, \ + V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25, \ + V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05, \ + V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25 #define MAX_1x7135 34 #define HDR_ENABLE_LEVEL_MIN 35 // bottom level of top half of the ramp diff --git a/hw/thefreeman/lin16dac/hwdef.c b/hw/thefreeman/lin16dac/hwdef.c index 191444e..89700d7 100644 --- a/hw/thefreeman/lin16dac/hwdef.c +++ b/hw/thefreeman/lin16dac/hwdef.c @@ -22,7 +22,7 @@ Channel channels[] = { void set_level_zero() { DAC_LVL = 0; // DAC off - DAC_VREF = V055; // low Vref + mcu_set_dac_vref(V055); // low Vref HDR_ENABLE_PORT &= ~(1 << HDR_ENABLE_PIN); // HDR off // prevent post-off flash @@ -50,8 +50,8 @@ void set_level_main(uint8_t level) { OPAMP_ENABLE_PORT |= (1 << OPAMP_ENABLE_PIN); // pre-load ramp data so it can be assigned faster later - PWM_DATATYPE dac_lvl = PWM_GET(pwm1_levels, level); - PWM_DATATYPE dac_vref = PWM_GET(pwm_tops, level); + PWM1_DATATYPE dac_lvl = PWM1_GET(level); + PWM2_DATATYPE dac_vref = PWM2_GET(level); // enable HDR on top half of ramp if (level >= (HDR_ENABLE_LEVEL_MIN-1)) @@ -69,7 +69,8 @@ void set_level_main(uint8_t level) { // set these in successive clock cycles to avoid getting out of sync // (minimizes ramp bumps when changing gears) DAC_LVL = dac_lvl; - DAC_VREF = dac_vref; + mcu_set_dac_vref(dac_vref); + } bool gradual_tick_main(uint8_t gt) { @@ -77,11 +78,11 @@ bool gradual_tick_main(uint8_t gt) { // otherwise, simply jump to the next ramp level // and let set_level() handle any gear changes - PWM_DATATYPE dac_next = PWM_GET(pwm1_levels, gt); - PWM_DATATYPE vref_next = PWM_GET(pwm_tops, gt); + PWM1_DATATYPE dac_next = PWM1_GET(gt); + PWM2_DATATYPE vref_next = PWM2_GET(gt); // different gear = full adjustment - if (vref_next != DAC_VREF) return true; // let parent set_level() for us + if (vref_next != (DAC_VREF & VREF_DAC0REFSEL_gm)) return true; // let parent set_level() for us // same gear = small adjustment GRADUAL_ADJUST_SIMPLE(dac_next, DAC_LVL); diff --git a/hw/thefreeman/lin16dac/hwdef.h b/hw/thefreeman/lin16dac/hwdef.h index dc4377a..a68d9c2 100644 --- a/hw/thefreeman/lin16dac/hwdef.h +++ b/hw/thefreeman/lin16dac/hwdef.h @@ -32,24 +32,16 @@ enum CHANNEL_MODES { #define CHANNEL_MODES_ENABLED 0b0000000000000001 -#define PWM_CHANNELS 1 // old, remove this - #define PWM_BITS 8 // 8-bit DAC -#define PWM_GET PWM_GET8 #define PWM_DATATYPE uint8_t #define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 #define PWM1_DATATYPE uint8_t // main LED ramp +#define PWM1_GET(l) PWM_GET8(pwm1_levels, l) +#define PWM2_DATATYPE uint8_t // DAC Vref table +#define PWM2_GET(l) PWM_GET8(pwm2_levels, l) // main LED outputs -#define DAC_LVL DAC0.DATA // 0 to 255, for 0V to Vref -#define DAC_VREF VREF.CTRLA // 0.55V or 2.5V -#define PWM_TOP_INIT 255 // highest value used in top half of ramp (unused?) -// Vref values -#define V055 16 -#define V11 17 -#define V25 18 -#define V43 19 -#define V15 20 +// (DAC_LVL + DAC_VREF + Vref values are defined in arch/*.h) // Opamp enable // For turning on and off the op-amp @@ -84,11 +76,9 @@ enum CHANNEL_MODES { inline void hwdef_setup() { - // set up the system clock to run at 10 MHz instead of the default 3.33 MHz - // (it'll get underclocked to 2.5 MHz later) - // TODO: maybe run even slower? - _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, - CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); + // TODO: for this DAC controlled-light, try to decrease the clock speed + // to reduce overall system power + mcu_clock_speed(); VPORTA.DIR = PIN6_bm // DAC | PIN7_bm; // Opamp @@ -121,11 +111,10 @@ inline void hwdef_setup() { // set up the DAC // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf // DAC ranges from 0V to (255 * Vref) / 256 - // also VREF_DAC0REFSEL_0V55_gc and VREF_DAC0REFSEL_1V1_gc and VREF_DAC0REFSEL_2V5_gc - VREF.CTRLA |= VREF_DAC0REFSEL_2V5_gc; - VREF.CTRLB |= VREF_DAC0REFEN_bm; - DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; - DAC0.DATA = 255; // set the output voltage + mcu_set_dac_vref(V05); // boot at lowest Vref setting + VREF.CTRLB |= VREF_DAC0REFEN_bm; // enable DAC Vref + DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; // enable DAC + DAC_LVL = 0; // turn off output at boot } -- cgit v1.2.3 From 1b6f40863b4f08365e39236496d687ab7806ed11 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 27 Nov 2023 07:31:56 -0700 Subject: fixed ADC on attiny1634 and related builds --- arch/attiny1634.c | 129 +++++++++++++++++++++++++++++------- arch/attiny1634.h | 40 +++++++---- hw/hank/emisar-2ch/fet/hwdef.h | 30 +-------- hw/hank/emisar-2ch/hwdef.h | 30 +-------- hw/hank/emisar-d4k-3ch/hwdef.h | 30 +-------- hw/hank/noctigon-dm11/boost/hwdef.h | 30 +-------- hw/hank/noctigon-dm11/hwdef.h | 30 +-------- hw/hank/noctigon-k1/boost/hwdef.h | 30 +-------- hw/hank/noctigon-k1/hwdef.h | 30 +-------- hw/hank/noctigon-k1/sbt90/hwdef.h | 31 +-------- hw/hank/noctigon-kr4/hwdef.h | 30 +-------- hw/hank/noctigon-m44/hwdef.h | 30 +-------- hw/hank/vdivider-1634.h | 39 +++++++++++ 13 files changed, 181 insertions(+), 328 deletions(-) create mode 100644 hw/hank/vdivider-1634.h diff --git a/arch/attiny1634.c b/arch/attiny1634.c index 0737a81..e29d1c3 100644 --- a/arch/attiny1634.c +++ b/arch/attiny1634.c @@ -7,14 +7,26 @@ ////////// clock speed / delay stuff ////////// +inline void mcu_clock_speed() { + // TODO? + // (or not; clock speed is set by the fuses) + // attiny1634 datasheet 6.5 + // CLKSR = [OSCRDY, CSTR, CKOUT_IO, SUT, CKSEL3/2/1/0] + // default 8MHz calibrated internal clock: SUT=0, CKSEL=0b0010 + #if 0 + cli(); + CCP = 0xD8; + CLKSR = 0b01000010; + CCP = 0xD8; + CLKPR = 0; // CLK / 1 = full speed, 8 MHz + sei(); + #endif +} + ///// clock dividers -// make it a NOP for now -// FIXME -//#define clock_prescale_set(x) ((void)0) -//#define clock_prescale_set(n) {cli(); CCP = 0xD8; CLKPR = n; sei();} -//#define clock_prescale_set(n) {cli(); CCP = 0xD8; CLKPR = n; sei();} inline void clock_prescale_set(uint8_t n) { cli(); + // _PROTECTED_WRITE(CLKPR, n); CCP = 0xD8; CLKPR = n; sei(); @@ -26,15 +38,33 @@ inline void clock_prescale_set(uint8_t n) { ////////// ADC voltage / temperature ////////// inline void mcu_set_admux_therm() { + // put the ADC in temperature mode + // DS table 19-3, 19-4, internal sensor / 1.1V ref + // [refs1, refs0, refen, adc0en, mux3, mux2, mux1, mux0] + // refs=0b10 : internal 1.1V ref + // mux=0b1110 : internal temperature sensor + //#define ADMUX_THERM 0b10001110 ADMUX = ADMUX_THERM; + // other stuff is already set, so no need to re-set it } inline void mcu_set_admux_voltage() { + // put the ADC in battery voltage measurement mode + // TODO: avr datasheet references #ifdef USE_VOLTAGE_DIVIDER // 1.1V / pin7 ADMUX = ADMUX_VOLTAGE_DIVIDER; + // disable digital input on divider pin to reduce power consumption + // TODO: this should be in hwdef init, not here + VOLTAGE_ADC_DIDR |= (1 << VOLTAGE_ADC); #else // VCC / 1.1V reference ADMUX = ADMUX_VCC; + // disable digital input on VCC pin to reduce power consumption + //VOLTAGE_ADC_DIDR |= (1 << VOLTAGE_ADC); // FIXME: unsure how to handle for VCC pin #endif + //ACSRA |= (1 << ACD); // turn off analog comparator to save power + // ADCSRB: [VDEN, VDPD, -, -, ADLAR, ADTS2, ADTS1, ADTS0] + ADCSRB = (1 << ADLAR); // left-adjust, free-running + //ADCSRB = 0; // right-adjust, free-running } inline void mcu_adc_sleep_mode() { @@ -42,31 +72,82 @@ inline void mcu_adc_sleep_mode() { } inline void mcu_adc_start_measurement() { - ADCSRA |= (1 << ADSC) | (1 << ADIE); -} - -inline void mcu_adc_on() { - hwdef_set_admux_voltage(); - #ifdef USE_VOLTAGE_DIVIDER - // disable digital input on divider pin to reduce power consumption - VOLTAGE_ADC_DIDR |= (1 << VOLTAGE_ADC); - #else - // disable digital input on VCC pin to reduce power consumption - //VOLTAGE_ADC_DIDR |= (1 << VOLTAGE_ADC); // FIXME: unsure how to handle for VCC pin - #endif - //ACSRA |= (1 << ACD); // turn off analog comparator to save power - ADCSRB |= (1 << ADLAR); // left-adjust flag is here instead of ADMUX - // enable, start, auto-retrigger, prescale - ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | ADC_PRSCL; + // [ADEN, ADSC, ADATE, adif, ADIE, ADPS2, ADPS1, ADPS0] + ADCSRA = (1 << ADEN) // enable + | (1 << ADSC) // start + | (1 << ADATE) // auto-retrigger + | (1 << ADIE) // interrupt enable + | ADC_PRSCL; // prescale } inline void mcu_adc_off() { ADCSRA &= ~(1<> 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.1 * 4096) / (measurement >> 4); + #endif + return vbat40; +} -inline uint8_t mcu_adc_lsb() { return (ADCL >> 6) + (ADCH << 2); } + +#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 left-aligned) + // Out: Kelvin << 6 + // Precision: 1/64th Kelvin (but noisy) + // attiny1634 datasheet section 19.12 + // nothing to do; input value is already "cooked" + return measurement; +} + +inline uint8_t mcu_adc_lsb() { + // left-adjusted mode: + return (ADCL >> 6) + (ADCH << 2); + // right-adjusted mode: + // datasheet 19.13.3.2: + // "When ADCL is read, the ADC Data Register is not updated + // until ADCH is read. ... ADCL must be read first, then ADCH." + // So... gotta read it even if not needed? + // (the value doesn't matter here, the lower bits are only used + // for generating some random seed data) + //return ADCL + ADCH; +} ////////// WDT ////////// @@ -85,6 +166,7 @@ inline void mcu_wdt_stop() { cli(); // needed because CCP, below wdt_reset(); // Reset the WDT MCUSR &= ~(1<> 6) + (ADCH << 2); } +inline uint8_t mcu_vdd_raw2cooked(uint16_t measurement) { + // In : 65535 * 1.1 / Vbat + // Out: uint8_t: Vbat * 40 + // 1.1 = ADC Vref + // 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.1 * 1024) / (measurement >> 6); + return vbat40; +} + + +#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 left-aligned) + // Out: Kelvin << 6 + // Precision: 1/64th Kelvin (but noisy) + // attiny1634 datasheet section 19.12 + // nothing to do; input value is already "cooked" + return measurement; +} + +inline uint8_t mcu_adc_lsb() { + // left-adjusted mode: + return (ADCL >> 6) + (ADCH << 2); +} ////////// WDT ////////// diff --git a/arch/attiny85.h b/arch/attiny85.h index 2753fd7..3f6ffcb 100644 --- a/arch/attiny85.h +++ b/arch/attiny85.h @@ -21,8 +21,6 @@ ////////// default hw_setup() ////////// -// FIXME: fsm/main should call hwdef_setup(), not hw_setup, -// and this function should be hwdef_setup #ifdef USE_GENERIC_HWDEF_SETUP static inline void hwdef_setup(); #endif @@ -48,8 +46,6 @@ inline void mcu_adc_sleep_mode(); inline void mcu_adc_start_measurement(); -inline void mcu_adc_on(); - inline void mcu_adc_off(); // NOP because interrupt flag clears itself @@ -57,6 +53,15 @@ inline void mcu_adc_off(); inline uint16_t mcu_adc_result(); +// 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/hw/lumintop/blf-gt/anduril.h b/hw/lumintop/blf-gt/anduril.h index 2fc359e..cc2f940 100644 --- a/hw/lumintop/blf-gt/anduril.h +++ b/hw/lumintop/blf-gt/anduril.h @@ -54,7 +54,14 @@ #undef BLINK_AT_RAMP_MIDDLE #undef BLINK_AT_RAMP_FLOOR +#define USE_SMOOTH_STEPS + // too big, turn off extra features //#undef USE_TACTICAL_MODE #undef USE_SOS_MODE +#undef USE_BEACON_MODE +#undef USE_RAMP_AFTER_MOON_CONFIG +//#undef USE_RAMP_SPEED_CONFIG +//#undef USE_VOLTAGE_CORRECTION +#undef USE_2C_STYLE_CONFIG diff --git a/hw/lumintop/blf-gt/hwdef.h b/hw/lumintop/blf-gt/hwdef.h index dbaf18e..68197ac 100644 --- a/hw/lumintop/blf-gt/hwdef.h +++ b/hw/lumintop/blf-gt/hwdef.h @@ -67,14 +67,18 @@ enum CHANNEL_MODES { //#define ADMUX_VOLTAGE_DIVIDER ((1 << V_REF) | (1 << ADLAR) | VOLTAGE_CHANNEL) // 1.1V reference, no left-adjust, ADC1/PB2 #define ADMUX_VOLTAGE_DIVIDER ((1 << V_REF) | VOLTAGE_CHANNEL) + +#undef voltage_raw2cooked +#define voltage_raw2cooked mcu_vdivider_raw2cooked + #define ADC_PRSCL 0x07 // clk/128 // Raw ADC readings at 4.4V and 2.2V (in-between, we assume values form a straight line) #ifndef ADC_44 -#define ADC_44 (184*4) +#define ADC_44 (184*4*4) #endif #ifndef ADC_22 -#define ADC_22 (92*4) +#define ADC_22 (92*4*4) #endif #define FAST 0xA3 // fast PWM both channels diff --git a/hw/mateminco/mf01s/hwdef.h b/hw/mateminco/mf01s/hwdef.h index fef5050..21ea1fd 100644 --- a/hw/mateminco/mf01s/hwdef.h +++ b/hw/mateminco/mf01s/hwdef.h @@ -67,14 +67,18 @@ enum CHANNEL_MODES { // 1.1V reference, no left-adjust, ADC1/PB2 #define ADMUX_VOLTAGE_DIVIDER ((1 << V_REF) | VOLTAGE_CHANNEL) #endif + +#undef voltage_raw2cooked +#define voltage_raw2cooked mcu_vdivider_raw2cooked + #define ADC_PRSCL 0x07 // clk/128 // Raw ADC readings at 4.4V and 2.2V (in-between, we assume values form a straight line) #ifndef ADC_44 -#define ADC_44 (234*4) +#define ADC_44 (234*4*4) #endif #ifndef ADC_22 -#define ADC_22 (117*4) +#define ADC_22 (117*4*4) #endif #define FAST 0xA3 // fast PWM both channels -- cgit v1.2.3 From c86ab86da7763e4d88c2c6865f916873af02742d Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 27 Nov 2023 09:00:32 -0700 Subject: fixed ADC on sp10-pro --- hw/sofirn/sp10-pro/hwdef.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/sofirn/sp10-pro/hwdef.h b/hw/sofirn/sp10-pro/hwdef.h index 047758b..f220318 100644 --- a/hw/sofirn/sp10-pro/hwdef.h +++ b/hw/sofirn/sp10-pro/hwdef.h @@ -66,16 +66,19 @@ enum CHANNEL_MODES { #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 +#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) // Resistors are 300,000 and 100,000 #ifndef ADC_44 -#define ADC_44 1023 // raw value at 4.40V +#define ADC_44 (4*1023) // raw value at 4.40V #endif #ifndef ADC_22 -#define ADC_22 512 // raw value at 2.20V +#define ADC_22 (4*512) // raw value at 2.20V #endif -- cgit v1.2.3 From 62e9337211eea3583daa24e84ce9fda5db5a35e7 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 27 Nov 2023 14:45:00 -0700 Subject: fw3x: fixed swapped red+blue, fixed battery measurements, added police color strobe --- hw/lumintop/fw3x-lume1/anduril.h | 27 ++++++++++++++++++++------- hw/lumintop/fw3x-lume1/hwdef.h | 15 +++++++++------ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/hw/lumintop/fw3x-lume1/anduril.h b/hw/lumintop/fw3x-lume1/anduril.h index b208fbc..5cde5e9 100644 --- a/hw/lumintop/fw3x-lume1/anduril.h +++ b/hw/lumintop/fw3x-lume1/anduril.h @@ -11,7 +11,7 @@ * - 85: https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-2586-AVR-8-bit-Microcontroller-ATtiny25-ATtiny45-ATtiny85_Datasheet.pdf */ -#include "lumintop/fw3x-lume1/hwdef.h" +#define HWDEF_H lumintop/fw3x-lume1/hwdef.h // set this light for 50C thermal ceiling #undef DEFAULT_THERM_CEIL @@ -46,11 +46,6 @@ #undef USE_DYNAMIC_UNDERCLOCKING #endif -// the entire ramp is regulated except turbo; don't blink halfway up -#ifdef BLINK_AT_RAMP_MIDDLE -#undef BLINK_AT_RAMP_MIDDLE -#endif - #define RAMP_SMOOTH_FLOOR 1 #define RAMP_SMOOTH_CEIL 149 // turn on BuckBoost from level 1 to 149, but not 150 @@ -59,21 +54,39 @@ #define LED_ENABLE_PIN_LEVEL_MAX 149 // 10 33 56 79 102 125 [149] #define RAMP_DISCRETE_FLOOR 10 -#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL #define RAMP_DISCRETE_STEPS 7 #define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR #define SIMPLE_UI_CEIL 120 #define SIMPLE_UI_STEPS 5 +// show each channel while it scroll by in the menu +#define USE_CONFIG_COLORS + +// blink numbers on the main LEDs by default (but allow user to change it) +#define DEFAULT_BLINK_CHANNEL CM_MAIN + // slow down party strobe; this driver can't pulse for too short a time #define PARTY_STROBE_ONTIME 4 +// use aux red + aux blue for police strobe +#define USE_POLICE_COLOR_STROBE_MODE +#define POLICE_STROBE_USES_AUX +#define POLICE_COLOR_STROBE_CH1 CM_AUXRED +#define POLICE_COLOR_STROBE_CH2 CM_AUXBLU + // stop panicking at ~85% regulated power or ~750 lm #define THERM_FASTER_LEVEL 140 #define THERM_CAL_OFFSET 0 // not needed due to external sensor +// don't blink while ramping +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif + + // can't reset the normal way because power is connected before the button #define USE_SOFT_FACTORY_RESET diff --git a/hw/lumintop/fw3x-lume1/hwdef.h b/hw/lumintop/fw3x-lume1/hwdef.h index ca412cc..e50d8b1 100644 --- a/hw/lumintop/fw3x-lume1/hwdef.h +++ b/hw/lumintop/fw3x-lume1/hwdef.h @@ -8,9 +8,9 @@ * * Pin / Name / Function in Lume1 Rev B * 1 PA6 Regulated PWM (PWM1B) - * 2 PA5 R: red aux LED (PWM0B) + * 2 PA5 B: blue aux LED (PWM0B) * 3 PA4 G: green aux LED - * 4 PA3 B: blue aux LED + * 4 PA3 R: red aux LED * 5 PA2 e-switch (PCINT2) * 6 PA1 Jumper 1 * 7 PA0 Jumper 2 @@ -111,16 +111,19 @@ enum CHANNEL_MODES { #define ADMUX_VOLTAGE_DIVIDER 0b00000101 #define ADC_PRSCL 0x06 // clk/64 +#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: // [(Vbatt)*(R2/(R2+R1)) / 2.5V] * 1023 // R1 = R2 = 100kR #ifndef ADC_44 -#define ADC_44 900 +#define ADC_44 (4*900) #endif #ifndef ADC_22 -#define ADC_22 450 +#define ADC_22 (4*450) #endif // Default ADMUX_THERM for Temperature is: 0b10001110 in arch/mcu.h @@ -139,9 +142,9 @@ enum CHANNEL_MODES { #define EXTERN_TEMP_FORMULA(m) (((m)-205)/4.09) // this driver allows for aux LEDs under the optic -#define AUXLED_R_PIN PA5 // pin 2 +#define AUXLED_R_PIN PA3 // pin 2 #define AUXLED_G_PIN PA4 // pin 3 -#define AUXLED_B_PIN PA3 // pin 4 +#define AUXLED_B_PIN PA5 // pin 4 #define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC #define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC #define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC -- cgit v1.2.3 From 6cb18249d33f57acaf8e78734f4d155ebfd72165 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 27 Nov 2023 16:08:11 -0700 Subject: FW3X: multiple upgrades... - upgraded to DSM: lower lows, *much* smoother ramp - made lows more efficient with underclocking - fixed party strobe being too blurry - calibrated UI speed / bogomips multiplier - added readme to document this hardware's multiple quirks --- hw/lumintop/fw3x-lume1/README.md | 26 +++++++++++++++ hw/lumintop/fw3x-lume1/anduril.h | 32 ++++++------------- hw/lumintop/fw3x-lume1/hwdef.c | 68 ++++++++++++++++++++++++++++++++++------ hw/lumintop/fw3x-lume1/hwdef.h | 60 ++++++++++++++++++++++------------- 4 files changed, 132 insertions(+), 54 deletions(-) create mode 100644 hw/lumintop/fw3x-lume1/README.md diff --git a/hw/lumintop/fw3x-lume1/README.md b/hw/lumintop/fw3x-lume1/README.md new file mode 100644 index 0000000..8609c49 --- /dev/null +++ b/hw/lumintop/fw3x-lume1/README.md @@ -0,0 +1,26 @@ +# Lumintop FW3X Lume1 + +A BLF FW3A with a new driver from LoneOceans. The new driver adds efficient +constant-current power regulation, RGB aux LEDs, and an upgraded temperature +sensor. + +## Notes of interest + +**Flashing firmware**: The MOSI and MISO pin are swapped, compared to a Hanklight. +LoneOceans sent a fixed driver design to Lumintop, but the new design didn't +get produced. So to flash firmware, swap the wires for those two pins first. + +**RGB mixup**: Lumintop seems to have swapped the wires for aux R and aux B. +This was fixed in firmware in 2023-12, but some lights were fixed in hardware +before that, so the firmware fix might cause the colors to be swapped again. + +**Turbo**: The driver uses regulation for levels 1 to 149, and level 150 is a +direct-drive FET. This is by design, and the FET cannot be ramped smoothly up +and down. Turbo is a single level at the top of the ramp, with a big sudden +drop to the next level. + +**Moon**: This light has a pretty bright preflash at moon level, and the +output is unstable so there is very visible ripple. The user can either raise +the ramp floor to a level high enough to avoid these issues, or learn to live +with the ripple and preflash. + diff --git a/hw/lumintop/fw3x-lume1/anduril.h b/hw/lumintop/fw3x-lume1/anduril.h index 5cde5e9..b7dbc82 100644 --- a/hw/lumintop/fw3x-lume1/anduril.h +++ b/hw/lumintop/fw3x-lume1/anduril.h @@ -8,7 +8,6 @@ * For more information: www.loneoceans.com/labs/ * Datasheets: * - 1634: http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-8303-8-bit-AVR-Microcontroller-tinyAVR-ATtiny1634_Datasheet.pdf - * - 85: https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-2586-AVR-8-bit-Microcontroller-ATtiny25-ATtiny45-ATtiny85_Datasheet.pdf */ #define HWDEF_H lumintop/fw3x-lume1/hwdef.h @@ -20,38 +19,25 @@ // this light has three aux LED channels: R, G, B #define USE_AUX_RGB_LEDS -// it has no independent LED in the button unlike emisar d4 -//#define USE_BUTTON_LED - // the aux LEDs are front-facing, so turn them off while main LEDs are on #ifdef USE_INDICATOR_LED_WHILE_RAMPING #undef USE_INDICATOR_LED_WHILE_RAMPING #endif -// ../../bin/level_calc.py cube 1 149 7135 0 0.5 1000, with 0 appended to the end. -// for FET PWM (PWM2), all values are 0, except for last value of 1023 -// (with max_pwm set to 1023) #define RAMP_SIZE 150 -//#define PWM1_LEVELS 0,0,0,0,1,1,1,1,2,2,2,3,3,4,4,5,5,6,7,7,8,9,10,11,12,13,14,15,16,17,19,20,22,23,25,26,28,30,32,34,36,38,40,42,45,47,49,52,55,58,60,63,66,70,73,76,80,83,87,91,94,98,102,107,111,115,120,124,129,134,139,144,150,155,160,166,172,178,184,190,196,203,209,216,223,230,237,244,252,259,267,275,283,291,299,308,316,325,334,343,353,362,372,382,392,402,412,423,433,444,455,466,478,489,501,513,525,538,550,563,576,589,602,616,630,644,658,672,687,701,716,731,747,762,778,794,810,827,844,861,878,895,913,930,948,967,985,1004,1023,0 -#define PWM1_LEVELS 1,1,1,1,2,2,2,2,3,3,3,4,4,5,5,6,6,7,8,8,9,10,11,12,13,14,15,16,17,18,20,21,23,24,26,27,29,31,33,35,37,39,41,43,45,48,50,53,56,58,61,64,67,70,74,77,80,84,88,91,95,99,103,108,112,116,121,125,130,135,140,145,150,156,161,167,173,178,184,191,197,203,210,217,223,230,238,245,252,260,268,275,283,292,300,308,317,326,335,344,353,363,372,382,392,402,413,423,434,445,456,467,478,490,502,514,526,538,551,563,576,589,603,616,630,644,658,672,687,702,717,732,747,763,778,794,811,827,844,861,878,895,913,931,949,967,985,1004,1023,0 -#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1023 + +// level_calc.py 5.01 1 149 7135 0 0.2 2000 --pwm 32640 +// regulated channel: 16-bit PWM+DSM for low lows and very smooth ramp +#define PWM1_LEVELS 0,1,2,3,4,5,6,7,9,10,12,14,17,19,22,25,29,33,37,41,46,51,57,63,70,77,85,93,103,112,123,134,146,159,172,187,203,219,237,256,276,297,319,343,368,394,422,452,483,516,551,587,625,666,708,753,799,848,900,954,1010,1069,1131,1195,1263,1333,1407,1483,1563,1647,1734,1825,1919,2017,2119,2226,2336,2451,2571,2694,2823,2957,3095,3239,3388,3542,3702,3868,4040,4217,4401,4591,4788,4992,5202,5419,5644,5876,6115,6362,6617,6880,7152,7432,7721,8018,8325,8641,8967,9302,9647,10003,10369,10745,11133,11531,11941,12363,12796,13241,13699,14169,14652,15148,15657,16180,16717,17268,17834,18414,19009,19620,20246,20888,21546,22221,22913,23621,24348,25091,25853,26634,27433,28251,29089,29946,30823,31721,32640,0 +// DD FET: 8-bit PWM (but hardware can only handle 0 and MAX) +#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255 #define DEFAULT_LEVEL 56 #define MAX_1x7135 149 -// TODO: test if underclocking works on lume1 -//#define HALFSPEED_LEVEL 14 -//#define QUARTERSPEED_LEVEL 5 -// don't slow down at low levels; this isn't that sort of light -// (it needs to stay at full speed for the 10-bit PWM to work) -#ifdef USE_DYNAMIC_UNDERCLOCKING -#undef USE_DYNAMIC_UNDERCLOCKING -#endif +#define HALFSPEED_LEVEL 21 +#define QUARTERSPEED_LEVEL 11 #define RAMP_SMOOTH_FLOOR 1 #define RAMP_SMOOTH_CEIL 149 -// turn on BuckBoost from level 1 to 149, but not 150 -// Level 150 is when BuckBoost is off and FET is ON 100% -#define LED_ENABLE_PIN_LEVEL_MIN 1 -#define LED_ENABLE_PIN_LEVEL_MAX 149 // 10 33 56 79 102 125 [149] #define RAMP_DISCRETE_FLOOR 10 #define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL @@ -68,7 +54,7 @@ #define DEFAULT_BLINK_CHANNEL CM_MAIN // slow down party strobe; this driver can't pulse for too short a time -#define PARTY_STROBE_ONTIME 4 +#define PARTY_STROBE_ONTIME 1 // use aux red + aux blue for police strobe #define USE_POLICE_COLOR_STROBE_MODE diff --git a/hw/lumintop/fw3x-lume1/hwdef.c b/hw/lumintop/fw3x-lume1/hwdef.c index 71cd799..0a8a62e 100644 --- a/hw/lumintop/fw3x-lume1/hwdef.c +++ b/hw/lumintop/fw3x-lume1/hwdef.c @@ -1,10 +1,11 @@ -// FW3X Lume1 PWM helper functions +// FW3X Lume1 helper functions // Copyright (C) 2023 Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "fsm/chan-rgbaux.c" + void set_level_zero(); void set_level_main(uint8_t level); @@ -21,6 +22,12 @@ Channel channels[] = { void set_level_zero() { + // disable timer overflow interrupt + // (helps improve button press handling from Off state) + DSM_INTCTRL &= ~DSM_OVF_bm; + + // turn off all LEDs + ch1_dsm_lvl = 0; CH1_PWM = 0; CH2_PWM = 0; PWM_CNT = 0; // reset phase @@ -29,19 +36,49 @@ void set_level_zero() { // single set of LEDs with 2 stacked power channels, regulated + DD FET void set_level_main(uint8_t level) { - CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN); // enable regulator + if (level == actual_level - 1) return; // prevent flicker on no-op - PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); - PWM_DATATYPE ch2_pwm = PWM_GET(pwm2_levels, level); + PWM1_DATATYPE ch1 = PWM1_GET(level); + PWM2_DATATYPE ch2 = PWM2_GET(level); - CH1_PWM = ch1_pwm; - CH2_PWM = ch2_pwm; + // set delta-sigma soft levels + ch1_dsm_lvl = ch1; + + // set hardware PWM levels and init dsm loop + CH1_PWM = ch1_pwm = ch1 >> 7; + CH2_PWM = ch2; + + // enable timer overflow interrupt so DSM can work + DSM_INTCTRL |= DSM_OVF_bm; // force reset phase when turning on from zero // (for faster, more consistent initial response) if (! actual_level) PWM_CNT = 0; + + // don't enable ch1 and ch2 at the same time + if (ch2) CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable regulator + else CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN); // enable regulator +} + +// delta-sigma modulation of PWM outputs +// happens on each Timer overflow (every 512 cpu clock cycles) +// uses 8-bit pwm w/ 7-bit dsm (0b 0PPP PPPP PDDD DDDD) +ISR(DSM_vect) { + // set new hardware values first, + // for best timing (reduce effect of interrupt jitter) + CH1_PWM = ch1_pwm; + + // calculate next values, now that timing matters less + + // accumulate error + ch1_dsm += (ch1_dsm_lvl & 0x007f); + // next PWM = base PWM value + carry bit + ch1_pwm = (ch1_dsm_lvl >> 7) + (ch1_dsm > 0x7f); + // clear carry bit + ch1_dsm &= 0x7f; } + bool gradual_tick_main(uint8_t gt) { // 150/150 is full FET + zero regulated, // 149/150 is zero FET + full regulated, @@ -51,10 +88,23 @@ bool gradual_tick_main(uint8_t gt) { return true; } - PWM_DATATYPE pwm1 = PWM_GET(pwm1_levels, gt); - GRADUAL_ADJUST_SIMPLE(pwm1, CH1_PWM); + PWM1_DATATYPE ch1 = PWM1_GET(gt); - if (pwm1 == CH1_PWM) return true; // done + // adjust multiple times based on current brightness + // (so it adjusts faster/coarser when bright, slower/finer when dim) + + // higher shift = slower/finer adjustments + const uint8_t shift = 9; // ((255 << 7) >> 9) = 63 max + uint8_t steps; + + steps = ch1_dsm_lvl >> shift; + for (uint8_t i=0; i<=steps; i++) + GRADUAL_ADJUST_SIMPLE(ch1, ch1_dsm_lvl); + + if ((ch1 == ch1_dsm_lvl) + ) { + return true; // done + } return false; // not done yet } diff --git a/hw/lumintop/fw3x-lume1/hwdef.h b/hw/lumintop/fw3x-lume1/hwdef.h index e50d8b1..bee98db 100644 --- a/hw/lumintop/fw3x-lume1/hwdef.h +++ b/hw/lumintop/fw3x-lume1/hwdef.h @@ -8,9 +8,9 @@ * * Pin / Name / Function in Lume1 Rev B * 1 PA6 Regulated PWM (PWM1B) - * 2 PA5 B: blue aux LED (PWM0B) + * 2 PA5 B: blue aux LED (PWM0B) (or red) * 3 PA4 G: green aux LED - * 4 PA3 R: red aux LED + * 4 PA3 R: red aux LED (or blue) * 5 PA2 e-switch (PCINT2) * 6 PA1 Jumper 1 * 7 PA0 Jumper 2 @@ -54,29 +54,38 @@ enum CHANNEL_MODES { #define CHANNEL_MODES_ENABLED 0b0000000000000001 -#define PWM_CHANNELS 2 // old, remove this - -// Added for Lume1 Buck Boost Driver -#define PWM_BITS 16 // 0 to 1023 at 3.9 kHz, not 0 to 255 at 15.6 kHz -#define PWM_GET PWM_GET16 +#define PWM_BITS 16 // 0 to 32640 (0 to 255 PWM + 0 to 127 DSM) at constant kHz #define PWM_DATATYPE uint16_t #define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 #define PWM1_DATATYPE uint16_t // regulated ramp -#define PWM2_DATATYPE uint16_t // DD FET ramp +#define PWM1_GET(x) PWM_GET16(pwm1_levels, x) +#define PWM2_DATATYPE uint8_t // DD FET ramp +#define PWM2_GET(x) PWM_GET8(pwm2_levels, x) // PWM parameters of both channels are tied together because they share a counter #define PWM_TOP ICR1 // holds the TOP value for variable-resolution PWM -#define PWM_TOP_INIT 1023 -#define PWM_CNT TCNT1 // for dynamic PWM, reset phase +#define PWM_TOP_INIT 255 +#define PWM_CNT TCNT1 // for checking / resetting phase +// (max is (255 << 7), because it's 8-bit PWM plus 7 bits of DSM) +#define DSM_TOP (255<<7) // 15-bit resolution leaves 1 bit for carry + +// timer interrupt for DSM +#define DSM_vect TIMER1_OVF_vect +#define DSM_INTCTRL TIMSK +#define DSM_OVF_bm (1<> 1; - */ - - #if 0 - // values stair-step between intervals of 64, with random variations - // of 1 or 2 in either direction, so if we chop off the last 6 bits - // it'll flap between N and N-1... but if we add half an interval, - // the values should be really stable after right-alignment - // (instead of 99.98, 100.00, and 100.02, it'll hit values like - // 100.48, 100.50, and 100.52... which are stable when truncated) - //measurement += 32; - //measurement = (measurement + 16) >> 5; - measurement = (measurement + 16) & 0xffe0; // 1111 1111 1110 0000 - - #ifdef USE_VOLTAGE_DIVIDER - voltage = calc_voltage_divider(measurement); - #else - // calculate actual voltage: volts * 10 - // ADC = 1.1 * 1024 / volts - // volts = 1.1 * 1024 / ADC - voltage = ((uint16_t)(2*1.1*1024*10)/(measurement>>6) - + VOLTAGE_FUDGE_FACTOR - #ifdef USE_VOLTAGE_CORRECTION - + VOLT_CORR - 7 - #endif - ) >> 1; - #endif - #endif - // if low, callback EV_voltage_low / EV_voltage_critical // (but only if it has been more than N seconds since last call) if (lvp_timer) { @@ -316,10 +280,17 @@ static inline void ADC_temperature_handler() { // 0 .. 65535 = 0 K .. 1024 K uint16_t measurement = temp_raw2cooked(adc_smooth[1]); + // let the UI see the current temperature in C // (Kelvin << 6) to Celsius + // Why 275? Because Atmel's docs use 275 instead of 273. temperature = (measurement>>6) + THERM_CAL_OFFSET + (int16_t)TH_CAL - 275; - #if 0 + // instead of (K << 6), use (K << 1) now + // TODO: use more precision, if it can be done without overflow in 16 bits + // (and still work on attiny85 without increasing ROM size) + #if 1 + measurement = measurement >> 5; + #else // TODO: is this still needed? // values stair-step between intervals of 64, with random variations // of 1 or 2 in either direction, so if we chop off the last 6 bits // it'll flap between N and N-1... but if we add half an interval, @@ -329,24 +300,7 @@ static inline void ADC_temperature_handler() { //measurement += 32; measurement = (measurement + 16) >> 5; //measurement = (measurement + 16) & 0xffe0; // 1111 1111 1110 0000 - - // let the UI see the current temperature in C - // Convert ADC units to Celsius (ish) - // FIXME: call something in arch/$mcu.h or hwdef.h - // instead of calculating this here - #ifndef USE_EXTERNAL_TEMP_SENSOR - // onboard sensor for attiny25/45/85/1634 - temperature = (measurement>>1) + THERM_CAL_OFFSET + (int16_t)TH_CAL - 275; - #else - // external sensor - temperature = EXTERN_TEMP_FORMULA(measurement>>1) + THERM_CAL_OFFSET + (int16_t)TH_CAL; #endif - #endif - - // instead of (K << 6), use (K << 1) now - // TODO: use more precision, if it can be done without overflow in 16 bits - // (and still work on attiny85 without increasing ROM size) - measurement = measurement >> 5; // how much has the temperature changed between now and a few seconds ago? int16_t diff; @@ -440,17 +394,38 @@ static inline void ADC_temperature_handler() { #ifdef USE_BATTCHECK #ifdef BATTCHECK_4bars PROGMEM const uint8_t voltage_blinks[] = { - 4*30, 4*35, 4*38, 4*40, 4*42, 255, + 4*30, + 4*35, + 4*38, + 4*40, + 4*42, + 255, }; #endif #ifdef BATTCHECK_6bars PROGMEM const uint8_t voltage_blinks[] = { - 4*30, 4*34, 4*36, 4*38, 4*40, 4*41, 4*43, 255, + 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[] = { - 4*30, 4*33, 4*35, 4*37, 4*38, 4*39, 4*40, 4*41, 4*42, 255, + 4*30, + 4*33, + 4*35, + 4*37, + 4*38, + 4*39, + 4*40, + 4*41, + 4*42, + 255, }; #endif void battcheck() { -- cgit v1.2.3 From 56370218c5ca1b542a967e72b134f43a82f69ddc Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 28 Nov 2023 12:36:39 -0700 Subject: fixed incorrect temperature history for a few seconds after waking (it used raw ADC units instead of cooked Kelvin units ... ... which was only noticeable on hardware which has different ADC units) --- fsm/adc.c | 20 +++++++++----------- fsm/adc.h | 4 ++-- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/fsm/adc.c b/fsm/adc.c index 93f9a1a..fbe84a1 100644 --- a/fsm/adc.c +++ b/fsm/adc.c @@ -166,7 +166,7 @@ void adc_deferred() { #ifdef USE_LVP -static inline void ADC_voltage_handler() { +static void ADC_voltage_handler() { // rate-limit low-voltage warnings to a max of 1 per N seconds static uint8_t lvp_timer = 0; #define LVP_TIMER_START (VOLTAGE_WARNING_SECONDS*ADC_CYCLES_PER_SECOND) // N seconds between LVP warnings @@ -240,7 +240,7 @@ static inline void ADC_voltage_handler() { #ifdef USE_THERMAL_REGULATION // generally happens once per second while awake -static inline void ADC_temperature_handler() { +static void ADC_temperature_handler() { // coarse adjustment #ifndef THERM_LOOKAHEAD #define THERM_LOOKAHEAD 4 @@ -265,15 +265,7 @@ static inline void ADC_temperature_handler() { static uint16_t temperature_history[NUM_TEMP_HISTORY_STEPS]; static int8_t warning_threshold = 0; - if (adc_reset) { // wipe out old data - // ignore average, use latest sample - uint16_t foo = adc_raw[1]; - adc_smooth[1] = foo; - - // forget any past measurements - for(uint8_t i=0; i> 5; - } + if (adc_reset) adc_smooth[1] = adc_raw[1]; // latest 16-bit ADC reading // convert raw ADC value to Kelvin << 6 @@ -302,6 +294,12 @@ static inline void ADC_temperature_handler() { //measurement = (measurement + 16) & 0xffe0; // 1111 1111 1110 0000 #endif + if (adc_reset) { // wipe out old data after waking up + // forget any past measurements + for(uint8_t i=0; i= RAMP_SIZE-1)) { - set_level(gt + 1); - return true; - } + // if target is in the top 2 levels, just let the parent handle it + if (gt >= RAMP_SIZE-2) return true; PWM1_DATATYPE ch1 = PWM1_GET(gt); @@ -110,6 +108,8 @@ bool gradual_tick_main(uint8_t gt) { ////////// external temperature sensor ////////// +#ifdef ADMUX_THERM_EXTERNAL_SENSOR + void hwdef_set_admux_therm() { // put the ADC in temperature mode // ADCSRB: [VDEN, VDPD, -, -, ADLAR, ADTS2, ADTS1, ADTS0] @@ -140,3 +140,5 @@ uint16_t temp_raw2cooked(uint16_t measurement) { return k6; } +#endif + -- cgit v1.2.3 From 4373ed25154fb77f44d3b0ba6d3f5cc78127cc45 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 28 Nov 2023 13:12:05 -0700 Subject: prevent future issues like the FW3X had 1/3rd of the ramp size is probably a more reliable default than MAX_1x7135. The 7135-based reference points need to eventually be removed entirely and replaced by something more universal, but for now at least don't fail when a thermal stepdown isn't defined. --- ui/anduril/ramp-mode.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ui/anduril/ramp-mode.h b/ui/anduril/ramp-mode.h index 59c8db0..1392981 100644 --- a/ui/anduril/ramp-mode.h +++ b/ui/anduril/ramp-mode.h @@ -4,14 +4,15 @@ #pragma once -#ifndef RAMP_LENGTH -#define RAMP_LENGTH 150 // default, if not overridden in a driver cfg file +#ifndef RAMP_SIZE +#define RAMP_SIZE 150 // default, if not overridden in a driver cfg file #endif +// TODO: Replace MAX_Xx7135 with MAX_CH1, MAX_CH2, MAX_REGULATED, etc + // thermal properties, if not defined per-driver #ifndef MIN_THERM_STEPDOWN -// TODO: Replace MAX_Xx7135 with MAX_CH1, MAX_CH2, MAX_REGULATED, etc -#define MIN_THERM_STEPDOWN MAX_1x7135 // lowest value it'll step down to +#define MIN_THERM_STEPDOWN (RAMP_SIZE/3) // lowest value it'll step down to #endif #ifndef THERM_FASTER_LEVEL #ifdef MAX_Nx7135 -- cgit v1.2.3 From 1153a7c8b4130abb62654476bc958399d687cbf2 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 30 Nov 2023 08:44:31 -0700 Subject: added a build target for FW3X with manually-fixed RGB aux wiring --- hw/lumintop/fw3x-lume1/hwdef.h | 12 +++++++++--- hw/lumintop/fw3x-lume1/rgbswap/anduril.h | 11 +++++++++++ hw/lumintop/fw3x-lume1/rgbswap/model | 1 + 3 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 hw/lumintop/fw3x-lume1/rgbswap/anduril.h create mode 100644 hw/lumintop/fw3x-lume1/rgbswap/model diff --git a/hw/lumintop/fw3x-lume1/hwdef.h b/hw/lumintop/fw3x-lume1/hwdef.h index 92a177f..021c4cf 100644 --- a/hw/lumintop/fw3x-lume1/hwdef.h +++ b/hw/lumintop/fw3x-lume1/hwdef.h @@ -153,9 +153,15 @@ uint16_t temp_raw2cooked(uint16_t measurement); #define ADMUX_THERM_EXTERNAL_SENSOR 0b00001011 // this driver allows for aux LEDs under the optic -#define AUXLED_R_PIN PA3 // pin 2 -#define AUXLED_G_PIN PA4 // pin 3 -#define AUXLED_B_PIN PA5 // pin 4 +#ifdef FW3X_RGB_SWAP // wiring fixed by end user + #define AUXLED_R_PIN PA5 // pin 2 + #define AUXLED_G_PIN PA4 // pin 3 + #define AUXLED_B_PIN PA3 // pin 4 +#else // Lumintop's factory wiring + #define AUXLED_R_PIN PA3 // pin 4 + #define AUXLED_G_PIN PA4 // pin 3 + #define AUXLED_B_PIN PA5 // pin 2 +#endif #define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC #define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC #define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC diff --git a/hw/lumintop/fw3x-lume1/rgbswap/anduril.h b/hw/lumintop/fw3x-lume1/rgbswap/anduril.h new file mode 100644 index 0000000..2fba7ff --- /dev/null +++ b/hw/lumintop/fw3x-lume1/rgbswap/anduril.h @@ -0,0 +1,11 @@ +// FW3X (RGB aux swapped) config options for Anduril +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +// Lumintop swapped red and blue wires. Some people fixed the wiring. +// Then the firmware fixed the pinouts to match Lumintop's wiring. +// This firmware exists for people who fixed their wiring. +#define FW3X_RGB_SWAP +#include "lumintop/fw3x-lume1/anduril.h" + diff --git a/hw/lumintop/fw3x-lume1/rgbswap/model b/hw/lumintop/fw3x-lume1/rgbswap/model new file mode 100644 index 0000000..44505ce --- /dev/null +++ b/hw/lumintop/fw3x-lume1/rgbswap/model @@ -0,0 +1 @@ +0315 -- cgit v1.2.3 From fdac6fcf22cd658785480c88c28243eeae62bcd0 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 30 Nov 2023 09:16:13 -0700 Subject: made the avr32dd20 flashing script more universal --- bin/flash-avr32dd20.sh | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/bin/flash-avr32dd20.sh b/bin/flash-avr32dd20.sh index ef8b0f3..dcd4967 100755 --- a/bin/flash-avr32dd20.sh +++ b/bin/flash-avr32dd20.sh @@ -1,13 +1,40 @@ #!/usr/bin/env bash +# AVR firmware flashing script, a wrapper for other tools +# Copyright (C) 2023 Selene ToyKeeper +# SPDX-License-Identifier: GPL-3.0-or-later + +# Usage: flash-MCUTYPE.sh hex/foo.hex +# (where the script name specifies the type of MCU chip, +# and the first parameter is the path to a .hex file) +# Example: +# ./bin/flash-avr32dd20.sh hex/anduril.thefreeman-avr32dd20-devkit.hex set -e +# Get the path to a .hex file [[ -z "$1" ]] && echo "No .hex file specified." && exit 1 HEX="$1" -#pymcuprog ping -t uart -u /dev/ttyUSB2 -d avr32dd20 -#pymcuprog erase -t uart -u /dev/ttyUSB2 -d avr32dd20 -#pymcuprog write verify -t uart -u /dev/ttyUSB2 -d avr32dd20 -f "$HEX" -#pymcuprog verify -t uart -u /dev/ttyUSB2 -d avr32dd20 -f "$HEX" +# assume the highest-numbered USB serial device is the correct one, +# since it was probably the most recently plugged in +TTYUSB=$(ls -1 /dev/tty* | grep -i usb | tail -1) + +# figure out the MCU type... +# TODO: find the relevant hw/*/arch file and use that to get MCU type +# use $2 if it exists, and use the name of this script maybe +MCUTYPE="unset" +[[ -n "$2" ]] && MCUTYPE="$2" +#MCUTYPE=$(echo "$0" | sed 's/.*flash-\(.*\).sh.*/\1/') +[[ "$0" =~ flash-(.*).sh ]] && MCUTYPE="${BASH_REMATCH[1]}" + +# Do the actual flashing +echo "Flashing $MCUTYPE MCU on port $TTYUSB: $HEX" +echo pymcuprog write \ + --erase \ + --verify \ + --timing \ + -t uart \ + -u "$TTYUSB" \ + -d "$MCUTYPE" \ + -f "$HEX" -pymcuprog write --erase --verify --timing -t uart -u /dev/ttyUSB2 -d avr32dd20 -f "$HEX" -- cgit v1.2.3 From 3fde090a8e55163288148b37e172b11cdeb3cc50 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 30 Nov 2023 09:17:46 -0700 Subject: eliminated direct CCP register access from arch/attiny1616 (the protected write macro exists for a reason, and should be used instead) --- arch/attiny1616.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/attiny1616.c b/arch/attiny1616.c index 2770d06..c5499dd 100644 --- a/arch/attiny1616.c +++ b/arch/attiny1616.c @@ -210,8 +210,8 @@ inline void mcu_pcint_off() { void reboot() { // put the WDT in hard reset mode, then trigger it cli(); - CCP = CCP_IOREG_gc; // temporarily disable change protection - WDT.CTRLA = WDT_PERIOD_8CLK_gc; // Enable, timeout 8ms + // Enable, timeout 8ms + _PROTECTED_WRITE(WDT.CTRLA, WDT_PERIOD_8CLK_gc); sei(); wdt_reset(); while (1) {} -- cgit v1.2.3