From f9fdd5937c65df328f2c2bf810115291e219aabe Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 17 May 2023 15:41:37 -0600 Subject: converted Noctigon DM11-12V build, renamed to noctigon-dm11-boost --- hwdef-noctigon-dm11-boost.c | 47 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 hwdef-noctigon-dm11-boost.c (limited to 'hwdef-noctigon-dm11-boost.c') diff --git a/hwdef-noctigon-dm11-boost.c b/hwdef-noctigon-dm11-boost.c new file mode 100644 index 0000000..2ea8f07 --- /dev/null +++ b/hwdef-noctigon-dm11-boost.c @@ -0,0 +1,47 @@ +// Noctigon DM11 (boost driver) PWM helper functions +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "chan-rgbaux.c" + +// single set of LEDs with single power channel, boost +void set_level_main(uint8_t level) { + if (level == 0) { + CH1_PWM = 0; + PWM_CNT = 0; // reset phase + LED_ENABLE_PORT &= ~(1 << LED_ENABLE_PIN ); // disable opamp + LED_ENABLE_PORT2 &= ~(1 << LED_ENABLE_PIN2); // disable PMIC + return; + } + + LED_ENABLE_PORT |= (1 << LED_ENABLE_PIN ); // enable opamp + LED_ENABLE_PORT2 |= (1 << LED_ENABLE_PIN2); // enable PMIC + + level --; // PWM array index = level - 1 + PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); + // pulse frequency modulation, a.k.a. dynamic PWM + uint16_t top = PWM_GET16(pwm_tops, level); + + CH1_PWM = ch1_pwm; + // wait to sync the counter and avoid flashes + while(actual_level && (PWM_CNT > (top - 32))) {} + PWM_TOP = top; + // force reset phase when turning on from zero + // (because otherwise the initial response is inconsistent) + if (! actual_level) PWM_CNT = 0; +} + +bool gradual_tick_main(uint8_t gt) { + PWM_DATATYPE pwm1 = PWM_GET(pwm1_levels, gt); + + GRADUAL_ADJUST_SIMPLE(pwm1, CH1_PWM); + + if ( (pwm1 == CH1_PWM) + ) { + return true; // done + } + return false; // not done yet +} + -- cgit v1.2.3 From 5c2fc000a5081b203174b79d09044665fd0483ff Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 22 Jul 2023 18:08:12 -0600 Subject: converted noctigon-dm11-* builds to multi-channel (but I could only test dm11-boost on actual hardware) (also, it looks like dm11-sbt90 is almost identical to the base kr4 build, so I removed its hwdef) --- hwdef-noctigon-dm11-boost.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'hwdef-noctigon-dm11-boost.c') diff --git a/hwdef-noctigon-dm11-boost.c b/hwdef-noctigon-dm11-boost.c index 2ea8f07..006cbf8 100644 --- a/hwdef-noctigon-dm11-boost.c +++ b/hwdef-noctigon-dm11-boost.c @@ -6,18 +6,31 @@ #include "chan-rgbaux.c" +void set_level_main(uint8_t level); +bool gradual_tick_main(uint8_t gt); + + +Channel channels[] = { + { // channel 1 only + .set_level = set_level_main, + .gradual_tick = gradual_tick_main + }, + RGB_AUX_CHANNELS +}; + + // single set of LEDs with single power channel, boost void set_level_main(uint8_t level) { if (level == 0) { CH1_PWM = 0; PWM_CNT = 0; // reset phase - LED_ENABLE_PORT &= ~(1 << LED_ENABLE_PIN ); // disable opamp - LED_ENABLE_PORT2 &= ~(1 << LED_ENABLE_PIN2); // disable PMIC + CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN ); // disable opamp + CH1_ENABLE_PORT2 &= ~(1 << CH1_ENABLE_PIN2); // disable PMIC return; } - LED_ENABLE_PORT |= (1 << LED_ENABLE_PIN ); // enable opamp - LED_ENABLE_PORT2 |= (1 << LED_ENABLE_PIN2); // enable PMIC + CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN ); // enable opamp + CH1_ENABLE_PORT2 |= (1 << CH1_ENABLE_PIN2); // enable PMIC level --; // PWM array index = level - 1 PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); -- cgit v1.2.3 From d34d0e7acb1f1e49d21af7cf1c9e08161ce95dd4 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 17 Sep 2023 04:37:25 -0600 Subject: fixed builds which weren't using set_level_zero() yet... - emisar-d4 - emisar-d4v2 - emisar-d4v2-nofet - emisar-d4sv2 - emisar-2ch - emisar-2ch-fet - noctigon-dm11-boost - noctigon-k1 - noctigon-kr4 - noctigon-kr4-nofet - sofirn-lt1s-pro ... and removed old build targets for d4sv2-tintramp, because it was replaced by emisar-2ch a while ago. --- hwdef-noctigon-dm11-boost.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'hwdef-noctigon-dm11-boost.c') diff --git a/hwdef-noctigon-dm11-boost.c b/hwdef-noctigon-dm11-boost.c index 006cbf8..08e2798 100644 --- a/hwdef-noctigon-dm11-boost.c +++ b/hwdef-noctigon-dm11-boost.c @@ -6,6 +6,8 @@ #include "chan-rgbaux.c" +void set_level_zero(); + void set_level_main(uint8_t level); bool gradual_tick_main(uint8_t gt); @@ -19,20 +21,18 @@ Channel channels[] = { }; +void set_level_zero() { + CH1_PWM = 0; + PWM_CNT = 0; // reset phase + CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN ); // disable opamp + CH1_ENABLE_PORT2 &= ~(1 << CH1_ENABLE_PIN2); // disable PMIC +} + // single set of LEDs with single power channel, boost void set_level_main(uint8_t level) { - if (level == 0) { - CH1_PWM = 0; - PWM_CNT = 0; // reset phase - CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN ); // disable opamp - CH1_ENABLE_PORT2 &= ~(1 << CH1_ENABLE_PIN2); // disable PMIC - return; - } - CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN ); // enable opamp CH1_ENABLE_PORT2 |= (1 << CH1_ENABLE_PIN2); // enable PMIC - level --; // PWM array index = level - 1 PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); // pulse frequency modulation, a.k.a. dynamic PWM uint16_t top = PWM_GET16(pwm_tops, level); -- cgit v1.2.3 From bcaf2686d9f0570dfbc508ddcac95ee55d501f48 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 29 Oct 2023 13:05:38 -0600 Subject: converted noctigon-dm11-boost to use PWM+DSM, and recalibrated timing for delays + smooth steps Anduril has gradually gotten faster over the years, apparently, so it needed longer delays to get accurate-ish timing for beacon and other modes. Adding DSM also changes the timing perceptibly, so I made it possible to calibrate the delay fudge factor on a per-build basis. --- hwdef-noctigon-dm11-boost.c | 63 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 13 deletions(-) (limited to 'hwdef-noctigon-dm11-boost.c') diff --git a/hwdef-noctigon-dm11-boost.c b/hwdef-noctigon-dm11-boost.c index 08e2798..932323a 100644 --- a/hwdef-noctigon-dm11-boost.c +++ b/hwdef-noctigon-dm11-boost.c @@ -1,11 +1,11 @@ // Noctigon DM11 (boost driver) PWM helper functions // Copyright (C) 2023 Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later - #pragma once #include "chan-rgbaux.c" + void set_level_zero(); void set_level_main(uint8_t level); @@ -22,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; PWM_CNT = 0; // reset phase CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN ); // disable opamp @@ -30,28 +36,59 @@ void set_level_zero() { // single set of LEDs with single power channel, boost void set_level_main(uint8_t level) { - CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN ); // enable opamp - CH1_ENABLE_PORT2 |= (1 << CH1_ENABLE_PIN2); // enable PMIC + PWM_DATATYPE ch1 = PWM_GET(pwm1_levels, level); - PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); - // pulse frequency modulation, a.k.a. dynamic PWM - uint16_t top = PWM_GET16(pwm_tops, level); + // set delta-sigma soft levels + ch1_dsm_lvl = ch1; + + // set hardware PWM levels and init dsm loop + CH1_PWM = ch1_pwm = ch1 >> 7; + + // enable timer overflow interrupt so DSM can work + DSM_INTCTRL |= DSM_OVF_bm; - CH1_PWM = ch1_pwm; - // wait to sync the counter and avoid flashes - while(actual_level && (PWM_CNT > (top - 32))) {} - PWM_TOP = top; // force reset phase when turning on from zero // (because otherwise the initial response is inconsistent) if (! actual_level) PWM_CNT = 0; + + CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN ); // enable opamp + CH1_ENABLE_PORT2 |= (1 << CH1_ENABLE_PIN2); // enable PMIC } +// 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) { - PWM_DATATYPE pwm1 = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE ch1 = PWM_GET(pwm1_levels, gt); + + // 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; - GRADUAL_ADJUST_SIMPLE(pwm1, CH1_PWM); + steps = ch1_dsm_lvl >> shift; + for (uint8_t i=0; i<=steps; i++) + GRADUAL_ADJUST_SIMPLE(ch1, ch1_dsm_lvl); - if ( (pwm1 == CH1_PWM) + if ((ch1 == ch1_dsm_lvl) ) { return true; // done } -- cgit v1.2.3