2024-02-21 10:11 AM
Hi,
I want to make an application in which 4 different signals to be produced with different frequencies. I am using timer output compare mode. My board is STM32F407VG-DISC1, so I use on board LEDs as TIM4_Channel1, TIM4_Channel2, TIM4_Channel3 and TIM4_Channel4.
I use HAL_TIM_OC_Start_IT API in order to change the value of CCR so that whenever interrupt occurs, the value in register is updated which enables me to control the generated frequency.
But this does not work.
First of all, 4 LEDs blink at the same rate, no matter what values I provide in the interrupt callback function via __HAL_TIM_SET_COMPARE function. I can control the frequency of the signal generated via the counter clock, under configuration tab of the TIM4 mode and configuration on STM32 Cube IDE.
The frequency increases when I lower the prescaler.
I have got few questions.
Thank you.
Solved! Go to Solution.
2024-02-22 05:50 AM
Sorry for the confusion, I haven't thoroughly read your initial post and assumed you are using PWM mode of the channels set to Output Compare. Now I see you're using Toggle mode, and with that, the scheme you've described should work (provided the interrupts are handled fast enough).
However, you've set ARR (period) to 1000 and also all CCRx (Pulse) values to 1000 - so far so good, the interrupts happen when CNT reaches 1000 - but then you increase CCRx. If CCRx>ARR, the interrupt always happens when CNT reaches ARR, that's why you see the same period all the time.
You want ARR to be higher than the longest period, and the calculation in the interrupt should wrap the result around properly (i.e.
__HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_2,(ccr_content+pulse2_value) % (ARR_value + 1));
It is a good idea to leave ARR at its maximum, which for the 16-bit TIM4 is 65535.
Also, in
uint32_t pulse1_value = 500000; uint32_t pulse2_value = 10000; uint32_t pulse3_value = 1000; uint32_t pulse4_value = 20000;
the first value is unrealistic with 16-bit timer.
Also, if you use CCRx preload, the value you write will get active only after the next Update. That is definitively not what you want here; so you don't want to use CCRx preload.
JW
2024-02-21 10:30 AM
There is only one counter per timer, so you can't generate several different PWM frequencies with one timer. What changing of compare register does is only the pulse width.
Read the timer chapter in Reference Manual.
JW
2024-02-21 09:05 PM
Thank you for the reply, yet it doesnt help much.
I havent understood the reference manual completely. Could you please elaborate your answers ?
2024-02-22 12:56 AM - edited 2024-02-22 01:01 AM
Maybe the following diagram helps you. There's only one counter (CNT), and so all PWMs (TIMx_CHx outputs) have the same frequency given by value in TIMx_ARR; they differ only in the duty cycle (pulse width), set in TIMx_CCRx:
(Drawn with https://wavedrom.com/editor.html ).
JW
2024-02-22 04:39 AM
I understand your point, thank you. However, in my code whenever a counter values reaches to CCR1 value, then interrupt is called in which CCR1 value is updated, so that another match is aimed. This will allow to obtain signals with different frequencies that is that is generated by Timer4.
Also about your diagram, why TIMx_CHx starts with high when up event occured ? In fact, why TIMx_CHx is toggled when counter reaches to threshold and up event occurs. This is not a case which CCRx and CNT values matches.
uint32_t ccr_content;
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim -> Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
ccr_content = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
__HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_1,ccr_content+pulse1_value);
}
if(htim -> Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
ccr_content = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
__HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_2,ccr_content+pulse2_value);
}
if(htim -> Channel == HAL_TIM_ACTIVE_CHANNEL_3)
{
ccr_content = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_3);
__HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_3,ccr_content+pulse3_value);
}
if(htim -> Channel == HAL_TIM_ACTIVE_CHANNEL_4)
{
ccr_content = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_4);
__HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_4,ccr_content+pulse4_value);
}
}
2024-02-22 05:50 AM
Sorry for the confusion, I haven't thoroughly read your initial post and assumed you are using PWM mode of the channels set to Output Compare. Now I see you're using Toggle mode, and with that, the scheme you've described should work (provided the interrupts are handled fast enough).
However, you've set ARR (period) to 1000 and also all CCRx (Pulse) values to 1000 - so far so good, the interrupts happen when CNT reaches 1000 - but then you increase CCRx. If CCRx>ARR, the interrupt always happens when CNT reaches ARR, that's why you see the same period all the time.
You want ARR to be higher than the longest period, and the calculation in the interrupt should wrap the result around properly (i.e.
__HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_2,(ccr_content+pulse2_value) % (ARR_value + 1));
It is a good idea to leave ARR at its maximum, which for the 16-bit TIM4 is 65535.
Also, in
uint32_t pulse1_value = 500000; uint32_t pulse2_value = 10000; uint32_t pulse3_value = 1000; uint32_t pulse4_value = 20000;
the first value is unrealistic with 16-bit timer.
Also, if you use CCRx preload, the value you write will get active only after the next Update. That is definitively not what you want here; so you don't want to use CCRx preload.
JW
2024-02-22 06:42 AM
Thank you @waclawek.jan all good now.
One point left open for me that is, what is the impact of Output Compare Preload field exactly?
When I enabled it, timer couldnt generate the expected signals.
2024-02-24 01:53 PM
> what is the impact of Output Compare Preload field exactly?
If Preload is enabled, the value you write into TIMx_CCRx is not used immediately, but only after an Update (i.e. timer overflow) happens.
JW