|
@@ -1138,30 +1138,38 @@ void matrix_scan_quantum() {
|
|
|
|
|
|
matrix_scan_kb();
|
|
matrix_scan_kb();
|
|
}
|
|
}
|
|
-#if defined(BACKLIGHT_ENABLE) && defined(BACKLIGHT_PIN)
|
|
+#if defined(BACKLIGHT_ENABLE) && (defined(BACKLIGHT_PIN) || defined(BACKLIGHT_PINS))
|
|
|
|
|
|
-static const uint8_t backlight_pin = BACKLIGHT_PIN;
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
|
|
-
|
|
|
|
#if BACKLIGHT_PIN == B7
|
|
#if BACKLIGHT_PIN == B7
|
|
|
|
+# define HARDWARE_PWM
|
|
# define TCCRxA TCCR1A
|
|
# define TCCRxA TCCR1A
|
|
# define TCCRxB TCCR1B
|
|
# define TCCRxB TCCR1B
|
|
# define COMxx1 COM1C1
|
|
# define COMxx1 COM1C1
|
|
# define OCRxx OCR1C
|
|
# define OCRxx OCR1C
|
|
# define ICRx ICR1
|
|
# define ICRx ICR1
|
|
#elif BACKLIGHT_PIN == B6
|
|
#elif BACKLIGHT_PIN == B6
|
|
|
|
+# define HARDWARE_PWM
|
|
# define TCCRxA TCCR1A
|
|
# define TCCRxA TCCR1A
|
|
# define TCCRxB TCCR1B
|
|
# define TCCRxB TCCR1B
|
|
# define COMxx1 COM1B1
|
|
# define COMxx1 COM1B1
|
|
# define OCRxx OCR1B
|
|
# define OCRxx OCR1B
|
|
# define ICRx ICR1
|
|
# define ICRx ICR1
|
|
#elif BACKLIGHT_PIN == B5
|
|
#elif BACKLIGHT_PIN == B5
|
|
|
|
+# define HARDWARE_PWM
|
|
# define TCCRxA TCCR1A
|
|
# define TCCRxA TCCR1A
|
|
# define TCCRxB TCCR1B
|
|
# define TCCRxB TCCR1B
|
|
# define COMxx1 COM1A1
|
|
# define COMxx1 COM1A1
|
|
# define OCRxx OCR1A
|
|
# define OCRxx OCR1A
|
|
# define ICRx ICR1
|
|
# define ICRx ICR1
|
|
#elif BACKLIGHT_PIN == C6
|
|
#elif BACKLIGHT_PIN == C6
|
|
|
|
+# define HARDWARE_PWM
|
|
# define TCCRxA TCCR3A
|
|
# define TCCRxA TCCR3A
|
|
# define TCCRxB TCCR3B
|
|
# define TCCRxB TCCR3B
|
|
# define COMxx1 COM1A1
|
|
# define COMxx1 COM1A1
|
|
@@ -1175,28 +1183,115 @@ static const uint8_t backlight_pin = BACKLIGHT_PIN;
|
|
# define ICRx ICR1
|
|
# define ICRx ICR1
|
|
# define TIMSK1 TIMSK
|
|
# define TIMSK1 TIMSK
|
|
#else
|
|
#else
|
|
-# define NO_HARDWARE_PWM
|
|
+# if !defined(BACKLIGHT_CUSTOM_DRIVER)
|
|
|
|
+# if !defined(B5_AUDIO) && !defined(B6_AUDIO) && !defined(B7_AUDIO)
|
|
|
|
+
|
|
|
|
+#pragma message "Using hardware timer 1 with software PWM"
|
|
|
|
+# define HARDWARE_PWM
|
|
|
|
+# define BACKLIGHT_PWM_TIMER
|
|
|
|
+# define TCCRxA TCCR1A
|
|
|
|
+# define TCCRxB TCCR1B
|
|
|
|
+# define OCRxx OCR1A
|
|
|
|
+# define OCRxAH OCR1AH
|
|
|
|
+# define OCRxAL OCR1AL
|
|
|
|
+# define TIMERx_COMPA_vect TIMER1_COMPA_vect
|
|
|
|
+# define TIMERx_OVF_vect TIMER1_OVF_vect
|
|
|
|
+# define OCIExA OCIE1A
|
|
|
|
+# define TOIEx TOIE1
|
|
|
|
+# define ICRx ICR1
|
|
|
|
+# ifndef TIMSK
|
|
|
|
+# define TIMSK TIMSK1
|
|
|
|
+# endif
|
|
|
|
+# elif !defined(C6_AUDIO) && !defined(C5_AUDIO) && !defined(C4_AUDIO)
|
|
|
|
+#pragma message "Using hardware timer 3 with software PWM"
|
|
|
|
+
|
|
|
|
+# define HARDWARE_PWM
|
|
|
|
+# define BACKLIGHT_PWM_TIMER
|
|
|
|
+# define TCCRxA TCCR3A
|
|
|
|
+# define TCCRxB TCCR3B
|
|
|
|
+# define OCRxx OCR3A
|
|
|
|
+# define OCRxAH OCR3AH
|
|
|
|
+# define OCRxAL OCR3AL
|
|
|
|
+# define TIMERx_COMPA_vect TIMER3_COMPA_vect
|
|
|
|
+# define TIMERx_OVF_vect TIMER3_OVF_vect
|
|
|
|
+# define OCIExA OCIE3A
|
|
|
|
+# define TOIEx TOIE3
|
|
|
|
+# define ICRx ICR1
|
|
|
|
+# ifndef TIMSK
|
|
|
|
+# define TIMSK TIMSK3
|
|
|
|
+# endif
|
|
|
|
+# else
|
|
|
|
+#pragma message "Audio in use - using pure software PWM"
|
|
|
|
+#define NO_HARDWARE_PWM
|
|
|
|
+# endif
|
|
|
|
+# else
|
|
|
|
+#pragma message "Custom driver defined - using pure software PWM"
|
|
|
|
+#define NO_HARDWARE_PWM
|
|
|
|
+# endif
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#ifndef BACKLIGHT_ON_STATE
|
|
#ifndef BACKLIGHT_ON_STATE
|
|
#define BACKLIGHT_ON_STATE 0
|
|
#define BACKLIGHT_ON_STATE 0
|
|
#endif
|
|
#endif
|
|
|
|
|
|
-#ifdef NO_HARDWARE_PWM
|
|
+void backlight_on(uint8_t backlight_pin) {
|
|
|
|
+#if BACKLIGHT_ON_STATE == 0
|
|
|
|
+ writePinLow(backlight_pin);
|
|
|
|
+#else
|
|
|
|
+ writePinHigh(backlight_pin);
|
|
|
|
+#endif
|
|
|
|
+}
|
|
|
|
|
|
-__attribute__ ((weak))
|
|
+void backlight_off(uint8_t backlight_pin) {
|
|
|
|
+#if BACKLIGHT_ON_STATE == 0
|
|
|
|
+ writePinHigh(backlight_pin);
|
|
|
|
+#else
|
|
|
|
+ writePinLow(backlight_pin);
|
|
|
|
+#endif
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+#if defined(NO_HARDWARE_PWM) || defined(BACKLIGHT_PWM_TIMER)
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+#ifndef BACKLIGHT_LED_COUNT
|
|
|
|
+#define BACKLIGHT_LED_COUNT 1
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+#if BACKLIGHT_LED_COUNT == 1
|
|
|
|
+#define BACKLIGHT_PIN_INIT { BACKLIGHT_PIN }
|
|
|
|
+#else
|
|
|
|
+#define BACKLIGHT_PIN_INIT BACKLIGHT_PINS
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+#define FOR_EACH_LED(x) \
|
|
|
|
+ for (uint8_t i = 0; i < BACKLIGHT_LED_COUNT; i++) \
|
|
|
|
+ { \
|
|
|
|
+ uint8_t backlight_pin = backlight_pins[i]; \
|
|
|
|
+ { \
|
|
|
|
+ x \
|
|
|
|
+ } \
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+static const uint8_t backlight_pins[BACKLIGHT_LED_COUNT] = BACKLIGHT_PIN_INIT;
|
|
|
|
+
|
|
|
|
+#else
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static const uint8_t backlight_pin = BACKLIGHT_PIN;
|
|
|
|
+#define FOR_EACH_LED(x) x
|
|
|
|
+
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+#ifdef NO_HARDWARE_PWM
|
|
|
|
+__attribute__((weak))
|
|
void backlight_init_ports(void)
|
|
void backlight_init_ports(void)
|
|
{
|
|
{
|
|
|
|
|
|
-
|
|
+ FOR_EACH_LED(
|
|
- _SFR_IO8((backlight_pin >> 4) + 1) |= _BV(backlight_pin & 0xF);
|
|
+ setPinOutput(backlight_pin);
|
|
- #if BACKLIGHT_ON_STATE == 0
|
|
+ backlight_on(backlight_pin);
|
|
-
|
|
+ )
|
|
- _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
|
|
|
|
- #else
|
|
|
|
-
|
|
|
|
- _SFR_IO8((backlight_pin >> 4) + 2) |= _BV(backlight_pin & 0xF);
|
|
|
|
- #endif
|
|
|
|
}
|
|
}
|
|
|
|
|
|
__attribute__ ((weak))
|
|
__attribute__ ((weak))
|
|
@@ -1207,21 +1302,14 @@ uint8_t backlight_tick = 0;
|
|
#ifndef BACKLIGHT_CUSTOM_DRIVER
|
|
#ifndef BACKLIGHT_CUSTOM_DRIVER
|
|
void backlight_task(void) {
|
|
void backlight_task(void) {
|
|
if ((0xFFFF >> ((BACKLIGHT_LEVELS - get_backlight_level()) * ((BACKLIGHT_LEVELS + 1) / 2))) & (1 << backlight_tick)) {
|
|
if ((0xFFFF >> ((BACKLIGHT_LEVELS - get_backlight_level()) * ((BACKLIGHT_LEVELS + 1) / 2))) & (1 << backlight_tick)) {
|
|
- #if BACKLIGHT_ON_STATE == 0
|
|
+ FOR_EACH_LED(
|
|
-
|
|
+ backlight_on(backlight_pin);
|
|
- _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
|
|
+ )
|
|
- #else
|
|
+ }
|
|
-
|
|
+ else {
|
|
- _SFR_IO8((backlight_pin >> 4) + 2) |= _BV(backlight_pin & 0xF);
|
|
+ FOR_EACH_LED(
|
|
- #endif
|
|
+ backlight_off(backlight_pin);
|
|
- } else {
|
|
+ )
|
|
- #if BACKLIGHT_ON_STATE == 0
|
|
|
|
-
|
|
|
|
- _SFR_IO8((backlight_pin >> 4) + 2) |= _BV(backlight_pin & 0xF);
|
|
|
|
- #else
|
|
|
|
-
|
|
|
|
- _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
|
|
|
|
- #endif
|
|
|
|
}
|
|
}
|
|
backlight_tick = (backlight_tick + 1) % 16;
|
|
backlight_tick = (backlight_tick + 1) % 16;
|
|
}
|
|
}
|
|
@@ -1233,7 +1321,52 @@ void backlight_task(void) {
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
|
|
-#else
|
|
+#else
|
|
|
|
+
|
|
|
|
+#ifdef BACKLIGHT_PWM_TIMER
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ISR(TIMERx_COMPA_vect) {
|
|
|
|
+ FOR_EACH_LED(
|
|
|
|
+ backlight_off(backlight_pin);
|
|
|
|
+ )
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ISR(TIMERx_OVF_vect) {
|
|
|
|
+#ifdef BACKLIGHT_BREATHING
|
|
|
|
+ breathing_task();
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ if (OCRxx > 256) {
|
|
|
|
+ FOR_EACH_LED(
|
|
|
|
+ backlight_on(backlight_pin);
|
|
|
|
+ )
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#endif
|
|
|
|
|
|
#define TIMER_TOP 0xFFFFU
|
|
#define TIMER_TOP 0xFFFFU
|
|
|
|
|
|
@@ -1265,11 +1398,28 @@ void backlight_set(uint8_t level) {
|
|
level = BACKLIGHT_LEVELS;
|
|
level = BACKLIGHT_LEVELS;
|
|
|
|
|
|
if (level == 0) {
|
|
if (level == 0) {
|
|
|
|
+ #ifdef BACKLIGHT_PWM_TIMER
|
|
|
|
+ if (OCRxx) {
|
|
|
|
+ TIMSK &= ~(_BV(OCIExA));
|
|
|
|
+ TIMSK &= ~(_BV(TOIEx));
|
|
|
|
+ FOR_EACH_LED(
|
|
|
|
+ backlight_off(backlight_pin);
|
|
|
|
+ )
|
|
|
|
+ }
|
|
|
|
+ #else
|
|
|
|
|
|
TCCRxA &= ~(_BV(COMxx1));
|
|
TCCRxA &= ~(_BV(COMxx1));
|
|
|
|
+ #endif
|
|
} else {
|
|
} else {
|
|
|
|
+ #ifdef BACKLIGHT_PWM_TIMER
|
|
|
|
+ if (!OCRxx) {
|
|
|
|
+ TIMSK |= _BV(OCIExA);
|
|
|
|
+ TIMSK |= _BV(TOIEx);
|
|
|
|
+ }
|
|
|
|
+ #else
|
|
|
|
|
|
TCCRxA |= _BV(COMxx1);
|
|
TCCRxA |= _BV(COMxx1);
|
|
|
|
+ #endif
|
|
}
|
|
}
|
|
|
|
|
|
set_pwm(cie_lightness(TIMER_TOP * (uint32_t)level / BACKLIGHT_LEVELS));
|
|
set_pwm(cie_lightness(TIMER_TOP * (uint32_t)level / BACKLIGHT_LEVELS));
|
|
@@ -1289,12 +1439,25 @@ static uint8_t breathing_period = BREATHING_PERIOD;
|
|
static uint8_t breathing_halt = BREATHING_NO_HALT;
|
|
static uint8_t breathing_halt = BREATHING_NO_HALT;
|
|
static uint16_t breathing_counter = 0;
|
|
static uint16_t breathing_counter = 0;
|
|
|
|
|
|
|
|
+#ifdef BACKLIGHT_PWM_TIMER
|
|
|
|
+static bool breathing = false;
|
|
|
|
+
|
|
|
|
+bool is_breathing(void) {
|
|
|
|
+ return breathing;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#define breathing_interrupt_enable() do { breathing = true; } while (0)
|
|
|
|
+#define breathing_interrupt_disable() do { breathing = false; } while (0)
|
|
|
|
+#else
|
|
|
|
+
|
|
bool is_breathing(void) {
|
|
bool is_breathing(void) {
|
|
return !!(TIMSK1 & _BV(TOIE1));
|
|
return !!(TIMSK1 & _BV(TOIE1));
|
|
}
|
|
}
|
|
|
|
|
|
#define breathing_interrupt_enable() do {TIMSK1 |= _BV(TOIE1);} while (0)
|
|
#define breathing_interrupt_enable() do {TIMSK1 |= _BV(TOIE1);} while (0)
|
|
#define breathing_interrupt_disable() do {TIMSK1 &= ~_BV(TOIE1);} while (0)
|
|
#define breathing_interrupt_disable() do {TIMSK1 &= ~_BV(TOIE1);} while (0)
|
|
|
|
+#endif
|
|
|
|
+
|
|
#define breathing_min() do {breathing_counter = 0;} while (0)
|
|
#define breathing_min() do {breathing_counter = 0;} while (0)
|
|
#define breathing_max() do {breathing_counter = breathing_period * 244 / 2;} while (0)
|
|
#define breathing_max() do {breathing_counter = breathing_period * 244 / 2;} while (0)
|
|
|
|
|
|
@@ -1368,10 +1531,14 @@ static inline uint16_t scale_backlight(uint16_t v) {
|
|
return v / BACKLIGHT_LEVELS * get_backlight_level();
|
|
return v / BACKLIGHT_LEVELS * get_backlight_level();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#ifdef BACKLIGHT_PWM_TIMER
|
|
|
|
+void breathing_task(void)
|
|
|
|
+#else
|
|
|
|
|
|
* about 244 times per second.
|
|
* about 244 times per second.
|
|
*/
|
|
*/
|
|
ISR(TIMER1_OVF_vect)
|
|
ISR(TIMER1_OVF_vect)
|
|
|
|
+#endif
|
|
{
|
|
{
|
|
uint16_t interval = (uint16_t) breathing_period * 244 / BREATHING_STEPS;
|
|
uint16_t interval = (uint16_t) breathing_period * 244 / BREATHING_STEPS;
|
|
|
|
|
|
@@ -1393,19 +1560,21 @@ __attribute__ ((weak))
|
|
void backlight_init_ports(void)
|
|
void backlight_init_ports(void)
|
|
{
|
|
{
|
|
|
|
|
|
-
|
|
+ FOR_EACH_LED(
|
|
- _SFR_IO8((backlight_pin >> 4) + 1) |= _BV(backlight_pin & 0xF);
|
|
+ setPinOutput(backlight_pin);
|
|
- #if BACKLIGHT_ON_STATE == 0
|
|
+ backlight_on(backlight_pin);
|
|
-
|
|
+ )
|
|
- _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
|
|
+
|
|
- #else
|
|
|
|
-
|
|
|
|
- _SFR_IO8((backlight_pin >> 4) + 2) |= _BV(backlight_pin & 0xF);
|
|
|
|
- #endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+#ifdef BACKLIGHT_PWM_TIMER
|
|
|
|
+
|
|
|
|
+ TCCRxA = _BV(WGM11);
|
|
|
|
+
|
|
|
|
+ TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10);
|
|
|
|
+#else
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1417,8 +1586,9 @@ void backlight_init_ports(void)
|
|
"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 [..]."
|
|
"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 [..]."
|
|
"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)."
|
|
"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)."
|
|
*/
|
|
*/
|
|
- TCCRxA = _BV(COMxx1) | _BV(WGM11);
|
|
+ TCCRxA = _BV(COMxx1) | _BV(WGM11);
|
|
TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10);
|
|
TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10);
|
|
|
|
+#endif
|
|
|
|
|
|
ICRx = TIMER_TOP;
|
|
ICRx = TIMER_TOP;
|
|
|
|
|
|
@@ -1428,9 +1598,9 @@ void backlight_init_ports(void)
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
-#endif
|
|
+#endif
|
|
|
|
|
|
-#else
|
|
+#else
|
|
|
|
|
|
__attribute__ ((weak))
|
|
__attribute__ ((weak))
|
|
void backlight_init_ports(void) {}
|
|
void backlight_init_ports(void) {}
|