From d80a1d2a2e01143970ffc13b971859a98ce9cb34 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 30 Nov 2023 13:50:35 -0700 Subject: added initial code for emisar-d3aa torch --- hw/hank/emisar-d3aa/anduril.h | 118 +++++++++++++++++++++++ hw/hank/emisar-d3aa/arch | 1 + hw/hank/emisar-d3aa/hwdef.c | 118 +++++++++++++++++++++++ hw/hank/emisar-d3aa/hwdef.h | 212 ++++++++++++++++++++++++++++++++++++++++++ hw/hank/emisar-d3aa/model | 1 + 5 files changed, 450 insertions(+) create mode 100644 hw/hank/emisar-d3aa/anduril.h create mode 100644 hw/hank/emisar-d3aa/arch create mode 100644 hw/hank/emisar-d3aa/hwdef.c create mode 100644 hw/hank/emisar-d3aa/hwdef.h create mode 100644 hw/hank/emisar-d3aa/model (limited to 'hw/hank/emisar-d3aa') diff --git a/hw/hank/emisar-d3aa/anduril.h b/hw/hank/emisar-d3aa/anduril.h new file mode 100644 index 0000000..3d65dc5 --- /dev/null +++ b/hw/hank/emisar-d3aa/anduril.h @@ -0,0 +1,118 @@ +// Emisar D3aa config options for Anduril +// Copyright (C) 2023 thefreeman, Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +#define HWDEF_H hank/emisar-d3aa/hwdef.h + +// HPRsense : 4.2+0.3+20 = 24.5mR +// Vsense=42.46mV, R1= 191k +// LPRsense : 2R +// HDR ratio: 131.5 +// transition DAC level 20, ramp level 48 +// fifth power ramp 0.02mA to 2001mA + +#define RAMP_SIZE 150 + +// 4 ramp segments: +// - low 1.024V +// - low 2.5 V +// - high 1.024V +// - high 2.5 V +// HDR ratio: 131.5 +// PWM1: DAC Data +// (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 \ + 3,4,5,7,9,12,15,19,24,29,35,43,51,61,72,84,99,115,133,153,176,202,230,262,297,335,377,424,475,531,592,658,730,809,894,986, \ + 444,488,535,586,641,700,763,830,903,980,1023, \ + 20,22,24,26,28,30,32,35,37,40,43,46,49,52,56,60,63,68,72,77,81,86,92,97,103,109,115,122,129,136,143,151,159,168,177,186,196,206,216,227,239,250,263,275,289,302,316,331,346,362,379,396,413,432,450,470,490,511,532,555,578,602,626,651,678,705,733,761,791,821,853,885,919,953,989, \ + 420,435,451,467,484,501,519,537,556,575,595,615,636,657,679,702,725,749,773,798,824,850,877,905,933,962,992,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,V10,V10,V10,V10,V10,V10, \ + 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, \ + 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 47 +#define HDR_ENABLE_LEVEL_MIN 48 +#define DEFAULT_LEVEL 50 + +// 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 119 // 35% / 0.7A / 700 lm +// 1 22 [44] 65 87 108 130 +#define RAMP_DISCRETE_FLOOR 1 +#define RAMP_DISCRETE_CEIL 119 +#define RAMP_DISCRETE_STEPS 7 + +// 20 [45] 70 95 120 +#define SIMPLE_UI_FLOOR 20 +#define SIMPLE_UI_CEIL 129 // 50% / ~1A / ~860 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 129 // stop panicking at 50%/1A +#define MIN_THERM_STEPDOWN MAX_1x7135 + + +// UI + +#define SIMPLE_UI_ACTIVE 0 // advanced UI by default, because prototype + +// 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/hank/emisar-d3aa/arch b/hw/hank/emisar-d3aa/arch new file mode 100644 index 0000000..bcf4552 --- /dev/null +++ b/hw/hank/emisar-d3aa/arch @@ -0,0 +1 @@ +avr32dd20 diff --git a/hw/hank/emisar-d3aa/hwdef.c b/hw/hank/emisar-d3aa/hwdef.c new file mode 100644 index 0000000..853e84d --- /dev/null +++ b/hw/hank/emisar-d3aa/hwdef.c @@ -0,0 +1,118 @@ +// Emisar D3AA 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 +} + + +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 / 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/hank/emisar-d3aa/hwdef.h b/hw/hank/emisar-d3aa/hwdef.h new file mode 100644 index 0000000..8677609 --- /dev/null +++ b/hw/hank/emisar-d3aa/hwdef.h @@ -0,0 +1,212 @@ +// hwdef for Emisar D3AA +// Copyright (C) 2023 thefreeman, Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * NiMH/li-ion 9V2A boost driver based on MP3432 + * with high dynamic range and DAC control + front aux RGB and button LED + * + * Pin Name Function + * 1 PA4 e-switch + * 2 PA5 BATT LVL (voltage divider) + * 3 PA6 EN: boost enable + * 4 PA7 A : button LED + * 5 PC1 - + * 6 PC2 - + * 7 PC3 - + * 8 VDDIO2 (BATT+ via solder jumper) + * 9 PD4 IN- NFET: absorb startup flash + * 10 PD5 HDR: high/low Rsense range + * 11 PD6 DAC: control voltage out + * 12 PD7 + * 13 VDD VCC + * 14 GND GND + * 15 PF6 RESET + * 16 PF7 UPDI + * 17 PA0 B: aux blue + * 18 PA1 + * 19 PA2 G: aux green + * 20 PA3 R: aux red + * + * 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 + * BATT LVL : Vbat * (100.0/(330+100)) + * VDDIO2 : can be connected to BATT+ with a solder jumper for VDDIO2 voltage sensing + * + */ + +#define HWDEF_C hank/emisar-d3aa/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 + + +#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 +// (DAC_LVL + DAC_VREF + Vref values are defined in arch/*.h) + +// BST enable +#define BST_ENABLE_PIN PIN6_bp +#define BST_ENABLE_PORT PORTA_OUT + +// HDR +// turns on HDR FET for the high current range +#define HDR_ENABLE_PIN PIN5_bp +#define HDR_ENABLE_PORT PORTD_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 PIN4_bp +#define IN_NFET_ENABLE_PORT PORTD_OUT + +// e-switch +#ifndef SWITCH_PIN +#define SWITCH_PIN PIN4_bp +#define SWITCH_PORT VPORTA.IN +#define SWITCH_ISC_REG PORTA.PIN4CTRL +#define SWITCH_VECT PORTA_PORT_vect +#define SWITCH_INTFLG VPORTA.INTFLAGS +#endif + +// TODO: define stuff for the voltage divider +// AVR datasheet table 3.1 I/O Multiplexing, PA5 ADC0 = AIN25 +#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is regulated +#define ADMUX_VOLTAGE_DIVIDER ADC_MUXPOS_AIN25_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); + + +// 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 PIN3_bp +#define AUXLED_G_PIN PIN2_bp +#define AUXLED_B_PIN PIN0_bp +#define AUXLED_RGB_PORT PORTA + +// this light has three aux LED channels: R, G, B +#define USE_AUX_RGB_LEDS + +// A: button LED +#ifndef BUTTON_LED_PIN +#define BUTTON_LED_PIN PIN7_bp +#define BUTTON_LED_PORT PORTA +#endif + + +inline void hwdef_setup() { + + // TODO: for this DAC controlled-light, try to decrease the clock speed + // to reduce overall system power + mcu_clock_speed(); + + VPORTA.DIR = PIN0_bm // B + | PIN2_bm // G + | PIN3_bm // R + | PIN6_bm // EN + | PIN7_bm; // A + VPORTD.DIR = PIN4_bm // IN- NFET + | PIN5_bm // HDR + | PIN6_bm; // DAC + + // enable pullups on the unused and input pins to reduce power + //PORTA.PIN0CTRL = PORT_PULLUPEN_bm; // B + PORTA.PIN1CTRL = PORT_PULLUPEN_bm; + //PORTA.PIN2CTRL = PORT_PULLUPEN_bm; // G + //PORTA.PIN3CTRL = PORT_PULLUPEN_bm; // R + PORTA.PIN4CTRL = PORT_PULLUPEN_bm + | PORT_ISC_BOTHEDGES_gc; // e-switch + //PORTA.PIN5CTRL = PORT_PULLUPEN_bm; // BATT LVL + //PORTA.PIN6CTRL = PORT_PULLUPEN_bm; // EN + //PORTA.PIN7CTRL = PORT_PULLUPEN_bm; // A + + //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; // IN- NFET + //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; + + // 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; // 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) + +} + + +// 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/hank/emisar-d3aa/model b/hw/hank/emisar-d3aa/model new file mode 100644 index 0000000..1d00063 --- /dev/null +++ b/hw/hank/emisar-d3aa/model @@ -0,0 +1 @@ +0144 -- cgit v1.2.3 From 4e72ee28f892b2f473545bc783b7efaf3a4503b8 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 30 Nov 2023 13:57:28 -0700 Subject: emisar-d3aa: new model number, since this is a new product line The 0144 model number is reserved for the successor to the Meteor M44. This is Hank's first AA light, so it's assigned as 0161: - 01: Emisar - 6: product line 6 - 1: model 1 --- hw/hank/emisar-d3aa/model | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/hank/emisar-d3aa') diff --git a/hw/hank/emisar-d3aa/model b/hw/hank/emisar-d3aa/model index 1d00063..298b713 100644 --- a/hw/hank/emisar-d3aa/model +++ b/hw/hank/emisar-d3aa/model @@ -1 +1 @@ -0144 +0161 -- cgit v1.2.3 From 843dc0ba1c06e4a9b1bf034fff0e6ec5f8c12c84 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 5 Dec 2023 16:47:24 -0700 Subject: d3aa: made it easy to switch between vddio2 and external voltage divider --- hw/hank/emisar-d3aa/hwdef.c | 2 ++ hw/hank/emisar-d3aa/hwdef.h | 21 ++++++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) (limited to 'hw/hank/emisar-d3aa') diff --git a/hw/hank/emisar-d3aa/hwdef.c b/hw/hank/emisar-d3aa/hwdef.c index 853e84d..5f41d9d 100644 --- a/hw/hank/emisar-d3aa/hwdef.c +++ b/hw/hank/emisar-d3aa/hwdef.c @@ -104,6 +104,7 @@ bool gradual_tick_main(uint8_t gt) { } +#ifdef USE_VOLTAGE_DIVIDER uint8_t voltage_raw2cooked(uint16_t measurement) { // In : 65535 * BATTLVL / 1.024V // Out: uint8_t: Vbat * 40 @@ -115,4 +116,5 @@ uint8_t voltage_raw2cooked(uint16_t measurement) { * 43 / 16128; return result; } +#endif diff --git a/hw/hank/emisar-d3aa/hwdef.h b/hw/hank/emisar-d3aa/hwdef.h index 8677609..1001e5d 100644 --- a/hw/hank/emisar-d3aa/hwdef.h +++ b/hw/hank/emisar-d3aa/hwdef.h @@ -97,17 +97,20 @@ enum CHANNEL_MODES { #define SWITCH_INTFLG VPORTA.INTFLAGS #endif -// TODO: define stuff for the voltage divider -// AVR datasheet table 3.1 I/O Multiplexing, PA5 ADC0 = AIN25 -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is regulated -#define ADMUX_VOLTAGE_DIVIDER ADC_MUXPOS_AIN25_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); - +// comment out to use VDDIO2 instead of external voltage divider +//#define USE_VOLTAGE_DIVIDER +#ifdef USE_VOLTAGE_DIVIDER + // AVR datasheet table 3.1 I/O Multiplexing, PA5 ADC0 = AIN25 + #define ADMUX_VOLTAGE_DIVIDER ADC_MUXPOS_AIN25_gc + // 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); +#else + #define USE_VOLTAGE_VDDIO2 +#endif // average drop across diode on this hardware #ifndef VOLTAGE_FUDGE_FACTOR -- cgit v1.2.3 From d623fe5a1bbe02d680094eae5c16cdc83732a984 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 4 Mar 2024 06:18:26 -0700 Subject: d3aa: fixed voltage measurement --- hw/hank/emisar-d3aa/anduril.h | 4 ++-- hw/hank/emisar-d3aa/hwdef.c | 2 +- hw/hank/emisar-d3aa/hwdef.h | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'hw/hank/emisar-d3aa') diff --git a/hw/hank/emisar-d3aa/anduril.h b/hw/hank/emisar-d3aa/anduril.h index 3d65dc5..ca2ed65 100644 --- a/hw/hank/emisar-d3aa/anduril.h +++ b/hw/hank/emisar-d3aa/anduril.h @@ -6,8 +6,8 @@ #define HWDEF_H hank/emisar-d3aa/hwdef.h // HPRsense : 4.2+0.3+20 = 24.5mR -// Vsense=42.46mV, R1= 191k -// LPRsense : 2R +// Vsense=42.46mV, R1= 165k +// LPRsense : 3R3 // HDR ratio: 131.5 // transition DAC level 20, ramp level 48 // fifth power ramp 0.02mA to 2001mA diff --git a/hw/hank/emisar-d3aa/hwdef.c b/hw/hank/emisar-d3aa/hwdef.c index 5f41d9d..a963bc2 100644 --- a/hw/hank/emisar-d3aa/hwdef.c +++ b/hw/hank/emisar-d3aa/hwdef.c @@ -113,7 +113,7 @@ uint8_t voltage_raw2cooked(uint16_t measurement) { // (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; + * 43 / 16000; return result; } #endif diff --git a/hw/hank/emisar-d3aa/hwdef.h b/hw/hank/emisar-d3aa/hwdef.h index 1001e5d..a104fc2 100644 --- a/hw/hank/emisar-d3aa/hwdef.h +++ b/hw/hank/emisar-d3aa/hwdef.h @@ -100,7 +100,7 @@ enum CHANNEL_MODES { #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) // comment out to use VDDIO2 instead of external voltage divider -//#define USE_VOLTAGE_DIVIDER +#define USE_VOLTAGE_DIVIDER #ifdef USE_VOLTAGE_DIVIDER // AVR datasheet table 3.1 I/O Multiplexing, PA5 ADC0 = AIN25 #define ADMUX_VOLTAGE_DIVIDER ADC_MUXPOS_AIN25_gc @@ -109,6 +109,7 @@ enum CHANNEL_MODES { #undef voltage_raw2cooked uint8_t voltage_raw2cooked(uint16_t measurement); #else + // doesn't work on this hardware in AA mode #define USE_VOLTAGE_VDDIO2 #endif -- cgit v1.2.3 From 412df484ddf0650c07da56193bfa906a8647d1dc Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 11 Mar 2024 17:51:14 -0600 Subject: d3aa fine-tuning: - new ramp - production style config defaults (simple mode, Hank config) - candle tuning - fixed way-too-fast thermal regulation (might still be a bit fast, but it's a lot better) --- hw/hank/emisar-d3aa/anduril.h | 60 ++++++++++++++++++++----------------------- hw/hank/emisar-d3aa/hwdef.c | 14 +++------- hw/hank/emisar-d3aa/hwdef.h | 7 ++--- 3 files changed, 35 insertions(+), 46 deletions(-) (limited to 'hw/hank/emisar-d3aa') diff --git a/hw/hank/emisar-d3aa/anduril.h b/hw/hank/emisar-d3aa/anduril.h index ca2ed65..a80557d 100644 --- a/hw/hank/emisar-d3aa/anduril.h +++ b/hw/hank/emisar-d3aa/anduril.h @@ -1,9 +1,10 @@ -// Emisar D3aa config options for Anduril +// Emisar D3AA config options for Anduril // Copyright (C) 2023 thefreeman, Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #define HWDEF_H hank/emisar-d3aa/hwdef.h +#include "hank/anduril.h" // HPRsense : 4.2+0.3+20 = 24.5mR // Vsense=42.46mV, R1= 165k @@ -21,36 +22,38 @@ // - high 2.5 V // HDR ratio: 131.5 // PWM1: DAC Data -// (level_calc.py 4.3287 1 150 7135 5 0.01 1400 --pwm 400000) -// (top level for each "gear": 30 40 120 150) +// 131.5 * 1024 * 2.5 = 336640 total dimming ratio +// ./bin/dac-scale.py $( ./bin/level_calc.py 4.106 1 150 7135 3 0.01 1400 --pwm 336640 | grep PWM1 | cut -d : -f 2- ) +// top level for each "gear": 30 40 119 150 #define PWM1_LEVELS \ - 3,4,5,7,9,12,15,19,24,29,35,43,51,61,72,84,99,115,133,153,176,202,230,262,297,335,377,424,475,531,592,658,730,809,894,986, \ - 444,488,535,586,641,700,763,830,903,980,1023, \ - 20,22,24,26,28,30,32,35,37,40,43,46,49,52,56,60,63,68,72,77,81,86,92,97,103,109,115,122,129,136,143,151,159,168,177,186,196,206,216,227,239,250,263,275,289,302,316,331,346,362,379,396,413,432,450,470,490,511,532,555,578,602,626,651,678,705,733,761,791,821,853,885,919,953,989, \ - 420,435,451,467,484,501,519,537,556,575,595,615,636,657,679,702,725,749,773,798,824,850,877,905,933,962,992,1023 + 3, 5, 6, 9, 12, 16, 21, 28, 35, 44, 55, 68, 83, 101, 121, 144, 170, 200, 234, 271, 313, 360, 412, 470, 534, 603, 680, 764, 855, 954, \ + 434, 482, 534, 590, 650, 715, 784, 858, 938,1023, \ + 20, 21, 23, 25, 27, 30, 32, 35, 37, 40, 43, 46, 49, 53, 56, 60, 64, 68, 73, 77, 82, 87, 93, 98, 104, 110, 116, 123, 129, 137, 144, 152, 160, 168, 177, 185, 195, 204, 214, 225, 235, 247, 258, 270, 282, 295, 308, 322, 336, 350, 365, 381, 396, 413, 430, 447, 465, 484, 503, 522, 543, 563, 585, 607, 629, 653, 677, 701, 726, 752, 779, 806, 834, 863, 892, 923, 954, 985,1018, \ + 430, 444, 459, 473, 488, 504, 520, 536, 552, 569, 587, 604, 622, 641, 660, 679, 699, 719, 740, 761, 782, 804, 827, 849, 873, 897, 921, 946, 971, 997,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,V10,V10,V10,V10,V10,V10, \ - 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, \ - 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 47 -#define HDR_ENABLE_LEVEL_MIN 48 + 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, \ + 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 40 +#define HDR_ENABLE_LEVEL_MIN 41 + #define DEFAULT_LEVEL 50 // 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 QUARTERSPEED_LEVEL 40 // seems to run fine at 10kHz/4, try reducing more? #define RAMP_SMOOTH_FLOOR 1 -#define RAMP_SMOOTH_CEIL 119 // 35% / 0.7A / 700 lm -// 1 22 [44] 65 87 108 130 -#define RAMP_DISCRETE_FLOOR 1 -#define RAMP_DISCRETE_CEIL 119 +#define RAMP_SMOOTH_CEIL 130 // 50% power +// 10 30 [50] 70 90 110 130 +#define RAMP_DISCRETE_FLOOR 10 +#define RAMP_DISCRETE_CEIL 130 #define RAMP_DISCRETE_STEPS 7 -// 20 [45] 70 95 120 -#define SIMPLE_UI_FLOOR 20 -#define SIMPLE_UI_CEIL 129 // 50% / ~1A / ~860 lm +// 10 [40] 70 100 130 +#define SIMPLE_UI_FLOOR 10 +#define SIMPLE_UI_CEIL 130 #define SIMPLE_UI_STEPS 5 // don't blink mid-ramp @@ -61,17 +64,12 @@ // thermal config // temperature limit -#define THERM_FASTER_LEVEL 129 // stop panicking at 50%/1A +#define THERM_FASTER_LEVEL 130 // stop panicking at 50%/1A #define MIN_THERM_STEPDOWN MAX_1x7135 // UI -#define SIMPLE_UI_ACTIVE 0 // advanced UI by default, because prototype - -// 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 @@ -88,7 +86,7 @@ // show each channel while it scroll by in the menu #define USE_CONFIG_COLORS -// blink numbers on the main LEDs by default +// blink numbers on the main LEDs by default (but allow user to change it) #define DEFAULT_BLINK_CHANNEL CM_MAIN // use aux red + aux blue for police strobe @@ -109,10 +107,8 @@ #define STROBE_OFF_LEVEL 1 // keep the regulator chip on between pulses // smoother candle mode with bigger oscillations -#define CANDLE_AMPLITUDE 40 +#define CANDLE_AMPLITUDE 33 -// enable 13H factory reset so it can be used on tail e-switch lights +// added for convenience #define USE_SOFT_FACTORY_RESET -// TODO: disable lowpass while asleep; the MCU oversamples - diff --git a/hw/hank/emisar-d3aa/hwdef.c b/hw/hank/emisar-d3aa/hwdef.c index a963bc2..e2fd315 100644 --- a/hw/hank/emisar-d3aa/hwdef.c +++ b/hw/hank/emisar-d3aa/hwdef.c @@ -84,17 +84,9 @@ bool gradual_tick_main(uint8_t gt) { 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); + // only adjust 1 dac level, max is 1023 + // (but speed it up with "#define GRADUAL_ADJUST_SPEED 4" elsewhere) + GRADUAL_ADJUST_SIMPLE(dac_next, dac_now); DAC_LVL = dac_now << 6; diff --git a/hw/hank/emisar-d3aa/hwdef.h b/hw/hank/emisar-d3aa/hwdef.h index a104fc2..56dd061 100644 --- a/hw/hank/emisar-d3aa/hwdef.h +++ b/hw/hank/emisar-d3aa/hwdef.h @@ -3,7 +3,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #pragma once -/* +/* * NiMH/li-ion 9V2A boost driver based on MP3432 * with high dynamic range and DAC control + front aux RGB and button LED * @@ -26,7 +26,7 @@ * 16 PF7 UPDI * 17 PA0 B: aux blue * 18 PA1 - * 19 PA2 G: aux green + * 19 PA2 G: aux green * 20 PA3 R: aux red * * BST EN enable the boost regulator and Op-Amp @@ -36,7 +36,7 @@ * IN- NFET : pull up after BST enable to eliminate startup flash, pull down otherwise * BATT LVL : Vbat * (100.0/(330+100)) * VDDIO2 : can be connected to BATT+ with a solder jumper for VDDIO2 voltage sensing - * + * */ #define HWDEF_C hank/emisar-d3aa/hwdef.c @@ -59,6 +59,7 @@ enum CHANNEL_MODES { #define CHANNEL_MODES_ENABLED 0b0000000000000001 +// DAC max is 1023, Anduril is written for 255, so regulate at 4X speed #undef GRADUAL_ADJUST_SPEED #define GRADUAL_ADJUST_SPEED 4 -- cgit v1.2.3 From a87812f436e08b14a7cede83e30306d779774872 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 25 Mar 2024 04:25:43 -0600 Subject: dammit, got alkaline detection half working and then my flashing adapter died (saving progress here so I can work on a different branch) --- hw/hank/emisar-d3aa/hwdef.c | 64 +++++++++++++++++++++++++++++++++++++++++++++ hw/hank/emisar-d3aa/hwdef.h | 9 +++++++ 2 files changed, 73 insertions(+) (limited to 'hw/hank/emisar-d3aa') diff --git a/hw/hank/emisar-d3aa/hwdef.c b/hw/hank/emisar-d3aa/hwdef.c index e2fd315..f6cf94e 100644 --- a/hw/hank/emisar-d3aa/hwdef.c +++ b/hw/hank/emisar-d3aa/hwdef.c @@ -4,6 +4,8 @@ #pragma once #include "fsm/chan-rgbaux.c" +#include "fsm/ramping.h" +#include "ui/anduril/misc.h" void set_level_zero(); @@ -110,3 +112,65 @@ uint8_t voltage_raw2cooked(uint16_t measurement) { } #endif +#ifdef USE_WEAK_BATTERY_PROTECTION +uint8_t quick_volt_measurement() { + // take the average of a few samples + // (assumes the ADC is in voltage mode and running continuously) + uint16_t total = 0; + for (uint8_t i=0; i<8; i++) { + uint16_t m = adc_raw[0]; + total += voltage_raw2cooked(m); + delay_zero(); + } + uint8_t v = total / 8; + return v; +} + +void detect_weak_battery() { + // guess at the cell strength with a load test... + // - measure voltage while LEDs off + // - measure again with LEDs on + // - determine how much to limit power + // - blink to indicate weak battery mode, if active + + uint16_t resting, loaded; + + set_level(0); + resting = quick_volt_measurement(); + + set_level(WEAK_BATTERY_CHECK_LEVEL); + loaded = quick_volt_measurement(); + set_level(0); + + int16_t diff = resting - loaded; + uint8_t extra_blinks = 0; + + if (loaded <= DUAL_VOLTAGE_LOW_LOW) { + // weak or empty AA battery has a low limit + ramp_level_hard_limit = WEAK_BATTERY_LOWEST_LIMIT; + extra_blinks = 2; + } else if (loaded >= VOLTAGE_RED) { + // reasonably strong li-ion battery + ramp_level_hard_limit = WEAK_BATTERY_HIGHEST_LIMIT; + } else if (diff <= (-5 * 4)) { + // marginal battery, dropped a lot under mild load + ramp_level_hard_limit = WEAK_BATTERY_MEDIUM_LIMIT; + extra_blinks = 1; + } + + for (uint8_t i=0; i WEAK_BATTERY_SAG_THRESHOLD) || + // Li-ion critical voltage + ((resting > VOLTAGE_LOW) && (loaded < VOLTAGE_LOW)) + ) { + ramp_level_hard_limit = l; + break; + } + } set_level(0); - int16_t diff = resting - loaded; - uint8_t extra_blinks = 0; + // TODO? limit NiMH to ~half power, even if it passed the sag test? + // (and if so, blink 2X for NiMH, 3X for alkaline) - if (loaded <= DUAL_VOLTAGE_LOW_LOW) { - // weak or empty AA battery has a low limit - ramp_level_hard_limit = WEAK_BATTERY_LOWEST_LIMIT; - extra_blinks = 2; - } else if (loaded >= VOLTAGE_RED) { - // reasonably strong li-ion battery - ramp_level_hard_limit = WEAK_BATTERY_HIGHEST_LIMIT; - } else if (diff <= (-5 * 4)) { - // marginal battery, dropped a lot under mild load - ramp_level_hard_limit = WEAK_BATTERY_MEDIUM_LIMIT; - extra_blinks = 1; - } + uint8_t extra_blinks = 0; + if (ramp_level_hard_limit) extra_blinks ++; for (uint8_t i=0; i DUAL_VOLTAGE_FLOOR) { + sag_limit = WEAK_BATTERY_SAG_THRESHOLD_LIION; + crit_voltage = VOLTAGE_LOW; + } else { + sag_limit = WEAK_BATTERY_SAG_THRESHOLD_AA; + crit_voltage = DUAL_VOLTAGE_LOW_LOW; + } + // progressively turn up the power until sag threshold is hit, // or critical voltage, or max testing level is reached for (uint8_t l=1; l WEAK_BATTERY_SAG_THRESHOLD) || - // Li-ion critical voltage - ((resting > VOLTAGE_LOW) && (loaded < VOLTAGE_LOW)) - ) { - ramp_level_hard_limit = l; - break; + if ( (loaded <= crit_voltage) || (sag > sag_limit) ) { + // battery empty or weak + ramp_level_hard_limit = l; + break; } } set_level(0); diff --git a/hw/hank/emisar-d3aa/hwdef.h b/hw/hank/emisar-d3aa/hwdef.h index 7cd2849..7fbffbe 100644 --- a/hw/hank/emisar-d3aa/hwdef.h +++ b/hw/hank/emisar-d3aa/hwdef.h @@ -119,8 +119,9 @@ enum CHANNEL_MODES { // (also helps protect firmware flashing adapters from overload) #define USE_RAMP_LEVEL_HARD_LIMIT #define USE_WEAK_BATTERY_PROTECTION -#define WEAK_BATTERY_TEST_MAX_LEVEL 75 // about 300 mA -#define WEAK_BATTERY_SAG_THRESHOLD (5*4) // 0.5 V +#define WEAK_BATTERY_TEST_MAX_LEVEL 75 // about 300 mA +#define WEAK_BATTERY_SAG_THRESHOLD_AA (3*4) // 0.3 V +#define WEAK_BATTERY_SAG_THRESHOLD_LIION (6*4) // 0.6 V // average drop across diode on this hardware #ifndef VOLTAGE_FUDGE_FACTOR -- cgit v1.2.3 From 3cafb86c00a95a70e58144230f641c2c94208e7b Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 29 Mar 2024 08:21:07 -0600 Subject: d3aa weak battery test: blink 3x instead of 2x, and omit number readout --- hw/hank/emisar-d3aa/anduril.h | 4 ++++ hw/hank/emisar-d3aa/hwdef.c | 16 ++++++++++++---- hw/hank/emisar-d3aa/hwdef.h | 3 ++- 3 files changed, 18 insertions(+), 5 deletions(-) (limited to 'hw/hank/emisar-d3aa') diff --git a/hw/hank/emisar-d3aa/anduril.h b/hw/hank/emisar-d3aa/anduril.h index a80557d..e4e4458 100644 --- a/hw/hank/emisar-d3aa/anduril.h +++ b/hw/hank/emisar-d3aa/anduril.h @@ -44,6 +44,10 @@ #define HALFSPEED_LEVEL 41 #define QUARTERSPEED_LEVEL 40 // seems to run fine at 10kHz/4, try reducing more? +// should be about 300 mA or ~100 lm, +// to avoid overloading firmware flashing adapters +#define WEAK_BATTERY_TEST_MAX_LEVEL 75 + #define RAMP_SMOOTH_FLOOR 1 #define RAMP_SMOOTH_CEIL 130 // 50% power // 10 30 [50] 70 90 110 130 diff --git a/hw/hank/emisar-d3aa/hwdef.c b/hw/hank/emisar-d3aa/hwdef.c index 8aaa893..36c6fed 100644 --- a/hw/hank/emisar-d3aa/hwdef.c +++ b/hw/hank/emisar-d3aa/hwdef.c @@ -123,9 +123,10 @@ uint8_t quick_volt_measurement() { void detect_weak_battery() { // guess at the cell strength with a load test... - // - measure voltage while LEDs off + // - measure voltage with LEDs off // - measure again with LEDs on // - determine how much to limit power + // (ramp up until battery becomes unstable) // - blink to indicate weak battery mode, if active ramp_level_hard_limit = 0; @@ -162,17 +163,23 @@ void detect_weak_battery() { } set_level(0); - // TODO? limit NiMH to ~half power, even if it passed the sag test? - // (and if so, blink 2X for NiMH, 3X for alkaline) + // Blink again if not in full-power mode: + // - 1 blink total: Strong Li-ion cell, full power enabled + // - 2 blinks: Strong AA cell, max AA power enabled + // (not used on this driver, strong AA uses mode 1) + // - 3 blinks: Weak battery, power severely limited uint8_t extra_blinks = 0; - if (ramp_level_hard_limit) extra_blinks ++; + if (ramp_level_hard_limit) extra_blinks += 2; for (uint8_t i=0; i