~ruther/qmk_firmware

6bdcbfb25ae068d9f5351af0f7c6a03385020661 — fauxpark 6 years ago c6850ba
Fix backlight breathing on C6 (#6102)

* Fix backlight breathing on C6

* Account for ATmega32A's single TIMSK register (MT40)

* Document hardware PWM on D4 for ATmega32A

* Add C6 and D4 to BACKLIGHT_PIN description
3 files changed, 38 insertions(+), 27 deletions(-)

M docs/config_options.md
M docs/feature_backlight.md
M quantum/quantum.c
M docs/config_options.md => docs/config_options.md +1 -1
@@ 76,7 76,7 @@ This is a C header file that is one of the first things included, and will persi
* `#define B7_AUDIO`
  * enables audio on pin B7 (duophony is enables if one of B[5-7]\_AUDIO is enabled along with one of C[4-6]\_AUDIO)
* `#define BACKLIGHT_PIN B7`
  * pin of the backlight - B5, B6, B7 use PWM, others use softPWM
  * pin of the backlight - `B5`, `B6`, `B7` and `C6` (and `D4` on ATmega32A) use hardware PWM, others use software implementation
* `#define BACKLIGHT_LEVELS 3`
  * number of levels your backlight will have (maximum 15 excluding off)
* `#define BACKLIGHT_BREATHING`

M docs/feature_backlight.md => docs/feature_backlight.md +8 -7
@@ 34,13 34,14 @@ Hardware PWM is only supported on certain pins of the MCU, so if the backlightin

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        |
| other         | Software PWM   |
| 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:


M quantum/quantum.c => quantum/quantum.c +29 -19
@@ 1027,35 1027,49 @@ void matrix_scan_quantum() {
#  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 COM1A1
#  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 TIMSK1 TIMSK
#  define TIMSKx TIMSK1
#else
#  if !defined(BACKLIGHT_CUSTOM_DRIVER)
#    if !defined(B5_AUDIO) && !defined(B6_AUDIO) && !defined(B7_AUDIO)


@@ 1066,15 1080,15 @@ void matrix_scan_quantum() {
#      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
#      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"


@@ 1084,16 1098,12 @@ void matrix_scan_quantum() {
#      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
#      define TIMSKx TIMSK3
#    else
#pragma message "Audio in use - using pure software PWM"
#define NO_HARDWARE_PWM


@@ 1274,8 1284,8 @@ void backlight_set(uint8_t level) {
  if (level == 0) {
    #ifdef BACKLIGHT_PWM_TIMER
      if (OCRxx) {
        TIMSK &= ~(_BV(OCIExA));
        TIMSK &= ~(_BV(TOIEx));
        TIMSKx &= ~(_BV(OCIExA));
        TIMSKx &= ~(_BV(TOIEx));
        FOR_EACH_LED(
          backlight_off(backlight_pin);
        )


@@ 1287,8 1297,8 @@ void backlight_set(uint8_t level) {
  } else {
    #ifdef BACKLIGHT_PWM_TIMER
      if (!OCRxx) {
        TIMSK |= _BV(OCIExA);
        TIMSK |= _BV(TOIEx);
        TIMSKx |= _BV(OCIExA);
        TIMSKx |= _BV(TOIEx);
      }
    #else
    // Turn on PWM control of backlight pin


@@ 1325,11 1335,11 @@ bool is_breathing(void) {
#else

bool is_breathing(void) {
    return !!(TIMSK1 & _BV(TOIE1));
    return !!(TIMSKx & _BV(TOIEx));
}

#define breathing_interrupt_enable() do {TIMSK1 |= _BV(TOIE1);} while (0)
#define breathing_interrupt_disable() do {TIMSK1 &= ~_BV(TOIE1);} while (0)
#define breathing_interrupt_enable() do {TIMSKx |= _BV(TOIEx);} while (0)
#define breathing_interrupt_disable() do {TIMSKx &= ~_BV(TOIEx);} while (0)
#endif

#define breathing_min() do {breathing_counter = 0;} while (0)


@@ 1411,7 1421,7 @@ void breathing_task(void)
/* Assuming a 16MHz CPU clock and a timer that resets at 64k (ICR1), the following interrupt handler will run
 * about 244 times per second.
 */
ISR(TIMER1_OVF_vect)
ISR(TIMERx_OVF_vect)
#endif
{
  uint16_t interval = (uint16_t) breathing_period * 244 / BREATHING_STEPS;