cancel
Showing results for 
Search instead for 
Did you mean: 

Timer doesn't work properly until the external interrupt was triggered.

NThon.1
Associate

Hello

I am quite new to microcontroller programming.

and this is my first code with my STM32F429

I write the code with least help of library to learn the basic principle of microcontoller programming.

This is what happened.

I write a program that suppose to turn on/off led every one second(using timer2) or blink the led when I press the button(EXTI0) but my led doesn't turn on/off but Instead keep itseft on(halft brightness) until I press the button and triggered EXTI0 and then everything start working as it supposes to do.

I am pretty sure,It my fault but I still can't figure it out what cause this weird problem.

Here is my code,It's not very clean tho.

#include "stm32f4xx.h"
 
void digitalWrite(GPIO_TypeDef *GPIOx,uint32_t pinNum,uint32_t state){
	if(state)GPIOx->BSRRL |= (1<<pinNum);
	else GPIOx->BSRRH |= (1<<pinNum);
}
 
int main(void)
{
	RCC->CFGR &= ~RCC_CFGR_HPRE;
	RCC->CFGR &= ~RCC_CFGR_PPRE1;
	RCC->CFGR |= (5<<10);
	RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
	RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
	RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
	RCC->AHB1ENR |= (1<<6);
	SYSCFG->EXTICR[1] &= ~(15);
	EXTI->IMR |= 1;
	EXTI->RTSR |= 1;
	TIM3->CNT = 0;
	TIM3->PSC = 59999;
	TIM3->ARR = 65535;
	TIM3->CR1 |= 1;
	GPIOG->MODER |= 1<<26;
	GPIOG->MODER |= 1<<28;
	GPIOG->OTYPER = 0;
	GPIOG->OSPEEDR |= 3<<26;
	GPIOG->OSPEEDR |= 3<<28;
	int i = 0;
	TIM3->CR1 |= 1;
	NVIC_EnableIRQ(EXTI0_IRQn);
  while (1)
  {
	  if(TIM3->CNT>1500){
		  i^=1;
			digitalWrite(GPIOG,14,i);
			TIM3->CNT = 1;
	  }
  }
}
void EXTI0_IRQHandler(){
	EXTI->PR |= 1;
	digitalWrite(GPIOG,14,1);
	for(int i = 0;i<50000;i++);
	digitalWrite(GPIOG,14,0);
 
}
uint32_t sEE_TIMEOUT_UserCallback(void)
{
  while (1)
  {
  }
}

 Thank in advance for your help

1 ACCEPTED SOLUTION

Accepted Solutions

> TIM3->PSC = 59999;

Prescaler is shadowed, i.e. this value gets written to an "intermediate" register, but gets used by the actual prescaler only when Update event happens. This normally happens at the counter overflow, i.e. when CNT reaches ARR and then rolls over to 0.

However, you don't allow this to happen by the forced reload of CNT in the main() loop.

You can force it by writing 1 to TIMx_EGR.UG, but keep in mind for further usage that that also sets the respective status flag thus causes interrupt if enabled (many "library" users are surprised by this).

Your EXTI handler probably lasts long enough to allow CNT to reach ARR and roll over (for testing OK, but it's a bad idea to use lengthy loopdelays and even worse idea to have a lengthy ISR).

Some remarks:

> RCC->AHB1ENR |= (1<<6);

it may be a good idea to stick to the symbols defined in the CMSIS-mandated device header, it helps

> GPIOx->BSRRL |= (1<<pinNum);

No, you want to write rather than read-modify-write (RMW) into the BSRR register, i.e. use = rather than |=

You also might want to use the full 32-bit BSRR register itself, rather than BSRRL/BSRRH.

> for(int i = 0;i<50000;i++);

You want to make the variable in loopdelay volatile, as otherwise the compiler when set to optimize would optimize this away completely and your loopdelay suddenly stops working.

JW

View solution in original post

2 REPLIES 2

> TIM3->PSC = 59999;

Prescaler is shadowed, i.e. this value gets written to an "intermediate" register, but gets used by the actual prescaler only when Update event happens. This normally happens at the counter overflow, i.e. when CNT reaches ARR and then rolls over to 0.

However, you don't allow this to happen by the forced reload of CNT in the main() loop.

You can force it by writing 1 to TIMx_EGR.UG, but keep in mind for further usage that that also sets the respective status flag thus causes interrupt if enabled (many "library" users are surprised by this).

Your EXTI handler probably lasts long enough to allow CNT to reach ARR and roll over (for testing OK, but it's a bad idea to use lengthy loopdelays and even worse idea to have a lengthy ISR).

Some remarks:

> RCC->AHB1ENR |= (1<<6);

it may be a good idea to stick to the symbols defined in the CMSIS-mandated device header, it helps

> GPIOx->BSRRL |= (1<<pinNum);

No, you want to write rather than read-modify-write (RMW) into the BSRR register, i.e. use = rather than |=

You also might want to use the full 32-bit BSRR register itself, rather than BSRRL/BSRRH.

> for(int i = 0;i<50000;i++);

You want to make the variable in loopdelay volatile, as otherwise the compiler when set to optimize would optimize this away completely and your loopdelay suddenly stops working.

JW

Thank you for asnwering my question, It's working now, and thanks for your useful advice.