aboutsummaryrefslogtreecommitdiff
path: root/quantum/backlight/backlight_avr.c
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/backlight/backlight_avr.c')
-rw-r--r--quantum/backlight/backlight_avr.c525
1 files changed, 241 insertions, 284 deletions
diff --git a/quantum/backlight/backlight_avr.c b/quantum/backlight/backlight_avr.c
index 519c0c2cf..ce6611fb5 100644
--- a/quantum/backlight/backlight_avr.c
+++ b/quantum/backlight/backlight_avr.c
@@ -2,7 +2,9 @@
2#include "backlight.h" 2#include "backlight.h"
3#include "debug.h" 3#include "debug.h"
4 4
5#if defined(BACKLIGHT_ENABLE) && (defined(BACKLIGHT_PIN) || defined(BACKLIGHT_PINS)) 5#if !defined(BACKLIGHT_PIN) && !defined(BACKLIGHT_PINS)
6# error "Backlight pin/pins not defined. Please configure."
7#endif
6 8
7// This logic is a bit complex, we support 3 setups: 9// This logic is a bit complex, we support 3 setups:
8// 10//
@@ -12,262 +14,223 @@
12// depends on the Audio setup (Audio wins over Backlight). 14// depends on the Audio setup (Audio wins over Backlight).
13// 3. Full software PWM, driven by the matrix scan, if both timers are used by Audio. 15// 3. Full software PWM, driven by the matrix scan, if both timers are used by Audio.
14 16
15# if (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) && (BACKLIGHT_PIN == B5 || BACKLIGHT_PIN == B6 || BACKLIGHT_PIN == B7) 17#if (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) && (BACKLIGHT_PIN == B5 || BACKLIGHT_PIN == B6 || BACKLIGHT_PIN == B7)
16# define HARDWARE_PWM 18# define HARDWARE_PWM
17# define ICRx ICR1 19# define ICRx ICR1
18# define TCCRxA TCCR1A 20# define TCCRxA TCCR1A
19# define TCCRxB TCCR1B 21# define TCCRxB TCCR1B
20# define TIMERx_OVF_vect TIMER1_OVF_vect 22# define TIMERx_OVF_vect TIMER1_OVF_vect
21# define TIMSKx TIMSK1 23# define TIMSKx TIMSK1
22# define TOIEx TOIE1 24# define TOIEx TOIE1
23 25
24# if BACKLIGHT_PIN == B5 26# if BACKLIGHT_PIN == B5
25# define COMxx0 COM1A0 27# define COMxx0 COM1A0
26# define COMxx1 COM1A1 28# define COMxx1 COM1A1
27# define OCRxx OCR1A 29# define OCRxx OCR1A
28# elif BACKLIGHT_PIN == B6 30# elif BACKLIGHT_PIN == B6
29# define COMxx0 COM1B0 31# define COMxx0 COM1B0
30# define COMxx1 COM1B1 32# define COMxx1 COM1B1
31# define OCRxx OCR1B 33# define OCRxx OCR1B
32# elif BACKLIGHT_PIN == B7 34# elif BACKLIGHT_PIN == B7
33# define COMxx0 COM1C0 35# define COMxx0 COM1C0
34# define COMxx1 COM1C1 36# define COMxx1 COM1C1
35# define OCRxx OCR1C 37# define OCRxx OCR1C
36# endif 38# endif
37# elif (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) && (BACKLIGHT_PIN == C4 || BACKLIGHT_PIN == C5 || BACKLIGHT_PIN == C6) 39#elif (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) && (BACKLIGHT_PIN == C4 || BACKLIGHT_PIN == C5 || BACKLIGHT_PIN == C6)
38# define HARDWARE_PWM 40# define HARDWARE_PWM
39# define ICRx ICR3 41# define ICRx ICR3
40# define TCCRxA TCCR3A 42# define TCCRxA TCCR3A
41# define TCCRxB TCCR3B 43# define TCCRxB TCCR3B
42# define TIMERx_OVF_vect TIMER3_OVF_vect 44# define TIMERx_OVF_vect TIMER3_OVF_vect
43# define TIMSKx TIMSK3 45# define TIMSKx TIMSK3
44# define TOIEx TOIE3 46# define TOIEx TOIE3
45 47
46# if BACKLIGHT_PIN == C4 48# if BACKLIGHT_PIN == C4
47# if (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) 49# if (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__))
48# error This MCU has no C4 pin! 50# error This MCU has no C4 pin!
49# else 51# else
50# define COMxx0 COM3C0 52# define COMxx0 COM3C0
51# define COMxx1 COM3C1 53# define COMxx1 COM3C1
52# define OCRxx OCR3C 54# define OCRxx OCR3C
53# endif
54# elif BACKLIGHT_PIN == C5
55# if (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__))
56# error This MCU has no C5 pin!
57# else
58# define COMxx0 COM3B0
59# define COMxx1 COM3B1
60# define OCRxx OCR3B
61# endif
62# elif BACKLIGHT_PIN == C6
63# define COMxx0 COM3A0
64# define COMxx1 COM3A1
65# define OCRxx OCR3A
66# endif 55# endif
67# elif (defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__)) && (BACKLIGHT_PIN == B7 || BACKLIGHT_PIN == C5 || BACKLIGHT_PIN == C6) 56# elif BACKLIGHT_PIN == C5
68# define HARDWARE_PWM 57# if (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__))
69# define ICRx ICR1 58# error This MCU has no C5 pin!
70# define TCCRxA TCCR1A 59# else
71# define TCCRxB TCCR1B 60# define COMxx0 COM3B0
72# define TIMERx_OVF_vect TIMER1_OVF_vect 61# define COMxx1 COM3B1
73# define TIMSKx TIMSK1 62# define OCRxx OCR3B
74# define TOIEx TOIE1
75
76# if BACKLIGHT_PIN == B7
77# define COMxx0 COM1C0
78# define COMxx1 COM1C1
79# define OCRxx OCR1C
80# elif BACKLIGHT_PIN == C5
81# define COMxx0 COM1B0
82# define COMxx1 COM1B1
83# define OCRxx OCR1B
84# elif BACKLIGHT_PIN == C6
85# define COMxx0 COM1A0
86# define COMxx1 COM1A1
87# define OCRxx OCR1A
88# endif 63# endif
89# elif defined(__AVR_ATmega32A__) && (BACKLIGHT_PIN == D4 || BACKLIGHT_PIN == D5) 64# elif BACKLIGHT_PIN == C6
90# define HARDWARE_PWM 65# define COMxx0 COM3A0
91# define ICRx ICR1 66# define COMxx1 COM3A1
92# define TCCRxA TCCR1A 67# define OCRxx OCR3A
93# define TCCRxB TCCR1B 68# endif
94# define TIMERx_OVF_vect TIMER1_OVF_vect 69#elif (defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__)) && (BACKLIGHT_PIN == B7 || BACKLIGHT_PIN == C5 || BACKLIGHT_PIN == C6)
70# define HARDWARE_PWM
71# define ICRx ICR1
72# define TCCRxA TCCR1A
73# define TCCRxB TCCR1B
74# define TIMERx_OVF_vect TIMER1_OVF_vect
75# define TIMSKx TIMSK1
76# define TOIEx TOIE1
77
78# if BACKLIGHT_PIN == B7
79# define COMxx0 COM1C0
80# define COMxx1 COM1C1
81# define OCRxx OCR1C
82# elif BACKLIGHT_PIN == C5
83# define COMxx0 COM1B0
84# define COMxx1 COM1B1
85# define OCRxx OCR1B
86# elif BACKLIGHT_PIN == C6
87# define COMxx0 COM1A0
88# define COMxx1 COM1A1
89# define OCRxx OCR1A
90# endif
91#elif defined(__AVR_ATmega32A__) && (BACKLIGHT_PIN == D4 || BACKLIGHT_PIN == D5)
92# define HARDWARE_PWM
93# define ICRx ICR1
94# define TCCRxA TCCR1A
95# define TCCRxB TCCR1B
96# define TIMERx_OVF_vect TIMER1_OVF_vect
97# define TIMSKx TIMSK
98# define TOIEx TOIE1
99
100# if BACKLIGHT_PIN == D4
101# define COMxx0 COM1B0
102# define COMxx1 COM1B1
103# define OCRxx OCR1B
104# elif BACKLIGHT_PIN == D5
105# define COMxx0 COM1A0
106# define COMxx1 COM1A1
107# define OCRxx OCR1A
108# endif
109#elif defined(__AVR_ATmega328P__) && (BACKLIGHT_PIN == B1 || BACKLIGHT_PIN == B2)
110# define HARDWARE_PWM
111# define ICRx ICR1
112# define TCCRxA TCCR1A
113# define TCCRxB TCCR1B
114# define TIMERx_OVF_vect TIMER1_OVF_vect
115# define TIMSKx TIMSK1
116# define TOIEx TOIE1
117
118# if BACKLIGHT_PIN == B1
119# define COMxx0 COM1A0
120# define COMxx1 COM1A1
121# define OCRxx OCR1A
122# elif BACKLIGHT_PIN == B2
123# define COMxx0 COM1B0
124# define COMxx1 COM1B1
125# define OCRxx OCR1B
126# endif
127#elif !defined(B5_AUDIO) && !defined(B6_AUDIO) && !defined(B7_AUDIO)
128// Timer 1 is not in use by Audio feature, Backlight can use it
129# pragma message "Using hardware timer 1 with software PWM"
130# define HARDWARE_PWM
131# define BACKLIGHT_PWM_TIMER
132# define ICRx ICR1
133# define TCCRxA TCCR1A
134# define TCCRxB TCCR1B
135# define TIMERx_COMPA_vect TIMER1_COMPA_vect
136# define TIMERx_OVF_vect TIMER1_OVF_vect
137# if defined(__AVR_ATmega32A__) // This MCU has only one TIMSK register
95# define TIMSKx TIMSK 138# define TIMSKx TIMSK
96# define TOIEx TOIE1
97
98# if BACKLIGHT_PIN == D4
99# define COMxx0 COM1B0
100# define COMxx1 COM1B1
101# define OCRxx OCR1B
102# elif BACKLIGHT_PIN == D5
103# define COMxx0 COM1A0
104# define COMxx1 COM1A1
105# define OCRxx OCR1A
106# endif
107# elif defined(__AVR_ATmega328P__) && (BACKLIGHT_PIN == B1 || BACKLIGHT_PIN == B2)
108# define HARDWARE_PWM
109# define ICRx ICR1
110# define TCCRxA TCCR1A
111# define TCCRxB TCCR1B
112# define TIMERx_OVF_vect TIMER1_OVF_vect
113# define TIMSKx TIMSK1
114# define TOIEx TOIE1
115
116# if BACKLIGHT_PIN == B1
117# define COMxx0 COM1A0
118# define COMxx1 COM1A1
119# define OCRxx OCR1A
120# elif BACKLIGHT_PIN == B2
121# define COMxx0 COM1B0
122# define COMxx1 COM1B1
123# define OCRxx OCR1B
124# endif
125# else 139# else
126# if !defined(BACKLIGHT_CUSTOM_DRIVER) 140# define TIMSKx TIMSK1
127# if !defined(B5_AUDIO) && !defined(B6_AUDIO) && !defined(B7_AUDIO)
128// Timer 1 is not in use by Audio feature, Backlight can use it
129# pragma message "Using hardware timer 1 with software PWM"
130# define HARDWARE_PWM
131# define BACKLIGHT_PWM_TIMER
132# define ICRx ICR1
133# define TCCRxA TCCR1A
134# define TCCRxB TCCR1B
135# define TIMERx_COMPA_vect TIMER1_COMPA_vect
136# define TIMERx_OVF_vect TIMER1_OVF_vect
137# if defined(__AVR_ATmega32A__) // This MCU has only one TIMSK register
138# define TIMSKx TIMSK
139# else
140# define TIMSKx TIMSK1
141# endif
142# define TOIEx TOIE1
143
144# define OCIExA OCIE1A
145# define OCRxx OCR1A
146# elif !defined(C6_AUDIO) && !defined(C5_AUDIO) && !defined(C4_AUDIO)
147# pragma message "Using hardware timer 3 with software PWM"
148// Timer 3 is not in use by Audio feature, Backlight can use it
149# define HARDWARE_PWM
150# define BACKLIGHT_PWM_TIMER
151# define ICRx ICR1
152# define TCCRxA TCCR3A
153# define TCCRxB TCCR3B
154# define TIMERx_COMPA_vect TIMER3_COMPA_vect
155# define TIMERx_OVF_vect TIMER3_OVF_vect
156# define TIMSKx TIMSK3
157# define TOIEx TOIE3
158
159# define OCIExA OCIE3A
160# define OCRxx OCR3A
161# else
162# pragma message "Audio in use - using pure software PWM"
163# define NO_HARDWARE_PWM
164# endif
165# else
166# pragma message "Custom driver defined - using pure software PWM"
167# define NO_HARDWARE_PWM
168# endif
169# endif 141# endif
142# define TOIEx TOIE1
170 143
171# ifndef BACKLIGHT_ON_STATE 144# define OCIExA OCIE1A
172# define BACKLIGHT_ON_STATE 1 145# define OCRxx OCR1A
173# endif 146#elif !defined(C6_AUDIO) && !defined(C5_AUDIO) && !defined(C4_AUDIO)
147# pragma message "Using hardware timer 3 with software PWM"
148// Timer 3 is not in use by Audio feature, Backlight can use it
149# define HARDWARE_PWM
150# define BACKLIGHT_PWM_TIMER
151# define ICRx ICR1
152# define TCCRxA TCCR3A
153# define TCCRxB TCCR3B
154# define TIMERx_COMPA_vect TIMER3_COMPA_vect
155# define TIMERx_OVF_vect TIMER3_OVF_vect
156# define TIMSKx TIMSK3
157# define TOIEx TOIE3
158
159# define OCIExA OCIE3A
160# define OCRxx OCR3A
161#elif defined(BACKLIGHT_CUSTOM_DRIVER)
162error("Please set 'BACKLIGHT_DRIVER = custom' within rules.mk")
163#else
164error("Please set 'BACKLIGHT_DRIVER = software' within rules.mk")
165#endif
166
167#ifndef BACKLIGHT_ON_STATE
168# define BACKLIGHT_ON_STATE 1
169#endif
174 170
175void backlight_on(pin_t backlight_pin) { 171void backlight_on(pin_t backlight_pin) {
176# if BACKLIGHT_ON_STATE == 1 172#if BACKLIGHT_ON_STATE == 1
177 writePinHigh(backlight_pin); 173 writePinHigh(backlight_pin);
178# else 174#else
179 writePinLow(backlight_pin); 175 writePinLow(backlight_pin);
180# endif 176#endif
181} 177}
182 178
183void backlight_off(pin_t backlight_pin) { 179void backlight_off(pin_t backlight_pin) {
184# if BACKLIGHT_ON_STATE == 1 180#if BACKLIGHT_ON_STATE == 1
185 writePinLow(backlight_pin); 181 writePinLow(backlight_pin);
186# else 182#else
187 writePinHigh(backlight_pin); 183 writePinHigh(backlight_pin);
188# endif 184#endif
189} 185}
190 186
191# if defined(NO_HARDWARE_PWM) || defined(BACKLIGHT_PWM_TIMER) // pwm through software 187#ifdef BACKLIGHT_PWM_TIMER // pwm through software
192 188
193// we support multiple backlight pins 189// we support multiple backlight pins
194# ifndef BACKLIGHT_LED_COUNT 190# ifndef BACKLIGHT_LED_COUNT
195# define BACKLIGHT_LED_COUNT 1 191# define BACKLIGHT_LED_COUNT 1
196# endif 192# endif
197 193
198# if BACKLIGHT_LED_COUNT == 1 194# if BACKLIGHT_LED_COUNT == 1
199# define BACKLIGHT_PIN_INIT \ 195# define BACKLIGHT_PIN_INIT \
200 { BACKLIGHT_PIN } 196 { BACKLIGHT_PIN }
201# else 197# else
202# define BACKLIGHT_PIN_INIT BACKLIGHT_PINS 198# define BACKLIGHT_PIN_INIT BACKLIGHT_PINS
203# endif 199# endif
204 200
205# define FOR_EACH_LED(x) \ 201# define FOR_EACH_LED(x) \
206 for (uint8_t i = 0; i < BACKLIGHT_LED_COUNT; i++) { \ 202 for (uint8_t i = 0; i < BACKLIGHT_LED_COUNT; i++) { \
207 pin_t backlight_pin = backlight_pins[i]; \ 203 pin_t backlight_pin = backlight_pins[i]; \
208 { x } \ 204 { x } \
209 } 205 }
210 206
211static const pin_t backlight_pins[BACKLIGHT_LED_COUNT] = BACKLIGHT_PIN_INIT; 207static const pin_t backlight_pins[BACKLIGHT_LED_COUNT] = BACKLIGHT_PIN_INIT;
212 208
213# else // full hardware PWM 209#else // full hardware PWM
214 210
215static inline void enable_pwm(void) { 211static inline void enable_pwm(void) {
216# if BACKLIGHT_ON_STATE == 1 212# if BACKLIGHT_ON_STATE == 1
217 TCCRxA |= _BV(COMxx1); 213 TCCRxA |= _BV(COMxx1);
218# else 214# else
219 TCCRxA |= _BV(COMxx1) | _BV(COMxx0); 215 TCCRxA |= _BV(COMxx1) | _BV(COMxx0);
220# endif 216# endif
221} 217}
222 218
223static inline void disable_pwm(void) { 219static inline void disable_pwm(void) {
224# if BACKLIGHT_ON_STATE == 1 220# if BACKLIGHT_ON_STATE == 1
225 TCCRxA &= ~(_BV(COMxx1)); 221 TCCRxA &= ~(_BV(COMxx1));
226# else 222# else
227 TCCRxA &= ~(_BV(COMxx1) | _BV(COMxx0)); 223 TCCRxA &= ~(_BV(COMxx1) | _BV(COMxx0));
228# endif 224# endif
229} 225}
230 226
231// we support only one backlight pin 227// we support only one backlight pin
232static const pin_t backlight_pin = BACKLIGHT_PIN; 228static const pin_t backlight_pin = BACKLIGHT_PIN;
233# define FOR_EACH_LED(x) x 229# define FOR_EACH_LED(x) x
234
235# endif
236
237# ifdef NO_HARDWARE_PWM
238void backlight_init_ports(void) {
239 // Setup backlight pin as output and output to on state.
240 FOR_EACH_LED(setPinOutput(backlight_pin); backlight_on(backlight_pin);)
241
242# ifdef BACKLIGHT_BREATHING
243 if (is_backlight_breathing()) {
244 breathing_enable();
245 }
246# endif
247}
248
249uint8_t backlight_tick = 0;
250
251# ifndef BACKLIGHT_CUSTOM_DRIVER
252void backlight_task(void) {
253 if ((0xFFFF >> ((BACKLIGHT_LEVELS - get_backlight_level()) * ((BACKLIGHT_LEVELS + 1) / 2))) & (1 << backlight_tick)) {
254 FOR_EACH_LED(backlight_on(backlight_pin);)
255 } else {
256 FOR_EACH_LED(backlight_off(backlight_pin);)
257 }
258 backlight_tick = (backlight_tick + 1) % 16;
259}
260# endif
261
262# ifdef BACKLIGHT_BREATHING
263# ifndef BACKLIGHT_CUSTOM_DRIVER
264# error "Backlight breathing only available with hardware PWM. Please disable."
265# endif
266# endif
267 230
268# else // hardware pwm through timer 231#endif
269 232
270# ifdef BACKLIGHT_PWM_TIMER 233#ifdef BACKLIGHT_PWM_TIMER
271 234
272// The idea of software PWM assisted by hardware timers is the following 235// The idea of software PWM assisted by hardware timers is the following
273// we use the hardware timer in fast PWM mode like for hardware PWM, but 236// we use the hardware timer in fast PWM mode like for hardware PWM, but
@@ -288,11 +251,11 @@ ISR(TIMERx_COMPA_vect) { FOR_EACH_LED(backlight_off(backlight_pin);) }
288// Triggered when the counter reaches the TOP value 251// Triggered when the counter reaches the TOP value
289// this one triggers at F_CPU/65536 =~ 244 Hz 252// this one triggers at F_CPU/65536 =~ 244 Hz
290ISR(TIMERx_OVF_vect) { 253ISR(TIMERx_OVF_vect) {
291# ifdef BACKLIGHT_BREATHING 254# ifdef BACKLIGHT_BREATHING
292 if (is_breathing()) { 255 if (is_breathing()) {
293 breathing_task(); 256 breathing_task();
294 } 257 }
295# endif 258# endif
296 // for very small values of OCRxx (or backlight level) 259 // for very small values of OCRxx (or backlight level)
297 // we can't guarantee this whole code won't execute 260 // we can't guarantee this whole code won't execute
298 // at the same time as the compare match interrupt 261 // at the same time as the compare match interrupt
@@ -306,9 +269,9 @@ ISR(TIMERx_OVF_vect) {
306 } 269 }
307} 270}
308 271
309# endif 272#endif
310 273
311# define TIMER_TOP 0xFFFFU 274#define TIMER_TOP 0xFFFFU
312 275
313// See http://jared.geek.nz/2013/feb/linear-led-pwm 276// See http://jared.geek.nz/2013/feb/linear-led-pwm
314static uint16_t cie_lightness(uint16_t v) { 277static uint16_t cie_lightness(uint16_t v) {
@@ -329,88 +292,86 @@ static uint16_t cie_lightness(uint16_t v) {
329// range for val is [0..TIMER_TOP]. PWM pin is high while the timer count is below val. 292// range for val is [0..TIMER_TOP]. PWM pin is high while the timer count is below val.
330static inline void set_pwm(uint16_t val) { OCRxx = val; } 293static inline void set_pwm(uint16_t val) { OCRxx = val; }
331 294
332# ifndef BACKLIGHT_CUSTOM_DRIVER
333void backlight_set(uint8_t level) { 295void backlight_set(uint8_t level) {
334 if (level > BACKLIGHT_LEVELS) level = BACKLIGHT_LEVELS; 296 if (level > BACKLIGHT_LEVELS) level = BACKLIGHT_LEVELS;
335 297
336 if (level == 0) { 298 if (level == 0) {
337# ifdef BACKLIGHT_PWM_TIMER 299#ifdef BACKLIGHT_PWM_TIMER
338 if (OCRxx) { 300 if (OCRxx) {
339 TIMSKx &= ~(_BV(OCIExA)); 301 TIMSKx &= ~(_BV(OCIExA));
340 TIMSKx &= ~(_BV(TOIEx)); 302 TIMSKx &= ~(_BV(TOIEx));
341 } 303 }
342# else 304#else
343 // Turn off PWM control on backlight pin 305 // Turn off PWM control on backlight pin
344 disable_pwm(); 306 disable_pwm();
345# endif 307#endif
346 FOR_EACH_LED(backlight_off(backlight_pin);) 308 FOR_EACH_LED(backlight_off(backlight_pin);)
347 } else { 309 } else {
348# ifdef BACKLIGHT_PWM_TIMER 310#ifdef BACKLIGHT_PWM_TIMER
349 if (!OCRxx) { 311 if (!OCRxx) {
350 TIMSKx |= _BV(OCIExA); 312 TIMSKx |= _BV(OCIExA);
351 TIMSKx |= _BV(TOIEx); 313 TIMSKx |= _BV(TOIEx);
352 } 314 }
353# else 315#else
354 // Turn on PWM control of backlight pin 316 // Turn on PWM control of backlight pin
355 enable_pwm(); 317 enable_pwm();
356# endif 318#endif
357 } 319 }
358 // Set the brightness 320 // Set the brightness
359 set_pwm(cie_lightness(TIMER_TOP * (uint32_t)level / BACKLIGHT_LEVELS)); 321 set_pwm(cie_lightness(TIMER_TOP * (uint32_t)level / BACKLIGHT_LEVELS));
360} 322}
361 323
362void backlight_task(void) {} 324void backlight_task(void) {}
363# endif // BACKLIGHT_CUSTOM_DRIVER
364 325
365# ifdef BACKLIGHT_BREATHING 326#ifdef BACKLIGHT_BREATHING
366 327
367# define BREATHING_NO_HALT 0 328# define BREATHING_NO_HALT 0
368# define BREATHING_HALT_OFF 1 329# define BREATHING_HALT_OFF 1
369# define BREATHING_HALT_ON 2 330# define BREATHING_HALT_ON 2
370# define BREATHING_STEPS 128 331# define BREATHING_STEPS 128
371 332
372static uint8_t breathing_halt = BREATHING_NO_HALT; 333static uint8_t breathing_halt = BREATHING_NO_HALT;
373static uint16_t breathing_counter = 0; 334static uint16_t breathing_counter = 0;
374 335
375# ifdef BACKLIGHT_PWM_TIMER 336# ifdef BACKLIGHT_PWM_TIMER
376static bool breathing = false; 337static bool breathing = false;
377 338
378bool is_breathing(void) { return breathing; } 339bool is_breathing(void) { return breathing; }
379 340
380# define breathing_interrupt_enable() \ 341# define breathing_interrupt_enable() \
381 do { \ 342 do { \
382 breathing = true; \ 343 breathing = true; \
383 } while (0) 344 } while (0)
384# define breathing_interrupt_disable() \ 345# define breathing_interrupt_disable() \
385 do { \ 346 do { \
386 breathing = false; \ 347 breathing = false; \
387 } while (0) 348 } while (0)
388# else 349# else
389 350
390bool is_breathing(void) { return !!(TIMSKx & _BV(TOIEx)); } 351bool is_breathing(void) { return !!(TIMSKx & _BV(TOIEx)); }
391 352
392# define breathing_interrupt_enable() \ 353# define breathing_interrupt_enable() \
393 do { \ 354 do { \
394 TIMSKx |= _BV(TOIEx); \ 355 TIMSKx |= _BV(TOIEx); \
395 } while (0) 356 } while (0)
396# define breathing_interrupt_disable() \ 357# define breathing_interrupt_disable() \
397 do { \ 358 do { \
398 TIMSKx &= ~_BV(TOIEx); \ 359 TIMSKx &= ~_BV(TOIEx); \
399 } while (0) 360 } while (0)
400# endif 361# endif
401 362
402# define breathing_min() \ 363# define breathing_min() \
403 do { \ 364 do { \
404 breathing_counter = 0; \ 365 breathing_counter = 0; \
405 } while (0) 366 } while (0)
406# define breathing_max() \ 367# define breathing_max() \
407 do { \ 368 do { \
408 breathing_counter = get_breathing_period() * 244 / 2; \ 369 breathing_counter = get_breathing_period() * 244 / 2; \
409 } while (0) 370 } while (0)
410 371
411void breathing_enable(void) { 372void breathing_enable(void) {
412 breathing_counter = 0; 373 breathing_counter = 0;
413 breathing_halt = BREATHING_NO_HALT; 374 breathing_halt = BREATHING_NO_HALT;
414 breathing_interrupt_enable(); 375 breathing_interrupt_enable();
415} 376}
416 377
@@ -451,20 +412,20 @@ static const uint8_t breathing_table[BREATHING_STEPS] PROGMEM = {0, 0, 0, 0, 0,
451// Use this before the cie_lightness function. 412// Use this before the cie_lightness function.
452static inline uint16_t scale_backlight(uint16_t v) { return v / BACKLIGHT_LEVELS * get_backlight_level(); } 413static inline uint16_t scale_backlight(uint16_t v) { return v / BACKLIGHT_LEVELS * get_backlight_level(); }
453 414
454# ifdef BACKLIGHT_PWM_TIMER 415# ifdef BACKLIGHT_PWM_TIMER
455void breathing_task(void) 416void breathing_task(void)
456# else 417# else
457/* Assuming a 16MHz CPU clock and a timer that resets at 64k (ICR1), the following interrupt handler will run 418/* Assuming a 16MHz CPU clock and a timer that resets at 64k (ICR1), the following interrupt handler will run
458 * about 244 times per second. 419 * about 244 times per second.
459 */ 420 */
460ISR(TIMERx_OVF_vect) 421ISR(TIMERx_OVF_vect)
461# endif 422# endif
462{ 423{
463 uint8_t breathing_period = get_breathing_period(); 424 uint8_t breathing_period = get_breathing_period();
464 uint16_t interval = (uint16_t)breathing_period * 244 / BREATHING_STEPS; 425 uint16_t interval = (uint16_t)breathing_period * 244 / BREATHING_STEPS;
465 // resetting after one period to prevent ugly reset at overflow. 426 // resetting after one period to prevent ugly reset at overflow.
466 breathing_counter = (breathing_counter + 1) % (breathing_period * 244); 427 breathing_counter = (breathing_counter + 1) % (breathing_period * 244);
467 uint8_t index = breathing_counter / interval % BREATHING_STEPS; 428 uint8_t index = breathing_counter / interval % BREATHING_STEPS;
468 429
469 if (((breathing_halt == BREATHING_HALT_ON) && (index == BREATHING_STEPS / 2)) || ((breathing_halt == BREATHING_HALT_OFF) && (index == BREATHING_STEPS - 1))) { 430 if (((breathing_halt == BREATHING_HALT_ON) && (index == BREATHING_STEPS / 2)) || ((breathing_halt == BREATHING_HALT_OFF) && (index == BREATHING_STEPS - 1))) {
470 breathing_interrupt_disable(); 431 breathing_interrupt_disable();
@@ -473,7 +434,7 @@ ISR(TIMERx_OVF_vect)
473 set_pwm(cie_lightness(scale_backlight((uint16_t)pgm_read_byte(&breathing_table[index]) * 0x0101U))); 434 set_pwm(cie_lightness(scale_backlight((uint16_t)pgm_read_byte(&breathing_table[index]) * 0x0101U)));
474} 435}
475 436
476# endif // BACKLIGHT_BREATHING 437#endif // BACKLIGHT_BREATHING
477 438
478void backlight_init_ports(void) { 439void backlight_init_ports(void) {
479 // Setup backlight pin as output and output to on state. 440 // Setup backlight pin as output and output to on state.
@@ -483,12 +444,12 @@ void backlight_init_ports(void) {
483 // Go read the ATmega32u4 datasheet. 444 // Go read the ATmega32u4 datasheet.
484 // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on 445 // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on
485 446
486# ifdef BACKLIGHT_PWM_TIMER 447#ifdef BACKLIGHT_PWM_TIMER
487 // TimerX setup, Fast PWM mode count to TOP set in ICRx 448 // TimerX setup, Fast PWM mode count to TOP set in ICRx
488 TCCRxA = _BV(WGM11); // = 0b00000010; 449 TCCRxA = _BV(WGM11); // = 0b00000010;
489 // clock select clk/1 450 // clock select clk/1
490 TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001; 451 TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001;
491# else // hardware PWM 452#else // hardware PWM
492 // Pin PB7 = OCR1C (Timer 1, Channel C) 453 // Pin PB7 = OCR1C (Timer 1, Channel C)
493 // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0 454 // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0
494 // (i.e. start high, go low when counter matches.) 455 // (i.e. start high, go low when counter matches.)
@@ -500,25 +461,21 @@ void backlight_init_ports(void) {
500 "In fast PWM mode, the compare units allow generation of PWM waveforms on the OCnx pins. Setting the COMnx1:0 bits to two will produce a non-inverted PWM [..]." 461 "In fast PWM mode, the compare units allow generation of PWM waveforms on the OCnx pins. Setting the COMnx1:0 bits to two will produce a non-inverted PWM [..]."
501 "In fast PWM mode the counter is incremented until the counter value matches either one of the fixed values 0x00FF, 0x01FF, or 0x03FF (WGMn3:0 = 5, 6, or 7), the value in ICRn (WGMn3:0 = 14), or the value in OCRnA (WGMn3:0 = 15)." 462 "In fast PWM mode the counter is incremented until the counter value matches either one of the fixed values 0x00FF, 0x01FF, or 0x03FF (WGMn3:0 = 5, 6, or 7), the value in ICRn (WGMn3:0 = 14), or the value in OCRnA (WGMn3:0 = 15)."
502 */ 463 */
503# if BACKLIGHT_ON_STATE == 1 464# if BACKLIGHT_ON_STATE == 1
504 TCCRxA = _BV(COMxx1) | _BV(WGM11); 465 TCCRxA = _BV(COMxx1) | _BV(WGM11);
505# else 466# else
506 TCCRxA = _BV(COMxx1) | _BV(COMxx0) | _BV(WGM11); 467 TCCRxA = _BV(COMxx1) | _BV(COMxx0) | _BV(WGM11);
507# endif 468# endif
508 469
509 TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10); 470 TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10);
510# endif 471#endif
511 // Use full 16-bit resolution. Counter counts to ICR1 before reset to 0. 472 // Use full 16-bit resolution. Counter counts to ICR1 before reset to 0.
512 ICRx = TIMER_TOP; 473 ICRx = TIMER_TOP;
513 474
514 backlight_init(); 475 backlight_init();
515# ifdef BACKLIGHT_BREATHING 476#ifdef BACKLIGHT_BREATHING
516 if (is_backlight_breathing()) { 477 if (is_backlight_breathing()) {
517 breathing_enable(); 478 breathing_enable();
518 } 479 }
519# endif 480#endif
520} 481}
521
522# endif // hardware backlight
523
524#endif // backlight