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 12, 2017 at 09:58

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

Yes. Simply write to it.

TIM5->CCR1 = current_value;

They may be some LL incantation for this if you insist on using a 'library'.

You may want to have TIMx_CCMRy.OCzPE set.

JW

Fede Rico
Associate III
Posted on October 12, 2017 at 10:06

Hello JW,

thanks for the reply.

Regarding

TIM5->CCR1 = current_value;

TIM5 is a definition or I should use the Timer Handler (TIM_HandleTypeDef)?

I'm using the hal library in my application.

Could you provide an example please?

BR

Posted on October 12, 2017 at 10:22

TIM5 is a definition

Yes, from the CMSIS-mandated device header. You did not tell us your STM32 model, but e.g. for STM32F407 it's at [STM32Cube_FW_F4_V1.16.0]\Drivers\CMSIS\Device\ST\STM32F4xx\Include\stm32f407xx.h to be #include-d indirectly through stm32f4xx.h in the same directory (and you probably have the path added in the compiling environment (IDE or whatever)).

Iit's basically a pointer to a structure which matches the layout of hardware registers of the timer. Your 'handler' will contain it as one of its fields, so you can indirectly use it from there, too. Look at the HAL sources, how they access the registers.

JW

Posted on October 12, 2017 at 10:33

Yes.

Maybe you didn't have to stop it with using the HAL either, but I don't know for sure, I don't Cube.

JW

Posted on October 12, 2017 at 10:04

The next step would be to leave DMA (driven by another timer) to pick values from a table and write to the target PWM CCR. That then runs with no involvement of the processor after initialization.

<shameless self-advertisement> An example for the DISCO-L4

http://www.efton.sk/STM32/breathl4.zip

</shameless self-advertisement>

JW

Posted on October 12, 2017 at 10:22

Thanks for the example. It's very useful. I try this implementation as next step.

Posted on October 12, 2017 at 10:25

Ok! I undestand! TIM5 map directly the timer register.

So in this way I don't need to stop the timer. Am I right?

Thanks!

Posted on October 12, 2017 at 10:36

Using HAL you must stop the timer. I tried.

I don't Cube.    

  

Posted on October 12, 2017 at 11:44

With HAL you can use this macro to alias the register access without having to stop the timer or anything (using HAL PWM channel config preload is always enabled):

__HAL_TIM_SET_COMPARE(

PWM_TimerHandler[timerId].handler, /* TIM handle pointer */

PWM_ChannelHandler[channelId], /* TIM channel */

newCompVal /* Compare register value to set */ );

HAL is nothing more than an abstraction library, therefore anything can be done with it, the only limitation is whether there is an abstraction method/macro or not. And if there isn't, you can just use handle->Instance to perform register access.