Author Topic: STM32: problem with timer interrupt  (Read 2963 times)

0 Members and 1 Guest are viewing this topic.

Offline bittumblerTopic starter

  • Regular Contributor
  • *
  • Posts: 55
  • Country: de
STM32: problem with timer interrupt
« on: May 24, 2021, 03:29:43 pm »
Hi,

i am new to stm32, so this may be a beginners problem:

I am trying to set up an interrupt for TIM2 timer.
My code hangs at the instruction that enables the interrupt:

TIM2->DIER |= TIM_DIER_UIE;

If i comment out this instruction, my code works (but without the interrupt...).
Any idea, what i am doing wrong?
Also: where/how do i configure the clock source for TIM2?

TIA
Matthias

Code: [Select]
#include "stm32g431xx.h"
#include <stdarg.h>
#include <stdio.h>


#define DEBUG 1

// Override the 'write' clib method to implement 'printf' over UART.
int _write( int handle, char* data, int size ) {
  int count = size;
  while( count-- ) {
        while (! (USART2->ISR & USART_ISR_TXE )) {};
        USART2->TDR = *data++;  // send a char
  }
  USART2->RQR |= (USART_RQR_TXFRQ); // flush
  return size;
}

void dbg_printf(const char *fmt, ...)
{
    #ifdef DEBUG
        char buffer[256];
        char c;

        va_list args;
        va_start(args, fmt);
        vsprintf (buffer, fmt, args);
        va_end (args);
        for(int i = 0 ; i < 256; i++) {
                c = buffer[i];
                if (c == '\0') {
                        break;
                }

                while (! (USART2->ISR & USART_ISR_TXE )) {};
                USART2->TDR = c;  // send a char
        }
        USART2->RQR |= (USART_RQR_TXFRQ); // flush
    #endif
}

void setupClock(void) {
        // switch clock source to external oscillator 8MHz
        RCC->AHB2ENR |=  (RCC_AHB2ENR_GPIOFEN);
        RCC->CR      |=  (RCC_CR_HSEBYP);
        RCC->CR      |=  (RCC_CR_HSEON);
        while (!(RCC->CR & RCC_CR_HSERDY)) {}; // wait for HSE to sync

        // configure PLL to 80 MHz
        RCC->CR      &= ~(RCC_CR_PLLON);
        while (RCC->CFGR & RCC_CR_PLLRDY) {}; // wait for PLL to stop
        RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLSRC);
        // RCC->PLLCFGR |= (RCC_PLLCFGR_PLLN_3 | RCC_PLLCFGR_PLLN_1); // Factor 10
        RCC->PLLCFGR |= (RCC_PLLCFGR_PLLN_4 | RCC_PLLCFGR_PLLN_2); // Factor 20
        RCC->PLLCFGR |= (RCC_PLLCFGR_PLLSRC_HSE);
        RCC->CR      |= (RCC_CR_PLLON);
        while (!(RCC->CR & RCC_CR_PLLRDY)) {}; // wait for PLL to sync
        // set PLLP  PLLQ PLLR
        RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLP); // divide by 7
        RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLQ); // divice by 2
        RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLR); // divice by 2
        RCC->PLLCFGR |= ( RCC_PLLCFGR_PLLPEN | RCC_PLLCFGR_PLLQEN | RCC_PLLCFGR_PLLREN);
        // configure System Clock source
        RCC->CFGR  &= ~(RCC_CFGR_SW);
        RCC->CFGR  |=  (RCC_CFGR_SW_PLL); // use PLL as system clock source
        while (!(RCC->CFGR & RCC_CFGR_SWS_PLL)) {}; // wait for System Clock to sync
        // core_clock_hz = 80000000;

}

