aboutsummaryrefslogtreecommitdiff
path: root/hw/lumintop
diff options
context:
space:
mode:
authorSelene ToyKeeper2023-11-27 16:08:11 -0700
committerSelene ToyKeeper2023-11-27 16:08:11 -0700
commit6cb18249d33f57acaf8e78734f4d155ebfd72165 (patch)
tree2d3cdc0c2bc9714ae7374a26380740b5bcc26e61 /hw/lumintop
parentfw3x: fixed swapped red+blue, fixed battery measurements, added police color ... (diff)
downloadanduril-6cb18249d33f57acaf8e78734f4d155ebfd72165.tar.gz
anduril-6cb18249d33f57acaf8e78734f4d155ebfd72165.tar.bz2
anduril-6cb18249d33f57acaf8e78734f4d155ebfd72165.zip
FW3X: multiple upgrades...
- upgraded to DSM: lower lows, *much* smoother ramp - made lows more efficient with underclocking - fixed party strobe being too blurry - calibrated UI speed / bogomips multiplier - added readme to document this hardware's multiple quirks
Diffstat (limited to 'hw/lumintop')
-rw-r--r--hw/lumintop/fw3x-lume1/README.md26
-rw-r--r--hw/lumintop/fw3x-lume1/anduril.h32
-rw-r--r--hw/lumintop/fw3x-lume1/hwdef.c68
-rw-r--r--hw/lumintop/fw3x-lume1/hwdef.h60
4 files changed, 132 insertions, 54 deletions
diff --git a/hw/lumintop/fw3x-lume1/README.md b/hw/lumintop/fw3x-lume1/README.md
new file mode 100644
index 0000000..8609c49
--- /dev/null
+++ b/hw/lumintop/fw3x-lume1/README.md
@@ -0,0 +1,26 @@
+# Lumintop FW3X Lume1
+
+A BLF FW3A with a new driver from LoneOceans. The new driver adds efficient
+constant-current power regulation, RGB aux LEDs, and an upgraded temperature
+sensor.
+
+## Notes of interest
+
+**Flashing firmware**: The MOSI and MISO pin are swapped, compared to a Hanklight.
+LoneOceans sent a fixed driver design to Lumintop, but the new design didn't
+get produced. So to flash firmware, swap the wires for those two pins first.
+
+**RGB mixup**: Lumintop seems to have swapped the wires for aux R and aux B.
+This was fixed in firmware in 2023-12, but some lights were fixed in hardware
+before that, so the firmware fix might cause the colors to be swapped again.
+
+**Turbo**: The driver uses regulation for levels 1 to 149, and level 150 is a
+direct-drive FET. This is by design, and the FET cannot be ramped smoothly up
+and down. Turbo is a single level at the top of the ramp, with a big sudden
+drop to the next level.
+
+**Moon**: This light has a pretty bright preflash at moon level, and the
+output is unstable so there is very visible ripple. The user can either raise
+the ramp floor to a level high enough to avoid these issues, or learn to live
+with the ripple and preflash.
+
diff --git a/hw/lumintop/fw3x-lume1/anduril.h b/hw/lumintop/fw3x-lume1/anduril.h
index 5cde5e9..b7dbc82 100644
--- a/hw/lumintop/fw3x-lume1/anduril.h
+++ b/hw/lumintop/fw3x-lume1/anduril.h
@@ -8,7 +8,6 @@
* For more information: www.loneoceans.com/labs/
* Datasheets:
* - 1634: http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-8303-8-bit-AVR-Microcontroller-tinyAVR-ATtiny1634_Datasheet.pdf
- * - 85: https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-2586-AVR-8-bit-Microcontroller-ATtiny25-ATtiny45-ATtiny85_Datasheet.pdf
*/
#define HWDEF_H lumintop/fw3x-lume1/hwdef.h
@@ -20,38 +19,25 @@
// this light has three aux LED channels: R, G, B
#define USE_AUX_RGB_LEDS
-// it has no independent LED in the button unlike emisar d4
-//#define USE_BUTTON_LED
-
// the aux LEDs are front-facing, so turn them off while main LEDs are on
#ifdef USE_INDICATOR_LED_WHILE_RAMPING
#undef USE_INDICATOR_LED_WHILE_RAMPING
#endif
-// ../../bin/level_calc.py cube 1 149 7135 0 0.5 1000, with 0 appended to the end.
-// for FET PWM (PWM2), all values are 0, except for last value of 1023
-// (with max_pwm set to 1023)
#define RAMP_SIZE 150
-//#define PWM1_LEVELS 0,0,0,0,1,1,1,1,2,2,2,3,3,4,4,5,5,6,7,7,8,9,10,11,12,13,14,15,16,17,19,20,22,23,25,26,28,30,32,34,36,38,40,42,45,47,49,52,55,58,60,63,66,70,73,76,80,83,87,91,94,98,102,107,111,115,120,124,129,134,139,144,150,155,160,166,172,178,184,190,196,203,209,216,223,230,237,244,252,259,267,275,283,291,299,308,316,325,334,343,353,362,372,382,392,402,412,423,433,444,455,466,478,489,501,513,525,538,550,563,576,589,602,616,630,644,658,672,687,701,716,731,747,762,778,794,810,827,844,861,878,895,913,930,948,967,985,1004,1023,0
-#define PWM1_LEVELS 1,1,1,1,2,2,2,2,3,3,3,4,4,5,5,6,6,7,8,8,9,10,11,12,13,14,15,16,17,18,20,21,23,24,26,27,29,31,33,35,37,39,41,43,45,48,50,53,56,58,61,64,67,70,74,77,80,84,88,91,95,99,103,108,112,116,121,125,130,135,140,145,150,156,161,167,173,178,184,191,197,203,210,217,223,230,238,245,252,260,268,275,283,292,300,308,317,326,335,344,353,363,372,382,392,402,413,423,434,445,456,467,478,490,502,514,526,538,551,563,576,589,603,616,630,644,658,672,687,702,717,732,747,763,778,794,811,827,844,861,878,895,913,931,949,967,985,1004,1023,0
-#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1023
+
+// level_calc.py 5.01 1 149 7135 0 0.2 2000 --pwm 32640
+// regulated channel: 16-bit PWM+DSM for low lows and very smooth ramp
+#define PWM1_LEVELS 0,1,2,3,4,5,6,7,9,10,12,14,17,19,22,25,29,33,37,41,46,51,57,63,70,77,85,93,103,112,123,134,146,159,172,187,203,219,237,256,276,297,319,343,368,394,422,452,483,516,551,587,625,666,708,753,799,848,900,954,1010,1069,1131,1195,1263,1333,1407,1483,1563,1647,1734,1825,1919,2017,2119,2226,2336,2451,2571,2694,2823,2957,3095,3239,3388,3542,3702,3868,4040,4217,4401,4591,4788,4992,5202,5419,5644,5876,6115,6362,6617,6880,7152,7432,7721,8018,8325,8641,8967,9302,9647,10003,10369,10745,11133,11531,11941,12363,12796,13241,13699,14169,14652,15148,15657,16180,16717,17268,17834,18414,19009,19620,20246,20888,21546,22221,22913,23621,24348,25091,25853,26634,27433,28251,29089,29946,30823,31721,32640,0
+// DD FET: 8-bit PWM (but hardware can only handle 0 and MAX)
+#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255
#define DEFAULT_LEVEL 56
#define MAX_1x7135 149
-// TODO: test if underclocking works on lume1
-//#define HALFSPEED_LEVEL 14
-//#define QUARTERSPEED_LEVEL 5
-// don't slow down at low levels; this isn't that sort of light
-// (it needs to stay at full speed for the 10-bit PWM to work)
-#ifdef USE_DYNAMIC_UNDERCLOCKING
-#undef USE_DYNAMIC_UNDERCLOCKING
-#endif
+#define HALFSPEED_LEVEL 21
+#define QUARTERSPEED_LEVEL 11
#define RAMP_SMOOTH_FLOOR 1
#define RAMP_SMOOTH_CEIL 149
-// turn on BuckBoost from level 1 to 149, but not 150
-// Level 150 is when BuckBoost is off and FET is ON 100%
-#define LED_ENABLE_PIN_LEVEL_MIN 1
-#define LED_ENABLE_PIN_LEVEL_MAX 149
// 10 33 56 79 102 125 [149]
#define RAMP_DISCRETE_FLOOR 10
#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL
@@ -68,7 +54,7 @@
#define DEFAULT_BLINK_CHANNEL CM_MAIN
// slow down party strobe; this driver can't pulse for too short a time
-#define PARTY_STROBE_ONTIME 4
+#define PARTY_STROBE_ONTIME 1
// use aux red + aux blue for police strobe
#define USE_POLICE_COLOR_STROBE_MODE
diff --git a/hw/lumintop/fw3x-lume1/hwdef.c b/hw/lumintop/fw3x-lume1/hwdef.c
index 71cd799..0a8a62e 100644
--- a/hw/lumintop/fw3x-lume1/hwdef.c
+++ b/hw/lumintop/fw3x-lume1/hwdef.c
@@ -1,10 +1,11 @@
-// FW3X Lume1 PWM helper functions
+// FW3X Lume1 helper functions
// Copyright (C) 2023 Selene ToyKeeper
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "fsm/chan-rgbaux.c"
+
void set_level_zero();
void set_level_main(uint8_t level);
@@ -21,6 +22,12 @@ Channel channels[] = {
void set_level_zero() {
+ // disable timer overflow interrupt
+ // (helps improve button press handling from Off state)
+ DSM_INTCTRL &= ~DSM_OVF_bm;
+
+ // turn off all LEDs
+ ch1_dsm_lvl = 0;
CH1_PWM = 0;
CH2_PWM = 0;
PWM_CNT = 0; // reset phase
@@ -29,19 +36,49 @@ void set_level_zero() {
// single set of LEDs with 2 stacked power channels, regulated + DD FET
void set_level_main(uint8_t level) {
- CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN); // enable regulator
+ if (level == actual_level - 1) return; // prevent flicker on no-op
- PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level);
- PWM_DATATYPE ch2_pwm = PWM_GET(pwm2_levels, level);
+ PWM1_DATATYPE ch1 = PWM1_GET(level);
+ PWM2_DATATYPE ch2 = PWM2_GET(level);
- CH1_PWM = ch1_pwm;
- CH2_PWM = ch2_pwm;
+ // set delta-sigma soft levels
+ ch1_dsm_lvl = ch1;
+
+ // set hardware PWM levels and init dsm loop
+ CH1_PWM = ch1_pwm = ch1 >> 7;
+ CH2_PWM = ch2;
+
+ // enable timer overflow interrupt so DSM can work
+ DSM_INTCTRL |= DSM_OVF_bm;
// force reset phase when turning on from zero
// (for faster, more consistent initial response)
if (! actual_level) PWM_CNT = 0;
+
+ // don't enable ch1 and ch2 at the same time
+ if (ch2) CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable regulator
+ else CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN); // enable regulator
+}
+
+// delta-sigma modulation of PWM outputs
+// happens on each Timer overflow (every 512 cpu clock cycles)
+// uses 8-bit pwm w/ 7-bit dsm (0b 0PPP PPPP PDDD DDDD)
+ISR(DSM_vect) {
+ // set new hardware values first,
+ // for best timing (reduce effect of interrupt jitter)
+ CH1_PWM = ch1_pwm;
+
+ // calculate next values, now that timing matters less
+
+ // accumulate error
+ ch1_dsm += (ch1_dsm_lvl & 0x007f);
+ // next PWM = base PWM value + carry bit
+ ch1_pwm = (ch1_dsm_lvl >> 7) + (ch1_dsm > 0x7f);
+ // clear carry bit
+ ch1_dsm &= 0x7f;
}
+
bool gradual_tick_main(uint8_t gt) {
// 150/150 is full FET + zero regulated,
// 149/150 is zero FET + full regulated,
@@ -51,10 +88,23 @@ bool gradual_tick_main(uint8_t gt) {
return true;
}
- PWM_DATATYPE pwm1 = PWM_GET(pwm1_levels, gt);
- GRADUAL_ADJUST_SIMPLE(pwm1, CH1_PWM);
+ PWM1_DATATYPE ch1 = PWM1_GET(gt);
- if (pwm1 == CH1_PWM) return true; // done
+ // adjust multiple times based on current brightness
+ // (so it adjusts faster/coarser when bright, slower/finer when dim)
+
+ // higher shift = slower/finer adjustments
+ const uint8_t shift = 9; // ((255 << 7) >> 9) = 63 max
+ uint8_t steps;
+
+ steps = ch1_dsm_lvl >> shift;
+ for (uint8_t i=0; i<=steps; i++)
+ GRADUAL_ADJUST_SIMPLE(ch1, ch1_dsm_lvl);
+
+ if ((ch1 == ch1_dsm_lvl)
+ ) {
+ return true; // done
+ }
return false; // not done yet
}
diff --git a/hw/lumintop/fw3x-lume1/hwdef.h b/hw/lumintop/fw3x-lume1/hwdef.h
index e50d8b1..bee98db 100644
--- a/hw/lumintop/fw3x-lume1/hwdef.h
+++ b/hw/lumintop/fw3x-lume1/hwdef.h
@@ -8,9 +8,9 @@
*
* Pin / Name / Function in Lume1 Rev B
* 1 PA6 Regulated PWM (PWM1B)
- * 2 PA5 B: blue aux LED (PWM0B)
+ * 2 PA5 B: blue aux LED (PWM0B) (or red)
* 3 PA4 G: green aux LED
- * 4 PA3 R: red aux LED
+ * 4 PA3 R: red aux LED (or blue)
* 5 PA2 e-switch (PCINT2)
* 6 PA1 Jumper 1
* 7 PA0 Jumper 2
@@ -54,29 +54,38 @@ enum CHANNEL_MODES {
#define CHANNEL_MODES_ENABLED 0b0000000000000001
-#define PWM_CHANNELS 2 // old, remove this
-
-// Added for Lume1 Buck Boost Driver
-#define PWM_BITS 16 // 0 to 1023 at 3.9 kHz, not 0 to 255 at 15.6 kHz
-#define PWM_GET PWM_GET16
+#define PWM_BITS 16 // 0 to 32640 (0 to 255 PWM + 0 to 127 DSM) at constant kHz
#define PWM_DATATYPE uint16_t
#define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255
#define PWM1_DATATYPE uint16_t // regulated ramp
-#define PWM2_DATATYPE uint16_t // DD FET ramp
+#define PWM1_GET(x) PWM_GET16(pwm1_levels, x)
+#define PWM2_DATATYPE uint8_t // DD FET ramp
+#define PWM2_GET(x) PWM_GET8(pwm2_levels, x)
// PWM parameters of both channels are tied together because they share a counter
#define PWM_TOP ICR1 // holds the TOP value for variable-resolution PWM
-#define PWM_TOP_INIT 1023
-#define PWM_CNT TCNT1 // for dynamic PWM, reset phase
+#define PWM_TOP_INIT 255
+#define PWM_CNT TCNT1 // for checking / resetting phase
+// (max is (255 << 7), because it's 8-bit PWM plus 7 bits of DSM)
+#define DSM_TOP (255<<7) // 15-bit resolution leaves 1 bit for carry
+
+// timer interrupt for DSM
+#define DSM_vect TIMER1_OVF_vect
+#define DSM_INTCTRL TIMSK
+#define DSM_OVF_bm (1<<TOIE1)
-// regulated channel
+#define DELAY_FACTOR 85 // less time in delay() because more time spent in interrupts
+
+// regulated channel uses PWM+DSM
+uint16_t ch1_dsm_lvl;
+uint8_t ch1_pwm, ch1_dsm;
#define CH1_PIN PA6 // pin 1, Buck Boost CTRL pin or 7135-eqv PWM
#define CH1_PWM OCR1B // OCR1B is the output compare register for PA6
#define CH1_ENABLE_PIN PA7 // pin 20, BuckBoost Enable
#define CH1_ENABLE_PORT PORTA // control port for PA7
-// DD FET channel
-#define CH2_PIN PB3 // pin 16, FET PWM Pin, but only used as on (1023) or off (0)
+// DD FET channel is on/off only (PWM=0, or PWM=MAX)
+#define CH2_PIN PB3 // pin 16, FET PWM Pin, but only used as on (255) or off (0)
#define CH2_PWM OCR1A // OCR1A is the output compare register for PB3
/* // For Jumpers X1 to X4, no SW support yet
@@ -174,24 +183,31 @@ inline void hwdef_setup() {
PUEC = (1 << JUMPER4_PIN);
*/
- // configure PWM for 10 bit at 3.9kHz
+ // configure PWM
// Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter
// pre-scale for timer: N = 1
- // WGM1[3:0]: 0,0,1,1: PWM, Phase Correct, 10-bit (DS table 12-5)
+ // PWM for both channels
+ // WGM1[3:0]: 1,0,1,0: PWM, Phase Correct, adjustable (DS table 12-5)
+ // WGM1[3:0]: 1,1,1,0: PWM, Fast, adjustable (DS table 12-5)
// CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6)
// COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4)
// COM1B[1:0]: 1,0: PWM OC1B in the normal direction (DS table 12-4)
- TCCR1A = (1<<WGM11) | (1<<WGM10) // 10-bit (TOP=0x03FF) (DS table 12-5)
- | (1<<COM1A1) | (0<<COM1A0) // PWM 1A Clear OC1A on Compare Match
- | (1<<COM1B1) | (0<<COM1B0) // PWM 1B Clear OC1B on Compare Match
- ;
- TCCR1B = (0<<CS12) | (0<<CS11) | (1<<CS10) // clk/1 (no prescaling) (DS table 12-6)
- | (0<<WGM13) | (0<<WGM12) // PWM, Phase Correct, 10-bit
- ;
+ TCCR1A = (1<<WGM11) | (0<<WGM10) // adjustable PWM (TOP=ICR1) (DS table 12-5)
+ | (1<<COM1A1) | (0<<COM1A0) // PWM 1A in normal direction (DS table 12-4)
+ | (1<<COM1B1) | (0<<COM1B0) // PWM 1B in normal direction (DS table 12-4)
+ ;
+ TCCR1B = (0<<CS12) | (0<<CS11) | (1<<CS10) // clk/1 (no prescaling) (DS table 12-6)
+ //| (1<<WGM13) | (1<<WGM12) // fast adjustable PWM (DS table 12-5)
+ | (1<<WGM13) | (0<<WGM12) // phase-correct adjustable PWM (DS table 12-5)
+ ;
// set PWM resolution
PWM_TOP = PWM_TOP_INIT;
+ // set up interrupt for delta-sigma modulation
+ // (moved to hwdef.c functions so it can be enabled/disabled based on ramp level)
+ //DSM_INTCTRL |= DSM_OVF_bm; // interrupt once for each timer cycle
+
// set up e-switch
SWITCH_PUE = (1 << SWITCH_PIN); // pull-up for e-switch
SWITCH_PCMSK = (1 << SWITCH_PCINT); // enable pin change interrupt