aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hwdef-Emisar_D4Sv2-tintramp.h22
-rw-r--r--spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp.h63
-rw-r--r--spaghetti-monster/fsm-ramping.c108
-rw-r--r--spaghetti-monster/fsm-ramping.h8
4 files changed, 121 insertions, 80 deletions
diff --git a/hwdef-Emisar_D4Sv2-tintramp.h b/hwdef-Emisar_D4Sv2-tintramp.h
index 1b24238..2b36ed4 100644
--- a/hwdef-Emisar_D4Sv2-tintramp.h
+++ b/hwdef-Emisar_D4Sv2-tintramp.h
@@ -40,11 +40,12 @@
#define ATTINY 1634
#include <avr/io.h>
-#define PWM_CHANNELS 2 // 1 for main LEDs, 1 for 2nd LEDs
+#define PWM_CHANNELS 1 // 1 virtual channel (1 for main LEDs + 1 for 2nd LEDs)
#define PWM_BITS 12 // 0 to 4095 at 1 kHz, not 0 to 255 at 16 kHz
#define PWM_TOP 4095
-// TODO: dynamic PWM with tint ramping
-//#define USE_DYN_PWM // dynamic frequency and speed
+// dynamic PWM with tint ramping
+#define USE_DYN_PWM // dynamic frequency and speed
+#define PWM_DATATYPE2 uint16_t // doesn't need 32-bit math
#define SWITCH_PIN PA7 // pin 20
#define SWITCH_PCINT PCINT7 // pin 20 pin change interrupt
@@ -53,15 +54,20 @@
#define SWITCH_PORT PINA // PINA or PINB or PINC
#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0]
+// usually PWM1_LVL would be a hardware register, but we need to abstract
+// it out to a soft brightness value, in order to handle tint ramping
+// (this allows smooth thermal regulation to work, and makes things
+// otherwise simpler and easier)
+uint16_t PWM1_LVL;
#define PWM1_PIN PB3 // pin 16, Opamp reference
-#define PWM1_LVL OCR1A // OCR1A is the output compare register for PB3
+#define TINT1_LVL OCR1A // OCR1A is the output compare register for PB3
#define PWM1_CNT TCNT1 // for dynamic PWM, reset phase
#define PWM2_PIN PA6 // pin 1, 2nd LED Opamp reference
-#define PWM2_LVL OCR1B // OCR1B is the output compare register for PA6
+#define TINT2_LVL OCR1B // OCR1B is the output compare register for PA6
-#define PWM3_PIN PC0 // pin 15, DD FET PWM
-#define PWM3_LVL OCR0A // OCR0A is the output compare register for PC0
+//#define PWM3_PIN PC0 // pin 15, DD FET PWM
+//#define PWM3_LVL OCR0A // OCR0A is the output compare register for PC0
// PWM parameters of both channels are tied together because they share a counter
#define PWM1_TOP ICR1 // holds the TOP value for for variable-resolution PWM
@@ -120,7 +126,7 @@
// ... so just hardcode it in each hwdef file instead
inline void hwdef_setup() {
// enable output ports
- DDRC = (1 << PWM3_PIN);
+ //DDRC = (1 << PWM3_PIN);
DDRB = (1 << PWM1_PIN);
DDRA = (1 << PWM2_PIN)
| (1 << AUXLED_R_PIN)
diff --git a/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp.h b/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp.h
index f3a6cdd..c808cd5 100644
--- a/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp.h
+++ b/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp.h
@@ -1,19 +1,12 @@
-// Noctigon K9.3 config options for Anduril
-#define MODEL_NUMBER "0261"
-#include "hwdef-Noctigon_K9.3.h"
+// Emisar D4S V2 tint-ramping config options for Anduril (based on Noctigon K9.3)
+#define MODEL_NUMBER "0135"
+#include "hwdef-Emisar_D4Sv2-tintramp.h"
#include "hank-cfg.h"
// ATTINY: 1634
-// this model requires some special code
-#define OVERRIDES_FILE cfg-noctigon-k9.3.c
-#define OVERRIDE_SET_LEVEL
-#define OVERRIDE_GRADUAL_TICK
-inline void set_level_override(uint8_t level);
-
// this light has three aux LED channels: R, G, B
#define USE_AUX_RGB_LEDS
// the aux LEDs are front-facing, so turn them off while main LEDs are on
-//#define USE_AUX_RGB_LEDS_WHILE_ON
// it also has an independent LED in the button
#define USE_BUTTON_LED
// TODO: the whole "indicator LED" thing needs to be refactored into
@@ -25,24 +18,22 @@ inline void set_level_override(uint8_t level);
// has two channels of independent LEDs
#define USE_TINT_RAMPING
-// ... but it doesn't make sense to ramp between; only toggle
-#define TINT_RAMP_TOGGLE_ONLY
+// how much to increase total brightness at middle tint
+// (0 = 100% brightness, 64 = 200% brightness)
+#define TINT_RAMPING_CORRECTION 0 // none, linear regulator doesn't need it
// main LEDs
-// max regulated: ~1750 lm
-// FET: ~8000 lm
+// output: unknown, 2000 lm?
+// FET: absent / unused?
// 2nd LEDs
-// max regulated: ~1500 lm
-// maxreg at 120: level_calc.py cube 2 150 7135 0 2.5 1740 FET 1 10 3190
+// output: unknown, 2000 lm?
#define RAMP_LENGTH 150
-// main LEDs
-#define PWM1_LEVELS 0,0,1,1,2,2,3,3,4,4,5,6,7,8,9,10,11,13,14,15,17,19,20,22,24,26,28,30,33,35,38,40,43,46,49,52,55,59,62,66,70,74,78,82,86,91,96,100,105,111,116,121,127,133,139,145,151,158,165,172,179,186,193,201,209,217,225,234,243,251,261,270,280,289,299,310,320,331,342,353,364,376,388,400,412,425,438,451,464,478,492,506,521,536,551,566,582,597,614,630,647,664,681,699,717,735,754,772,792,811,831,851,871,892,913,935,956,978,1001,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,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,22,51,79,109,138,168,198,229,260,292,324,357,390,423,457,492,527,562,598,634,671,708,746,784,822,861,901,941,982,1023
-// 2nd LEDs
-#define PWM3_LEVELS 0,0,1,1,2,2,3,3,4,4,5,5,6,7,8,9,10,11,12,13,15,16,17,18,20,21,23,24,26,27,29,31,33,35,37,39,41,43,45,48,50,53,55,58,61,63,66,69,72,75,79,82,85,89,92,96,100,104,108,112,116,120,125,129,134,138,143,148,153,158,163,169,174,180,185,191,197,203,209,215,222,228,235,242,248,255,263,270,277,285,292,300,308,316,324,333,341,350,359,368,377,386,395,405,414,424,434,444,454,465,475,486,497,508,519,531,542,554,566,578,590,603,615,628,641,654,667,680,694,708,722,736,750,765,779,794,809,825,840,856,872,888,904,920,937,954,971,988,1005,1023
-#define DEFAULT_LEVEL 46
-#define MAX_1x7135 120
-#define MAX_Nx7135 MAX_1x7135
+// level_calc.py 5.01 1 150 7135 1 0.2 2000 --pwm dyn:80:16383:255
+// abstract ramp (power is split between both sets of LEDs)
+#define PWM1_LEVELS 1,1,1,2,2,2,3,4,4,5,6,6,7,8,9,10,12,13,14,16,17,19,21,23,25,27,29,31,33,36,38,41,44,47,50,53,56,59,62,66,69,73,76,80,83,87,90,94,98,101,104,108,111,114,117,120,122,125,127,129,130,131,132,132,132,131,130,128,125,122,118,113,108,101,93,84,75,63,51,37,22,23,24,26,27,28,29,30,32,33,34,36,37,39,40,42,44,46,47,49,51,53,55,57,60,62,64,66,69,71,74,77,80,82,85,88,91,95,98,101,105,108,112,116,120,123,128,132,136,140,145,149,154,159,164,169,174,180,185,191,197,203,209,215,221,228,234,241,248,255
+#define PWM_TOPS 16383,13682,10747,15453,11909,8095,12781,14776,12231,13453,14029,11886,12249,12339,12249,12032,12939,12468,11964,12288,11697,11793,11770,11661,11489,11268,11012,10729,10425,10411,10063,9968,9833,9668,9479,9273,9054,8825,8590,8482,8233,8097,7843,7691,7439,7278,7033,6869,6702,6470,6245,6085,5872,5668,5470,5280,5056,4882,4678,4485,4268,4064,3872,3664,3468,3260,3066,2863,2652,2457,2257,2054,1866,1659,1453,1248,1060,847,651,448,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
+#define DEFAULT_LEVEL 70
+#define MAX_1x7135 150
#define HALFSPEED_LEVEL 10
#define QUARTERSPEED_LEVEL 2
@@ -50,9 +41,9 @@ inline void set_level_override(uint8_t level);
//#define DEFAULT_MANUAL_MEMORY DEFAULT_LEVEL
//#define DEFAULT_MANUAL_MEMORY_TIMER 10
-#define RAMP_SMOOTH_FLOOR 3 // level 1 is unreliable (?)
-#define RAMP_SMOOTH_CEIL 120
-// 10, 28, [46], 65, 83, 101, [120]
+#define RAMP_SMOOTH_FLOOR 10 // level 1 is unreliable (?)
+#define RAMP_SMOOTH_CEIL 130
+// 10, 30, 50, [70], 90, 110, [130]
#define RAMP_DISCRETE_FLOOR 10
#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL
#define RAMP_DISCRETE_STEPS 7
@@ -62,21 +53,29 @@ inline void set_level_override(uint8_t level);
#define SIMPLE_UI_CEIL RAMP_DISCRETE_CEIL
#define SIMPLE_UI_STEPS 5
-// stop panicking at ~25% power or ~1000 lm
-#define THERM_FASTER_LEVEL 100
-#define MIN_THERM_STEPDOWN DEFAULT_LEVEL
-//#define THERM_NEXT_WARNING_THRESHOLD 16 // accumulate less error before adjusting
-//#define THERM_RESPONSE_MAGNITUDE 128 // bigger adjustments
+// stop panicking at ~1500 lm
+#define THERM_FASTER_LEVEL 140
+#define MIN_THERM_STEPDOWN 80
// use the brightest setting for strobe
#define STROBE_BRIGHTNESS MAX_LEVEL
// slow down party strobe; this driver can't pulse for 1ms or less
#define PARTY_STROBE_ONTIME 2
+// the default of 26 looks a bit flat, so increase it
+#define CANDLE_AMPLITUDE 40
+
+// the power regulator is a bit slow, so push it harder for a quick response from off
+#define DEFAULT_JUMP_START_LEVEL 21
+#define BLINK_BRIGHTNESS DEFAULT_LEVEL
#define BLINK_ONCE_TIME 12 // longer blink, since main LEDs are slow
#define THERM_CAL_OFFSET 5
+#ifdef BLINK_AT_RAMP_MIDDLE
+#undef BLINK_AT_RAMP_MIDDLE
+#endif
+
// for consistency with KR4 (not otherwise necessary though)
#define USE_SOFT_FACTORY_RESET
diff --git a/spaghetti-monster/fsm-ramping.c b/spaghetti-monster/fsm-ramping.c
index 54ca45c..c3a5147 100644
--- a/spaghetti-monster/fsm-ramping.c
+++ b/spaghetti-monster/fsm-ramping.c
@@ -89,6 +89,10 @@ void set_level(uint8_t level) {
#if PWM_CHANNELS >= 4
PWM4_LVL = 0;
#endif
+ #ifdef USE_TINT_RAMPING
+ TINT1_LVL = 0;
+ TINT2_LVL = 0;
+ #endif
// disable the power channel, if relevant
#ifdef LED_ENABLE_PIN
LED_ENABLE_PORT &= ~(1 << LED_ENABLE_PIN);
@@ -117,44 +121,6 @@ void set_level(uint8_t level) {
// PWM array index = level - 1
level --;
- #ifdef USE_TINT_RAMPING
- #ifndef TINT_RAMPING_CORRECTION
- #define TINT_RAMPING_CORRECTION 26 // 140% brightness at middle tint
- #endif
- // calculate actual PWM levels based on a single-channel ramp
- // and a global tint value
- uint8_t brightness = PWM_GET(pwm1_levels, level);
- uint8_t warm_PWM, cool_PWM;
-
- // auto-tint modes
- uint8_t mytint;
- #if 1
- // perceptual by ramp level
- if (tint == 0) { mytint = 255 * (uint16_t)level / RAMP_SIZE; }
- else if (tint == 255) { mytint = 255 - (255 * (uint16_t)level / RAMP_SIZE); }
- #else
- // linear with power level
- //if (tint == 0) { mytint = brightness; }
- //else if (tint == 255) { mytint = 255 - brightness; }
- #endif
- // stretch 1-254 to fit 0-255 range (hits every value except 98 and 198)
- else { mytint = (tint * 100 / 99) - 1; }
-
- // middle tints sag, so correct for that effect
- uint16_t base_PWM = brightness;
- // correction is only necessary when PWM is fast
- if (level > HALFSPEED_LEVEL) {
- base_PWM = brightness
- + ((((uint16_t)brightness) * TINT_RAMPING_CORRECTION / 64) * triangle_wave(mytint) / 255);
- }
-
- cool_PWM = (((uint16_t)mytint * (uint16_t)base_PWM) + 127) / 255;
- warm_PWM = base_PWM - cool_PWM;
-
- PWM1_LVL = warm_PWM;
- PWM2_LVL = cool_PWM;
- #else // ifdef USE_TINT_RAMPING
-
#if PWM_CHANNELS >= 1
PWM1_LVL = PWM_GET(pwm1_levels, level);
#endif
@@ -168,8 +134,6 @@ void set_level(uint8_t level) {
PWM4_LVL = PWM_GET(pwm4_levels, level);
#endif
- #endif // ifdef USE_TINT_RAMPING
-
#ifdef USE_DYN_PWM
uint16_t top = PWM_GET(pwm_tops, level);
#ifdef PWM1_CNT
@@ -214,6 +178,10 @@ void set_level(uint8_t level) {
}
#endif
}
+ #ifdef USE_TINT_RAMPING
+ update_tint();
+ #endif
+
#ifdef PWM1_CNT
prev_level = api_level;
#endif
@@ -289,6 +257,9 @@ void gradual_tick() {
{
actual_level = gt + 1;
}
+ #ifdef USE_TINT_RAMPING
+ update_tint();
+ #endif
#ifdef USE_DYNAMIC_UNDERCLOCKING
auto_clock_speed();
#endif
@@ -296,5 +267,62 @@ void gradual_tick() {
#endif // ifdef OVERRIDE_GRADUAL_TICK
#endif // ifdef USE_SET_LEVEL_GRADUALLY
+
+#ifdef USE_TINT_RAMPING
+void update_tint() {
+ #ifndef TINT_RAMPING_CORRECTION
+ #define TINT_RAMPING_CORRECTION 26 // 140% brightness at middle tint
+ #endif
+
+ // calculate actual PWM levels based on a single-channel ramp
+ // and a global tint value
+ //PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level);
+ PWM_DATATYPE brightness = PWM1_LVL;
+ PWM_DATATYPE warm_PWM, cool_PWM;
+
+ // auto-tint modes
+ uint8_t mytint;
+ uint8_t level = actual_level - 1;
+ #if 1
+ // perceptual by ramp level
+ if (tint == 0) { mytint = 255 * (uint16_t)level / RAMP_SIZE; }
+ else if (tint == 255) { mytint = 255 - (255 * (uint16_t)level / RAMP_SIZE); }
+ #else
+ // linear with power level
+ //if (tint == 0) { mytint = brightness; }
+ //else if (tint == 255) { mytint = 255 - brightness; }
+ #endif
+ // stretch 1-254 to fit 0-255 range (hits every value except 98 and 198)
+ else { mytint = (tint * 100 / 99) - 1; }
+
+ // middle tints sag, so correct for that effect
+ PWM_DATATYPE2 base_PWM = brightness;
+ // correction is only necessary when PWM is fast
+ #if defined(TINT_RAMPING_CORRECTION) && (TINT_RAMPING_CORRECTION > 0)
+ if (level > HALFSPEED_LEVEL) {
+ base_PWM = brightness
+ + ((((PWM_DATATYPE2)brightness) * TINT_RAMPING_CORRECTION / 64) * triangle_wave(mytint) / 255);
+ }
+ #endif
+
+ cool_PWM = (((PWM_DATATYPE2)mytint * (PWM_DATATYPE2)base_PWM) + 127) / 255;
+ warm_PWM = base_PWM - cool_PWM;
+
+ TINT1_LVL = warm_PWM;
+ TINT2_LVL = cool_PWM;
+
+ // disable the power channel, if relevant
+ #ifdef LED_ENABLE_PIN
+ if (! warm_PWM)
+ LED_ENABLE_PORT &= ~(1 << LED_ENABLE_PIN);
+ #endif
+ #ifdef LED2_ENABLE_PIN
+ if (! cool_PWM)
+ LED2_ENABLE_PORT &= ~(1 << LED2_ENABLE_PIN);
+ #endif
+}
+#endif // ifdef USE_TINT_RAMPING
+
+
#endif // ifdef USE_RAMPING
#endif
diff --git a/spaghetti-monster/fsm-ramping.h b/spaghetti-monster/fsm-ramping.h
index 7a4fa3b..d8aad18 100644
--- a/spaghetti-monster/fsm-ramping.h
+++ b/spaghetti-monster/fsm-ramping.h
@@ -42,6 +42,10 @@ inline void set_level_gradually(uint8_t lvl);
void gradual_tick();
#endif
+#ifdef USE_TINT_RAMPING
+void update_tint();
+#endif
+
// auto-detect the data type for PWM tables
#ifndef PWM_BITS
#define PWM_BITS 8
@@ -49,10 +53,14 @@ void gradual_tick();
#endif
#if PWM_BITS <= 8
#define PWM_DATATYPE uint8_t
+#define PWM_DATATYPE2 uint16_t
#define PWM_TOP 255
#define PWM_GET(x,y) pgm_read_byte(x+y)
#else
#define PWM_DATATYPE uint16_t
+#ifndef PWM_DATATYPE2
+#define PWM_DATATYPE2 uint32_t
+#endif
#ifndef PWM_TOP
#define PWM_TOP 1023 // 10 bits by default
#endif
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.