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
#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)
{
};
}