2025-04-12 11:55 PM
The UART2 IRQ Handler gets called consistently and never clears a few milliseconds after initialization.
If the debugger is not present on the RX line, the program always gets stuck in the IRQ Handler forever, until I touch the RX pin with my finger. Then the program begins executing normally.
On our STM32WL5MOCH-based board, the debug port (UART2) pins are left floating.
Here is the beginning of our main.c, which only uses default STM32CubeMX generated driver files, nothing custom. Please note the included project .ioc file in this post.
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC_Init();
MX_DAC_Init();
MX_LPUART1_UART_Init();
MX_USART1_UART_Init();
MX_USART2_UART_Init();
MX_TIM1_Init();
MX_RTC_Init();
MX_I2C2_Init();
MX_TIM16_Init();
Basically, the program only gets down to MX_TIM16_Init() before it gets stuck in this ISR forever. The program gets stuck every time. If we touch any other pins, the program remains stuck. The only pin which actually breaks the loop is the RX pin for USART2.
The default IRQ handler is defined in the stm32wlxx_hal_uart.c file:
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
uint32_t isrflags = READ_REG(huart->Instance->ISR);
uint32_t cr1its = READ_REG(huart->Instance->CR1);
uint32_t cr3its = READ_REG(huart->Instance->CR3);
uint32_t errorflags;
uint32_t errorcode;
...
At the break point, the variables usually evaluate as follows:
isrFlags = 0x6200F2
cr1its = 0x2D
cr3lits = 0x0
errorflags = 2
errorcode = <optimized out>
When we define our own HAL_UART_ErrorCallback(), the callback is never executed. Since cr3lits is zero, and cr1lits does not correspond with any defined flags, none of the flags are cleared and none of the error callbacks are ever executed. So the ISR sits there looping around and around forever. This has to be a HAL ISR bug - because there are no valid states upon which the program can clear anything and recover.
If I touch the RX pin with my finger, the system fixes itself and proceeds with program execution - almost as if the UART error registers finally read acceptable values. When attached to a serial converter TX and RX, it never gets stuck on startup. It also never gets stuck when pulled up with a 10k resistor to VDD. Setting the internal pullup for the RX pin does not fix the issue in the function call MX_GPIO_Init();
/*Configure GPIO pin : PIN_USART2_RX_Pin */
GPIO_InitStruct.Pin = GPIO_PIN_3; // Replace with the actual RX pin number
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP; // Add pull-up resistor to RX pin
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // Replace GPIOA with the correct port
Conclusion
1. If the hardware can generate a condition upon which the IRQ handler cannot break out of the loop, then it means the HAL IRQ should have an additional exception / clearing function.
2. Also, I have never had a microcontroller which couldn't tolerate an open debug uart port before. Didn't expect it to be so sensitive! (we've made plenty of designs with Atmel, Microchip, TI, ARM, AVR, PIC, MSP, and more).
Solved! Go to Solution.
2025-04-13 4:18 AM
Don't configure as an INPUT
Configure as a normal UART AF pins, with the PULL-UP setting. You need the associtivity with the UART. Or don't set the RE (RX Enable) on the UART.
You could also pull pin low, and check if an interface is connected or not.
2025-04-13 12:51 AM - edited 2025-04-13 12:52 AM
My opinion:
A) cmos inputs MUST always be driven - otherwise they are antennas receving any kind of EMI - the best is the device, the higher the input impedence and the sensistivity
B) use pullups/pulldown provided in MCU if you do nor plan any external connection
C) disable device untill driven.
2025-04-13 4:18 AM
Don't configure as an INPUT
Configure as a normal UART AF pins, with the PULL-UP setting. You need the associtivity with the UART. Or don't set the RE (RX Enable) on the UART.
You could also pull pin low, and check if an interface is connected or not.
2025-04-13 6:38 AM
The ISR value indicates NE (noise error) is set but since EIE=0 this shouldn't be triggering the IRQ handler.
If the above is true, it would indicate a silicon issue (IRQ triggering despite no relevant flags set), not a software one. I would want more evidence before believing that though. HAL isn't calling Error Handler because EIE isn't set, which is valid.
Since it happens right after TIM16, my guess is noise from a timer channel is causing other issues on the line besides NE. Probably FE.
As @Tesla DeLorean says, solution enable the pullup on the pin so the signal is valid when the line is not connected.
2025-04-13 1:51 PM
You are correct: configuring the RX pin as a pullup in the HAL_UART_MspInit() function generated by CubeMX consistently prevents the issue. We changed the GPIO pullup setting and regenerated the code using CubeMX rather than adding the line manually.
void HAL_UART_MspInit()
{
...
GPIO_InitStruct.Pin = PIN_DBG_RX_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
HAL_GPIO_Init(PIN_DBG_RX_GPIO_Port, &GPIO_InitStruct);
...
}
This works every time on every board we have tested so far.
2025-04-13 2:06 PM
I think you are correct - this likely has something to do with hardware and the pullup is the answer. I'd be curious to know why the UART ISR is always being called and the UART Error Handler is never called.
To replicate and observe this behavior, we attach the debugger but disconnect the RX line. We have tested this behavior on multiple PBCs, and they all freeze in the exact same way, unless the RX line is touched with a finger, pulled up or attached to a driving circuit. When we step through the ISR handler, it never clears anything because the register values are not expected. The program continually calls that ISR over and over again.
Thanks for your replies.