cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F303CC TIM2 needs a counter overflow before ARR match

AAnth.1
Senior

Hi and happy new year,

Migrating from STM32F103 to STM32F303, I mostly copy&paste my code from STM32103 to STM32F303, and only adjust what's necessary. However, I am having troubles with the TIM2 peripheral. Before starting the counter, the CNT register shows the correct reset value of 0x0000. My ARR register is set to 499. When I start the timer, I do not enter my ISR. When I halt the program, I see that the counter has incremented far beyond my ARR value (11052779 when I halted the program). The ISR was not entered between CNT=0 and CNT=11052779).

When I let the program run for a while (couple of minutes), the counter keeps incrementing until an overflow occurs (counter value > 2^32), starting from 0 again. When this happens, I enter the ISR, service it and leave the ISR again. Then, my ISR gets entered every 500ms, as supposed.

Can anyone tell me, why the counter misses the first ARR, needs to go all the way up to 2^32, overflows, and then matches the ARR regularly in the required 500ms intervals? Comparing the ref manuals of these two microcontrollers, the only difference I notice is that TIM2 on the F303 is a 32bit counter.

To answer the question where the 500ms might come from:

I use internal 8MHz clock and a prescaler of 7999. This gives a counter frequency of 8MHz/(7999+1) = 1000. This yields a 1ms timer increment. Counting to 499 gives 500ms.

0693W000006HJV6QAO.png 

/**
 * STM32F303CC General Purpose Timer
 * Uses TIM2_CH2 (PA1): Triggers every 500ms and toggles an LED on PC13
 * OC2M configuration: 000 Frozen Comparison between CCR2 and CNT does not affect OC2REF
 */
 
#include <stdint.h>
#include "stm32f3xx.h"
 
int main(void)
{
	__NVIC_EnableIRQ(TIM2_IRQn);
 
	// Check which bus PC13 sits on
	RCC->AHBENR |= RCC_AHBENR_GPIOCEN;
	uint8_t i = 0;
	for(;i<255;i++);
	i=0;
	GPIOC->MODER |= GPIO_MODER_MODER13_0;
 
	// Enables TIM2 bus
	RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
	for(;i<255;i++);
	i=0;
	TIM2->CR1 |= TIM_CR1_ARPE | TIM_CR1_URS;
	TIM2->DIER |= TIM_DIER_UIE;
	TIM2->PSC = 7999;
	TIM2->ARR = 499;
 
	TIM2->CR1 |= TIM_CR1_CEN;
 
	/* Loop forever */
	for(;;);
}
 
void TIM2_IRQHandler(void)
{
	static char flag = 0;
	TIM2->SR &= ~TIM_SR_UIF;
	if(flag)
	{
		GPIOC->BSRR = GPIO_BSRR_BR_13;
		flag = 0;
	}
	else
	{
		GPIOC->BSRR = GPIO_BSRR_BS_13;
		flag = 1;
	}
}

1 ACCEPTED SOLUTION

Accepted Solutions

Hello Happy new year.

Te ARR is preloaded. So will update in first update event.

Clear ARPE bit in CR1 before you load the ARR or leave it as is and before start counter, make an update event by setting UG bit in EGR (to update the ARR shadow reg)

View solution in original post

3 REPLIES 3

Hello Happy new year.

Te ARR is preloaded. So will update in first update event.

Clear ARPE bit in CR1 before you load the ARR or leave it as is and before start counter, make an update event by setting UG bit in EGR (to update the ARR shadow reg)

Thank you very much. That makes sense. It works as expected now. Thank you.

Cheers,

Don't use this form TIM2->SR &= ~TIM_SR_UIF;

Use this one TIM2->SR = ~TIM_SR_UIF; it is designed to work with a single atomic write

Update is clocked into CNT == 0 state

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..