void setupUART(void) {
        // configure PA2/PA3 as AF7  for USART2
        // PA2 Pin7 is TX, PA3 Pin8 is RX
        RCC->AHB2ENR  |= (RCC_AHB2ENR_GPIOAEN);
        RCC->APB1ENR1 |= (RCC_APB1ENR1_USART2EN); // Turn on USART2

        GPIOA->MODER    &= ~( GPIO_MODER_MODE2                   | GPIO_MODER_MODE3);
        GPIOA->MODER    |=  ( ( 0x2 << GPIO_MODER_MODE2_Pos)     | ( 0x2 << GPIO_MODER_MODE3_Pos) );
        GPIOA->OTYPER   &= ~( GPIO_OTYPER_OT2                    | GPIO_OTYPER_OT3 );
        GPIOA->OSPEEDR  &= ~( GPIO_OSPEEDR_OSPEED2               | GPIO_OSPEEDR_OSPEED3);
        GPIOA->OSPEEDR  |=  ( ( 0x3 << GPIO_OSPEEDR_OSPEED2_Pos) | (0x3 << GPIO_OSPEEDR_OSPEED3_Pos) );
        GPIOA->PUPDR    &= ~( GPIO_PUPDR_PUPD2                   | GPIO_PUPDR_PUPD3);
        GPIOA->AFR[0]   &= ~( GPIO_AFRL_AFSEL2                   | GPIO_AFRL_AFSEL3);
        GPIOA->AFR[0]   |=  ( ( 0x7 << GPIO_AFRL_AFSEL2_Pos )    | ( 0x7 << GPIO_AFRL_AFSEL3_Pos ) );

        USART2->CR1     &= ~( USART_CR1_M0 | USART_CR1_M1);  // 8 data bits
        // USART2->CR1  |=  ( USART_CR1_FIFOEN );
        USART2->BRR     = (80000000/9600);
        USART2->CR2     &= ~( USART_CR2_STOP_0 | USART_CR2_STOP_1 ); // 1 stop bit
        USART2->CR1     |= ( USART_CR1_RE | USART_CR1_TE | USART_CR1_UE ); // enable USART
        USART2->CR1     |= ( USART_CR1_TE ); // send idle frame
}

void setupTIM2 (void) {
        // TIM2 is 32bit
        RCC->APB1ENR1 |= RCC_APB1ENR1_TIM2EN; // Enable the TIM2 clock.
        RCC->APB1SMENR1 |= RCC_APB1SMENR1_TIM2SMEN;
        NVIC_SetPriority(TIM2_IRQn, 0x23); // Enable the NVIC interrupt for TIM2.
        NVIC_EnableIRQ(TIM2_IRQn);
}

void startTIM2(uint32_t ms) {
        TIM2->CR1 &= ~(TIM_CR1_CEN); // make sure timer is off.
        RCC->APB1RSTR1 |=  (RCC_APB1RSTR1_TIM2RST); // reset timer
        RCC->APB1RSTR1 &= ~(RCC_APB1RSTR1_TIM2RST);
        TIM2->PSC   = (uint16_t) (80000000 / 10000);
        TIM2->ARR   = ms * 10;       // (32 bit)
        TIM2->EGR  |= TIM_EGR_UG; // reset timer and apply settings.
dbg_printf("TIM2 3\n\r");
        // reaches here
        TIM2->DIER |= TIM_DIER_UIE; // Enable the hardware interrupt.
        // never reaches here
dbg_printf("TIM2 4\n\r");
        TIM2->CR1  |= TIM_CR1_CEN; // Enable the timer.
dbg_printf("TIM2 5\n\r");
}

void waitTIM2(void) {
        __WFE();
}

void stopTIM2 (void) {
        TIM2->CR1 &= ~(TIM_CR1_CEN); // turn off time
        TIM2->SR  &= ~(TIM_SR_UIF);  // clear interrupt flag
}

void TIM2_IRQ_handler(void) {
        // Handle a timer 'update' interrupt event
        if (TIM2->SR & TIM_SR_UIF) {
                TIM2->SR &= ~(TIM_SR_UIF);
                // wake up and do something.
        }
dbg_printf("TIM2 Interrupt\n\r");
}

int main(void)
{
        setupClock();

        setupUART();

        dbg_printf("\n\r");

        dbg_printf("setup TIM2\n\r");
        setupTIM2();
        dbg_printf("start TIM2\n\r");
        startTIM2(1000);
        dbg_printf("wait TIM2\n\r");
        waitTIM2();
        dbg_printf("wait done TIM2\n\r");

        while (1)
        {
        };
}



 

Offline Tagli

  • Contributor
  • Posts: 31
  • Country: tr
Re: STM32: problem with timer interrupt
« Reply #1 on: May 24, 2021, 03:41:37 pm »
I didn't check all of your code, but it seems your ISR is missing. The name of the ISR which is defined in startup_stm32fxxxxxxx.s file (which is vendor supplied) should match exactly with the function name you define in the C code. By default, it's TIM2_IRQHandler (unless you modify that file), not TIM2_IRQ_handler. The compiler gives no errors or warnings in this situation. But when the interrupt is triggered, the execution jumps into a predefined default handler, which is just an infinite loop.

Update: They (ST) may have changed the naming conventions and thus the names of the ISRs. If so, please ignore my post.
« Last Edit: May 24, 2021, 03:48:04 pm by Tagli »
Gokce Taglioglu
 

Offline bittumblerTopic starter

  • Regular Contributor
  • *
  • Posts: 55
  • Country: de
Re: STM32: problem with timer interrupt
« Reply #2 on: May 24, 2021, 03:50:15 pm »
Hi Tagli,

thanks a lot for you help, that was exactly the problem! Now it works.
 
Already searched a few hours, and could not find it...

Thanks

Matthias
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf

 

- - -
-->