2020-08-02 08:06 PM
Dear Members,
How can I get exactly 1Hz interrupt from TIM3 ?
I use STM32F4 Discovery and looking at TIM_TimeBase Example, but I can not get exactly 1Hz yet...
Thanks
Code :
TIM_OCInitTypeDef TIM_OCInitStructure;
__IO uint16_t CCR1_Val = 54618;
__IO uint16_t CCR2_Val = 27309;
__IO uint16_t CCR3_Val = 13654;
__IO uint16_t CCR4_Val = 6826;
/* -----------------------------------------------------------------------
TIM3 Configuration: Output Compare Timing Mode:
In this example TIM3 input clock (TIM3CLK) is set to 2 * APB1 clock (PCLK1),
since APB1 prescaler is different from 1.
TIM3CLK = 2 * PCLK1
PCLK1 = HCLK / 4
=> TIM3CLK = HCLK / 2 = SystemCoreClock /2
To get TIM3 counter clock at 50 MHz, the prescaler is computed as follows:
Prescaler = (TIM3CLK / TIM3 counter clock) - 1
Prescaler = ((SystemCoreClock /2) /50 MHz) - 1
CC1 update rate = TIM3 counter clock / CCR1_Val = 9.154 Hz
==> Toggling frequency = 4.57 Hz
C2 update rate = TIM3 counter clock / CCR2_Val = 18.31 Hz
==> Toggling frequency = 9.15 Hz
CC3 update rate = TIM3 counter clock / CCR3_Val = 36.62 Hz
==> Toggling frequency = 18.31 Hz
CC4 update rate = TIM3 counter clock / CCR4_Val = 73.25 Hz
==> Toggling frequency = 36.62 Hz
/* Compute the prescaler value */
//PrescalerValue = (uint16_t) ((SystemCoreClock / 2) / 500000) - 1;
PrescalerValue = (uint16_t) ((SystemCoreClock / 2) / 6826) - 1; //TIM3 counter clock at 6826Hz
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
/* Prescaler configuration */
TIM_PrescalerConfig(TIM3, PrescalerValue, TIM_PSCReloadMode_Immediate);
/* Output Compare Timing Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR1_Val;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Disable);
/* Output Compare Timing Mode configuration: Channel2 */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR2_Val;
TIM_OC2Init(TIM3, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Disable);
/* Output Compare Timing Mode configuration: Channel3 */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR3_Val;
TIM_OC3Init(TIM3, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Disable);
/* Output Compare Timing Mode configuration: Channel4 */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR4_Val;
TIM_OC4Init(TIM3, &TIM_OCInitStructure);
TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Disable);
/* TIM Interrupts enable */
TIM_ITConfig(TIM3, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE);
This example shows how to configure the TIM peripheral in Output Compare Timing
mode with the corresponding Interrupt requests for each channel in order to generate
4 different time bases.
The TIM3CLK frequency is set to SystemCoreClock / 2 (Hz), to get TIM3 counter
clock at 500 KHz so the Prescaler is computed as following:
- Prescaler = (TIM3CLK / TIM3 counter clock) - 1
SystemCoreClock is set to 168 MHz for STM32F4xx Devices Revision A.
The TIM3 CC1 register value is equal to 54618,
CC1 update rate = TIM3 counter clock / CCR1_Val = 9.154 Hz,
so the TIM3 Channel 1 generates an interrupt each 109.2ms
The TIM3 CC2 register is equal to 27309,
CC2 update rate = TIM3 counter clock / CCR2_Val = 18.31 Hz
so the TIM3 Channel 2 generates an interrupt each 54.6ms
The TIM3 CC3 register is equal to 13654,
CC3 update rate = TIM3 counter clock / CCR3_Val = 36.62 Hz
so the TIM3 Channel 3 generates an interrupt each 27.3ms
The TIM3 CC4 register is equal to 6826,
CC4 update rate = TIM3 counter clock / CCR4_Val = 73.25 Hz
so the TIM3 Channel 4 generates an interrupt each 13.65ms.
When the counter value reaches the Output compare registers values, the Output
Compare interrupts are generated and, in the handler routine, 4 pins(PD.12, PD.13,
PD.14 and PD.15) are toggled with the following frequencies:
- PD.12: 4.57 Hz (CC1)
- PD.13: 9.15 Hz (CC2)
- PD.14: 18.31 Hz (CC3)
- PD.15: 36.62 Hz (CC4)
2020-08-03 07:22 PM
prevent it from overflow, reset the counter ? or reduce the timer clock ?
Or you know a better idea ? it's puzzling me...
Thanks
2020-08-03 08:04 PM
I looked at the example a bit more closely. The reason they're getting different interrupt frequencies is that the interrupt itself changes the CCRx value an increments it by the corresponding CCRx_Val defined value. Because of this, it also sneakily requires TIM_Period = 65535 so that it can rely on 16-bit overflow to calculate the correct next CCRx value.
To get 1Hz and 0.5Hz interrupts, use your original example but change:
// to get 1 Hz interrupt
__IO uint16_t CCR1_Val = 2000;
// to get 0.5 Hz interrupt
__IO uint16_t CCR2_Val = 4000;
...
// to get 2kHz timer clock
// (if SystemCoreClock = 168MHz, this evaluates to 41999)
PrescalerValue = (uint16_t) ((SystemCoreClock / 2) / 2000) - 1;
Did not test, but it probably works.
Original project:
2020-08-03 08:22 PM
thanks for the reply,
Here's my experiment :
__IO uint16_t CCR1_Val = 1000;
__IO uint16_t CCR2_Val = 2000;
__IO uint16_t CCR3_Val = 4000;
__IO uint16_t CCR4_Val = 8000;
PrescalerValue = (uint16_t) ((SystemCoreClock / 2) / 1000) - 1; //TIM3 counter clock at 1000Hz
suppose to be 1Hz, 0.5Hz, 0.25Hz and 0.125Hz
the interrupt service,
/**
* @brief This function handles TIM3 global interrupt request.
* @param None
* @retval None
*/
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
/* LED4 toggling with frequency = 4.57 Hz */
STM_EVAL_LEDToggle(LED4);
capture = TIM_GetCapture1(TIM3);
TIM_SetCompare1(TIM3, capture + CCR1_Val);
}
else if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);
/* LED3 toggling with frequency = 9.15 Hz */
STM_EVAL_LEDToggle(LED3);
capture = TIM_GetCapture2(TIM3);
TIM_SetCompare2(TIM3, capture + CCR2_Val);
}
else if (TIM_GetITStatus(TIM3, TIM_IT_CC3) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_CC3);
/* LED5 toggling with frequency = 18.31 Hz */
STM_EVAL_LEDToggle(LED5);
capture = TIM_GetCapture3(TIM3);
TIM_SetCompare3(TIM3, capture + CCR3_Val);
}
else
{
TIM_ClearITPendingBit(TIM3, TIM_IT_CC4);
/* LED6 toggling with frequency = 36.62 Hz */
STM_EVAL_LEDToggle(LED6);
capture = TIM_GetCapture4(TIM3);
TIM_SetCompare4(TIM3, capture + CCR4_Val);
}
}
I'll give a try and posted,
Cheers
2020-08-03 08:24 PM
What's the minimum frequency for TIM3 counter ?
2020-08-03 09:22 PM
Is it possible that I change
uint32_t SystemCoreClock = 168000000;
to lower frequency ? for example 50000000 for preventing my TIM3 overflow ?
2020-08-04 06:47 AM
Min_frequency = TIMER_CLK / 65536
2020-08-04 06:59 AM
it means that if I have timer_CLK = 1000Hz
PrescalerValue = (uint16_t) ((SystemCoreClock / 2) / 1000) - 1; //TIM3 counter clock at 1000Hz
minimum TIM3 counter = 65.536Hz ?
2020-08-04 07:08 AM
I had a typo,
TIM3_CLK is SystemCoreClock / 2 (usually APB clock)
for a "GIVEN" TIM3_CLK the minimum is:
Min_frequency = TIM3_CLK / 65536
2020-08-04 07:42 AM
you also could extend the timer using overflow calkback and increment a global 32 bit variable.... that starts to look like a sw RTC....
2020-08-04 12:07 PM
> How to avoid overflow ? I want to get 1Hz, 0.5Hz, 0.1Hz and 0.05Hz
The longest period is 20 s (for 0,05 Hz) and it must not overflow 65'536. For that a period of 60'000 would be a nice number and for that to work, you need a timer frequency of 60000 / 20 s = 3 kHz. Set a prescaler to 84 MHz / 3 kHz = 28'000. Adjust a period for the faster frequencies and you are done.
But you cannot get multiple simultaneous frequencies from a single timer without readjustment in a software interrupt on every cycle!
Anyway this sounds like a possibly wrong solution for the job. If it is for some software retry/polling cycles, then it really is a job for software timers...