aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSelene ToyKeeper2023-11-27 16:08:11 -0700
committerSelene ToyKeeper2023-11-27 16:08:11 -0700
commit6cb18249d33f57acaf8e78734f4d155ebfd72165 (patch)
tree2d3cdc0c2bc9714ae7374a26380740b5bcc26e61
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
-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
If you find this content useful please consider a small donation via bitcoin: bitcoin:1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2?amount=0.001&message=Donation Scraping git contents via cgit is very resource intensive. The continued hosting of these git repositories is entirely financed by your bitcoin contributions. For donations of a least 1 mBTC you include your IP address in the message of your bitcoin donation. This will remove this message in the future for requests from your IP, which will significantly reduce token usage. In any case, any contributions to bitcoin address 1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2 are very welcome. Thanks in advance for you contribution to a self-sustaining ecosystem.