cancel
Showing results for 
Search instead for 
Did you mean: 

Set up UART Interrupt using register

MLi.6
Associate II

My UART example works very well.  But, I want to do with the UART interrupt.  Currently it does not work because it always jumps to an infinite loop in the start up assembly code.

Infinite_Loop:  // startup_stm32f411retx.s

 b Infinite_Loop

Here is my source code. It works great without USART receive interrupt enabled.  USART2_IRQHandler is never executed. I have put a breakpoint inside it. Instead, it always jumps to the Infinit_loop line. What did I do wrong? Why your HAL / LL examples work?  I looked into the HAL / LL code.  It is very similar to my source code.

Thank you for any help you can provide.

Michael

//#include "my_stm32f4_uart_driver.h" // No NVIC_SetPriority, NVIC_EnableIRQ

#include <ctype.h>

#include "string.h"

#include "stm32f4xx.h" // I need to use this library for NVIC_SetPriority, NVIC_EnableIRQ

int main(void){

RCC->AHB1ENR |= 1; //Enable GPIOA clock

RCC->APB1ENR |= 0x20000; //Enable USART2 clock

GPIOA->MODER |= 0x0020 | 0x0080;

GPIOA->AFR[0] |= 0x0700 | 0x7000;

USART2->CR1  |= 0x0008 | 0x0004; //Enable Tx/Rx, 8-bit data

 USART2->BRR = 0x0683; //9600 baud @ 16 Mhz

 USART2->CR2 = 0x0000; //1 stop bit

 USART2->CR3 = 0x0000; //no flow control

 USART2->CR1 |= 0x0020; // RXEIE (Recieve Interrupt)?

//  USART2->CR1 |= 0x0080; // TXEIE (Transmit Interrupt)

 USART2->CR1 |= 0x2000;

 //ENABLE interrupt for USART2 on NVIC side

 NVIC_SetPriority(USART2_IRQn,0);

 NVIC_EnableIRQ(USART2_IRQn);

while(1){

// USART2_write(toupper(UART2_Read())); // This works!!!

    }

}

char UART2_Read(void){

while(!(USART2->SR & 0x0020)){}//Wait till character arrives (blocking code)

return USART2->DR;

}

void USART2_write(int ch){

while(!(USART2->SR & 0x0080)){} //Wait for transfer buffer to be empty

  USART2->DR = (ch&0xFF);

}

char temp; // global char variable.

// This does not work. It causes an error exception handle jumping to an infinite loop.

void USART2_IRQHandler(void) {

if (USART2->SR & 0x0020) //Wait till character arrives (blocking code)

temp = USART2->DR;

}

1 ACCEPTED SOLUTION

Accepted Solutions

0693W00000LvtgyQAB.pngAs TDK said above:

> If using C++, you need to ensure USART2_IRQHandler has C linkage by using extern C.

Or just don't use C++ .

JW

View solution in original post

7 REPLIES 7
TDK
Guru

When it's in the infinite loop, pause and examine VECTACTIVE field to see which interrupt it's in. If it's USART2_IRQn, then the linker doesn't see your function correctly. C++ or C? Verify vector table entry for that IRQ points to your function and not the default handler.

If you feel a post has answered your question, please click "Accept as Solution".
MLi.6
Associate II

Thank you for guiding me.

VECTACTIVE = 3 (Is it HardFault_Handler?).

I am using C++, STM32CubeIDE

Version: 1.9.0

Build: 12015_20220302_0855 (UTC)

0693W00000LvtOpQAJ.png

TDK
Guru

Yes, 3 indicates IRQn_Type of -13 which is a hard fault.

I don't think any of the code you've presented would cause a hard fault. But in any case, if it's repeatable, you can step through to see which line causes it. You can also examine the hard fault registers to find the offending instruction.

You can step through at the disassembly level to do individual instructions if necessary.

Looks like CSFR indicates a UNDEFINSTR flag.

If using C++, you need to ensure USART2_IRQHandler has C linkage by using extern C. Unlikely to be the issue here.

If you feel a post has answered your question, please click "Accept as Solution".
MLi.6
Associate II

It jumps to 54 or 0x36 (USART2_IRQHandler).

184-130 = 54 or 0x36 USART2 IRQ Handler

VECTACTIVE = 0x36

0693W00000LvtUEQAZ.pngUSART2->RXNE flag = 1,USART2->DR= ‘a’

0693W00000LvtUxQAJ.pngAfter this, it jumps to the infinite loop. USART2->DR = 'a' (always). It looks that it can't jump to my ISR subroutine for some reason.

MLi.6
Associate II

In my working HAL USART1 project, I searched for USART1_IRQHandler. . It seems USART1_IRQHandle is not defined. I thought that STM HAL library will somehow pass the HAL_UART_IRQHandle function address to USART1_IRQHandler. What is their trick? Why does it work within the HAL library?

// My main code.

void USART1_IRQHandler(void) {

HAL_UART_IRQHandler(&huart1);

}

Here I try to reverse engineer to see how it is done in the HAL library.

Best,

Michael

0693W00000LvtgyQAB.pngAs TDK said above:

> If using C++, you need to ensure USART2_IRQHandler has C linkage by using extern C.

Or just don't use C++ .

JW

MLi.6
Associate II

It finally works. Thank you to TDK and waclamwek. Now the program will stop at the breakpoint inside my ISR. I can get the letter 'a' character. I am creating classes for GPIO and UART in my bigger OOP firmware, so I must use C++ here. That is the reason for using C++.

extern "C" void USART2_IRQHandler(void);

I have also learned why extern C is so important to use in this case. In C++, the function is often overloaded with multiple parameters. C++ compiler will alter the function name to distinguish these overloaded function names according to the stackflow post.

Thus, the ISR function name linkage is broken in my usart2 example. The program cannot jump to my ISR routine because it cannot find the matched name. Extern C will solve the problem by preventing the function name to be changed by the C++ compiler. Now the linkage is preserved that the interrupt vector can call upon my ISR function.

https://stackoverflow.com/questions/1041866/what-is-the-effect-of-extern-c-in-c

I have learn a lot from both of you today. Thank you!

0693W00000Lvti6QAB.png