aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbin/build.sh13
-rwxr-xr-xbin/level_calc.py101
-rw-r--r--hwdef-Noctigon_KR4.h16
-rw-r--r--spaghetti-monster/anduril/MODELS2
-rw-r--r--spaghetti-monster/anduril/anduril-manual.txt4
-rwxr-xr-xspaghetti-monster/anduril/build-all.sh44
-rw-r--r--spaghetti-monster/anduril/cfg-emisar-d18-219.h4
-rw-r--r--spaghetti-monster/anduril/cfg-noctigon-k9.3-219.h18
-rw-r--r--spaghetti-monster/anduril/cfg-noctigon-kr4-219.h8
-rw-r--r--spaghetti-monster/anduril/cfg-noctigon-kr4-219b.h13
-rw-r--r--spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h25
-rw-r--r--spaghetti-monster/anduril/cfg-noctigon-kr4.h55
-rw-r--r--spaghetti-monster/anduril/config-default.h14
-rw-r--r--spaghetti-monster/anduril/factory-reset.c2
-rw-r--r--spaghetti-monster/anduril/misc.c7
-rw-r--r--spaghetti-monster/anduril/off-mode.c13
-rw-r--r--spaghetti-monster/anduril/ramp-mode.c3
-rw-r--r--spaghetti-monster/fsm-ramping.c29
-rw-r--r--spaghetti-monster/fsm-ramping.h8
19 files changed, 316 insertions, 63 deletions
diff --git a/bin/build.sh b/bin/build.sh
index c733320..aa983c8 100755
--- a/bin/build.sh
+++ b/bin/build.sh
@@ -12,9 +12,18 @@ fi
export ATTINY=$1 ; shift
export PROGRAM=$1 ; shift
-# path to the Atmel ATtiny device family pack: (for attiny1616 support)
+# give a more useful error message when AVR DFP is needed but not installed
+# (Atmel ATtiny device family pack, for attiny1616 support)
# http://packs.download.atmel.com/
-if [ -z "$ATTINY_DFP" ]; then export ATTINY_DFP=~/avr/attiny_dfp ; fi
+#if [ -z "$ATTINY_DFP" ]; then export ATTINY_DFP=~/avr/attiny_dfp ; fi
+SERIES1=' 416 417 816 817 1616 1617 3216 3217 '
+if [[ $SERIES1 =~ " $ATTINY " ]]; then
+ if [ -z "$ATTINY_DFP" ]; then
+ echo "ATtiny$ATTINY support requires Atmel attiny device family pack."
+ echo "More info is in /README under tiny1616 support."
+ exit 1
+ fi
+fi
export MCU=attiny$ATTINY
export CC=avr-gcc
diff --git a/bin/level_calc.py b/bin/level_calc.py
index a780405..2998b44 100755
--- a/bin/level_calc.py
+++ b/bin/level_calc.py
@@ -9,11 +9,29 @@ interactive = False
#ramp_shape = 'cube'
max_pwm = 255
+max_pwms = []
+dyn_pwm = False
def main(args):
"""Calculates PWM levels for visually-linear steps.
"""
+ cli_answers = []
+ global max_pwm, max_pwms, dyn_pwm
+ pwm_arg = str(max_pwm)
+
+ i = 0
+ while i < len(args):
+ a = args[i]
+ if a in ('--pwm',):
+ i += 1
+ pwm_arg = args[i]
+ else:
+ #print('unrecognized option: "%s"' % (a,))
+ cli_answers.append(a)
+
+ i += 1
+
# Get parameters from the user
questions_main = [
(str, 'ramp_shape', 'cube', 'Ramp shape? [cube, square, fifth, seventh, ninth, log, N.NN]'),
@@ -30,7 +48,7 @@ def main(args):
def ask(questions, ans):
for typ, name, default, text in questions:
- value = get_value(text, default, args)
+ value = get_value(text, default, cli_answers)
if not value:
value = default
else:
@@ -40,14 +58,33 @@ def main(args):
answers = Empty()
ask(questions_main, answers)
- global ramp_shape
+ if pwm_arg:
+ if pwm_arg.startswith('dyn:'):
+ dyn_pwm = True
+ parts = pwm_arg.split(':')
+ dpwm_steps = int(parts[1])
+ dpwn_max = int(parts[2])
+ dpwn_min = int(parts[3])
+ max_pwms = [dpwn_min] * answers.num_levels
+ for i in range(dpwm_steps):
+ span = dpwn_max - dpwn_min
+ x = dpwn_min + (span * (float(dpwm_steps - i) / dpwm_steps))
+ max_pwms[i] = int(x)
+ max_pwm = dpwn_min
+
+ else:
+ val = int(pwm_arg)
+ max_pwm = val
+ max_pwms = [val] * answers.num_levels
+
+ global ramp_shape
ramp_shape = answers.ramp_shape
channels = []
- if not args:
+ if not answers:
print('Describe the channels in order of lowest to highest power.')
for chan_num in range(answers.num_channels):
- if not args:
+ if not answers:
print('===== Channel %s =====' % (chan_num+1))
chan = Empty()
chan.pwm_max = max_pwm
@@ -119,32 +156,60 @@ def multi_pwm(answers, channels):
channel.modes.append(0.0)
# Normal non-turbo mode or non-FET turbo
else:
- channel.modes.append(channel.pwm_max)
+ channel.modes.append(max_pwms[i])
# This channel's active ramp-up range
#elif goal_lm > (channel.prev_lm + channel.lm_min):
elif goal_lm > channel.prev_lm:
# assume 7135 channels all add together
if channel.type == '7135':
- diff = channel.lm_max - channel.lm_min
+ lm_avail = channel.lm_max - channel.lm_min
# assume FET channel gets higher output on its own
elif channel.type == 'FET':
- diff = channel.lm_max - channel.prev_lm - channel.lm_min
-
- needed = goal_lm - channel.prev_lm - channel.lm_min
-
- ratio = needed / diff * (channel.pwm_max-channel.pwm_min)
- pwm = max(0, ratio + channel.pwm_min)
+ lm_avail = channel.lm_max - channel.prev_lm - channel.lm_min
+
+ lm_needed = goal_lm - channel.prev_lm - channel.lm_min
+
+ pwm_top = max_pwms[i]
+ pwm_avail = pwm_top - channel.pwm_min
+ pwm_needed = pwm_avail * lm_needed / lm_avail
+ if dyn_pwm and (pwm_top > max_pwm):
+ this_step = max(1, math.floor(pwm_needed))
+ next_step = this_step + 1
+ fpart = pwm_needed - math.floor(pwm_needed)
+ correction = (next_step - fpart) / next_step
+ pwm_top = int(pwm_avail * correction) + channel.pwm_min
+ pwm_avail = pwm_top - channel.pwm_min
+ pwm_needed = pwm_avail * lm_needed / lm_avail
+ max_pwms[i] = pwm_top
+ # save the result
+ pwm = max(0, pwm_needed + channel.pwm_min)
channel.modes.append(pwm)
+ # how close did we get?
+ #ptop = int(round(pwm - channel.pwm_min))
+ #pbot = pwm_top - channel.pwm_min
+ #print('%.3f%% needed, %.3f%% actual' % (
+ # 100.0 * lm_needed / lm_avail,
+ # 100.0 * ptop / pbot,
+ # ))
# This channel isn't active yet, output too low
else:
channel.modes.append(0)
# Show individual levels in detail
+ prev_ratios = [0.0] * len(channels)
for i in range(answers.num_levels):
goal_vis, goal_lm = goals[i]
pwms = []
- for channel in channels:
- pwms.append('%.2f/%i' % (channel.modes[i], channel.pwm_max))
+ for c, channel in enumerate(channels):
+ top = channel.modes[i] - channel.pwm_min
+ if top < 0: top = 0
+ bot = max_pwms[i] - channel.pwm_min
+ ratio = 100 * (int(round(top)) / float(bot))
+ top, bot = channel.modes[i], max_pwms[i]
+ pwms.append('%.2f/%i (%.3f%%)' % (top, bot, ratio))
+ if (ratio < prev_ratios[c]) and (ratio > 0):
+ pwms.append('WARN')
+ prev_ratios[c] = ratio
print('%i: visually %.2f (%.2f lm): %s' %
(i+1, goal_vis, goal_lm, ', '.join(pwms)))
@@ -154,15 +219,19 @@ def multi_pwm(answers, channels):
(cnum+1,
','.join([str(int(round(i))) for i in channel.modes])))
+ # Show PFM values (PWM TOP)
+ if dyn_pwm:
+ print('PWM_TOP: %s' % (','.join(str(x) for x in max_pwms)))
+
# Show highest level for each channel before next channel starts
for cnum, channel in enumerate(channels[:-1]):
prev = 0
i = 1
while (i < answers.num_levels) \
- and (channel.modes[i] >= channel.modes[i-1]) \
and (channels[cnum+1].modes[i] == 0):
+ #and (channel.modes[i] >= channel.modes[i-1]) \
i += 1
- print('Ch%i max: %i (%.2f/%s)' % (cnum, i, channel.modes[i-1], max_pwm))
+ print('Ch%i max: %i (%.2f/%s)' % (cnum, i, channel.modes[i-1], max_pwms[i]))
def get_value(text, default, args):
diff --git a/hwdef-Noctigon_KR4.h b/hwdef-Noctigon_KR4.h
index feb49e6..eee4e08 100644
--- a/hwdef-Noctigon_KR4.h
+++ b/hwdef-Noctigon_KR4.h
@@ -41,8 +41,9 @@
#include <avr/io.h>
#define PWM_CHANNELS 2
-#define PWM_BITS 10 // 0 to 1023 at 4 kHz, not 0 to 255 at 16 kHz
-#define PWM_TOP 1023
+#define PWM_BITS 16 // data type needs 16 bits, not 8
+#define PWM_TOP 255 // highest value used in top half of ramp
+#define USE_DYN_PWM // dynamic frequency and speed
#define SWITCH_PIN PB2 // pin 17
#define SWITCH_PCINT PCINT10 // pin 17 pin change interrupt
@@ -58,10 +59,14 @@
#define PWM1_PIN PB3 // pin 16, Opamp reference
#define PWM1_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, DD FET PWM
#define PWM2_LVL OCR1B // OCR1B is the output compare register for PA6
+// 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
+
#define LED_ENABLE_PIN PB0 // pin 19, Opamp power
#define LED_ENABLE_PORT PORTB // control port for PB0
@@ -131,14 +136,17 @@ inline void hwdef_setup() {
// 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)
+ 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)
- | (0<<WGM13) | (0<<WGM12) // phase-correct PWM (DS table 12-5)
+ | (1<<WGM13) | (0<<WGM12) // phase-correct adjustable PWM (DS table 12-5)
;
+ // set PWM resolution
+ PWM1_TOP = PWM_TOP;
+
// set up e-switch
//PORTB = (1 << SWITCH_PIN); // TODO: configure PORTA / PORTB / PORTC?
PUEB = (1 << SWITCH_PIN); // pull-up for e-switch
diff --git a/spaghetti-monster/anduril/MODELS b/spaghetti-monster/anduril/MODELS
index 27241ef..f4a0531 100644
--- a/spaghetti-monster/anduril/MODELS
+++ b/spaghetti-monster/anduril/MODELS
@@ -16,11 +16,13 @@ Model numbers:
0211 noctigon-kr4
0212 noctigon-kr4-nofet
0213 noctigon-kr4-219
+0214 noctigon-kr4-219b
0251 noctigon-k1
0252 noctigon-k1-sbt90
0253 noctigon-k1-12v
0261 noctigon-k9.3
0262 noctigon-k9.3-nofet
+0263 noctigon-k9.3-219
0311 fw3a
0312 fw3a-219
0313 fw3a-nofet
diff --git a/spaghetti-monster/anduril/anduril-manual.txt b/spaghetti-monster/anduril/anduril-manual.txt
index e3b3cf5..57f1986 100644
--- a/spaghetti-monster/anduril/anduril-manual.txt
+++ b/spaghetti-monster/anduril/anduril-manual.txt
@@ -182,13 +182,15 @@ Memory determines which brightness level the light goes to with 1 click
from off. There are three types of brightness memory to choose from:
- Automatic: Always uses the last-ramped brightness.
+ (does not memorize levels accessed by a shortcut,
+ like turbo, 2C for ceiling, or 1H-from-off for floor)
- Manual: Always uses the user's saved brightness.
- Hybrid: Uses the automatic memory brightness if the light was only
off for a short time, or resets to the manual memory level if it was
off for a longer time.
- The timer for this is configurable from 0 to 255 minutes.
+ The timer for this is configurable from 0 to ~140 minutes.
Another way to think of it is: There are three styles of memory for the
last-ramped brightness level...
diff --git a/spaghetti-monster/anduril/build-all.sh b/spaghetti-monster/anduril/build-all.sh
index 42a36fd..b9f6d15 100755
--- a/spaghetti-monster/anduril/build-all.sh
+++ b/spaghetti-monster/anduril/build-all.sh
@@ -1,15 +1,57 @@
#!/bin/sh
+# Usage: build-all.sh [pattern]
+# If pattern given, only build targets which match.
+
+if [ ! -z "$1" ]; then
+ SEARCH="$1"
+fi
+
UI=anduril
date '+#define VERSION_NUMBER "%Y%m%d"' > version.h
+PASS=0
+FAIL=0
+PASSED=''
+FAILED=''
+
for TARGET in cfg-*.h ; do
+
+ # maybe limit builds to a specific pattern
+ if [ ! -z "$SEARCH" ]; then
+ echo "$TARGET" | grep -i "$SEARCH" > /dev/null
+ if [ 0 != $? ]; then continue ; fi
+ fi
+
+ # friendly name for this build
NAME=$(echo "$TARGET" | perl -ne '/cfg-(.*).h/ && print "$1\n";')
echo "===== $NAME ====="
+
+ # figure out MCU type
ATTINY=$(grep 'ATTINY:' $TARGET | awk '{ print $3 }')
if [ -z "$ATTINY" ]; then ATTINY=85 ; fi
+
+ # try to compile
echo ../../../bin/build.sh $ATTINY "$UI" "-DCONFIGFILE=${TARGET}"
../../../bin/build.sh $ATTINY "$UI" "-DCONFIGFILE=${TARGET}"
- mv -f "$UI".hex "$UI".$NAME.hex
+
+ # track result, and rename compiled files
+ if [ 0 = $? ] ; then
+ mv -f "$UI".hex "$UI".$NAME.hex
+ PASS=$(($PASS + 1))
+ PASSED="$PASSED $NAME"
+ else
+ echo "ERROR: build failed"
+ FAIL=$(($FAIL + 1))
+ FAILED="$FAILED $NAME"
+ fi
+
done
+
+# summary
+echo "===== $PASS builds succeeded, $FAIL failed ====="
+#echo "PASS: $PASSED"
+if [ 0 != $FAIL ]; then
+ echo "FAIL:$FAILED"
+fi
diff --git a/spaghetti-monster/anduril/cfg-emisar-d18-219.h b/spaghetti-monster/anduril/cfg-emisar-d18-219.h
index 23229f4..1f3a3c2 100644
--- a/spaghetti-monster/anduril/cfg-emisar-d18-219.h
+++ b/spaghetti-monster/anduril/cfg-emisar-d18-219.h
@@ -8,7 +8,7 @@
#undef PWM2_LEVELS
#define PWM1_LEVELS 1,1,2,2,3,4,4,5,6,7,8,9,10,11,15,16,18,20,22,24,26,28,30,33,36,39,43,47,51,56,61,66,72,78,85,92,99,107,116,125,135,145,156,168,180,194,208,222,238,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,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 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,7,8,10,11,13,14,16,18,19,21,23,26,28,30,33,35,38,41,44,47,51,54,58,62,66,70,75,79,84,90,95,101,106,112,119,126,133,140,147,155,164,172,181,190,200,210,221,232,243,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
-// 65% FET power
+// 85% FET power
#undef PWM3_LEVELS
-#define PWM3_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,4,5,6,8,9,10,12,13,15,17,19,21,23,25,26,29,31,34,36,38,41,43,46,49,52,55,58,62,65,68,72,75,79,83,88,91,96,101,105,110,115,119,125,130,136,142,147,153,160,166
+#define PWM3_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,5,6,8,10,12,13,16,17,20,22,24,27,29,32,34,38,40,44,46,50,53,57,60,64,68,72,76,80,85,89,94,98,103,108,114,119,125,131,137,143,150,156,163,170,177,185,193,200,209,217
diff --git a/spaghetti-monster/anduril/cfg-noctigon-k9.3-219.h b/spaghetti-monster/anduril/cfg-noctigon-k9.3-219.h
new file mode 100644
index 0000000..a88ad2c
--- /dev/null
+++ b/spaghetti-monster/anduril/cfg-noctigon-k9.3-219.h
@@ -0,0 +1,18 @@
+// Noctigon K9.3 (reduced FET) config options for Anduril
+#include "cfg-noctigon-k9.3.h"
+#undef MODEL_NUMBER
+#define MODEL_NUMBER "0263"
+// ATTINY: 1634
+
+// main LEDs
+#undef PWM1_LEVELS
+#undef PWM2_LEVELS
+// don't turn off first channel at turbo level
+#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,1023
+// 65% FET power
+#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,15,34,52,71,90,110,129,149,169,190,211,233,254,275,298,320,343,366,389,413,437,461,485,510,535,560,586,612,639,665
+
+// 2nd LEDs (unchanged)
+//#undef PWM3_LEVELS
+//#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
+
diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4-219.h b/spaghetti-monster/anduril/cfg-noctigon-kr4-219.h
index 1c86b10..28fc595 100644
--- a/spaghetti-monster/anduril/cfg-noctigon-kr4-219.h
+++ b/spaghetti-monster/anduril/cfg-noctigon-kr4-219.h
@@ -1,4 +1,4 @@
-// Noctigon KR4 (75% FET) config options for Anduril
+// Noctigon KR4 (reduced FET) config options for Anduril
#include "cfg-noctigon-kr4.h"
#undef MODEL_NUMBER
#define MODEL_NUMBER "0213"
@@ -6,8 +6,8 @@
// don't turn off first channel at turbo level
#undef PWM1_LEVELS
-#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,1023
-// 65% FET power
+#define PWM1_LEVELS 0,1,1,2,2,3,4,5,6,7,8,9,11,12,14,16,17,19,22,24,26,29,31,34,37,40,43,46,49,53,56,60,63,67,71,74,78,82,86,89,93,96,99,103,105,108,110,112,114,115,116,116,115,114,112,109,106,101,95,89,81,71,60,48,34,19,20,21,22,23,24,26,27,28,30,31,32,34,36,37,39,41,43,45,47,49,51,53,56,58,61,63,66,69,72,75,78,81,84,88,91,95,99,103,107,111,115,119,124,129,133,138,143,149,154,159,165,171,177,183,189,196,203,210,217,224,231,239,247,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
+// 60% FET power
#undef PWM2_LEVELS
-#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,15,34,52,71,90,110,129,149,169,190,211,233,254,275,298,320,343,366,389,413,437,461,485,510,535,560,586,612,639,665
+#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,6,12,18,25,32,38,45,53,60,68,75,83,91,99,108,117,125,135,144,153
diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4-219b.h b/spaghetti-monster/anduril/cfg-noctigon-kr4-219b.h
new file mode 100644
index 0000000..39ac57c
--- /dev/null
+++ b/spaghetti-monster/anduril/cfg-noctigon-kr4-219b.h
@@ -0,0 +1,13 @@
+// Noctigon KR4 (reduced FET) config options for Anduril
+#include "cfg-noctigon-kr4.h"
+#undef MODEL_NUMBER
+#define MODEL_NUMBER "0214"
+// ATTINY: 1634
+
+// don't turn off first channel at turbo level
+#undef PWM1_LEVELS
+#define PWM1_LEVELS 0,1,1,2,2,3,4,5,6,7,8,9,11,12,14,16,17,19,22,24,26,29,31,34,37,40,43,46,49,53,56,60,63,67,71,74,78,82,86,89,93,96,99,103,105,108,110,112,114,115,116,116,115,114,112,109,106,101,95,89,81,71,60,48,34,19,20,21,22,23,24,26,27,28,30,31,32,34,36,37,39,41,43,45,47,49,51,53,56,58,61,63,66,69,72,75,78,81,84,88,91,95,99,103,107,111,115,119,124,129,133,138,143,149,154,159,165,171,177,183,189,196,203,210,217,224,231,239,247,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
+// 50% FET power
+#undef PWM2_LEVELS
+#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,5,10,15,21,26,32,38,44,50,56,63,69,76,83,90,97,104,112,120,128
+
diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h b/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h
index 3043035..383a0c8 100644
--- a/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h
+++ b/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h
@@ -10,13 +10,16 @@
// 0/1023: 0.35 lm
// 1/1023: 2.56 lm
// max regulated: 1740 lm
-// level_calc.py 3.0 1 150 7135 0 5 1740
#undef PWM_CHANNELS
#define PWM_CHANNELS 1
#define RAMP_LENGTH 150
+// prioritize low lows, at risk of visible ripple
+// level_calc.py 5.01 1 149 7135 1 0.3 1740 --pwm dyn:78:16384:255
#undef PWM1_LEVELS
-#define PWM1_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 PWM1_LEVELS 0,1,1,1,2,3,3,4,5,6,7,8,9,10,11,13,14,16,17,19,21,23,25,27,29,31,34,36,39,42,44,47,50,53,57,60,63,67,70,74,77,81,85,88,92,96,99,103,107,110,113,117,120,123,126,128,130,133,134,136,137,137,137,137,136,135,133,130,126,122,117,111,104,96,87,76,65,52,38,22,23,25,26,27,28,29,30,32,33,34,36,37,39,40,42,43,45,47,49,51,53,55,57,59,61,63,66,68,70,73,76,78,81,84,87,90,93,96,99,103,106,110,113,117,121,125,129,133,137,142,146,151,155,160,165,170,175,181,186,192,197,203,209,215,222,228,234,241,248,255
#undef PWM2_LEVELS
+#undef PWM_TOPS
+#define PWM_TOPS 16383,16383,12404,8140,11462,14700,11041,12947,13795,14111,14124,13946,13641,13248,12791,13418,12808,13057,12385,12428,12358,12209,12000,11746,11459,11147,11158,10793,10708,10576,10173,9998,9800,9585,9527,9278,9023,8901,8634,8486,8216,8053,7881,7615,7440,7261,7009,6832,6656,6422,6196,6031,5819,5615,5419,5190,4973,4803,4571,4386,4179,3955,3745,3549,3340,3145,2940,2729,2513,2312,2109,1903,1697,1491,1286,1070,871,662,459,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,255
#undef DEFAULT_LEVEL
#define DEFAULT_LEVEL 50
#undef MAX_1x7135
@@ -28,14 +31,14 @@
#undef RAMP_DISCRETE_CEIL
#undef RAMP_DISCRETE_STEPS
-#define RAMP_SMOOTH_FLOOR 3 // level 1 is unreliable
+#define RAMP_SMOOTH_FLOOR 11 // low levels may be unreliable
#define RAMP_SMOOTH_CEIL 130
-// 10, 30, [50], 70, 90, 110, 130 (plus [150] on turbo)
-#define RAMP_DISCRETE_FLOOR 10
+// 11, 30, [50], 70, 90, 110, 130 (plus [150] on turbo)
+#define RAMP_DISCRETE_FLOOR 11
#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL
#define RAMP_DISCRETE_STEPS 7
-// safe limit ~67% power / ~1200 lm (can sustain 900 lm)
+// safe limit ~1000 lm (can sustain 900 lm)
#undef SIMPLE_UI_FLOOR
#undef SIMPLE_UI_CEIL
#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR
@@ -49,9 +52,13 @@
// (only needed on no-FET build)
#define PARTY_STROBE_ONTIME 2
-// stop panicking at ~90% power or ~1600 lm
+// jump start a bit higher than base driver
+#undef JUMP_START_MOON
+#define JUMP_START_MOON 31
+
+// stop panicking at ~1300 lm
#undef THERM_FASTER_LEVEL
-#define THERM_FASTER_LEVEL 143
+#define THERM_FASTER_LEVEL 140
#undef MIN_THERM_STEPDOWN
-#define MIN_THERM_STEPDOWN DEFAULT_LEVEL
+#define MIN_THERM_STEPDOWN 80 // must be > end of dynamic PWM range
diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4.h b/spaghetti-monster/anduril/cfg-noctigon-kr4.h
index 82b8df5..d584445 100644
--- a/spaghetti-monster/anduril/cfg-noctigon-kr4.h
+++ b/spaghetti-monster/anduril/cfg-noctigon-kr4.h
@@ -24,33 +24,43 @@
// 1/1023: 2.56 lm
// max regulated: 1740 lm
// FET: ~3700 lm
-// maxreg at 130: level_calc.py cube 2 150 7135 0 2.5 1740 FET 1 10 2565
-// maxreg at 120: level_calc.py cube 2 150 7135 0 2.5 1740 FET 1 10 3190
#define RAMP_LENGTH 150
-#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
-#define DEFAULT_LEVEL 46
-#define MAX_1x7135 120
-#define HALFSPEED_LEVEL 10
-#define QUARTERSPEED_LEVEL 2
-
-#define RAMP_SMOOTH_FLOOR 3 // level 1 is unreliable
-#define RAMP_SMOOTH_CEIL 120
-// 10, 28, [46], 65, 83, 101, [120]
-#define RAMP_DISCRETE_FLOOR 10
+#define USE_DYN_PWM
+// nice low lows, but might have visible ripple on some lights:
+// maxreg at 130, dynamic PWM: level_calc.py 5.01 2 149 7135 1 0.3 1740 FET 1 10 3190 --pwm dyn:64:16384:255
+// (plus one extra level at the beginning for moon)
+#define PWM1_LEVELS 0,1,1,2,2,3,4,5,6,7,8,9,11,12,14,16,17,19,22,24,26,29,31,34,37,40,43,46,49,53,56,60,63,67,71,74,78,82,86,89,93,96,99,103,105,108,110,112,114,115,116,116,115,114,112,109,106,101,95,89,81,71,60,48,34,19,20,21,22,23,24,26,27,28,30,31,32,34,36,37,39,41,43,45,47,49,51,53,56,58,61,63,66,69,72,75,78,81,84,88,91,95,99,103,107,111,115,119,124,129,133,138,143,149,154,159,165,171,177,183,189,196,203,210,217,224,231,239,247,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,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,9,20,30,41,52,63,75,87,99,112,125,138,151,165,179,194,208,224,239,255
+#define PWM_TOPS 16383,16383,11750,14690,9183,12439,13615,13955,13877,13560,13093,12529,13291,12513,12756,12769,11893,11747,12085,11725,11329,11316,10851,10713,10518,10282,10016,9729,9428,9298,8971,8794,8459,8257,8043,7715,7497,7275,7052,6753,6538,6260,5994,5798,5501,5271,5006,4758,4525,4268,4030,3775,3508,3263,3010,2752,2517,2256,1998,1763,1512,1249,994,749,497,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,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
+// less ripple, but lows are a bit higher than ideal:
+// maxreg at 130, dynamic PWM: level_calc.py 5.01 2 149 7135 1 0.3 1740 FET 1 10 3190 --pwm dyn:64:4096:255
+// (plus one extra level at the beginning for moon)
+//#define PWM1_LEVELS 0,1,1,1,1,1,1,2,2,2,2,3,3,3,4,4,5,5,6,6,7,8,8,9,10,11,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,32,33,33,34,34,34,34,34,34,33,32,31,30,28,26,24,21,19,20,21,22,23,24,26,27,28,30,31,32,34,36,37,39,41,43,45,47,49,51,53,56,58,61,63,66,69,72,75,78,81,84,88,91,95,99,103,107,111,115,119,124,129,133,138,143,149,154,159,165,171,177,183,189,196,203,210,217,224,231,239,247,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,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,9,20,30,41,52,63,75,87,99,112,125,138,151,165,179,194,208,224,239,255
+//#define PWM_TOPS 4095,4095,3760,3403,3020,2611,2176,3582,3062,2515,1940,3221,2761,2283,2998,2584,3004,2631,2899,2555,2735,2836,2538,2606,2636,2638,2387,2382,2361,2328,2286,2238,2185,2129,2070,2010,1949,1887,1826,1766,1706,1648,1591,1536,1482,1429,1379,1329,1242,1199,1122,1084,1016,953,895,842,791,723,659,602,549,482,422,367,302,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,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
+#define MAX_1x7135 130
+#define DEFAULT_LEVEL 50
+#define HALFSPEED_LEVEL 12
+#define QUARTERSPEED_LEVEL 4
+
+#define RAMP_SMOOTH_FLOOR 11 // low levels may be unreliable
+#define RAMP_SMOOTH_CEIL 130
+// 11 30 [50] 70 90 110 [130]
+#define RAMP_DISCRETE_FLOOR 11
#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL
#define RAMP_DISCRETE_STEPS 7
-// safe limit ~30% power / ~1400 lm (can sustain 900 lm)
+// safe limit ~30% power / ~1300 lm (can sustain 900 lm)
#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR
-#define SIMPLE_UI_CEIL 110
+#define SIMPLE_UI_CEIL 120
#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 ~1300 lm
+#define THERM_FASTER_LEVEL 120
+#define MIN_THERM_STEPDOWN 66 // must be > end of dynamic PWM range
+// no longer needed, after switching to dynamic PWM
+//#define THERM_NEXT_WARNING_THRESHOLD 16 // accumulate less error before adjusting
+//#define THERM_RESPONSE_MAGNITUDE 128 // bigger adjustments
// slow down party strobe; this driver can't pulse for 1ms or less
// (only needed on no-FET build)
@@ -58,5 +68,10 @@
#define THERM_CAL_OFFSET 5
+// the power regulator is a bit slow, so push it harder for a quick response from off
+#define JUMP_START_MOON 26
+#define BLINK_BRIGHTNESS DEFAULT_LEVEL
+#define BLINK_ONCE_TIME 12
+
// can't reset the normal way because power is connected before the button
#define USE_SOFT_FACTORY_RESET
diff --git a/spaghetti-monster/anduril/config-default.h b/spaghetti-monster/anduril/config-default.h
index 31fcbf4..a50be5d 100644
--- a/spaghetti-monster/anduril/config-default.h
+++ b/spaghetti-monster/anduril/config-default.h
@@ -37,7 +37,19 @@
// overheat protection
#define USE_THERMAL_REGULATION
#define DEFAULT_THERM_CEIL 45 // try not to get hotter than this (in C)
-
+// Comment out to disable automatic calibration on factory reset
+// - If so, be sure to set THERM_CAL_OFFSET to the correct calibration offset
+// - Calibration can still be overridden in temperature check mode
+// Or uncomment to use the default auto-calibrate on factory reset
+//
+// To determine THERM_CAL_OFFSET, comment out USE_THERM_AUTOCALIBRATE to
+// disable auto-calibration, compile and flash, let flashlight rest at a known
+// temperature, then enter temp check mode (do NOT enter calibration mode).
+//
+// THERM_CAL_OFFSET = known_temperature - temp_check_blinks + THERM_CAL_OFFSET
+//
+// (include THERM_CAL_OFFSET in sum as it might already be a non-zero number)
+#define USE_THERM_AUTOCALIBRATE
// Include a simplified UI for non-enthusiasts?
#define USE_SIMPLE_UI
diff --git a/spaghetti-monster/anduril/factory-reset.c b/spaghetti-monster/anduril/factory-reset.c
index c327e65..5377b09 100644
--- a/spaghetti-monster/anduril/factory-reset.c
+++ b/spaghetti-monster/anduril/factory-reset.c
@@ -43,7 +43,7 @@ void factory_reset() {
}
// explode, if button pressed long enough
if (reset) {
- #ifdef USE_THERMAL_REGULATION
+ #if defined(USE_THERMAL_REGULATION) && defined(USE_THERM_AUTOCALIBRATE)
// auto-calibrate temperature... assume current temperature is 21 C
thermal_config_save(1, 21);
#endif
diff --git a/spaghetti-monster/anduril/misc.c b/spaghetti-monster/anduril/misc.c
index 523bbf0..9c7f0dd 100644
--- a/spaghetti-monster/anduril/misc.c
+++ b/spaghetti-monster/anduril/misc.c
@@ -25,7 +25,7 @@
/* no longer used
void blink_confirm(uint8_t num) {
uint8_t brightness = actual_level;
- uint8_t bump = actual_level + (MAX_LEVEL/6);
+ uint8_t bump = actual_level + BLINK_BRIGHTNESS;
if (bump > MAX_LEVEL) bump = 0;
for (; num>0; num--) {
set_level(bump);
@@ -41,9 +41,12 @@ void blink_confirm(uint8_t num) {
#ifndef BLINK_ONCE_TIME
#define BLINK_ONCE_TIME 10
#endif
+#ifndef BLINK_BRIGHTNESS
+#define BLINK_BRIGHTNESS (MAX_LEVEL/6)
+#endif
void blink_once() {
uint8_t brightness = actual_level;
- uint8_t bump = brightness + (MAX_LEVEL/6);
+ uint8_t bump = brightness + BLINK_BRIGHTNESS;
if (bump > MAX_LEVEL) bump = 0;
set_level(bump);
diff --git a/spaghetti-monster/anduril/off-mode.c b/spaghetti-monster/anduril/off-mode.c
index ae54f60..b1faf47 100644
--- a/spaghetti-monster/anduril/off-mode.c
+++ b/spaghetti-monster/anduril/off-mode.c
@@ -96,6 +96,12 @@ uint8_t off_state(Event event, uint16_t arg) {
#if (B_TIMING_ON == B_PRESS_T)
// hold (initially): go to lowest level (floor), but allow abort for regular click
else if (event == EV_click1_press) {
+ #ifdef JUMP_START_MOON
+ if (!arg) {
+ set_level(JUMP_START_MOON);
+ delay_4ms(3);
+ }
+ #endif
set_level(nearest_level(1));
return MISCHIEF_MANAGED;
}
@@ -110,6 +116,13 @@ uint8_t off_state(Event event, uint16_t arg) {
} else
#endif
#else // B_RELEASE_T or B_TIMEOUT_T
+ #ifdef JUMP_START_MOON
+ // pulse the output for a moment to wake up the power regulator
+ if (!arg) {
+ set_level(JUMP_START_MOON);
+ delay_4ms(3);
+ }
+ #endif
set_level(nearest_level(1));
#endif
// don't start ramping immediately;
diff --git a/spaghetti-monster/anduril/ramp-mode.c b/spaghetti-monster/anduril/ramp-mode.c
index 0baffde..8ab4ec4 100644
--- a/spaghetti-monster/anduril/ramp-mode.c
+++ b/spaghetti-monster/anduril/ramp-mode.c
@@ -462,6 +462,9 @@ void manual_memory_timer_config_save(uint8_t step, uint8_t value) {
// item 1: disable manual memory, go back to automatic
if (step == 1) { manual_memory = 0; }
// item 2: set manual memory timer duration
+ // FIXME: should be limited to (65535 / SLEEP_TICKS_PER_MINUTE)
+ // to avoid overflows or impossibly long timeouts
+ // (by default, the effective limit is 145, but it allows up to 255)
else { manual_memory_timer = value; }
}
diff --git a/spaghetti-monster/fsm-ramping.c b/spaghetti-monster/fsm-ramping.c
index d6a14ef..1a08149 100644
--- a/spaghetti-monster/fsm-ramping.c
+++ b/spaghetti-monster/fsm-ramping.c
@@ -151,6 +151,35 @@ void set_level(uint8_t level) {
#endif
#endif // ifdef USE_TINT_RAMPING
+
+ #ifdef USE_DYN_PWM
+ uint16_t top = PWM_GET(pwm_tops, level);
+ #ifdef PWM1_CNT
+ // wait to ensure compare match won't be missed
+ // (causes visible flickering when missed, because the counter
+ // goes all the way to 65535 before returning)
+ // (see attiny1634 reference manual page 103 for a warning about
+ // the timing of changing the TOP value (section 12.8.4))
+ // to be safe, allow at least 64 cycles to update TOP
+ while(PWM1_CNT > (top - 64)) {}
+ #endif
+ // pulse frequency modulation, a.k.a. dynamic PWM
+ PWM1_TOP = top;
+
+ // repeat for other channels if necessary
+ #ifdef PMW2_TOP
+ #ifdef PWM2_CNT
+ while(PWM2_CNT > (top - 64)) {}
+ #endif
+ PWM2_TOP = top;
+ #endif
+ #ifdef PMW3_TOP
+ #ifdef PWM3_CNT
+ while(PWM3_CNT > (top - 64)) {}
+ #endif
+ PWM3_TOP = top;
+ #endif
+ #endif // ifdef USE_DYN_PWM
}
#endif // ifdef OVERRIDE_SET_LEVEL
#ifdef USE_DYNAMIC_UNDERCLOCKING
diff --git a/spaghetti-monster/fsm-ramping.h b/spaghetti-monster/fsm-ramping.h
index 8fd89c7..d1ef6bc 100644
--- a/spaghetti-monster/fsm-ramping.h
+++ b/spaghetti-monster/fsm-ramping.h
@@ -53,7 +53,9 @@ void gradual_tick();
#define PWM_GET(x,y) pgm_read_byte(x+y)
#else
#define PWM_DATATYPE uint16_t
+#ifndef PWM_TOP
#define PWM_TOP 1023 // 10 bits by default
+#endif
// pointer plus 2*y bytes
//#define PWM_GET(x,y) pgm_read_word(x+(2*y))
// nope, the compiler was already doing the math correctly
@@ -74,6 +76,12 @@ PROGMEM const PWM_DATATYPE pwm3_levels[] = { PWM3_LEVELS };
PROGMEM const PWM_DATATYPE pwm4_levels[] = { PWM4_LEVELS };
#endif
+// pulse frequency modulation, a.k.a. dynamic PWM
+// (different ceiling / frequency at each ramp level)
+#ifdef USE_DYN_PWM
+PROGMEM const PWM_DATATYPE pwm_tops[] = { PWM_TOPS };
+#endif
+
// default / example ramps
#ifndef PWM1_LEVELS
#if PWM_CHANNELS == 1
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.