Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #3566 use an hardware timer for software PWM stability #3615

Merged
merged 2 commits into from
Apr 22, 2019

Conversation

masterzen
Copy link
Contributor

With my XD60, I noticed that when typing the backlight was flickering (see issue #3566).

The XD60 doesn't have the backlight wired to a hardware PWM pin (too bad), unlike the dz60.

I assumed it was a timing issue in the matrix scan that made the PWM lit the LED a bit too longer. I verified it because the more keys that were pressed, the more lighting flicker I observed.

This patch removes the matrix scan based PWM computation, and instead adds a timer interrupt that ticks the backlight PWMs, leading to a better time stability, and removing all flickering on my keyboard :)

I think this patch might not work with some other software PWM based keyboards as I'm using Timer1B (and have only this xd60 to test with).

I'd be more than happy to amend this patch with a more generic fix or a better solution if needed :)

Thanks,
Brice

@drashna
Copy link
Member

drashna commented Aug 10, 2018

Timer 1 is used by audio, in some cases, so this may cause issues.

@masterzen masterzen force-pushed the fix/3566-hardware-timer-for-soft-pwm branch from 1946519 to c988317 Compare August 11, 2018 13:57
@masterzen
Copy link
Contributor Author

masterzen commented Aug 11, 2018

@drashna ,

Thanks for the input!
I've modified my PR to disable the hardware timer whenever audio is enabled (do you think that's enough?).

I've also fixed the mt40 compilation. Hopefully the travis tests will pass now.

Thanks,
Brice

@drashna
Copy link
Member

drashna commented Aug 11, 2018

I think that a warning should be generated, actually.

That way, there isn't any confusion about why it's having issues if you have audio enabled.

Though, to clarify, it's the B pins (B5, B6, B7) that use Timer 1. So you could detect if B5_AUDIO, B6_AUDIO or B7_AUDIO is defined, and then error out then, rather than if audio is enabled in general

@masterzen
Copy link
Contributor Author

Hi @drashna

I did something a bit differently than what you suggested. If any of B5_AUDIO, B6_AUDIO, B7_AUDIO is enabled, we'll use Timer 3. If it's any of C6_AUDIO, C5_AUDIO, or C4_AUDIO, (or nothing) then we'll use Timer 1. If both timers are in use with audio then we won't use this feature and revert to matrix scan PWM computation.

I think this is the best solution, WDYT?

I've tested both timers on my xd60, but since I have no keyboard with audio it's possible I've missed something.

Thanks!
Brice

@masterzen masterzen force-pushed the fix/3566-hardware-timer-for-soft-pwm branch from 02803ce to 205889b Compare August 12, 2018 11:05
@drashna
Copy link
Member

drashna commented Aug 12, 2018

That sounds good!

@jackhumbert ?

@masterzen masterzen force-pushed the fix/3566-hardware-timer-for-soft-pwm branch from 205889b to 77b20ff Compare August 12, 2018 18:42
@masterzen
Copy link
Contributor Author

@drashna , I've added a small documentation change, but since I'm not an English native speaker, you might want to proof-read it (or propose some rewriting).

docs/feature_backlight.md Outdated Show resolved Hide resolved
@masterzen masterzen force-pushed the fix/3566-hardware-timer-for-soft-pwm branch from 77b20ff to 7162e37 Compare August 13, 2018 18:30
@masterzen
Copy link
Contributor Author

@drashna were you able to proof-read the latest version of the documentation I pushed yesterday
?

Let me know if there's any modifications I should add.

Thanks,
Brice

@drashna
Copy link
Member

drashna commented Aug 14, 2018

Documentation looks good to me

@masterzen
Copy link
Contributor Author

While thinking about this, I have a better idea that can reuse most of the hardware PWM code and will allow breathing to work in software PWM mode. I'll work on this during the week-end and push there when ready.

@masterzen masterzen force-pushed the fix/3566-hardware-timer-for-soft-pwm branch from 7162e37 to 2ad22d6 Compare August 25, 2018 17:36
@masterzen
Copy link
Contributor Author

I've pushed the latest changes which works well for my xd60 implementing this last idea:

  • reuses most of hardware PWM code
  • compatible with Audio if only one pin is in use by Audio
  • supports breathing in software mode
  • doesn't flicker when typing like software mode
  • contains documentation and several code comments to explain it
  • support for multiple backlight pins (allows for instance to control the brightness of other leds to match the backlight leds, useful when Caps Lock is mapped as another key and you want the caps lock led to be part of the backlight). This feature is only available in pure software mode and this new hybrid mode, but not hardware mode.

I haven't unfortunately been able to test if hardware PWM mode is still working (I don't see why it wouldn't), because I don't have any keyboards with this mode. I'd appreciate if someone could test that for me.

Thanks for taking a look, I'm ready for comments and suggestions :)

