2017-10-12 12:36 AM
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.2017-10-12 12:58 AM
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
2017-10-12 01:06 AM
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
2017-10-12 01:22 AM
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
2017-10-12 01:33 AM
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
2017-10-12 03:04 AM
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
2017-10-12 03:22 AM
Thanks for the example. It's very useful. I try this implementation as next step.
2017-10-12 03:25 AM
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!
2017-10-12 03:36 AM
Using HAL you must stop the timer. I tried.
I don't Cube.
2017-10-12 04:44 AM
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.