Skip to main content
Graduate II
January 15, 2025
Question

Problem with Timer2

  • January 15, 2025
  • 4 replies
  • 1200 views

Hi

  I have am using the Timer2 on the STM32L433 chip, and for some reason the interupt gets called as soon as timer is started.  Below is my code, and the  clocks are running at 60MHz.  Anyone any idea what I have done wrong?

 

Many Thanks

Scott.

 

void main(void)
{
 .....
 Timer2_Init();
 Start_OneShotTimer2(3000); //set for 3 seconds, but interupt routine gets called straight away

 while(1){}
}

void Timer2_Init(void)
{
	 // Enable Timer 2 clock
	RCC->APB1ENR1 |= RCC_APB1ENR1_TIM2EN;

	// Configure the timer for one-pulse mode
	TIM2->CR1 |= TIM_CR1_OPM; // One-Pulse Mode (counter stops after update event)

	// Enable TIM2 interrupt in NVIC
	NVIC_EnableIRQ(TIM2_IRQn);
}


void Start_OneShotTimer2(uint32_t milliseconds)
{
	uint32_t prescaler;
	// 1. Stop the timer before modifying its configuration
	TIM2->CR1 &= ~TIM_CR1_CEN; // Stop the timer (disable counter)

	// 2. Clear any previous interrupt flags
	TIM2->SR = 0; // Clear all status flags, including UIF

	// 3. Disable the interrupt while configuring the timer
	TIM2->DIER &= ~TIM_DIER_UIE; // Disable the update interrupt

	// 4. Calculate the prescaler (prescale to 1 µs)
	TIM2->PSC = 59999; // Set the prescaler for 1 µs ticks

	// 5. Set the auto-reload value for the desired delay (milliseconds converted to µs)
	uint32_t arr = (milliseconds * 1000) - 1; // Convert ms to µs
	TIM2->ARR = arr; // Set auto-reload value

	// 6. Reset the counter to ensure it starts from 0
	TIM2->CNT = 0; // Reset the counter value

	// 7. Enable the update interrupt (only now)
	TIM2->DIER |= TIM_DIER_UIE; // Enable the update interrupt

	// 8. Start the timer
	TIM2->CR1 |= TIM_CR1_CEN;
}

void TIM2_IRQHandler(void)
{
 if (TIM2->SR & TIM_SR_UIF)
 { // Check for the update interrupt flag
 TIM2->SR &= ~TIM_SR_UIF; // Clear the interrupt flag
.......

 }
 
}

 

 

    This topic has been closed for replies.

    4 replies

    Technical Moderator
    January 16, 2025

    Hello @SSmit.13 

    Try adding a delay before starting the timer to ensure that all configurations are correctly applied.

    SSmit.13Author
    Graduate II
    January 17, 2025

    Hi Imen

      Added a short delay (and tried longer), but no luck.

     

    Cheers

    Scott

    Super User
    January 16, 2025

    TIMx_PSC is preloaded, so the first timer period after enabling it is with the original prescaler value, which by default is 0.

    You can force update (which would load the preloaded PSC value into the real PSC register) by setting TIMx_EGR.UG.

    Note that that will set the TIMx_SR.UIF flag, so you have to clear it before enabling the interrupt in TIMx_DIER. Alternatively (and possibly better), use TIMx_CR1.URS to avoid TIMx_SR.UIF being set through setting TIMx_EGR.UG.

    JW

     

    SSmit.13Author
    Graduate II
    January 17, 2025

    Hi JW

    Many thanks for your reply.  I added the line for setting the TIM2_EGR.UG , and cleared the TIM2_SR.UIF flag, see below up date.  But still the interupt routine is called straight after enabled. Any idea what I am doing wrong?

     

    Thanks

    Scott

    void Timer2_Init(void)
    {
    	 RCC->APB1ENR1 |= RCC_APB1ENR1_TIM2EN;
    
    	 // Ensure TIM2 is reset
    	 TIM2->CR1 = 0x0000; // Reset control register
    	 TIM2->CR2 = 0x0000; // Reset control register 2
    	 TIM2->DIER = 0x0000; // Reset interrupt enable register
    	 TIM2->SR = 0x0000; // Clear status register
    
    	 // Enable TIM2 interrupt in NVIC
    	 NVIC_EnableIRQ(TIM2_IRQn);
    	 NVIC_SetPriority(TIM2_IRQn, 1);
    }
    
    
    void Start_OneShotTimer2(uint32_t milliseconds)
    {
    
    
    	// Disable TIM2 to configure it
    	 // Disable TIM2 to ensure clean configuration
     TIM2->CR1 = 0; // Reset the control register
     TIM2->CR1 |= TIM_CR1_OPM; // Enable One-Pulse Mode
     TIM2->CR1 |= TIM_CR1_URS; // Only overflow/underflow generates an update interrupt
    
    	// Disable update events during configuration
    	TIM2->CR1 |= TIM_CR1_UDIS;
    
    	// Set the Auto-Reload Register (ARR) for the desired delay in milliseconds
    	TIM2->ARR = milliseconds * 1000 - 1; // Convert ms to µs (1 ms = 1000 µs)
    
    	// Configure prescaler for 1 µs resolution (16 MHz / 1 MHz - 1)
    	TIM2->PSC = 59999;
    
    	// Reset the counter to ensure a clean start
    	TIM2->CNT = 0;
    
    	TIM2->EGR = TIM_EGR_UG; << Added here
    
    	// Re-enable update events
    	TIM2->CR1 &= ~TIM_CR1_UDIS;
    
    	TIM2->CR1 |= TIM_CR1_DIR;
    	// Clear the update interrupt flag
    	TIM2->SR &= ~TIM_SR_UIF;
    
    	// Enable update interrupt
    	TIM2->DIER |= TIM_DIER_UIE;
    	// Start the timer
    
    	TIM2->CR1 |= TIM_CR1_CEN;
    }
    
    void TIM2_IRQHandler(void)
    {
     if (TIM2->SR & TIM_SR_UIF)
     { // Check for the update interrupt flag
     TIM2->SR &= ~TIM_SR_UIF; // Clear the interrupt flag
     }
    }

     

    Super User
    January 18, 2025

    > But still the interupt routine is called straight after enabled

    How do you know? How do you observe this?

    JW

    Visitor II
    January 18, 2025

    An article on Timers that may help

    ARM Tutorial Part 2 Timers