@masterzen masterzen force-pushed the fix/3566-hardware-timer-for-soft-pwm branch 2 times, most recently from 414b4a1 to e8df7e6 Compare August 28, 2018 21:19
@masterzen
Copy link
Contributor Author

Just fixed the conflict in the documentation. I think you can remove the in progress and needs doc label :)

@drashna
Copy link
Member

drashna commented Nov 2, 2018

Well, that PR is applied, so both PRs should be good to go, I think.

@drashna
Copy link
Member

drashna commented Jan 25, 2019

@jackhumbert @skullydazed @fredizzimo

This looks ready to go, and just needs to be reviewed.

@jbarrios
Copy link

jbarrios commented Feb 2, 2019

I have a xd60 rev3 and I fetched and checkout the PR, the backlights works better than the origin code but it's not perfect (I'll use it without doubt).
I detected the issues that in sometimes without press any key the backlight flicks, more frequently with low backlight level. And with breathing backlight this flicks are more common when starts the cycle

@masterzen
Copy link
Contributor Author

@jbarrios do you have the rgb underglow activated?

I've also noticed that it sometimes flickers when it is activated. I haven't yet found the cause, since it doesn't happen that frequently (it's less than one time per minute). I need to rebuild my firmware with more debug and let it run to "see" why it sometimes jumps...

Those flickers happens because PWM is very sensible to timing, so if we "miss" an interrupt for one cycle the led will stay on and it looks like it flickers.

At low level, it is more problematic because the "turn off" interrupt can happen approximately at the same time as the "turn on" one (I haven't yet understood exactly how it is possible since normally there can be only one interrupt executing at the same time).

@masterzen
Copy link
Contributor Author

@jbarrios , I did more testing today.
Indeed this is coming from the rgblight feature. If you deactivate or use a still color or a very slow rgb underglow effect, then there is no flickering appearing.
If you instead use rgblight with a quickly color changing scheme, then flickering appears.

My explanation is that, all rgblight effects are using timer_read and timer_elapsed. Those are blocking interrupts to happen while reading the timer. If interrupts are blocked, even for a very short time, my hybrid implementation interrupts that powers on and off the backlight led is either not called or called to late, leaving the leds on for a bit too long. Indeed the frequency of my hybrid interrupt is quite high to be able to support breathing.

Unfortunately, I don't see how this can be fixed, unless rewriting the rgb effects to not depend on timer_read but instead depend on a fixed time interrupt (like this backlight code as discussed in this PR).

Meanwhile I suggest using a slow motion RGB effect or no RGB effect at all :)

@jbarrios
Copy link

jbarrios commented Feb 9, 2019

Hello, @masterzen, I've been writing without rgblight around the last 3 days and you are right, the flickering has disapear.

Actually i'm using a close case and the underglow have no sense at all, I'll use the backlight with this PR.

Thank you for the explanation and the implementation, maybe someday we will enjoy all full features :)

@masterzen
Copy link
Contributor Author

Thanks @jbarrios for confirming.

On my side I've found the real cause of flicker during rgb underglow changes. Unfortunately to control the rgb lights, the MCU globally disable the interrupts (see https://github.com/qmk/qmk_firmware/blob/master/drivers/avr/ws2812.c#L275) while sending the data to the rgblights.

So if you have a rapidly changing lighting pattern, the longer the MCU will run with interrupts disabled, and the longer the interrupts are disabled, the higher is the chance to have the backlights leds to stay on after the PWM duty cycle, leading to flickering.

I don't think this is solvable, because we need the backlight interrupts to arrive on time, but you need a precise timing to control the rgb led array.
Both seems to be exclusive.

Copy link
Contributor

@mechmerlin mechmerlin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@mechmerlin mechmerlin merged commit b61baf4 into qmk:master Apr 22, 2019
@masterzen
Copy link
Contributor Author

Hey @mechmerlin and @drashna, thanks for merging this PR !
I'm going to update #4324 ASAP.

