STM32: problem with timer interrupt - Page 1
Forum section: electronics / general

author: bittumbler
author_rank: Contributor
timestamp: May 24, 2021, 03:29:43 pm
content: 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?TIAMatthiasCode:#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); // flushreturn size;}void dbg_printf(const char *fmt, ...){#ifdef DEBUGchar buffer;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;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 8MHzRCC->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 MHzRCC->CR &= ~(RCC_CR_PLLON);while (RCC->CFGR & RCC_CR_PLLRDY) {}; // wait for PLL to stopRCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLSRC);// RCC->PLLCFGR |= (RCC_PLLCFGR_PLLN_3 | RCC_PLLCFGR_PLLN_1); // Factor 10RCC->PLLCFGR |= (RCC_PLLCFGR_PLLN_4 | RCC_PLLCFGR_PLLN_2); // Factor 20RCC->PLLCFGR |= (RCC_PLLCFGR_PLLSRC_HSE);RCC->CR |= (RCC_CR_PLLON);while (!(RCC->CR & RCC_CR_PLLRDY)) {}; // wait for PLL to sync// set PLLP PLLQ PLLRRCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLP); // divide by 7RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLQ); // divice by 2RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLR); // divice by 2RCC->PLLCFGR |= ( RCC_PLLCFGR_PLLPEN | RCC_PLLCFGR_PLLQEN | RCC_PLLCFGR_PLLREN);// configure System Clock sourceRCC->CFGR &= ~(RCC_CFGR_SW);RCC->CFGR |= (RCC_CFGR_SW_PLL); // use PLL as system clock sourcewhile (!(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 RXRCC->AHB2ENR |= (RCC_AHB2ENR_GPIOAEN);RCC->APB1ENR1 |= (RCC_APB1ENR1_USART2EN); // Turn on USART2GPIOA->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 &= ~( GPIO_AFRL_AFSEL2 | GPIO_AFRL_AFSEL3);GPIOA->AFR |= ( ( 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 bitUSART2->CR1 |= ( USART_CR1_RE | USART_CR1_TE | USART_CR1_UE ); // enable USARTUSART2->CR1 |= ( USART_CR1_TE ); // send idle frame}void setupTIM2 (void) {// TIM2 is 32bitRCC->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 timerRCC->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 hereTIM2->DIER |= TIM_DIER_UIE; // Enable the hardware interrupt.// never reaches heredbg_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 timeTIM2->SR &= ~(TIM_SR_UIF); // clear interrupt flag}void TIM2_IRQ_handler(void) {// Handle a timer 'update' interrupt eventif (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){};}

author: Tagli
author_rank: Contributor
timestamp: May 24, 2021, 03:41:37 pm
content: 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'sTIM2_IRQHandler(unless you modify that file), notTIM2_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.

author: bittumbler
author_rank: Contributor
timestamp: May 24, 2021, 03:50:15 pm
content: 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...ThanksMatthias