Skip to main content
NThon.1
Associate
January 24, 2020
Solved

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

  • January 24, 2020
  • 1 reply
  • 962 views

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

This topic has been closed for replies.
Best answer by waclawek.jan

> 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

1 reply

waclawek.jan
waclawek.janBest answer
Super User
January 24, 2020

> 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

NThon.1
NThon.1Author
Associate
January 24, 2020

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