aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorSelene ToyKeeper2023-11-30 13:50:35 -0700
committerSelene ToyKeeper2023-11-30 13:50:35 -0700
commitd80a1d2a2e01143970ffc13b971859a98ce9cb34 (patch)
tree4b5a043068b4bc3077f1291ffd6d412a2864410f /hw
parentfixed RGB aux turning on in momentary mode when post-off voltage was enabled (diff)
downloadanduril-d80a1d2a2e01143970ffc13b971859a98ce9cb34.tar.gz
anduril-d80a1d2a2e01143970ffc13b971859a98ce9cb34.tar.bz2
anduril-d80a1d2a2e01143970ffc13b971859a98ce9cb34.zip
added initial code for emisar-d3aa torch
Diffstat (limited to '')
-rw-r--r--hw/hank/emisar-d3aa/anduril.h118
-rw-r--r--hw/hank/emisar-d3aa/arch1
-rw-r--r--hw/hank/emisar-d3aa/hwdef.c118
-rw-r--r--hw/hank/emisar-d3aa/hwdef.h212
-rw-r--r--hw/hank/emisar-d3aa/model1
5 files changed, 450 insertions, 0 deletions
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