Skip to content

Commit

Permalink
platform/technic_hub: fix LED full brightness when small duty cycle
Browse files Browse the repository at this point in the history
b22ad15 didn't fully fix this problem. There are still certain
duty cycle values that cause the LED to be full brightness. This appears
to be a hardware bug where the CxIF interrupt just doesn't fire at at
all. We work around this by manually comparing the CNT and CCRx
registers just as the timer does internally. Colors might be a bit off
at low brightness values, but at least they will now error on the side
of being off rather than full brightness.

Fixes: pybricks/support#224
  • Loading branch information
dlech committed Mar 3, 2021
1 parent 0299350 commit 79c88e1
Showing 1 changed file with 11 additions and 6 deletions.
17 changes: 11 additions & 6 deletions lib/pbio/platform/technic_hub/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,13 +324,19 @@ const pbdrv_pwm_stm32_tim_platform_data_t
// for the LEDs. The pin mux doesn't work out, so we have to manually write
// the GPIOs in the timer interrupt handler.
void TIM2_IRQHandler(void) {
uint32_t cnt = TIM2->CNT;
uint32_t sr = TIM2->SR;
uint32_t handled = TIM_SR_UIF;

// NB: there seems to be hardware bug where sometimes we don't get the CCxIF
// interrupt or only get it 1/2 of the time for certain bands of small duty
// cycle values. So we are comparing CNT to CCRx in addition to just looking
// at the interrupt. This works best when the red and green values are near
// each other since that minimizes the error.

// green LED
if (TIM2->CCR1 == 0 || sr & TIM_SR_CC1IF) {
// If channel 1 duty cycle is 0 or we have reached the CC1 count,
// turn the GPIO off
if (cnt >= TIM2->CCR1 || sr & TIM_SR_CC1IF) {
// If we have reached the CC1 count, turn the GPIO off
GPIOA->BRR = GPIO_BRR_BR11;
handled |= TIM_SR_CC1IF;
} else if (sr & TIM_SR_UIF) {
Expand All @@ -339,9 +345,8 @@ void TIM2_IRQHandler(void) {
}

// red LED
if (TIM2->CCR2 == 0 || sr & TIM_SR_CC2IF) {
// If channel 2 duty cycle is 0 or we have reached the CC2 count,
// turn the GPIO off
if (cnt >= TIM2->CCR2 || sr & TIM_SR_CC2IF) {
// If we have reached the CC2 count, turn the GPIO off
GPIOB->BRR = GPIO_BRR_BR15;
handled |= TIM_SR_CC2IF;
} else if (sr & TIM_SR_UIF) {
Expand Down

0 comments on commit 79c88e1

Please sign in to comment.