2022-03-27 08:59 AM
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;
}
Solved! Go to Solution.
2022-03-27 01:30 PM
As 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
2022-03-27 09:20 AM
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.
2022-03-27 11:24 AM
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)
2022-03-27 11:41 AM
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.
2022-03-27 12:00 PM
It jumps to 54 or 0x36 (USART2_IRQHandler).
184-130 = 54 or 0x36 USART2 IRQ Handler
VECTACTIVE = 0x36
USART2->RXNE flag = 1,USART2->DR= ‘a’
After 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.
2022-03-27 12:16 PM
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
2022-03-27 01:30 PM
As 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
2022-03-27 01:50 PM
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!