aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--hwdef-BLF_LT1-t1616.h105
-rw-r--r--hwdef-blf-lt1-t1616.c149
-rw-r--r--hwdef-blf-lt1-t1616.h141
-rw-r--r--hwdef-sofirn-lt1s-pro.h51
4 files changed, 314 insertions, 132 deletions
diff --git a/hwdef-BLF_LT1-t1616.h b/hwdef-BLF_LT1-t1616.h
deleted file mode 100644
index 3e1d946..0000000
--- a/hwdef-BLF_LT1-t1616.h
+++ /dev/null
@@ -1,105 +0,0 @@
-// BLF LT1 driver layout using the Attiny1616
-// Copyright (C) 2021-2023 (FIXME)
-// SPDX-License-Identifier: GPL-3.0-or-later
-#pragma once
-
-/*
- * Driver pinout:
- * eSwitch: PA5
- * Aux LED: PB5
- * PWM FET: PB0 (TCA0 WO0)
- * PWM 1x7135: PB1 (TCA0 WO1)
- * Voltage: VCC
- */
-
-
-#define LAYOUT_DEFINED
-
-#ifdef ATTINY
-#undef ATTINY
-#endif
-#define ATTINY 1616
-#include <avr/io.h>
-
-#define PWM_CHANNELS 1
-
-#ifndef SWITCH_PIN
-#define SWITCH_PIN PIN5_bp
-#define SWITCH_PORT VPORTA.IN
-#define SWITCH_ISC_REG PORTA.PIN2CTRL
-#define SWITCH_VECT PORTA_PORT_vect
-#define SWITCH_INTFLG VPORTA.INTFLAGS
-#endif
-
-
-// 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)
-uint8_t PWM1_LVL;
-
-// warm tint channel
-#ifndef PWM1_PIN
-#define PWM1_PIN PB1 //
-#define TINT1_LVL TCA0.SINGLE.CMP1 // CMP1 is the output compare register for PB1
-#endif
-
-// cold tint channel
-#ifndef PWM2_PIN
-#define PWM2_PIN PB0 //
-#define TINT2_LVL TCA0.SINGLE.CMP0 // CMP0 is the output compare register for PB0
-#endif
-
-// average drop across diode on this hardware
-#ifndef VOLTAGE_FUDGE_FACTOR
-#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V
-#endif
-
-
-// lighted button
-#ifndef AUXLED_PIN
-#define AUXLED_PIN PIN5_bp
-#define AUXLED_PORT PORTB
-#endif
-
-
-// with so many pins, doing this all with #ifdefs gets awkward...
-// ... so just hardcode it in each hwdef file instead
-inline void hwdef_setup() {
-
- // set up the system clock to run at 5 MHz instead of the default 3.33 MHz
- _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_4X_gc | CLKCTRL_PEN_bm );
-
- //VPORTA.DIR = ...;
- VPORTB.DIR = PIN0_bm | PIN1_bm | PIN5_bm; // Outputs: Aux LED and PWMs
- //VPORTC.DIR = ...;
-
- // enable pullups on the unused pins to reduce power
- PORTA.PIN0CTRL = PORT_PULLUPEN_bm;
- PORTA.PIN1CTRL = PORT_PULLUPEN_bm;
- PORTA.PIN2CTRL = PORT_PULLUPEN_bm;
- PORTA.PIN3CTRL = PORT_PULLUPEN_bm;
- PORTA.PIN4CTRL = PORT_PULLUPEN_bm;
- PORTA.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc; // eSwitch
- PORTA.PIN6CTRL = PORT_PULLUPEN_bm;
- PORTA.PIN7CTRL = PORT_PULLUPEN_bm;
-
- //PORTB.PIN0CTRL = PORT_PULLUPEN_bm; // cold tint channel
- //PORTB.PIN1CTRL = PORT_PULLUPEN_bm; // warm tint channel
- PORTB.PIN2CTRL = PORT_PULLUPEN_bm;
- PORTB.PIN3CTRL = PORT_PULLUPEN_bm;
- PORTB.PIN4CTRL = PORT_PULLUPEN_bm;
- //PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // Aux LED
-
- PORTC.PIN0CTRL = PORT_PULLUPEN_bm;
- PORTC.PIN1CTRL = PORT_PULLUPEN_bm;
- PORTC.PIN2CTRL = PORT_PULLUPEN_bm;
- PORTC.PIN3CTRL = PORT_PULLUPEN_bm;
-
- // set up the PWM
- // TODO: add references to MCU documentation
- TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_CMP1EN_bm | TCA_SINGLE_WGMODE_SINGLESLOPE_gc;
- TCA0.SINGLE.PER = 255;
- TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm;
-}
-
diff --git a/hwdef-blf-lt1-t1616.c b/hwdef-blf-lt1-t1616.c
new file mode 100644
index 0000000..ea7e6b4
--- /dev/null
+++ b/hwdef-blf-lt1-t1616.c
@@ -0,0 +1,149 @@
+// Sofirn LT1-t1616 PWM helpers
+// Copyright (C) 2023 SiteRelEnby, Selene ToyKeeper
+// (adapted from emisar-2ch 15/10/2023)
+#pragma once
+
+#include "chan-aux.c"
+
+
+void set_level_zero();
+
+void set_level_ch1(uint8_t level);
+void set_level_ch2(uint8_t level);
+void set_level_both(uint8_t level);
+void set_level_blend(uint8_t level);
+void set_level_auto(uint8_t level);
+
+bool gradual_tick_ch1(uint8_t gt);
+bool gradual_tick_ch2(uint8_t gt);
+bool gradual_tick_both(uint8_t gt);
+bool gradual_tick_blend(uint8_t gt);
+bool gradual_tick_auto(uint8_t gt);
+
+
+Channel channels[] = {
+ { // channel 1 only
+ .set_level = set_level_ch1,
+ .gradual_tick = gradual_tick_ch1,
+ .has_args = 0
+ },
+ { // channel 2 only
+ .set_level = set_level_ch2,
+ .gradual_tick = gradual_tick_ch2,
+ .has_args = 0
+ },
+ { // both channels, tied together (max "200%" power)
+ .set_level = set_level_both,
+ .gradual_tick = gradual_tick_both,
+ .has_args = 0
+ },
+ { // both channels, manual blend (max "100%" power)
+ .set_level = set_level_blend,
+ .gradual_tick = gradual_tick_blend,
+ .has_args = 1
+ },
+ { // both channels, auto blend
+ .set_level = set_level_auto,
+ .gradual_tick = gradual_tick_auto,
+ .has_args = 1
+ },
+ AUX_CHANNELS
+};
+
+
+void set_level_zero() {
+ CH1_PWM = 0;
+ CH2_PWM = 0;
+}
+
+void set_pwms(PWM_DATATYPE ch1_pwm, PWM_DATATYPE ch2_pwm) {
+ CH1_PWM = ch1_pwm;
+ CH2_PWM = ch2_pwm;
+}
+
+void set_level_ch1(uint8_t level) {
+ set_pwms(PWM_GET(pwm1_levels, level), 0);
+}
+
+void set_level_ch2(uint8_t level) {
+ set_pwms(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);
+}
+
+void set_level_blend(uint8_t level) {
+ PWM_DATATYPE ch1_pwm, ch2_pwm;
+ PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level);
+ uint8_t blend = cfg.channel_mode_args[channel_mode];
+
+ calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, PWM_TOP_INIT, blend);
+
+ set_pwms(ch1_pwm, ch2_pwm);
+}
+
+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);
+}
+
+
+///// 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);
+
+ // check for completion
+ if ((ch1_pwm == CH1_PWM)
+ && (ch2_pwm == CH2_PWM)) {
+ return true; // done
+ }
+ return false; // not done yet
+}
+
+bool gradual_tick_ch1(uint8_t gt) {
+ PWM_DATATYPE pwm = PWM_GET(pwm1_levels, gt);
+ return gradual_adjust(pwm, 0);
+}
+
+bool gradual_tick_ch2(uint8_t gt) {
+ PWM_DATATYPE pwm = PWM_GET(pwm1_levels, gt);
+ return gradual_adjust(0, pwm);
+}
+
+bool gradual_tick_both(uint8_t gt) {
+ PWM_DATATYPE pwm = PWM_GET(pwm1_levels, gt);
+ return gradual_adjust(pwm, pwm);
+}
+
+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);
+}
+
+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);
+}
+
diff --git a/hwdef-blf-lt1-t1616.h b/hwdef-blf-lt1-t1616.h
new file mode 100644
index 0000000..4a411d4
--- /dev/null
+++ b/hwdef-blf-lt1-t1616.h
@@ -0,0 +1,141 @@
+// BLF LT1 driver layout using the Attiny1616
+// Copyright (C) 2021-2023 (gchart), Selene ToyKeeper
+// SPDX-License-Identifier: GPL-3.0-or-later
+#pragma once
+
+/*
+ * Driver pinout:
+ * eSwitch: PA5
+ * Aux LED: PB5
+ * PWM cool: PB0 (TCA0 WO0)
+ * PWM warm: PB1 (TCA0 WO1)
+ * Voltage: VCC
+ */
+
+#define ATTINY 1616
+#include <avr/io.h>
+
+#define HWDEF_C_FILE hwdef-blf-lt1-t1616.c
+
+// allow using aux LEDs as extra channel modes
+#include "chan-aux.h"
+
+// channel modes:
+// * 0. warm only
+// * 1. cool only
+// * 2. both channels, tied together, max "200%" power
+// * 3. both channels, manual blend, max "100%" power
+// * 4. both channels, auto blend, reversible
+#define NUM_CHANNEL_MODES 6
+enum channel_modes_e {
+ CM_CH1 = 0,
+ CM_CH2,
+ CM_BOTH,
+ CM_BLEND,
+ CM_AUTO,
+ CM_AUX
+};
+
+// right-most bit first, modes are in fedcba9876543210 order
+#define CHANNEL_MODES_ENABLED 0b00011000
+#define USE_CHANNEL_MODE_ARGS
+// _, _, _, 128=middle CCT, 0=warm-to-cool
+#define CHANNEL_MODE_ARGS 0,0,0,128,0,0
+
+// can use some of the common handlers
+#define USE_CALC_2CH_BLEND
+
+
+#define PWM_CHANNELS 1 // old, remove this
+
+#define PWM_BITS 8 //
+
+#define PWM_GET PWM_GET8
+#define PWM_DATATYPE uint8_t
+#define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255
+#define PWM1_DATATYPE uint8_t //
+
+// PWM parameters of both channels are tied together because they share a counter
+#define PWM_TOP_INIT 255 // highest value used in the top half of the ramp
+#define PWM_TOP TCA0.SINGLE.PERBUF // holds the TOP value for for variable-resolution PWM
+#define PWM_CNT TCA0.SINGLE.CNT // for resetting phase after each TOP adjustment
+// TODO: implement DSM
+#define DSM_TOP (255<<7) // 15-bit resolution leaves 1 bit for carry
+
+// warm LEDs
+#define CH1_PIN PB1
+#define CH1_PWM TCA0.SINGLE.CMP1 // CMP1 is the output compare register for PB1
+
+// cold LEDs
+#define CH2_PIN PB0
+#define CH2_PWM TCA0.SINGLE.CMP0 // CMP0 is the output compare register for PB0
+
+// lighted button
+#define AUXLED_PIN PIN5_bp
+#define AUXLED_PORT PORTB
+
+// e-switch
+#define SWITCH_PIN PIN5_bp
+#define SWITCH_PORT VPORTA.IN
+#define SWITCH_ISC_REG PORTA.PIN2CTRL
+#define SWITCH_VECT PORTA_PORT_vect
+#define SWITCH_INTFLG VPORTA.INTFLAGS
+
+// average drop across diode on this hardware
+#ifndef VOLTAGE_FUDGE_FACTOR
+#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V
+#endif
+
+
+inline void hwdef_setup() {
+
+ // set up the system clock to run at 5 MHz instead of the default 3.33 MHz
+ _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_4X_gc | CLKCTRL_PEN_bm );
+
+ //VPORTA.DIR = ...;
+ // Outputs:
+ VPORTB.DIR = PIN0_bm // cool white
+ | PIN1_bm // warm white
+ | PIN5_bm; // aux LED
+ //VPORTC.DIR = ...;
+
+ // enable pullups on the unused pins to reduce power
+ PORTA.PIN0CTRL = PORT_PULLUPEN_bm;
+ PORTA.PIN1CTRL = PORT_PULLUPEN_bm;
+ PORTA.PIN2CTRL = PORT_PULLUPEN_bm;
+ PORTA.PIN3CTRL = PORT_PULLUPEN_bm;
+ PORTA.PIN4CTRL = PORT_PULLUPEN_bm;
+ PORTA.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc; // eSwitch
+ PORTA.PIN6CTRL = PORT_PULLUPEN_bm;
+ PORTA.PIN7CTRL = PORT_PULLUPEN_bm;
+
+ //PORTB.PIN0CTRL = PORT_PULLUPEN_bm; // cold tint channel
+ //PORTB.PIN1CTRL = PORT_PULLUPEN_bm; // warm tint channel
+ PORTB.PIN2CTRL = PORT_PULLUPEN_bm;
+ PORTB.PIN3CTRL = PORT_PULLUPEN_bm;
+ PORTB.PIN4CTRL = PORT_PULLUPEN_bm;
+ //PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // Aux LED
+
+ PORTC.PIN0CTRL = PORT_PULLUPEN_bm;
+ PORTC.PIN1CTRL = PORT_PULLUPEN_bm;
+ PORTC.PIN2CTRL = PORT_PULLUPEN_bm;
+ PORTC.PIN3CTRL = PORT_PULLUPEN_bm;
+
+ // set up the PWM
+ // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf
+ // PB0 is TCA0:WO0, use TCA_SINGLE_CMP0EN_bm
+ // PB1 is TCA0:WO1, use TCA_SINGLE_CMP1EN_bm
+ // For Fast (Single Slope) PWM use TCA_SINGLE_WGMODE_SINGLESLOPE_gc
+ // For Phase Correct (Dual Slope) PWM use TCA_SINGLE_WGMODE_DSBOTTOM_gc
+ // TODO: add references to MCU documentation
+ TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm
+ | TCA_SINGLE_CMP1EN_bm
+ | TCA_SINGLE_WGMODE_SINGLESLOPE_gc;
+ PWM_TOP = PWM_TOP_INIT;
+ TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc
+ | TCA_SINGLE_ENABLE_bm;
+}
+
+
+#define LAYOUT_DEFINED
+
diff --git a/hwdef-sofirn-lt1s-pro.h b/hwdef-sofirn-lt1s-pro.h
index 3cc0ca9..97de7d7 100644
--- a/hwdef-sofirn-lt1s-pro.h
+++ b/hwdef-sofirn-lt1s-pro.h
@@ -43,57 +43,54 @@ enum channel_modes_e {
//#define USE_CALC_AUTO_3CH_BLEND
-// TODO: remove this as soon as it's not needed
-#define PWM_CHANNELS 1
+#define PWM_CHANNELS 1 // old, remove this
-#define SWITCH_PIN PIN5_bp
-#define SWITCH_PORT VPORTA.IN
-#define SWITCH_ISC_REG PORTA.PIN2CTRL
-#define SWITCH_VECT PORTA_PORT_vect
-#define SWITCH_INTFLG VPORTA.INTFLAGS
+// only using 16-bit PWM on this light
+#define PWM_BITS 16
+#define PWM_GET PWM_GET16
+#define PWM_DATATYPE uint16_t
+#define PWM1_DATATYPE uint16_t
+#define PWM_DATATYPE2 uint32_t
// dynamic PWM
// PWM parameters of all channels are tied together because they share a counter
-#define PWM_TOP_INIT 511 // highest value used in the top half of the ramp
+#define PWM_TOP_INIT 511 // highest value used in the top half of the ramp
#define PWM_TOP TCA0.SINGLE.PERBUF // holds the TOP value for for variable-resolution PWM
#define PWM_CNT TCA0.SINGLE.CNT // for resetting phase after each TOP adjustment
-// warm tint channel
+// warm LEDs
//#define WARM_PWM_PIN PB0
#define WARM_PWM_LVL TCA0.SINGLE.CMP0BUF // CMP1 is the output compare register for PB0
-// cold tint channel
+// cold LEDs
//#define COOL_PWM_PIN PB1
#define COOL_PWM_LVL TCA0.SINGLE.CMP1BUF // CMP0 is the output compare register for PB1
-// red channel
+// red LEDs
//#define RED_PWM_PIN PB2
#define RED_PWM_LVL TCA0.SINGLE.CMP2BUF // CMP2 is the output compare register for PB2
-// only using 16-bit PWM on this light
-#define PWM_BITS 16
-#define PWM_GET PWM_GET16
-#define PWM_DATATYPE uint16_t
-#define PWM1_DATATYPE uint16_t
-#define PWM_DATATYPE2 uint32_t
-
-
-// average drop across diode on this hardware
-#ifndef VOLTAGE_FUDGE_FACTOR
-#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V
-#endif
-
-
// lighted button
-#define AUXLED_PIN PIN5_bp
-#define AUXLED_PORT PORTB
+#define AUXLED_PIN PIN5_bp
+#define AUXLED_PORT PORTB
// the button lights up
#define USE_INDICATOR_LED
// the button is visible while main LEDs are on
#define USE_INDICATOR_LED_WHILE_RAMPING
+// e-switch
+#define SWITCH_PIN PIN5_bp
+#define SWITCH_PORT VPORTA.IN
+#define SWITCH_ISC_REG PORTA.PIN2CTRL
+#define SWITCH_VECT PORTA_PORT_vect
+#define SWITCH_INTFLG VPORTA.INTFLAGS
+
+// average drop across diode on this hardware
+#ifndef VOLTAGE_FUDGE_FACTOR
+#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V
+#endif
inline void hwdef_setup() {
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.