Skip to main content
antonius
Associate III
August 3, 2020
Question

1Hz interrupt from TIM3 ?

  • August 3, 2020
  • 24 replies
  • 4739 views

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)

This topic has been closed for replies.

24 replies

antonius
antoniusAuthor
Associate III
August 3, 2020

The file : STM32F4-Discovery_FW_V1.1.0\Project\Peripheral_Examples\TIM_TimeBase\readme.txt

prain
Visitor II
August 3, 2020

Getting 1Hz is not possible with this prescaler value. Increase prescaler value. for example set timer clock to 1KHz:

PrescalerValue = (uint16_t) ((SystemCoreClock / 2) / 1000) - 1;

then set your desired CCx channel to 1000 :

__IO uint16_t CCR1_Val = 1000;

TDK
August 3, 2020

> PrescalerValue = (uint16_t) ((SystemCoreClock / 2) / 1000) - 1;

At a clock of 168 MHz, this will overflow 16 bits.

"If you feel a post has answered your question, please click ""Accept as Solution""."
antonius
antoniusAuthor
Associate III
August 3, 2020

How​ to avoid overflow ? I want to get 1Hz, 0.5Hz, 0.1Hz and 0.05Hz Thanks

TDK
August 3, 2020

The CCR values for TIM1 are 16-bit (max of 65535), so you need to increase the prescaler if you want a 1Hz interrupt.

Use

PrescalerValue = (uint16_t) ((SystemCoreClock / 2) / 50000) - 1;

to set the timer clock to 50kHz and use TIM_Period = 49999 to have an update interrupt at 1 Hz.

That example is showing how to toggle LEDs multiple times within an update period. Doesn't seem like what you're asking for.

"If you feel a post has answered your question, please click ""Accept as Solution""."
antonius
antoniusAuthor
Associate III
August 3, 2020

I don't understand, if I want to get 0.5 Hz ?

What's the value for

__IO uint16_t CCR1_Val = 49999; // 1Hz

__IO uint16_t CCR2_Val = 49999*2; // to get 0.5Hz ==> correct me ?

if

TIM_Period = 49999

and

TIM3 counter clock at 50 KHz, I'm thinking to reduce TIM3 counter clock to 1KHz, but I can't get a good result ?

Cheers,

TDK
August 3, 2020

> 49999*2

This overflows. What did you have to do before to prevent it from overflowing?

"If you feel a post has answered your question, please click ""Accept as Solution""."
S.Ma
Principal
August 3, 2020

The precision also depends on clock tolerances, so don t use HSI internal oscillators. Ideally use 32.768khz LSE clock as RTC purpose is calendar and time clock. In some products like STM32L4 48MHz can be generated by MSI from LSE.

TDK
August 4, 2020

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:

https://github.com/USTPGW/Workspace/blob/583e96715a9fd9dda5bd5c1dbb662284a81d102f/Workspace/STM32F4-Discovery_FW_V1.1.0/Project/Peripheral_Examples/TIM_TimeBase/main.c

"If you feel a post has answered your question, please click ""Accept as Solution""."
antonius
antoniusAuthor
Associate III
August 4, 2020

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

antonius
antoniusAuthor
Associate III
August 4, 2020

What's the minimum frequency for TIM3 counter ?

prain
Visitor II
August 4, 2020

Min_frequency = TIMER_CLK / 65536

antonius
antoniusAuthor
Associate III
August 4, 2020

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 ?

prain
Visitor II
August 4, 2020

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

S.Ma
Principal
August 4, 2020

you also could extend the timer using overflow calkback and increment a global 32 bit variable.... that starts to look like a sw RTC....

Piranha
Principal III
August 4, 2020

> 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...

antonius
antoniusAuthor
Associate III
August 5, 2020

Like this :

__IO uint16_t CCR1_Val = 3000;
__IO uint16_t CCR2_Val = 6000;
__IO uint16_t CCR3_Val = 12000;
__IO uint16_t CCR4_Val = 60000;
 
.
.
.
PrescalerValue = (uint16_t) ((SystemCoreClock / 2) / 3000) - 1; //TIM3 counter clock at 3000Hz
 
.
.
/* 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;
 
.
.
.
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);
 }
}

Piranha
Principal III
August 5, 2020

You still have set prescaler to 65'536. That's why you are getting 65'536 / 28'000 = 2,34 Hz instead of 1 Hz and some other x2 factor which turns it into 4,68 Hz.

CCR3_Val is not set to 0,1 Hz. Compare value = timer_clock (Hz) / compare_frequency (Hz).

antonius
antoniusAuthor
Associate III
August 5, 2020

do you mean :

TIM_TimeBaseStructure.TIM_Period = 65535;

?

Timer clock = 3000 Hz and compare frequency = 0.5 Hz

CCR3_Val is a variable on TIM3_IRQHandler

Compare Value = 3000 Hz / 0.5 Hz