aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--MODELS1
-rw-r--r--fsm/misc.c58
-rw-r--r--fsm/misc.h3
-rw-r--r--hw/hank/lume-x1/anduril.h114
-rw-r--r--hw/hank/lume-x1/arch1
-rw-r--r--hw/hank/lume-x1/hwdef.c116
-rw-r--r--hw/hank/lume-x1/hwdef.h232
-rw-r--r--hw/hank/lume-x1/model1
-rw-r--r--hw/hank/lume-x1/readme.md34
-rw-r--r--ui/anduril/anduril.c9
10 files changed, 568 insertions, 1 deletions
diff --git a/MODELS b/MODELS
index caa4bf5..0099b29 100644
--- a/MODELS
+++ b/MODELS
@@ -24,6 +24,7 @@ Model MCU Name
0143 attiny1634 hank-noctigon-m44
0151 attiny1634 hank-emisar-d4k-3ch
0161 avr32dd20 hank-emisar-d3aa
+0171 avr32dd20 hank-lume-x1
0211 attiny1634 hank-noctigon-kr4
0212 attiny1634 hank-noctigon-kr4-nofet
0213 attiny1634 hank-noctigon-kr4-219
diff --git a/fsm/misc.c b/fsm/misc.c
index fa8ddd7..915dbd4 100644
--- a/fsm/misc.c
+++ b/fsm/misc.c
@@ -65,6 +65,16 @@ uint8_t blink_digit(uint8_t num) {
return nice_delay_ms(BLINK_SPEED * 8 / 12);
}
+#ifdef USE_LONG_BLINK_FOR_NEGATIVE_SIGN
+void blink_negative() {
+ // "negative" symbol gets a single long blink
+ uint8_t ontime = BLINK_SPEED * 2 / 12;
+ set_level(BLINK_BRIGHTNESS);
+ nice_delay_ms(ontime * 3);
+ set_level(0);
+ nice_delay_ms(ontime * 5);
+}
+#endif
#endif
#ifdef USE_BLINK_BIG_NUM
@@ -245,6 +255,50 @@ void rgb_led_set(uint8_t value) {
// FIXME: move this logic to arch/*
#if (MCU==0x1616) || (MCU==0x32dd20) // ATTINY816, 817, etc
+ // FIXME: this *really* needs to be moved to somewhere hardware-specific
+ #ifdef AUXLED_RGB_DIFFERENT_PORTS
+
+ case 0: // LED off
+ if (i == 0) {
+ AUXLED_R_PORT.DIRSET = (1 << pin);
+ AUXLED_R_PORT.OUTCLR = (1 << pin);
+ } else if (i == 1) {
+ AUXLED_G_PORT.DIRSET = (1 << pin);
+ AUXLED_G_PORT.OUTCLR = (1 << pin);
+ } else if (i == 2) {
+ AUXLED_B_PORT.DIRSET = (1 << pin);
+ AUXLED_B_PORT.OUTCLR = (1 << pin);
+ }
+ break;
+
+ case 1: // LED low
+ if (i == 0) {
+ AUXLED_R_PORT.DIRCLR = (1 << pin);
+ *((uint8_t *)&AUXLED_R_PORT + 0x10 + pin) = PORT_PULLUPEN_bm;
+ } else if (i == 1) {
+ AUXLED_G_PORT.DIRCLR = (1 << pin);
+ *((uint8_t *)&AUXLED_G_PORT + 0x10 + pin) = PORT_PULLUPEN_bm;
+ } else if (i == 2) {
+ AUXLED_B_PORT.DIRCLR = (1 << pin);
+ *((uint8_t *)&AUXLED_B_PORT + 0x10 + pin) = PORT_PULLUPEN_bm;
+ }
+ break;
+
+ default: // LED high
+ if (i==0) {
+ AUXLED_R_PORT.DIRSET = (1 << pin);
+ AUXLED_R_PORT.OUTSET = (1 << pin);
+ } else if (i==1) {
+ AUXLED_G_PORT.DIRSET = (1 << pin);
+ AUXLED_G_PORT.OUTSET = (1 << pin);
+ } else if (i==2) {
+ AUXLED_B_PORT.DIRSET = (1 << pin);
+ AUXLED_B_PORT.OUTSET = (1 << pin);
+ }
+ break;
+
+ #else // not ifdef AUXLED_RGB_DIFFERENT_PORTS
+
case 0: // LED off
AUXLED_RGB_PORT.DIRSET = (1 << pin); // set as output
AUXLED_RGB_PORT.OUTCLR = (1 << pin); // set output low
@@ -258,8 +312,10 @@ void rgb_led_set(uint8_t value) {
AUXLED_RGB_PORT.DIRSET = (1 << pin); // set as output
AUXLED_RGB_PORT.OUTSET = (1 << pin); // set as high
break;
+
+ #endif
- #else
+ #else // not #if (MCU==0x1616) || (MCU==0x32dd20)
case 0: // LED off
AUXLED_RGB_DDR &= 0xff ^ (1 << pin);
diff --git a/fsm/misc.h b/fsm/misc.h
index ba1f8d9..0b13496 100644
--- a/fsm/misc.h
+++ b/fsm/misc.h
@@ -28,6 +28,9 @@ void auto_clock_speed();
#ifdef USE_BLINK_NUM
//#define USE_BLINK
uint8_t blink_num(uint8_t num);
+#ifdef USE_LONG_BLINK_FOR_NEGATIVE_SIGN
+void blink_negative();
+#endif
#endif
/*
diff --git a/hw/hank/lume-x1/anduril.h b/hw/hank/lume-x1/anduril.h
new file mode 100644
index 0000000..c409e43
--- /dev/null
+++ b/hw/hank/lume-x1/anduril.h
@@ -0,0 +1,114 @@
+// Hank Emisar/Noctigon Lume-X1 config options for Anduril
+// Copyright (C) 2018-2024 Selene ToyKeeper, Loneoceans
+// SPDX-License-Identifier: GPL-3.0-or-later
+#pragma once
+
+// For flashlights using the Loneoceans Lume-X1-40W boost driver (AVR32DD20)
+// - Same firmware for 6V, 9V, or 12V configs
+// same as loneoceans lume-x1-avr32dd20 but with Hank-specific defaults
+
+#define HWDEF_H hank/lume-x1/hwdef.h
+#include "hank/anduril.h"
+
+
+
+//***************************************
+//** RAMP TABLE AND OPERATIONS **
+//***************************************
+
+#define RAMP_SIZE 150 // Change to 160 as well as table and values below if desired
+
+// PWM1: DAC Data
+// UDR x^4 curves specifically for Lume-X1 (AVR32DD20)
+
+// levels 1 to 5:
+// ./bin/level_calc.py 5.2 1 5 7135 100 0.01 0.1 --pwm 2500
+// (with the last 2 values divided to fit)
+// levels 6 to 150:
+// ./bin/dac-scale.py $( ./bin/level_calc.py 5.3 1 145 7135 17 0.2 3000 --pwm 240000 | grep PWM1 | cut -d : -f 2- )
+// top level for each "gear": 3 5 / 39 50 / 123 150
+#define PWM1_LEVELS \
+ 100, 359, 790, 588,1023, \
+ 17, 21, 24, 29, 34, 39, 46, 54, 62, 71, 82, 94, 107, 122, 138, 157, 177, 199, 223, 250, 279, 311, 346, 385, 426, 471, 520, 573, 630, 692, 758, 830, 907, 990, \
+ 441, 480, 522, 567, 615, 666, 720, 778, 840, 905, 974, \
+ 26, 28, 30, 33, 35, 37, 40, 43, 46, 49, 52, 56, 59, 63, 67, 71, 76, 80, 85, 90, 96, 101, 107, 113, 120, 126, 133, 141, 148, 156, 165, 173, 182, 192, 202, 212, 222, 234, 245, 257, 269, 282, 296, 310, 324, 339, 355, 371, 387, 405, 422, 441, 460, 480, 501, 522, 544, 567, 590, 614, 640, 665, 692, 720, 748, 778, 808, 839, 872, 905, 939, 975,1011, \
+ 429, 445, 461, 478, 495, 513, 531, 550, 570, 589, 610, 631, 653, 675, 698, 721, 745, 770, 795, 821, 848, 875, 903, 932, 962, 992,1023
+#define PWM2_LEVELS \
+ V10, V10, V10, 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, \
+ 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, \
+ 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 LED_PATH1_PIN_LEVEL_MIN 1
+#define LED_PATH2_PIN_LEVEL_MIN 6
+#define LED_PATH3_PIN_LEVEL_MIN 51
+
+#define HALFSPEED_LEVEL 20
+#define QUARTERSPEED_LEVEL 10
+
+#define DEFAULT_LEVEL 50
+#define MAX_1x7135 49
+
+#define RAMP_SMOOTH_FLOOR 1
+#define RAMP_SMOOTH_CEIL 130
+
+#define RAMP_DISCRETE_FLOOR 10
+#define RAMP_DISCRETE_CEIL 130
+#define RAMP_DISCRETE_STEPS 7
+
+#define SIMPLE_UI_FLOOR 10
+#define SIMPLE_UI_CEIL 110 // about ~12W
+#define SIMPLE_UI_STEPS 5
+
+// don't blink mid-ramp
+#ifdef BLINK_AT_RAMP_MIDDLE
+#undef BLINK_AT_RAMP_MIDDLE
+#endif
+
+//***************************************
+//** THERMAL SETTINGS **
+//***************************************
+
+// stop panicking at 6W (not sure of this numbers yet since it depends on the host..)
+#define THERM_FASTER_LEVEL 100 // about 6W
+#define MIN_THERM_STEPDOWN 60 // similar to single amc7135 in a 3V light
+
+//***************************************
+//** AUX LEDs and MISC **
+//***************************************
+
+#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 (but allow user to change it)
+#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
+
+#define PARTY_STROBE_ONTIME 1 // slow down party strobe
+#define STROBE_OFF_LEVEL 1 // keep the regulator chips on between pulses
+
+// smoother candle mode with bigger oscillations
+#define CANDLE_AMPLITUDE 30 // default 25
+
+// avr32dd20 has enough space to smooth out voltage readings
+#define USE_VOLTAGE_LOWPASS
+
+// enable long-blink as negative sign
+#define USE_LONG_BLINK_FOR_NEGATIVE_SIGN
+
diff --git a/hw/hank/lume-x1/arch b/hw/hank/lume-x1/arch
new file mode 100644
index 0000000..bcf4552
--- /dev/null
+++ b/hw/hank/lume-x1/arch
@@ -0,0 +1 @@
+avr32dd20
diff --git a/hw/hank/lume-x1/hwdef.c b/hw/hank/lume-x1/hwdef.c
new file mode 100644
index 0000000..3fe32f3
--- /dev/null
+++ b/hw/hank/lume-x1/hwdef.c
@@ -0,0 +1,116 @@
+// Copyright (C) 2017-2023 Selene ToyKeeper
+// 2021-2024 loneoceans
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+//***********************************************
+//** HELPER FUNCTIONS FOR LUME-X1-AVR32DD20 **
+//***********************************************
+
+#pragma once
+
+#include "fsm/chan-rgbaux.c"
+
+// Declare variables and functions to support UDR multiple power paths
+uint8_t is_boost_currently_on = 0; // for turn-on delay during first turn on
+
+void set_level_zero();
+void set_level_udr(uint8_t level);
+bool gradual_tick_main(uint8_t gt);
+void set_power_path(uint8_t ramp_level);
+
+Channel channels[] = {
+ { // main LEDs
+ .set_level = set_level_udr,
+ .gradual_tick = gradual_tick_main
+ },
+ RGB_AUX_CHANNELS
+};
+
+// turn off
+void set_level_zero() {
+
+ DAC_LVL = 0; // set DAC to 0
+ DAC_VREF = V10; // set DAC Vref to lowest
+
+ // turn off DC/DC converter and amplifier
+ BST_ENABLE_PORT &= ~(1 << BST_ENABLE_PIN);
+ is_boost_currently_on = 0;
+
+ // turn off all UDR paths
+ LED_PATH1_PORT &= ~LED_PATH1_PIN;
+ LED_PATH2_PORT &= ~LED_PATH2_PIN;
+ LED_PATH3_PORT &= ~LED_PATH3_PIN;
+}
+
+// UDR for set_level, which sets the led brightness based on ramp tables.
+// single set of LED(s), fully regulated boost at all levels
+void set_level_udr(uint8_t level) {
+ if (level == actual_level - 1) return; // no-op
+
+ // get the ramp data
+ PWM1_DATATYPE dac_lvl = PWM1_GET(level) << 6; // dac register is left-aligned
+ PWM2_DATATYPE dac_vref = PWM2_GET(level);
+
+ if(is_boost_currently_on != 1){
+ // boost is not on, enable buck and add boot-up delay
+ is_boost_currently_on = 1;
+ BST_ENABLE_PORT |= (1 << BST_ENABLE_PIN); // turn on buck and amplifier
+ delay_4ms(BST_ON_DELAY/4); // boot-up delay
+ }
+ // set the DAC
+ DAC_LVL = dac_lvl;
+ DAC_VREF = dac_vref;
+
+ // set the power paths
+ set_power_path(level);
+}
+
+// handles dynamic Vref used in the ramp tables
+bool gradual_tick_main(uint8_t gt) {
+ // TODO overall smoothness can be improved due to gt using linear
+ // adjustments, but ramp table is non-linear.
+
+ // if Vref is the same, make gradual adjustments.
+ // else, jump to the next ramp level and use set_level() to handle power paths.
+ PWM2_DATATYPE vref_next = PWM2_GET(gt); // DAC ramp table Vref
+
+ // if different vref level, make a ramp level adjustment..
+ if (vref_next != DAC_VREF) return true; // use set_level() to handle normally
+
+ // .. else, same vref, adjust level gradually.
+ PWM1_DATATYPE dac_next = PWM1_GET(gt); // DAC ramp table data
+ PWM1_DATATYPE dac_curr = DAC_LVL >> 6; // register is left-aligned
+
+ GRADUAL_ADJUST_SIMPLE(dac_next, dac_curr);
+ DAC_LVL = dac_curr << 6;
+
+ if (dac_next == dac_curr) return true; // done
+
+ return false;
+}
+
+// handles dynamic power pathways based on threshold levels
+void set_power_path(uint8_t ramp_level){
+
+ ramp_level ++; // convert to 1-based indexing
+
+ if (ramp_level >= LED_PATH3_PIN_LEVEL_MIN) {
+ // high mode
+ LED_PATH1_PORT |= LED_PATH1_PIN;
+ LED_PATH2_PORT |= LED_PATH2_PIN;
+ LED_PATH3_PORT |= LED_PATH3_PIN;
+ }
+ else if (ramp_level >= LED_PATH2_PIN_LEVEL_MIN) {
+ // low mode
+ LED_PATH1_PORT |= LED_PATH1_PIN;
+ LED_PATH2_PORT |= LED_PATH2_PIN;
+ LED_PATH3_PORT &= ~LED_PATH3_PIN;
+ }
+ else if (ramp_level >= LED_PATH1_PIN_LEVEL_MIN) {
+ // firefly mode
+ LED_PATH1_PORT |= LED_PATH1_PIN;
+ LED_PATH2_PORT &= ~LED_PATH2_PIN;
+ LED_PATH3_PORT &= ~LED_PATH3_PIN;
+ }
+}
+
diff --git a/hw/hank/lume-x1/hwdef.h b/hw/hank/lume-x1/hwdef.h
new file mode 100644
index 0000000..250e8ee
--- /dev/null
+++ b/hw/hank/lume-x1/hwdef.h
@@ -0,0 +1,232 @@
+// Copyright (C) 2017-2023 Selene ToyKeeper
+// 2021-2024 loneoceans
+// SPDX-License-Identifier: GPL-3.0-or-later
+#pragma once
+
+//**************************************************
+//** HARDWARE DEFINITIONS FOR LUME-X1-AVR32DD20 **
+//**************************************************
+
+/* Loneoceans Lume-X1 with AVR32DD20
+
+ 40W Boost Driver with Ultra Dynamic Range, RGB & SW Aux, Powerbank.
+
+ The following pins are invariant (20 QFN package 3x3 0.4mm BSC)
+ - PD6 / PP11 - DAC OUT
+ - PF6 / PP15 - nRST
+ - PF7 / PP16 - UPDI
+ - xx / PP13 - VDD (read voltage from VDD, PFET RPP, no voltage drop)
+ - xx / PP8 - VDDIO2
+ - xx / PP14 - GND
+
+ Used Pins
+ - PA0 / PP17 - FET via PWM (TCA0-WO0) - N/C for Lume X1
+ - PA5 / PP2 - PATH3 - High Range
+ - PA6 / PP3 - PATH2 - Low Range
+ - PA7 / PP4 - PATH1 - Moon Range
+ - PC1 / PP5 - Enable for Boost, Amplifier
+ - PC2 / PP6 - Enable for Microphone - N/C
+ - PC3 / PP7 - Neo Dat - N/C
+ - PD4 / PP9 - E-Switch
+ - PD5 / PP10 - Mic Output - N/C
+ - PD6 / PP11 - DAC Out
+ - PD7 / PP12 - Power Bank - N/C
+ - PA1 / PP18 - AUX R LED
+ - PA2 / PP19 - AUX G LED
+ - PA3 / PP20 - AUX B LED
+ - PA4 / PP1 - AUX SW LED
+
+*/
+
+#define HWDEF_C hank/lume-x1/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
+
+//***************************************
+//** SET UP DAC AND PWM **
+//***************************************
+
+// Define DAC control
+#define PWM_BITS 16 // 10-bit DAC
+#define PWM_DATATYPE uint16_t
+#define PWM_DATATYPE2 uint32_t
+#define PWM1_DATATYPE uint16_t // main regulated ramp 10-bit
+#define PWM1_GET(x) PWM_GET16(pwm1_levels, x)
+#define PWM2_DATATYPE uint8_t // DAC Vref table (4/6 options)
+#define PWM2_GET(x) PWM_GET8(pwm2_levels, x)
+
+//***************************************
+//** PIN DEFINITIONS **
+//***************************************
+
+// Boost and Amplifier Enable (PC1)
+#define BST_ENABLE_PIN PIN1_bp
+#define BST_ENABLE_PORT PORTC_OUT
+#define BST_ON_DELAY 8 // ms delay turning on the led after enable
+
+// Ultra Dynamic Range (UDR)
+/*
+ UDR makes use of the concept of multiple power paths. 3 are used in this
+ design to achieve extremely low moonlight levels. This is combined with
+ dynamic Vref for smoother brightness level transitions that would
+ normally be limited by the 10-bit DAC resolution.
+
+ Lume drivers uses the internal DAC to generate a reference voltage for
+ a current-regulated amplifier which drives the LED. Each power path
+ routes current through different sense resistors, allowing for improved
+ current sense resolution especially at the low end. Using UDR, Lume1/X1
+ is capable of ultra-low firefly / moonlight levels with a dynamic range
+ on the order of >10-50 million : 1.
+*/
+
+// For UDR Path 1 (firefly mode) - PA7
+#define LED_PATH1_PIN PIN7_bm
+#define LED_PATH1_PORT PORTA_OUT
+
+// For UDR Path 2 (low mode) - PA6
+#define LED_PATH2_PIN PIN6_bm
+#define LED_PATH2_PORT PORTA_OUT
+
+// For UDR Path 3 (high mode) - PA5
+#define LED_PATH3_PIN PIN5_bm
+#define LED_PATH3_PORT PORTA_OUT
+
+// Define Aux LED Pins
+
+// lighted switch button aux led (PA4)
+#ifndef BUTTON_LED_PIN
+#define BUTTON_LED_PIN PIN4_bp
+#define BUTTON_LED_PORT PORTA
+#endif
+
+// this driver allows for aux LEDs under the optic
+#define AUXLED_R_PIN PIN1_bp
+#define AUXLED_G_PIN PIN2_bp
+#define AUXLED_B_PIN PIN3_bp
+
+#define AUXLED_RGB_PORT PORTA
+
+/*
+#define AUXLED_R_PORT PORTA
+#define AUXLED_G_PORT PORTA
+#define AUXLED_B_PORT PORTA
+
+// if aux leds are on different ports
+#define AUXLED_RGB_DIFFERENT_PORTS
+*/
+
+// this light has three aux LED channels: R, G, B
+#define USE_AUX_RGB_LEDS
+
+// Define e-switch Pin and ISR
+#ifndef SWITCH_PIN // PD4
+#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
+
+// average drop across diode on this hardware
+#ifndef VOLTAGE_FUDGE_FACTOR
+#define VOLTAGE_FUDGE_FACTOR 1 // PFET for RRP, essentially 0 v-drop, but experimentally add 0.05V for better UX
+#endif
+
+//***************************************
+//** HARDWARE INIT **
+//***************************************
+
+inline void hwdef_setup() {
+
+ // TODO: for this DAC controlled-light, try to decrease the clock speed
+ // to reduce overall system power
+ mcu_clock_speed();
+
+ // set output pins
+ VPORTA.DIR = PIN1_bm | PIN2_bm | PIN3_bm |
+ PIN4_bm | PIN5_bm | PIN6_bm | PIN7_bm;
+ VPORTC.DIR = PIN1_bm;
+ VPORTD.DIR = PIN6_bm;
+
+ // now set pullups on input pins, and unused pins (reduce power)
+ PORTA.PIN0CTRL = PORT_PULLUPEN_bm; // FET
+ //PORTA.PIN1CTRL = PORT_PULLUPEN_bm; // AUX R
+ //PORTA.PIN2CTRL = PORT_PULLUPEN_bm; // AUX G
+ //PORTA.PIN3CTRL = PORT_PULLUPEN_bm; // AUX B
+ //PORTA.PIN4CTRL = PORT_PULLUPEN_bm; // AUX SW
+ //PORTA.PIN5CTRL = PORT_PULLUPEN_bm; // PATH3
+ //PORTA.PIN6CTRL = PORT_PULLUPEN_bm; // PATH2
+ //PORTA.PIN7CTRL = PORT_PULLUPEN_bm; // PATH1
+
+ //PORTC.PIN1CTRL = PORT_PULLUPEN_bm; // ENABLE
+ PORTC.PIN2CTRL = PORT_PULLUPEN_bm; // MIC ENABLE
+ PORTC.PIN3CTRL = PORT_PULLUPEN_bm; // NEO
+
+ //PORTD.PIN4CTRL = PORT_PULLUPEN_bm; // ESW (100kR PULLUP)
+ PORTD.PIN5CTRL = PORT_PULLUPEN_bm; // MIC OUT
+ //PORTD.PIN6CTRL = PORT_PULLUPEN_bm; // DAC OUT
+ PORTD.PIN7CTRL = PORT_PULLUPEN_bm; // PWR BNK ENABLE
+
+ // clear some pins we don't need for now or want to initialize as low
+ PORTC_OUT &= ~(1 << PIN1_bp); // ENABLE
+ PORTC_OUT &= ~(1 << PIN2_bp); // MIC ENABLE
+ PORTD_OUT &= ~(1 << PIN7_bp); // PWR BNK ENABLE
+
+ //E-Switch (now uses external pullup)
+ PORTD.DIRCLR = PIN4_bm; // set ESW as input pin
+ PORTD.PIN4CTRL = PORT_ISC_BOTHEDGES_gc;
+
+ // set up the DAC (used for the switching regulator)
+ // https://www.microchip.com/en-us/product/avr32dd20
+ // DAC ranges from 0V to (255 * Vref) / 256
+
+ // Datasheet 34.3.1-2/2: input for DAC must be disabled
+ PORTD.PIN6CTRL = PORT_ISC_INPUT_DISABLE_gc;
+ //VREF.CTRLA |= VREF_DAC0REFSEL_2V5_gc; // also VREF_DAC0REFSEL_0V55_gc and VREF_DAC0REFSEL_1V1_gc and VREF_DAC0REFSEL_2V5_gc
+ //VREF.CTRLB |= VREF_DAC0REFEN_bm; // enable vref
+ DAC_VREF = V10;
+ DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; // enable DAC
+ DAC_LVL = 0; // lowest output during 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/lume-x1/model b/hw/hank/lume-x1/model
new file mode 100644
index 0000000..5a0d2ba
--- /dev/null
+++ b/hw/hank/lume-x1/model
@@ -0,0 +1 @@
+0281
diff --git a/hw/hank/lume-x1/readme.md b/hw/hank/lume-x1/readme.md
new file mode 100644
index 0000000..eba5949
--- /dev/null
+++ b/hw/hank/lume-x1/readme.md
@@ -0,0 +1,34 @@
+# Hank / loneoceans Lume X1 40W
+
+Regulated boost driver for Hank lights (Emisar / Noctigon) by loneoceans.
+
+Second Hank light to use the new avr32dd20 MCU. Performs better than older
+MCUs and provides more space for extra features and future firmware updates.
+
+Originally from https://github.com/loneoceans/anduril
+
+Features UDR (Ultra Dynamic Range) for smooth dimming all the way down to
+*literally zero*, meaning an effectively infinite dimming ratio:
+
+- 3 power paths or "gears" for the regulator chip's sense resistors:
+ - Firefly "gear": 0 to ~0.1 lm
+ - Low "gear": ~0.1 to ~40 lm
+ - High "gear": ~40 lm to full power (2k or 3k lm?)
+- Internal resolution of 2500 steps per "gear" allows very precise control over
+ brightness. Anduril's 150 step ramp does not fully take advantage of this.
+- Constant current, no pulsing or flicker or ripple
+- No preflash
+- No need for jump start; regulator has a quick response at all levels
+
+The firefly part of the ramp is compressed to just a few levels, to avoid
+making the rest of the ramp artificially low. It aims to be reasonably
+consistent compared to the ramp shape of Hank's other lights, but a few levels
+at the bottom are set aside for moon and firefly modes.
+
+The regulator can go much, much lower than the brightness of the button LEDs,
+but there isn't much point because the glowing button overpowers the main LEDs.
+The button and aux LEDs (on low) also use significantly less power despite
+being brighter, because they do not require the MCU to be awake. So that part
+of the ramp is mostly omitted. However, it can be added with a firmware
+modification if desired.
+
diff --git a/ui/anduril/anduril.c b/ui/anduril/anduril.c
index a7e4199..383acbc 100644
--- a/ui/anduril/anduril.c
+++ b/ui/anduril/anduril.c
@@ -341,6 +341,15 @@ void loop() {
#ifdef USE_THERMAL_REGULATION
// TODO: blink out therm_ceil during thermal_config_state?
else if (state == tempcheck_state) {
+ // temperature is type int16_t
+ // but blink_num is uint8_t, so -10 will blink as 246
+ #ifdef USE_LONG_BLINK_FOR_NEGATIVE_SIGN
+ if (temperature < 0) {
+ blink_negative();
+ blink_num(-temperature);
+ }
+ else
+ #endif
blink_num(temperature);
nice_delay_ms(1000);
}