aboutsummaryrefslogtreecommitdiff
path: root/hw/wurkkos/ts26/hwdef.c
diff options
context:
space:
mode:
authorSelene ToyKeeper2026-03-14 16:52:44 -0600
committerSelene ToyKeeper2026-03-14 16:52:44 -0600
commite7ef591138edc625815b1208ce1e012370621e04 (patch)
tree1ce34ca52773118462ade5009f8efdbe08d9897d /hw/wurkkos/ts26/hwdef.c
parentadded &hank-kr1aa build for new Emisar / Noctigon KR1AA (diff)
parentcalibrated for latest TS26 sample (diff)
downloadanduril-trunk.tar.gz
anduril-trunk.tar.bz2
anduril-trunk.zip
Merge branch 'wurkkos-ts26' into trunkHEADtrunk
I guess the hardware is shipping now? So, time to release. I never heard back about some calibration details, particularly about whether the floor level is reliable on many items or just mine... but I guess it must have been fine if it's shipping. * wurkkos-ts26: calibrated for latest TS26 sample wurkkos-ts26: increase default floor to 5/150 to reduce flicker (by request) renamed wurkkos-ts25-boost to wurkkos-ts26 wurkkos ts25-boost: calibrated for 20250210 prototype ts25-boost: calibrated for new prototype - battery voltage readings - RGB button aux - less moon flicker (but brighter, less efficient moon) - reduced blink brightness (old brightness was so high it was throwing off battery readings) ts25-boost: reduced visible PWM, made party strobe less blurry wurkkos-ts25-boost: calibrated the battery voltage measurements attiny1616 mcu_vdivider_raw2cooked: factor in the offset, not just slope added wurkkos-ts25-boost (early version made from spec, no clue if it works) # Conflicts: # MODELS
Diffstat (limited to 'hw/wurkkos/ts26/hwdef.c')
-rw-r--r--hw/wurkkos/ts26/hwdef.c101
1 files changed, 101 insertions, 0 deletions
diff --git a/hw/wurkkos/ts26/hwdef.c b/hw/wurkkos/ts26/hwdef.c
new file mode 100644
index 0000000..e6c77a2
--- /dev/null
+++ b/hw/wurkkos/ts26/hwdef.c
@@ -0,0 +1,101 @@
+// Wurkkos TS26 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);
+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
+};
+
+
+void set_level_zero() {
+ // disable timer overflow interrupt
+ // (helps improve button press handling from Off state)
+ DSM_INTCTRL = 0;
+
+ // turn off all LEDs
+ ch1_dsm_lvl = 0;
+ CH1_PWM = 0;
+ PWM_CNT = 0; // reset phase
+ CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable regulator
+}
+
+// single set of LEDs with single power channel, boost
+void set_level_main(uint8_t level) {
+ if (level == actual_level - 1) return; // prevent flicker on no-op
+
+ PWM_DATATYPE ch1 = PWM_GET(pwm1_levels, 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;
+
+ // 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 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;
+
+ // clear the interrupt flag to indicate it was handled
+ // as per: https://onlinedocs.microchip.com/pr/GUID-C37FFBA8-82C6-4339-A2B1-ABD9A0F6C162-en-US-8/index.html?GUID-C2A2BEFD-158F-413D-B9D4-0F0556AA79BD
+ DSM_INTFLAGS = DSM_OVF_bm;
+}
+
+
+bool gradual_tick_main(uint8_t 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;
+
+ 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
+}
+