2025-11-08 2:25 AM
Hello everyone,
I'm working on a custom board with an STM32H563 and using CubeMX, HAL, and ThreadX.
I am trying to receive variable-length UART data via DMA using HAL_UARTEx_ReceiveToIdle_DMA(). My problem is that the HAL_UARTEx_RxEventCallback never triggers for the HAL_UART_RXEVENT_IDLE event. It only triggers for HAL_UART_RXEVENT_HT (Half Transfer) and HAL_UART_RXEVENT_TC (Transfer Complete).
Setup
Here is the .ioc
Here is the RX line on the scope:
Problem
Expected Behavior: Given the long idle time, I expect HAL_UARTEx_RxEventCallback to be called with an event type of HAL_UART_RXEVENT_IDLE after each packet.
Actual Behavior: The IDLE event never fires. I only get Half Transfer and Transfer Complete events (so when the buffer is half full or full).
Here is my RxEventCallback handler:
// This is the callback I EXPECT to fire for IDLE
void Radar_Handler_HandleRxEvent(UART_HandleTypeDef *huart, uint16_t Size)
{
if (huart->Instance == _radar1_handle.huart_data->Instance)
{
switch (HAL_UARTEx_GetRxEventType(huart))
{
case HAL_UART_RXEVENT_TC:
io_handler_send_usb_message("Transmission completed\n");
break;
case HAL_UART_RXEVENT_IDLE:
// THIS CASE NEVER EXECUTES
io_handler_send_usb_message("Transmission idle\n");
break;
case HAL_UART_RXEVENT_HT:
io_handler_send_usb_message("Transmission half complete\n");
break;
default:
io_handler_send_usb_message("Unknown UART RX event\n");
break;
}
snprintf(msg, sizeof(msg), "%u bytes\r\n", Size);
io_handler_send_usb_message(msg);
}
}This produces the following debug output, showing only HT and TC events:
Transmission half complete
500 bytes
Transmission completed
1000 bytes
Transmission half complete
500 bytes
Transmission completed
1000 bytes
...Initialization
Here is how I initialize the DMA.
HAL_StatusTypeDef Radar_Handler_Init(UART_HandleTypeDef *huart_control,
UART_HandleTypeDef *huart_data,
GPIO_TypeDef *nreset_port,
uint16_t nreset_pin)
{
// ... (internal init)
// Start the DMA reception
HAL_UARTEx_ReceiveToIdle_DMA(_radar1_handle.huart_data,
_radar1_handle.data_rx_buffer,
sizeof(_radar1_handle.data_rx_buffer));
// This is a workaround but it is commented out.
// Calling it causes the "Weird Behavior" described below.
// UART_CheckIdleState(_radar1_handle.huart_data);
// ... (semaphore create)
return status;
}Callbacks in main.c:
/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
Radar_Handler_HandleRxInterrupt(huart);
}
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
Radar_Handler_HandleRxEvent(huart, Size);
}
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
uint32_t error = huart->ErrorCode;
io_handler_send_usb_message("UART1 error occurred\n");
if (error & HAL_UART_ERROR_ORE)
__HAL_UART_CLEAR_OREFLAG(huart);
}
/* USER CODE END 4 */Weird behavior
This is the part that makes me suspect a HAL or config bug.
If I uncomment the line UART_CheckIdleState(_radar1_handle.huart_data); in my Init function, the entire interrupt behavior changes:
HAL_UARTEx_RxEventCallback() stops triggering entirely.
The HAL_UART_RxCpltCallback() starts triggering instead.
Inside the handler for HAL_UART_RxCpltCallback, I added a test function to manually check the IDLE flag.
Test function called by HAL_UART_RxCpltCallback:
void Radar_Handler_HandleRxInterrupt(UART_HandleTypeDef *huart)
{
if (huart->Instance == _radar1_handle.huart_data->Instance)
{
// Manually check the IDLE flag
if (__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE))
{
io_handler_send_usb_message("IDLE Interruption (from RxCplt)\n");
}
}
}This produces the following output. It seems the IDLE flag is being set, but only the interruption callback fires, not the rx event one, and it appears to fire only when the buffer is full (at TC).
IDLE Interruption (from RxCplt)
IDLE Interruption (from RxCplt)
...Simply calling UART_CheckIdleState() (which I assume is a read-only check) should not change which callback (RxEvent vs. RxCplt) is active. This seems to indicate a state problem.
What I have tried
I appreciate any tip or advice, I don't think the problem is with my custom board as everything else, I2S, USB, HSE, works without a problem.