aboutsummaryrefslogtreecommitdiff
path: root/hwdef-blf-lt1-t1616.c
diff options
context:
space:
mode:
authorSelene ToyKeeper2023-10-28 07:02:38 -0600
committerSelene ToyKeeper2023-10-28 07:02:38 -0600
commitaaa760e5243cf87a43297945b20e41a448c906e4 (patch)
treea29f30ceeeedf5573be58e43d486f8ec393f3657 /hwdef-blf-lt1-t1616.c
parentenabled smooth steps on blf-q8 and sofirn-sp36, instead of tactical mode (diff)
downloadanduril-aaa760e5243cf87a43297945b20e41a448c906e4.tar.gz
anduril-aaa760e5243cf87a43297945b20e41a448c906e4.tar.bz2
anduril-aaa760e5243cf87a43297945b20e41a448c906e4.zip
switched blf-lt1-t1616 from plain PWM to PWM+DSM
(and made DSM interrupt definitions a bit cleaner)
Diffstat (limited to 'hwdef-blf-lt1-t1616.c')
-rw-r--r--hwdef-blf-lt1-t1616.c143
1 files changed, 100 insertions, 43 deletions
diff --git a/hwdef-blf-lt1-t1616.c b/hwdef-blf-lt1-t1616.c
index ea7e6b4..48a401d 100644
--- a/hwdef-blf-lt1-t1616.c
+++ b/hwdef-blf-lt1-t1616.c
@@ -1,6 +1,6 @@
// Sofirn LT1-t1616 PWM helpers
// Copyright (C) 2023 SiteRelEnby, Selene ToyKeeper
-// (adapted from emisar-2ch 15/10/2023)
+// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "chan-aux.c"
@@ -52,59 +52,125 @@ Channel channels[] = {
void set_level_zero() {
- CH1_PWM = 0;
- CH2_PWM = 0;
+ // 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;
+ ch2_dsm_lvl = 0;
+ CH1_PWM = 0;
+ CH2_PWM = 0;
+ PWM_CNT = 0;
}
-void set_pwms(PWM_DATATYPE ch1_pwm, PWM_DATATYPE ch2_pwm) {
+void set_hw_levels(PWM_DATATYPE ch1, PWM_DATATYPE ch2) {
+
+ bool was_on = (CH1_PWM>0) || (CH2_PWM>0);
+
+ // set delta-sigma soft levels
+ ch1_dsm_lvl = ch1;
+ ch2_dsm_lvl = ch2;
+
+ // set hardware PWM levels and init dsm loop
+ CH1_PWM = ch1_pwm = ch1 >> 7;
+ CH2_PWM = ch2_pwm = ch2 >> 7;
+
+ // enable timer overflow interrupt so DSM can work
+ DSM_INTCTRL |= DSM_OVF_bm;
+
+ // reset phase when turning on
+ if (! was_on) PWM_CNT = 0;
+
+}
+
+// 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;
CH2_PWM = ch2_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;
+
+ // repeat for other channels
+
+ ch2_dsm += (ch2_dsm_lvl & 0x007f);
+ ch2_pwm = (ch2_dsm_lvl >> 7) + (ch2_dsm > 0x7f);
+ ch2_dsm &= 0x7f;
}
+
void set_level_ch1(uint8_t level) {
- set_pwms(PWM_GET(pwm1_levels, level), 0);
+ set_hw_levels(PWM_GET(pwm1_levels, level), 0);
}
void set_level_ch2(uint8_t level) {
- set_pwms(0, PWM_GET(pwm1_levels, level));
+ set_hw_levels(0, PWM_GET(pwm1_levels, level));
}
void set_level_both(uint8_t level) {
PWM_DATATYPE pwm = PWM_GET(pwm1_levels, level);
- set_pwms(pwm, pwm);
+ set_hw_levels(pwm, pwm);
}
-void set_level_blend(uint8_t level) {
- PWM_DATATYPE ch1_pwm, ch2_pwm;
+void blend_helper(PWM_DATATYPE *warm, PWM_DATATYPE *cool, uint8_t level) {
PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level);
- uint8_t blend = cfg.channel_mode_args[channel_mode];
+ uint8_t blend;
+ if (channel_mode == CM_AUTO) {
+ blend = 255 * (uint16_t)level / RAMP_SIZE;
+ if (cfg.channel_mode_args[channel_mode] & 0b01000000)
+ blend = 255 - blend;
+ } else {
+ blend = cfg.channel_mode_args[channel_mode];
+ }
- calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, PWM_TOP_INIT, blend);
+ calc_2ch_blend(warm, cool, brightness, DSM_TOP, blend);
+}
- set_pwms(ch1_pwm, ch2_pwm);
+void set_level_blend(uint8_t level) {
+ PWM_DATATYPE warm, cool;
+ blend_helper(&warm, &cool, level);
+ set_hw_levels(warm, cool);
}
void set_level_auto(uint8_t level) {
- PWM_DATATYPE ch1_pwm, ch2_pwm;
- PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level);
- uint8_t blend = 255 * (uint16_t)level / RAMP_SIZE;
- if (cfg.channel_mode_args[channel_mode] & 0b01000000)
- blend = 255 - blend;
-
- calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, PWM_TOP_INIT, blend);
-
- set_pwms(ch1_pwm, ch2_pwm);
+ PWM_DATATYPE warm, cool;
+ blend_helper(&warm, &cool, level);
+ set_hw_levels(warm, cool);
}
+///// "gradual tick" functions for smooth thermal regulation /////
+// (and other smooth adjustments)
///// bump each channel toward a target value /////
-bool gradual_adjust(uint16_t ch1_pwm, uint16_t ch2_pwm) {
- GRADUAL_ADJUST_SIMPLE(ch1_pwm, CH1_PWM);
- GRADUAL_ADJUST_SIMPLE(ch2_pwm, CH2_PWM);
+bool gradual_adjust(PWM_DATATYPE ch1, PWM_DATATYPE ch2) {
+ // 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;
- // check for completion
- if ((ch1_pwm == CH1_PWM)
- && (ch2_pwm == CH2_PWM)) {
+ steps = ch1_dsm_lvl >> shift;
+ for (uint8_t i=0; i<=steps; i++)
+ GRADUAL_ADJUST_SIMPLE(ch1, ch1_dsm_lvl);
+
+ steps = ch2_dsm_lvl >> shift;
+ for (uint8_t i=0; i<=steps; i++)
+ GRADUAL_ADJUST_SIMPLE(ch2, ch2_dsm_lvl);
+
+ if ((ch1 == ch1_dsm_lvl)
+ && (ch2 == ch2_dsm_lvl )) {
return true; // done
}
return false; // not done yet
@@ -126,24 +192,15 @@ bool gradual_tick_both(uint8_t gt) {
}
bool gradual_tick_blend(uint8_t gt) {
- PWM_DATATYPE ch1_pwm, ch2_pwm;
- PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt);
- uint8_t blend = cfg.channel_mode_args[channel_mode];
-
- calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, PWM_TOP_INIT, blend);
-
- return gradual_adjust(ch1_pwm, ch2_pwm);
+ PWM_DATATYPE warm, cool;
+ blend_helper(&warm, &cool, gt);
+ return gradual_adjust(warm, cool);
}
bool gradual_tick_auto(uint8_t gt) {
- PWM_DATATYPE ch1_pwm, ch2_pwm;
- PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt);
- uint8_t blend = 255 * (uint16_t)gt / RAMP_SIZE;
- if (cfg.channel_mode_args[channel_mode] & 0b01000000)
- blend = 255 - blend;
-
- calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, PWM_TOP_INIT, blend);
-
- return gradual_adjust(ch1_pwm, ch2_pwm);
+ PWM_DATATYPE warm, cool;
+ blend_helper(&warm, &cool, gt);
+ return gradual_adjust(warm, cool);
}
+