diff options
| -rw-r--r-- | .github/workflows/compile.yml | 2 | ||||
| -rw-r--r-- | ChangeLog.md | 16 | ||||
| -rw-r--r-- | MODELS | 1 | ||||
| -rwxr-xr-x | bin/build-all.sh | 8 | ||||
| -rw-r--r-- | fsm/misc.c | 58 | ||||
| -rw-r--r-- | fsm/misc.h | 3 | ||||
| -rw-r--r-- | hw/hank/emisar-d3aa/hwdef.c | 31 | ||||
| -rw-r--r-- | hw/hank/emisar-d3aa/hwdef.h | 2 | ||||
| -rw-r--r-- | hw/hank/lume-x1/anduril.h | 114 | ||||
| -rw-r--r-- | hw/hank/lume-x1/arch | 1 | ||||
| -rw-r--r-- | hw/hank/lume-x1/hwdef.c | 116 | ||||
| -rw-r--r-- | hw/hank/lume-x1/hwdef.h | 232 | ||||
| -rw-r--r-- | hw/hank/lume-x1/model | 1 | ||||
| -rw-r--r-- | hw/hank/lume-x1/readme.md | 34 | ||||
| -rwxr-xr-x | make | 20 | ||||
| -rw-r--r-- | ui/anduril/anduril.c | 9 | ||||
| -rw-r--r-- | ui/anduril/lockout-mode.c | 22 |
17 files changed, 645 insertions, 25 deletions
diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index c77ac85..629f7e1 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -52,7 +52,7 @@ jobs: echo "ARTIFACT_NAME=${GITHUB_WORKFLOW}-$(git rev-parse --short ${GITHUB_SHA})-${GITHUB_RUN_NUMBER}" >> "${GITHUB_ENV}" - name: Store Artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ env.ARTIFACT_NAME }} if-no-files-found: error diff --git a/ChangeLog.md b/ChangeLog.md index 4a71e4e..a60b662 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -14,6 +14,22 @@ formats: # Next +# 2025-04-29 + +Pretty minor release. Things have been weird lately. + +General: + +- Removed access to strobe/mood modes in Extended Simple UI, to make it more + safe and simple by default. + +New lights: + +- Added &hank-lume-x1 (0281): Covers all of Hank's recent Lume X1-based lights. +- Added &wurkkos-ts10-rgbaux-lowfet (0712): Variant with lower max power, + created at Wurkkos's request, to stop new batches of low-Vf lights from + damaging themselves. + # 2024-04-20 General: @@ -43,6 +43,7 @@ Model MCU Name 0272 attiny1634 hank-noctigon-dm11-nofet 0273 attiny1634 hank-noctigon-dm11-boost 0274 attiny1634 hank-noctigon-dm11-sbt90 +0281 avr32dd20 hank-lume-x1 0311 attiny85 lumintop-fw3a 0312 attiny85 lumintop-fw3a-219 0313 attiny85 lumintop-fw3a-nofet diff --git a/bin/build-all.sh b/bin/build-all.sh index f2420a7..c2256e5 100755 --- a/bin/build-all.sh +++ b/bin/build-all.sh @@ -11,12 +11,8 @@ shopt -s globstar function main { - if [ "$#" -gt 0 ]; then - # multiple search terms with "AND" - SEARCH=( "$@" ) - # memes - [ "$1" = "me" ] && shift && shift && echo "Make your own $*." && exit 1 - fi + # multiple search terms with "AND" + [ "$#" -gt 0 ] && SEARCH=( "$@" ) # TODO: detect UI from $0 and/or $* UI=anduril @@ -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); @@ -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/emisar-d3aa/hwdef.c b/hw/hank/emisar-d3aa/hwdef.c index be673e1..0ac0ddc 100644 --- a/hw/hank/emisar-d3aa/hwdef.c +++ b/hw/hank/emisar-d3aa/hwdef.c @@ -22,15 +22,26 @@ Channel channels[] = { }; +inline void nfet_delay() { + #if IN_NFET_DELAY_TIME > 0 + delay_4ms(IN_NFET_DELAY_TIME/4); + #else + delay_zero(); + delay_zero(); + #endif +} + 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); + if (actual_level) { + // prevent post-off flash + IN_NFET_ENABLE_PORT |= (1 << IN_NFET_ENABLE_PIN); + nfet_delay(); + IN_NFET_ENABLE_PORT &= ~(1 << IN_NFET_ENABLE_PIN); + } // turn off boost last BST_ENABLE_PORT &= ~(1 << BST_ENABLE_PIN); // BST off @@ -45,11 +56,9 @@ void set_level_main(uint8_t level) { if ((! actual_level) && (level < HDR_ENABLE_LEVEL_MIN)) { noflash = 1; IN_NFET_ENABLE_PORT |= (1 << IN_NFET_ENABLE_PIN); + //nfet_delay(); } - // 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; @@ -66,9 +75,15 @@ void set_level_main(uint8_t level) { DAC_LVL = dac_lvl; DAC_VREF = dac_vref; + // if turning on from off, let things stabilize before enabling power + if (noflash) { nfet_delay(); } + + // BST on last, after its inputs are set and stabilized + BST_ENABLE_PORT |= (1 << BST_ENABLE_PIN); + if (noflash) { // wait for flash prevention to finish - delay_4ms(IN_NFET_DELAY_TIME/4); + nfet_delay(); IN_NFET_ENABLE_PORT &= ~(1 << IN_NFET_ENABLE_PIN); } } diff --git a/hw/hank/emisar-d3aa/hwdef.h b/hw/hank/emisar-d3aa/hwdef.h index 87740ba..889b721 100644 --- a/hw/hank/emisar-d3aa/hwdef.h +++ b/hw/hank/emisar-d3aa/hwdef.h @@ -85,7 +85,7 @@ enum CHANNEL_MODES { // IN- NFET // pull high to force output to zero to eliminate the startup flash -#define IN_NFET_DELAY_TIME 12 // (ms) +#define IN_NFET_DELAY_TIME 0 // (ms) #define IN_NFET_ENABLE_PIN PIN4_bp #define IN_NFET_ENABLE_PORT PORTD_OUT 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. + @@ -82,6 +82,9 @@ function main() { todo) grep -E 'TODO:|FIXME:' -- **/*.[ch] **/*.md ;; + me) + memes "$@" + ;; *) exec ./bin/build-all.sh "$@" ;; @@ -96,6 +99,23 @@ function make-docs () { done } +function memes () { + # memes + shift ; shift + if [ "$UID" = "0" ]; then + echo "Okay." + for l in . . . ' 10%' ' .' . . ' 20%' ' .' . . '' "!" '' . . . ' 35%' ' .' . . . . ' 69%' '' '' '' ' (nice)' '' '' '' '\b\b\b\b\b\b \b\b\b\b\b\b.' . . ' 95%' ' .' . . ' 99%' ' .' . . ' 99.5%' ' .' . . '' ' ?' '' ' .' . . ' 99.7%' ' .' . . '' '' ' processing...' '' ' .' . . ' 99.8%' ' .' . . '' . '' '' ' urgh!' '' ' .' . . '' '' '' ' #@*%!\a' '' '' ' .' . . '' '' ' PROCESSING!' '' ' .' '' . '' . '' . '' . ' 99.9% ' '' . '' . '' . '' '' '' ' HRRRNNGH!!' '' '' ' .' '' '' . '' '' ' 99.95%' '' '' ' .' '' '' '' . '' '' " j/k NOT!" ; do + t=$( printf '%.3f' $(( 500 + $RANDOM / 32 ))e-3 ) + sleep "$t" + echo -ne "$l" + done ; echo + echo "Make your own $*, dammit!" + else + echo "Make your own $*." + fi + exit 1 +} + # go to the repo root BASEDIR=$(dirname "$0") cd "$BASEDIR" || (echo "Error: Can't cd to basedir." && exit 1) diff --git a/ui/anduril/anduril.c b/ui/anduril/anduril.c index ac8da74..5972eb2 100644 --- a/ui/anduril/anduril.c +++ b/ui/anduril/anduril.c @@ -345,6 +345,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); } diff --git a/ui/anduril/lockout-mode.c b/ui/anduril/lockout-mode.c index c3f82ea..255ab22 100644 --- a/ui/anduril/lockout-mode.c +++ b/ui/anduril/lockout-mode.c @@ -12,24 +12,30 @@ uint8_t lockout_state(Event event, uint16_t arg) { // button is being held #ifdef USE_AUX_RGB_LEDS // don't turn on during RGB aux LED configuration - if (event == EV_click7_hold) { set_level(0); } else + //if (event == EV_click7_hold) { set_level(0); } else #endif - if ((event & (B_CLICK | B_PRESS)) == (B_CLICK | B_PRESS)) { - // hold: lowest floor - // click, hold: highest floor (or manual mem level) + uint8_t click_num = event & B_COUNT; + if ( // button pressed 1st or 2nd time + ((B_CLICK | B_PRESS) == (event & (B_CLICK | B_PRESS))) + && (click_num <= 2) + ) { uint8_t lvl = cfg.ramp_floors[0]; - if (1 == (event & 0x0f)) { // first click + // hold: lowest floor + if (1 == click_num) { // 1st click if (cfg.ramp_floors[1] < lvl) lvl = cfg.ramp_floors[1]; - } else { // 2nd click or later - if (cfg.ramp_floors[1] > lvl) lvl = cfg.ramp_floors[1]; + } + // click, hold: highest floor (or manual mem level) + else { // 2nd click #ifdef USE_MANUAL_MEMORY if (cfg.manual_memory) lvl = cfg.manual_memory; + else #endif + if (cfg.ramp_floors[1] > lvl) lvl = cfg.ramp_floors[1]; } off_state_set_level(lvl); } // button was released - else if ((event & (B_CLICK | B_PRESS)) == (B_CLICK)) { + else if ((B_CLICK) == (event & (B_CLICK | B_PRESS))) { off_state_set_level(0); } #endif // ifdef USE_MOON_DURING_LOCKOUT_MODE |