Shinichi-Ohki added a commit to Shinichi-Ohki/qmk_firmware that referenced this pull request Apr 26, 2019
* 'master' of https://github.com/qmk/qmk_firmware: (99 commits)
  [Keyboard] Add a new keyboard ADKB96 (qmk#5685)
  test commit
  add RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS; to rgblight_update_dword()
  add RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS; to eeconfig_update_rgblight_default()
  Refactor cospad to current standards and enable support for backlight keycodes (qmk#5582)
  [Keymap] update (mouse emulation, rev 6 compatibility) (qmk#5696)
  [Keyboard] fix project zen rev1 bootloader declaration (qmk#5695)
  [FIX] Misspelled RGB_YELLOW (qmk#5692)
  [Keymap] Fix broken Shift-Insert binding (qmk#5689)
  [Keyboard] forgot to omit k05 from the electrical matrix in hhkb layout (qmk#5684)
  [Keyboard] Fix red an green leds location (qmk#5698)
  Translate docs into Chinese (qmk#5693)
  [Keymap] Fix my userspace RGB bug (qmk#5686)
  Boston meetup 2019 (qmk#5611)
  [Keymap] Update to Drashna Keymaps (qmk#5594)
  fix LIB_SRC and QUANTUM_LIB_SRC for ARM (qmk#5623)
  RGB Matrix Animations: Three/six new reactive effects (wide, cross, nexus) (qmk#5602)
  Fix qmk#3566 use an hardware timer for software PWM stability (qmk#3615)
  added info.json for ymd96 (qmk#4982)
  Define RGB colors (qmk#5300)
  ...
KauyonKais pushed a commit to KauyonKais/qmk_firmware that referenced this pull request Apr 27, 2019
With my XD60, I noticed that when typing the backlight was flickering.

The XD60 doesn't have the backlight wired to a hardware PWM pin.
I assumed it was a timing issue in the matrix scan that made the PWM
lit the LED a bit too longer. I verified it because the more keys that
were pressed, the more lighting I observed.

This patch makes the software PWM be called during CPU interruptions.
It works almost like the hardware PWM, except instead of using
the CPU waveform generation, the CPU will fire interruption
when the LEDs need be turned on or off.

Using the same timer system as for hardware PWM, when the counter
will reach OCRxx (the current backlight level), an Output Compare
match interrupt will be fired and we'll turn the LEDs off.
When the counter reaches its maximum value, an overflow interrupt
will be triggered in which we turn the LEDs on.
This way we replicate the hardware backlight PWM duty cycle.

This gives a better time stability of the PWM computation than pure
software PWM, leading to a flicker free backlight.

Since this is reusing the hardware PWM code, software PWM also supports
backlight breathing.

Note that if timer1 is used for audio, backlight will use timer3, and if
timer3 is used for audio backlight will use timer1.
If both timers are used for audio, then this feature is disabled and we
revert to the matrix scan based PWM computation.

Signed-off-by: Brice Figureau <[email protected]>
foosinn pushed a commit to foosinn/qmk_firmware that referenced this pull request May 6, 2019
With my XD60, I noticed that when typing the backlight was flickering.

The XD60 doesn't have the backlight wired to a hardware PWM pin.
I assumed it was a timing issue in the matrix scan that made the PWM
lit the LED a bit too longer. I verified it because the more keys that
were pressed, the more lighting I observed.

This patch makes the software PWM be called during CPU interruptions.
It works almost like the hardware PWM, except instead of using
the CPU waveform generation, the CPU will fire interruption
when the LEDs need be turned on or off.

Using the same timer system as for hardware PWM, when the counter
will reach OCRxx (the current backlight level), an Output Compare
match interrupt will be fired and we'll turn the LEDs off.
When the counter reaches its maximum value, an overflow interrupt
will be triggered in which we turn the LEDs on.
This way we replicate the hardware backlight PWM duty cycle.

This gives a better time stability of the PWM computation than pure
software PWM, leading to a flicker free backlight.

Since this is reusing the hardware PWM code, software PWM also supports
backlight breathing.

Note that if timer1 is used for audio, backlight will use timer3, and if
timer3 is used for audio backlight will use timer1.
If both timers are used for audio, then this feature is disabled and we
revert to the matrix scan based PWM computation.

Signed-off-by: Brice Figureau <[email protected]>
@al3ph
Copy link

al3ph commented May 19, 2019

Will this work for the XD87 (pin D0) ? As that has flickering backlight problems, though it's random, and not related to key presses (as far as I can tell), I assume the firmware is servicing USB events and that causes the soft PWM servicing to get briefly delayed causing the flicker.

Timbus pushed a commit to Timbus/qmk_firmware that referenced this pull request Jun 23, 2019
With my XD60, I noticed that when typing the backlight was flickering.

The XD60 doesn't have the backlight wired to a hardware PWM pin.
I assumed it was a timing issue in the matrix scan that made the PWM
lit the LED a bit too longer. I verified it because the more keys that
were pressed, the more lighting I observed.

This patch makes the software PWM be called during CPU interruptions.
It works almost like the hardware PWM, except instead of using
the CPU waveform generation, the CPU will fire interruption
when the LEDs need be turned on or off.

Using the same timer system as for hardware PWM, when the counter
will reach OCRxx (the current backlight level), an Output Compare
match interrupt will be fired and we'll turn the LEDs off.
When the counter reaches its maximum value, an overflow interrupt
will be triggered in which we turn the LEDs on.
This way we replicate the hardware backlight PWM duty cycle.

This gives a better time stability of the PWM computation than pure
software PWM, leading to a flicker free backlight.

Since this is reusing the hardware PWM code, software PWM also supports
backlight breathing.

Note that if timer1 is used for audio, backlight will use timer3, and if
timer3 is used for audio backlight will use timer1.
If both timers are used for audio, then this feature is disabled and we
revert to the matrix scan based PWM computation.

Signed-off-by: Brice Figureau <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants