cancel
Showing results for 
Search instead for 
Did you mean: 

Efficient way to fade a LED

Fede Rico
Associate III
Posted on October 12, 2017 at 09:36

Hi there,

I'm trying to Fade (In and Out) a LED with TIM5.

This is my configuration (Just a recap of the configuration):

1) Configure TIM5 in order to generate a signal with 100 Hz as period with no pulse.

htim5.Instance = TIM5;

htim5.Init.Prescaler = 9;

htim5.Init.CounterMode = TIM_COUNTERMODE_UP;

htim5.Init.Period = 63999;

htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

sConfigOC.OCMode = TIM_OCMODE_PWM1;

sConfigOC.Pulse = 0;

sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;

sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;

2) I write this function to vary the duty cycle:

StatusCode_e PWM_Configure( PWM_TimerId_e timerId, PWM_ChannelId_e channelId, uint8_t dutyCyclePercent )

{

TIM_OC_InitTypeDef outputConfiguration;

outputConfiguration.OCMode = TIM_OCMODE_PWM1;

outputConfiguration.Pulse = (((PWM_TimerHandler[PWM_TIMER_ID_1].timPeriod + 1) * dutyCyclePercent) / 100) + 1;

outputConfiguration.OCPolarity = TIM_OCPOLARITY_HIGH;

outputConfiguration.OCFastMode = TIM_OCFAST_DISABLE;

HAL_TIM_PWM_ConfigChannel( PWM_TimerHandler[timerId].handler, &outputConfiguration, PWM_ChannelHandler[channelId] );

return StatusCode_OK;

}

3) I realise the fade effects with this function:

StatusCode_e LED_FADE_FadeIn( LED_FADE_Id_e ledFadeId, uint16_t fadeMs )

{

uint8_t dutyCycleCnt;

for( dutyCycleCnt = 1; dutyCycleCnt <= 100; dutyCycleCnt++ )

{

PWM_Off( LED_FADE_Handler[ledFadeId].timerId, LED_FADE_Handler[ledFadeId].channelId );

PWM_Configure( LED_FADE_Handler[ledFadeId].timerId, LED_FADE_Handler[ledFadeId].channelId, dutyCycleCnt );

PWM_On( LED_FADE_Handler[ledFadeId].timerId, LED_FADE_Handler[ledFadeId].channelId );

OS_Delay(LED_FADE_DUTY_CYCLE_STEP_MS);

}

return StatusCode_OK;

}

This method works well but I think that is not efficient. In fact every time I want to increase the Duty Cycle, the timer must be stopped, reconfigure the output channel and start the timer.

These action are repeated for 100 times to fade the led.

Is there a best way to change the CCR without stop the timer?

Thanks for the help.

Federico

#fade #timer #pwm #led

Note: this post was migrated and contained many threaded conversations, some content may be missing.
24 REPLIES 24
Posted on October 13, 2017 at 14:40

If the Compare register value is higher than the Reload register's, then the compare event will never occur (the relation is always CCR > ARR), and depending on PWM1 or PWM2 mode the output will always be 0 or 1.

In this case the output will be stationary as you say, but the internal compare *event* *will* occur.

When the contents of TIMx_CCR1 are greater than the contents of TIMx_ARR, the CC1IF bit

goes high on the counter overflow (in upcounting and up/down-counting modes) or underflow

(in downcounting mode).

JW

Posted on October 13, 2017 at 14:43

I didn't mention it, because the cube and source is there, but the demo is running on F7 at 216mhz. The timer sees 108mhz, and uses pre scaler of 108 for 1us ticks. The ARR is 10000 for 10ms (100Hz). 100 fade steps from 0 to 10000 (100%). Fade takes 1sec.

Posted on October 13, 2017 at 14:50

So, is my table wrong?

This is my settings:

  • Clock = 64Mhz
  • Prescaler = 9
  • ARR ( Timer Period) = 63999

I use this formula to compute the CCR values starting from a PWM = 0 to 100.

CCR = ((Timer Period + 1) * dutyCyclePercent) / 100) + 1 

Is this formula right? How can I build a complete and correct CCR table ?

Thanks for your time.

BR

Posted on October 13, 2017 at 15:02

Unless there is an app specific tick size is required or I need every last bit of timer resolution, I always configure the timer (pre scaler) so is tick give a nice decade value, 1us, 10us, ... 1ms. It makes making buffers like yours much more readable, it makes logic traces match ARR and CCx values. Debugging is simpler. Let's face it, your doing 100Hz led blinking and 100 brightness levels. Do you need 15-16bit resolution or simpler code?

Posted on October 13, 2017 at 15:23

CCR = trunc((Timer Period * dutyCyclePercent) / 100)

TimerPeriod = ARR + 1

JW

PS You might want to take into account that human vision's light intensity perception is not linear - far from it. For 'pleasant' experience you may want a nonlinear table - exponential might be closer to what's perceived as linear. This is one of the things I demonstrated in the code I've given above. Also, although of less importance in 'normal' cases, if you push thing off the cliff and PWM frequency approaches the LED's 'speed' (given mainly by recombination time of the excess charge carriers injected into the active zone, i.e. the 'off' time - highly dependent on particular type of LED and also its temperature), the average light output won't be linearly dependent on the PWM fill ratio.