aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--hwdef-emisar-d4k-3ch.c279
-rw-r--r--hwdef-emisar-d4k-3ch.h26
2 files changed, 149 insertions, 156 deletions
diff --git a/hwdef-emisar-d4k-3ch.c b/hwdef-emisar-d4k-3ch.c
index 8c46003..3fed41a 100644
--- a/hwdef-emisar-d4k-3ch.c
+++ b/hwdef-emisar-d4k-3ch.c
@@ -81,133 +81,138 @@ void set_level_zero() {
MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN);
LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN );
LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN );
+ main2_dsm_lvl = 0;
+ led3_dsm_lvl = 0;
+ led4_dsm_lvl = 0;
MAIN2_PWM_LVL = 0;
LED3_PWM_LVL = 0;
LED4_PWM_LVL = 0;
PWM_CNT = 0;
- PWM_TOP = PWM_TOP_INIT;
+ //PWM_TOP = PWM_TOP_INIT;
+}
+
+// wrap setting the dsm vars, to get a faster response
+// (just setting *_dsm_lvl doesn't work well for strobes)
+void set_hw_levels(PWM_DATATYPE main2, // brightness, 0 to DSM_TOP
+ PWM_DATATYPE led3,
+ PWM_DATATYPE led4,
+ bool main2_en, // enable even at PWM=0?
+ bool led3_en,
+ bool led4_en
+ ) {
+
+ // enable/disable LED power channels
+ if (main2 | main2_en)
+ MAIN2_ENABLE_PORT |= (1 << MAIN2_ENABLE_PIN);
+ else MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN);
+
+ if (led3 | led3_en )
+ LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN);
+ else LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN);
+
+ if (led4 | led4_en )
+ LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN);
+ else LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN);
+
+ // set delta-sigma soft levels
+ main2_dsm_lvl = main2;
+ led3_dsm_lvl = led3;
+ led4_dsm_lvl = led4;
+ // set hardware PWM levels and init dsm loop
+ MAIN2_PWM_LVL = main2_pwm = main2 >> 7;
+ LED3_PWM_LVL = led3_pwm = led3 >> 7;
+ LED4_PWM_LVL = led4_pwm = led4 >> 7;
+ // force phase reset
+ PWM_CNT = PWM_CNT2 = 0;
+}
+
+// delta-sigma modulation of PWM outputs
+// happens on each Timer0 overflow (every 512 cpu clock cycles)
+// uses 8-bit pwm w/ 7-bit dsm (0b 0PPP PPPP PDDD DDDD)
+ISR(TIMER0_OVF_vect) {
+ // set new hardware values first,
+ // for best timing (reduce effect of interrupt jitter)
+ MAIN2_PWM_LVL = main2_pwm;
+ LED3_PWM_LVL = led3_pwm;
+ LED4_PWM_LVL = led4_pwm;
+
+ // calculate next values, now that timing matters less
+
+ // accumulate error
+ main2_dsm += (main2_dsm_lvl & 0x007f);
+ // next PWM = base PWM value + carry bit
+ main2_pwm = (main2_dsm_lvl >> 7) + (main2_dsm > 0x7f);
+ // clear carry bit
+ main2_dsm &= 0x7f;
+
+ // repeat for other channels
+
+ led3_dsm += (led3_dsm_lvl & 0x007f);
+ led3_pwm = (led3_dsm_lvl >> 7) + (led3_dsm > 0x7f);
+ led3_dsm &= 0x7f;
+
+ led4_dsm += (led4_dsm_lvl & 0x007f);
+ led4_pwm = (led4_dsm_lvl >> 7) + (led4_dsm > 0x7f);
+ led4_dsm &= 0x7f;
}
// LEDs 1+2 are 8-bit
// this 8-bit channel may be LEDs 1+2 or LED 4, depending on wiring
void set_level_main2(uint8_t level) {
- LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off unused LEDs
- LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off unused LEDs
-
- MAIN2_ENABLE_PORT |= (1 << MAIN2_ENABLE_PIN);
- MAIN2_PWM_LVL = PWM_GET8(pwm1_levels, level);
+ set_hw_levels(PWM_GET(pwm1_levels, level), 0, 0,
+ 1, 0, 0);
}
// LED 3 is 16-bit
void set_level_led3(uint8_t level) {
- MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off unused LEDs
- LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off unused LEDs
-
- LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN);
- LED3_PWM_LVL = PWM_GET16(pwm2_levels, level);
- uint16_t top = PWM_GET16(pwm_tops, level);
- while(actual_level && (PWM_CNT > (top - 32))) {}
- PWM_TOP = top;
- if (! actual_level) PWM_CNT = 0;
+ set_hw_levels(0, PWM_GET(pwm1_levels, level), 0,
+ 0, 1, 0);
}
// this 16-bit channel may be LED 4 or LEDs 1+2, depending on wiring
void set_level_led4(uint8_t level) {
- MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off unused LEDs
- LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off unused LEDs
-
- // gotta turn on the opamp before light can come out
- LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN);
- LED4_PWM_LVL = PWM_GET16(pwm2_levels, level);
- // pulse frequency modulation, a.k.a. dynamic PWM
- uint16_t top = PWM_GET16(pwm_tops, level);
- // 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;
+ set_hw_levels(0, 0, PWM_GET(pwm1_levels, level),
+ 0, 0, 1);
}
void set_level_all(uint8_t level) {
- MAIN2_ENABLE_PORT |= (1 << MAIN2_ENABLE_PIN);
- LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN );
- LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN );
- // FIXME? It might be better to calculate the 8-bit value from the
- // 16-bit tables instead of using the 8-bit ramp
- // 8bit = max(1, 16bit * 255 / top)
- MAIN2_PWM_LVL = PWM_GET8 (pwm1_levels, level);
- LED3_PWM_LVL = PWM_GET16(pwm2_levels, level);
- LED4_PWM_LVL = PWM_GET16(pwm2_levels, level);
- uint16_t top = PWM_GET16(pwm_tops, level);
- while(actual_level && (PWM_CNT > (top - 32))) {}
- PWM_TOP = top;
- if (! actual_level) PWM_CNT = 0;
+ PWM_DATATYPE pwm = PWM_GET(pwm1_levels, level);
+ set_hw_levels(pwm, pwm, pwm, 1, 1, 1);
}
// 8/16/16 wiring, mix 16+16
void set_level_led34a_blend(uint8_t level) {
- MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off unused LEDs
-
PWM_DATATYPE warm_PWM, cool_PWM;
- PWM_DATATYPE brightness = PWM_GET16(pwm2_levels, level);
- PWM_DATATYPE top = PWM_GET16(pwm_tops, level);
+ PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level);
uint8_t blend = cfg.channel_mode_args[channel_mode];
- calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend);
+ calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, DSM_TOP, blend);
- if (warm_PWM > 0) LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN);
- if (cool_PWM > 0) LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN);
- LED3_PWM_LVL = warm_PWM;
- LED4_PWM_LVL = cool_PWM;
- while(actual_level && (PWM_CNT > (top - 32))) {}
- PWM_TOP = top;
- if (! actual_level) PWM_CNT = 0;
+ set_hw_levels(0, warm_PWM, cool_PWM,
+ 0, (blend<170), (blend>85));
}
// 16/16/8 wiring, mix 16+8
void set_level_led34b_blend(uint8_t level) {
- LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off unused LEDs
-
- const uint16_t top = 2047;
- uint16_t warm_PWM, cool_PWM; // 11 bits, 8 bits
+ PWM_DATATYPE warm_PWM, cool_PWM;
+ PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level);
uint8_t blend = cfg.channel_mode_args[channel_mode];
- uint16_t brightness = PWM_GET8(pwm1_levels, level);
-
- if (0 == brightness) brightness = 1;
- brightness = brightness << 3;
-
- calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend);
- // adjust to halfway between 8-bit steps
- warm_PWM -= 4;
- if (warm_PWM > top) warm_PWM = 0;
+ calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, DSM_TOP, blend);
- if (cool_PWM > 0) MAIN2_ENABLE_PORT |= (1 << MAIN2_ENABLE_PIN);
- if (warm_PWM > 0) LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN);
- MAIN2_PWM_LVL = (uint8_t)(cool_PWM >> 3);
- LED3_PWM_LVL = warm_PWM;
- //while(actual_level && (PWM_CNT > (top - 32))) {}
- PWM_TOP = top;
- if (! actual_level) PWM_CNT = 0;
+ set_hw_levels(cool_PWM, warm_PWM, 0,
+ (blend>85), (blend<170), 0);
}
void set_level_hsv(uint8_t level) {
RGB_t color;
uint8_t h = cfg.channel_mode_args[channel_mode];
uint8_t s = 255; // TODO: drop saturation at brightest levels
- uint8_t v = PWM_GET8(pwm1_levels, level);
+ PWM_DATATYPE v = PWM_GET(pwm1_levels, level);
color = hsv2rgb(h, s, v);
- if (color.r > 0) MAIN2_ENABLE_PORT |= (1 << MAIN2_ENABLE_PIN);
- if (color.g > 0) LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN );
- if (color.b > 0) LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN );
- MAIN2_PWM_LVL = color.r;
- LED3_PWM_LVL = color.g;
- LED4_PWM_LVL = color.b;
- //while(actual_level && (PWM_CNT > (255 - 32))) {}
- PWM_TOP = 255;
- if (! actual_level) PWM_CNT = 0;
+ set_hw_levels(color.r, color.g, color.b,
+ 0, 0, 0);
}
// calculate a 3-channel "auto tint" blend
@@ -216,15 +221,12 @@ void set_level_hsv(uint8_t level) {
// level : ramp level to convert into 3 channel levels
// (assumes ramp table is "pwm1_levels")
void calc_auto_3ch_blend(
- uint16_t *a, // red
- uint16_t *b, // warm
- uint8_t *c, // cool
+ PWM_DATATYPE *a, // red
+ PWM_DATATYPE *b, // warm
+ PWM_DATATYPE *c, // cool
uint8_t level) {
- // led4=red, led3=warm
- uint16_t vpwm = PWM_GET16(pwm2_levels, level);
- // main2=white, 8-bit
- uint8_t vpwm8 = PWM_GET8 (pwm1_levels, level);
+ PWM_DATATYPE vpwm = PWM_GET(pwm1_levels, level);
// tint goes from 0 (red) to 127 (warm white) to 255 (cool white)
uint8_t mytint;
@@ -244,106 +246,88 @@ void calc_auto_3ch_blend(
*b = (((PWM_DATATYPE2)triangle_wave(mytint)
* (PWM_DATATYPE2)vpwm) ) / 255;
// cool white is low at 0, high at 255 (linear)
- *c = (uint8_t)(
- (((PWM_DATATYPE2)rising
- * (PWM_DATATYPE2)vpwm8) + 127) / 255
- );
+ *c = (((PWM_DATATYPE2)rising
+ * (PWM_DATATYPE2)vpwm) + 127) / 255;
}
// 3-channel "auto tint" channel mode
void set_level_auto3(uint8_t level) {
- uint16_t a, b;
- uint8_t c;
+ PWM_DATATYPE a, b, c;
calc_auto_3ch_blend(&a, &b, &c, level);
- // pulse frequency modulation, a.k.a. dynamic PWM
- uint16_t top = PWM_GET(pwm_tops, level);
+ set_hw_levels(c, b, a,
+ 0, 0, (0 == level));
+}
- if ((a > 0) || (0 == level)) // don't turn off at bottom level
- LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN );
- else LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN );
- if (b > 0) LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN );
- else LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN );
- if (c > 0) MAIN2_ENABLE_PORT |= (1 << MAIN2_ENABLE_PIN);
- else MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN);
+///// "gradual tick" functions for smooth thermal regulation /////
- LED4_PWM_LVL = a; // red
- LED3_PWM_LVL = b; // warm
- MAIN2_PWM_LVL = c; // cool
+bool gradual_adjust(PWM_DATATYPE main2, PWM_DATATYPE led3, PWM_DATATYPE led4) {
+ // adjust multiple times based on current brightness
+ // (so it adjusts faster/coarser when bright, slower/finer when dim)
- while(actual_level && (PWM_CNT > (255 - 32))) {}
- PWM_TOP = top;
- if (! actual_level) PWM_CNT = 0;
-}
+ // higher shift = slower/finer adjustments
+ const uint8_t shift = 9; // ((255 << 7) >> 9) = 63 max
+ uint8_t steps;
-///// "gradual tick" functions for smooth thermal regulation /////
+ steps = main2_dsm_lvl >> shift;
+ for (uint8_t i=0; i<=steps; i++)
+ GRADUAL_ADJUST_SIMPLE(main2, main2_dsm_lvl);
-bool gradual_adjust(uint8_t main2, uint16_t led3, uint16_t led4) {
- GRADUAL_ADJUST_SIMPLE(main2, MAIN2_PWM_LVL);
- GRADUAL_ADJUST_SIMPLE(led3, LED3_PWM_LVL );
- GRADUAL_ADJUST_SIMPLE(led4, LED4_PWM_LVL );
+ steps = led3_dsm_lvl >> shift;
+ for (uint8_t i=0; i<=steps; i++)
+ GRADUAL_ADJUST_SIMPLE(led3, led3_dsm_lvl );
- if ((main2 == MAIN2_PWM_LVL)
- && (led3 == LED3_PWM_LVL )
- && (led4 == LED4_PWM_LVL )) {
+ steps = led4_dsm_lvl >> shift;
+ for (uint8_t i=0; i<=steps; i++)
+ GRADUAL_ADJUST_SIMPLE(led4, led4_dsm_lvl );
+
+ if ((main2 == main2_dsm_lvl)
+ && (led3 == led3_dsm_lvl )
+ && (led4 == led4_dsm_lvl )) {
return true; // done
}
return false; // not done yet
}
bool gradual_tick_main2(uint8_t gt) {
- uint8_t main2 = PWM_GET8(pwm1_levels, gt);
+ PWM_DATATYPE main2 = PWM_GET(pwm1_levels, gt);
return gradual_adjust(main2, 0, 0);
}
bool gradual_tick_led3(uint8_t gt) {
- uint16_t led3 = PWM_GET16(pwm2_levels, gt);
+ PWM_DATATYPE led3 = PWM_GET(pwm1_levels, gt);
return gradual_adjust(0, led3, 0);
}
bool gradual_tick_led4(uint8_t gt) {
- uint16_t led4 = PWM_GET16(pwm2_levels, gt);
+ PWM_DATATYPE led4 = PWM_GET(pwm1_levels, gt);
return gradual_adjust(0, 0, led4);
}
bool gradual_tick_all(uint8_t gt) {
- uint8_t main2 = PWM_GET8 (pwm1_levels, gt);
- uint16_t led3 = PWM_GET16(pwm2_levels, gt);
- uint16_t led4 = PWM_GET16(pwm2_levels, gt);
- return gradual_adjust(main2, led3, led4);
+ PWM_DATATYPE pwm = PWM_GET(pwm1_levels, gt);
+ return gradual_adjust(pwm, pwm, pwm);
}
// 8/16/16 wiring, mix 16+16
bool gradual_tick_led34a_blend(uint8_t gt) {
PWM_DATATYPE warm_PWM, cool_PWM;
- PWM_DATATYPE brightness = PWM_GET16(pwm2_levels, gt);
- PWM_DATATYPE top = PWM_GET16(pwm_tops, gt);
+ PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt);
uint8_t blend = cfg.channel_mode_args[channel_mode];
- calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend);
+ calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, DSM_TOP, blend);
return gradual_adjust(0, warm_PWM, cool_PWM);
}
// 16/16/8 wiring, mix 16+8
bool gradual_tick_led34b_blend(uint8_t gt) {
- const uint16_t top = 2047;
- uint16_t warm_PWM, cool_PWM; // 11 bits, 8 bits
+ PWM_DATATYPE warm_PWM, cool_PWM;
+ PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt);
uint8_t blend = cfg.channel_mode_args[channel_mode];
- uint16_t brightness = PWM_GET8(pwm1_levels, gt);
-
- if (0 == brightness) brightness = 1;
- brightness = brightness << 3;
-
- calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend);
-
- // adjust to halfway between 8-bit steps
- warm_PWM -= 4;
- if (warm_PWM > top) warm_PWM = 0;
- // convert to 8-bit
- cool_PWM = (uint8_t)(cool_PWM >> 3);
+ calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, DSM_TOP, blend);
return gradual_adjust(cool_PWM, warm_PWM, 0);
}
@@ -353,7 +337,7 @@ bool gradual_tick_hsv(uint8_t gt) {
RGB_t color;
uint8_t h = cfg.channel_mode_args[channel_mode];
uint8_t s = 255; // TODO: drop saturation at brightest levels
- uint8_t v = PWM_GET8(pwm1_levels, gt);
+ PWM_DATATYPE v = PWM_GET(pwm1_levels, gt);
color = hsv2rgb(h, s, v);
return gradual_adjust(color.r, color.g, color.b);
@@ -361,8 +345,7 @@ bool gradual_tick_hsv(uint8_t gt) {
bool gradual_tick_auto3(uint8_t gt) {
// figure out what exact PWM levels we're aiming for
- uint16_t red, warm;
- uint8_t cool;
+ PWM_DATATYPE red, warm, cool;
calc_auto_3ch_blend(&red, &warm, &cool, gt);
return gradual_adjust(cool, warm, red);
}
diff --git a/hwdef-emisar-d4k-3ch.h b/hwdef-emisar-d4k-3ch.h
index 538e3f6..59e6f01 100644
--- a/hwdef-emisar-d4k-3ch.h
+++ b/hwdef-emisar-d4k-3ch.h
@@ -68,7 +68,7 @@ enum channel_modes_e {
RGB_AUX_ENUMS
};
-#define CHANNEL_MODES_ENABLED 0b0000000000011111
+#define CHANNEL_MODES_ENABLED 0b0000000000001111
#define USE_CHANNEL_MODE_ARGS
// _, _, _, _, 128=middle CCT, 128=middle CCT, 213=purple, _
#define CHANNEL_MODE_ARGS 0,0,0,0,128,128,213,0,RGB_AUX_CM_ARGS
@@ -86,28 +86,35 @@ enum channel_modes_e {
#define PWM_GET PWM_GET16
#define PWM_DATATYPE uint16_t
#define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255
-#define PWM1_DATATYPE uint8_t // 8-bit PWM on main2
-#define PWM2_DATATYPE uint16_t // dynamic PWM on led3 + led4
+#define PWM1_DATATYPE uint16_t // 15-bit PWM+DSM ramp
// dynamic PWM
#define PWM_TOP ICR1 // holds the TOP value for for variable-resolution PWM
-#define PWM_TOP_INIT 511 // highest value used in top half of ramp
-#define PWM_CNT TCNT1 // for dynamic PWM, reset phase
+#define PWM_TOP_INIT 255 // highest value used in top half of ramp
+#define PWM_CNT TCNT1 // for checking / resetting phase
+#define PWM_CNT2 TCNT0 // for checking / resetting phase
+// (max is (255 << 7), because it's 8-bit PWM plus 7 bits of DSM)
+#define DSM_TOP (255<<7) // 15-bit resolution leaves 1 bit for carry
// main 2 LEDs / 1st channel (2 LEDs)
+uint16_t main2_dsm_lvl;
+uint8_t main2_pwm, main2_dsm;
#define MAIN2_PWM_PIN PC0
#define MAIN2_PWM_LVL OCR0A // OCR0A is the output compare register for PC0
#define MAIN2_ENABLE_PIN PB0 // Opamp power
#define MAIN2_ENABLE_PORT PORTB // control port for PB0
// LED 3 / 2nd channel (1 LED)
+uint16_t led3_dsm_lvl;
+uint8_t led3_pwm, led3_dsm;
#define LED3_PWM_PIN PB3
#define LED3_PWM_LVL OCR1A // OCR1A is the output compare register for PB3
#define LED3_ENABLE_PIN PA1 // Opamp power
#define LED3_ENABLE_PORT PORTA // control port for PA1
// LED 4 / 3rd channel (1 LED)
-// 8-bit PWM only on OCR0A :(
+uint16_t led4_dsm_lvl;
+uint8_t led4_pwm, led4_dsm;
#define LED4_PWM_PIN PA6
#define LED4_PWM_LVL OCR1B // OCR1B is the output compare register for PA6
#define LED4_ENABLE_PIN PA0 // Opamp power
@@ -206,6 +213,8 @@ inline void hwdef_setup() {
//| (1<<WGM13) | (1<<WGM12) // fast adjustable PWM (DS table 12-5)
| (1<<WGM13) | (0<<WGM12) // phase-correct adjustable PWM (DS table 12-5)
;
+ // set PWM resolution
+ PWM_TOP = PWM_TOP_INIT;
// 8-bit PWM channel (LEDs 1+2 or LED 4)
// WGM0[2:0]: 0,0,1: PWM, Phase Correct, 8-bit (DS table 11-8)
@@ -219,8 +228,9 @@ inline void hwdef_setup() {
TCCR0B = (0<<CS02) | (0<<CS01) | (1<<CS00) // clk/1 (no prescaling) (DS table 11-9)
| (0<<WGM02) // phase-correct PWM (DS table 11-8)
;
- // set PWM resolution
- PWM_TOP = PWM_TOP_INIT;
+
+ // set up interrupt for delta-sigma modulation
+ TIMSK |= (1<<TOIE0); // interrupt once for each timer 0 cycle
// set up e-switch
SWITCH_PUE = (1 << SWITCH_PIN); // pull-up for e-switch
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.