This feature is distinct from both the [RGB underglow](feature_rgblight.md) and [RGB matrix](feature_rgb_matrix.md) features as it usually allows for only a single colour per switch, though you can obviously use multiple different coloured LEDs on a keyboard.
-Hardware PWM is only supported on certain pins of the MCU, so if the backlighting is not connected to one of them, a software PWM implementation triggered by hardware timer interrupts will be used.
-
Hardware PWM is supported according to the following table:
-| Backlight Pin | Hardware timer |
-|---------------|-------------------------|
-|`B5` | Timer 1 |
-|`B6` | Timer 1 |
-|`B7` | Timer 1 |
-|`C6` | Timer 3 |
-|`D4` | Timer 1 (ATmega32A only)|
-| other | Software PWM |
-
-The [audio feature](feature_audio.md) also uses hardware timers. Please refer to the following table to know what hardware timer the software PWM will use depending on the audio configuration:
-
-| Audio Pin(s) | Audio Timer | Software PWM Timer |
-|--------------|-------------|--------------------|
-| `C4` | Timer 3 | Timer 1 |
-| `C5` | Timer 3 | Timer 1 |
-| `C6` | Timer 3 | Timer 1 |
-| `B5` | Timer 1 | Timer 3 |
-| `B6` | Timer 1 | Timer 3 |
-| `B7` | Timer 1 | Timer 3 |
-| `Bx` & `Cx` | Timer 1 & 3 | None |
-
-When all timers are in use for [audio](feature_audio.md), the backlight software PWM will not use a hardware timer, but instead will be triggered during the matrix scan. In this case the backlight doesn't support breathing and might show lighting artifacts (for instance flickering), because the PWM computation might not be called with enough timing precision.
+|Backlight Pin|AT90USB64/128|ATmega16/32U4|ATmega16/32U2|ATmega32A|
+|-------------|-------------|-------------|-------------|---------|
+|`B5` |Timer 1 |Timer 1 | | |
+|`B6` |Timer 1 |Timer 1 | | |
+|`B7` |Timer 1 |Timer 1 |Timer 1 | |
+|`C4` |Timer 3 | | | |
+|`C5` |Timer 3 | |Timer 1 | |
+|`C6` |Timer 3 |Timer 3 |Timer 1 | |
+|`D4` | | | |Timer 1 |
+|`D5` | | | |Timer 1 |
+
+All other pins will use software PWM. If the [Audio](feature_audio.md) feature is disabled or only using one timer, the backlight PWM can be triggered by a hardware timer:
+
+|Audio Pin|Audio Timer|Software PWM Timer|
+|---------|-----------|------------------|
+|`C4` |Timer 3 |Timer 1 |
+|`C5` |Timer 3 |Timer 1 |
+|`C6` |Timer 3 |Timer 1 |
+|`B5` |Timer 1 |Timer 3 |
+|`B6` |Timer 1 |Timer 3 |
+|`B7` |Timer 1 |Timer 3 |
+
+When both timers are in use for Audio, the backlight PWM will not use a hardware timer, but will instead be triggered during the matrix scan. In this case, breathing is not supported, and the backlight might flicker, because the PWM computation may not be called with enough timing precision.
## Configuration
}
#if defined(BACKLIGHT_ENABLE) && (defined(BACKLIGHT_PIN) || defined(BACKLIGHT_PINS))
-// The logic is a bit complex, we support 3 setups:
-// 1. hardware PWM when backlight is wired to a PWM pin
-// depending on this pin, we use a different output compare unit
-// 2. software PWM with hardware timers, but the used timer depends
-// on the audio setup (audio wins other backlight)
-// 3. full software PWM
-
-#if BACKLIGHT_PIN == B7
-# define HARDWARE_PWM
-# define TCCRxA TCCR1A
-# define TCCRxB TCCR1B
-# define COMxx1 COM1C1
-# define OCRxx OCR1C
-# define TIMERx_OVF_vect TIMER1_OVF_vect
-# define TOIEx TOIE1
-# define ICRx ICR1
-# define TIMSKx TIMSK1
-#elif BACKLIGHT_PIN == B6
-# define HARDWARE_PWM
-# define TCCRxA TCCR1A
-# define TCCRxB TCCR1B
-# define COMxx1 COM1B1
-# define OCRxx OCR1B
-# define TIMERx_OVF_vect TIMER1_OVF_vect
-# define TOIEx TOIE1
-# define ICRx ICR1
-# define TIMSKx TIMSK1
-#elif BACKLIGHT_PIN == B5
-# define HARDWARE_PWM
-# define TCCRxA TCCR1A
-# define TCCRxB TCCR1B
-# define COMxx1 COM1A1
-# define OCRxx OCR1A
-# define TIMERx_OVF_vect TIMER1_OVF_vect
-# define TOIEx TOIE1
-# define ICRx ICR1
-# define TIMSKx TIMSK1
-#elif BACKLIGHT_PIN == C6
-# define HARDWARE_PWM
-# define TCCRxA TCCR3A
-# define TCCRxB TCCR3B
-# define COMxx1 COM3A1
-# define OCRxx OCR3A
-# define TIMERx_OVF_vect TIMER3_OVF_vect
-# define TOIEx TOIE3
-# define ICRx ICR3
-# define TIMSKx TIMSK3
-#elif defined(__AVR_ATmega32A__) && BACKLIGHT_PIN == D4
-# define TCCRxA TCCR1A
-# define TCCRxB TCCR1B
-# define COMxx1 COM1B1
-# define OCRxx OCR1B
-# define TIMERx_OVF_vect TIMER1_OVF_vect
-# define TOIEx TOIE1
-# define ICRx ICR1
-# define TIMSKx TIMSK1
+// This logic is a bit complex, we support 3 setups:
+//
+// 1. Hardware PWM when backlight is wired to a PWM pin.
+// Depending on this pin, we use a different output compare unit.
+// 2. Software PWM with hardware timers, but the used timer
+// depends on the Audio setup (Audio wins over Backlight).
+// 3. Full software PWM, driven by the matrix scan, if both timers are used by Audio.
+
+#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)
+ #define HARDWARE_PWM
+ #define ICRx ICR1
+ #define TCCRxA TCCR1A
+ #define TCCRxB TCCR1B
+ #define TIMERx_OVF_vect TIMER1_OVF_vect
+ #define TIMSKx TIMSK1
+ #define TOIEx TOIE1
+
+ #if BACKLIGHT_PIN == B5
+ #define COMxx1 COM1A1
+ #define OCRxx OCR1A
+ #elif BACKLIGHT_PIN == B6
+ #define COMxx1 COM1B1
+ #define OCRxx OCR1B
+ #elif BACKLIGHT_PIN == B7
+ #define COMxx1 COM1C1
+ #define OCRxx OCR1C
+ #endif
+#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)
+ #define HARDWARE_PWM
+ #define ICRx ICR3
+ #define TCCRxA TCCR3A
+ #define TCCRxB TCCR3B
+ #define TIMERx_OVF_vect TIMER3_OVF_vect
+ #define TIMSKx TIMSK3
+ #define TOIEx TOIE3
+
+ #if BACKLIGHT_PIN == C4
+ #if (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__))
+ #error This MCU has no C4 pin!
+ #else
+ #define COMxx1 COM3C1
+ #define OCRxx OCR3C
+ #endif
+ #elif BACKLIGHT_PIN == C5
+ #if (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__))
+ #error This MCU has no C5 pin!
+ #else
+ #define COMxx1 COM3B1
+ #define OCRxx OCR3B
+ #endif
+ #elif BACKLIGHT_PIN == C6
+ #define COMxx1 COM3A1
+ #define OCRxx OCR3A
+ #endif
+#elif (defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__)) \
+ && (BACKLIGHT_PIN == B7 || BACKLIGHT_PIN == C5 || BACKLIGHT_PIN == C6)
+ #define HARDWARE_PWM
+ #define ICRx ICR1
+ #define TCCRxA TCCR1A
+ #define TCCRxB TCCR1B
+ #define TIMERx_OVF_vect TIMER1_OVF_vect
+ #define TIMSKx TIMSK1
+ #define TOIEx TOIE1
+
+ #if BACKLIGHT_PIN == B7
+ #define COMxx1 COM1C1
+ #define OCRxx OCR1C
+ #elif BACKLIGHT_PIN == C5
+ #define COMxx1 COM1B1
+ #define OCRxx OCR1B
+ #elif BACKLIGHT_PIN == C6
+ #define COMxx1 COM1A1
+ #define OCRxx OCR1A
+ #endif
+#elif defined(__AVR_ATmega32A__) \
+ && (BACKLIGHT_PIN == D4 || BACKLIGHT_PIN == D5)
+ #define HARDWARE_PWM
+ #define ICRx ICR1
+ #define TCCRxA TCCR1A
+ #define TCCRxB TCCR1B
+ #define TIMERx_OVF_vect TIMER1_OVF_vect
+ #define TIMSKx TIMSK
+ #define TOIEx TOIE1
+
+ #if BACKLIGHT_PIN == D4
+ #define COMxx1 COM1B1
+ #define OCRxx OCR1B
+ #elif BACKLIGHT_PIN == D5
+ #define COMxx1 COM1A1
+ #define OCRxx OCR1A
+ #endif
#else
-# if !defined(BACKLIGHT_CUSTOM_DRIVER)
-# if !defined(B5_AUDIO) && !defined(B6_AUDIO) && !defined(B7_AUDIO)
- // timer 1 is not used by audio , backlight can use it
-#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 TIMERx_COMPA_vect TIMER1_COMPA_vect
-# define TIMERx_OVF_vect TIMER1_OVF_vect
-# define OCIExA OCIE1A
-# define TOIEx TOIE1
-# define ICRx ICR1
-# if defined(__AVR_ATmega32A__) // This MCU has only one TIMSK register
-# define TIMSKx TIMSK
-# else
-# define TIMSKx TIMSK1
-# endif
-# elif !defined(C6_AUDIO) && !defined(C5_AUDIO) && !defined(C4_AUDIO)
-#pragma message "Using hardware timer 3 with software PWM"
-// timer 3 is not used by audio, backlight can use it
-# define HARDWARE_PWM
-# define BACKLIGHT_PWM_TIMER
-# define TCCRxA TCCR3A
-# define TCCRxB TCCR3B
-# define OCRxx OCR3A
-# define TIMERx_COMPA_vect TIMER3_COMPA_vect
-# define TIMERx_OVF_vect TIMER3_OVF_vect
-# define OCIExA OCIE3A
-# define TOIEx TOIE3
-# define ICRx ICR1
-# define TIMSKx TIMSK3
-# 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
+ #if !defined(BACKLIGHT_CUSTOM_DRIVER)
+ #if !defined(B5_AUDIO) && !defined(B6_AUDIO) && !defined(B7_AUDIO)
+ // Timer 1 is not in use by Audio feature, Backlight can use it
+ #pragma message "Using hardware timer 1 with software PWM"
+ #define HARDWARE_PWM
+ #define BACKLIGHT_PWM_TIMER
+ #define ICRx ICR1
+ #define TCCRxA TCCR1A
+ #define TCCRxB TCCR1B
+ #define TIMERx_COMPA_vect TIMER1_COMPA_vect
+ #define TIMERx_OVF_vect TIMER1_OVF_vect
+ #if defined(__AVR_ATmega32A__) // This MCU has only one TIMSK register
+ #define TIMSKx TIMSK
+ #else
+ #define TIMSKx TIMSK1
+ #endif
+ #define TOIEx TOIE1
+
+ #define OCIExA OCIE1A
+ #define OCRxx OCR1A
+ #elif !defined(C6_AUDIO) && !defined(C5_AUDIO) && !defined(C4_AUDIO)
+ #pragma message "Using hardware timer 3 with software PWM"
+ // Timer 3 is not in use by Audio feature, Backlight can use it
+ #define HARDWARE_PWM
+ #define BACKLIGHT_PWM_TIMER
+ #define ICRx ICR1
+ #define TCCRxA TCCR3A
+ #define TCCRxB TCCR3B
+ #define TIMERx_COMPA_vect TIMER3_COMPA_vect
+ #define TIMERx_OVF_vect TIMER3_OVF_vect
+ #define TIMSKx TIMSK3
+ #define TOIEx TOIE3
+
+ #define OCIExA OCIE3A
+ #define OCRxx OCR3A
+ #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
#ifndef BACKLIGHT_ON_STATE
// range for val is [0..TIMER_TOP]. PWM pin is high while the timer count is below val.
static inline void set_pwm(uint16_t val) {
- OCRxx = val;
+ OCRxx = val;
}
#ifndef BACKLIGHT_CUSTOM_DRIVER