2025-06-04 5:42 AM - edited 2025-06-04 7:22 AM
Hi all! What event is generated if the MCU receives a data packet equal to the buffer value passed to the HAL_UARTEx_ReceiveToIdle_IT (or HAL_UARTEx_ReceiveToIdle_DMA) function? There will essentially be two events: HAL_UART_RXEVENT_TC and HAL_UART_RXEVENT_IDLE . But which of them will be available in the HAL_UARTEx_RxEventCallback ?
2025-06-06 12:02 AM
Hi! Thanks for the advice! I got distracted by other tasks)) I need to test this behavior, I'll get to it in the next couple of days and be sure to let you know the results.
2025-06-06 12:08 AM - edited 2025-06-06 12:10 AM
Hi! I'm doing something similar in my handler
void Drivers::Stm32UartEx::handlerRxEvent(UART_HandleTypeDef* huart, uint16_t size)
{
uint32_t rxEvent = HAL_UARTEx_GetRxEventType(huart);
if (rxEvent == HAL_UART_RXEVENT_IDLE || rxEvent == HAL_UART_RXEVENT_TC) {
mRxBufCount = size;
if (mUseDmaRx) {
HAL_UARTEx_ReceiveToIdle_DMA(&mrHuart, mpRxBuf, mRxBufLen);
} else if (mUseIt) {
HAL_UARTEx_ReceiveToIdle_IT(&mrHuart, mpRxBuf, mRxBufLen);
}
}
}
As I already wrote above in my reply to user TDK, I will look into this in the next couple of days and will definitely post the result!
2025-06-06 5:58 AM
This person said it works this way (No IDLE event in circular mode if buffer is exactly full) on the L1 series.
STM32L152 UART code missing in driver - STMicroelectronics Community
2025-06-06 7:12 AM
I tested this on the F4. It works exactly as expected. No IDLE events are missed.
Sending 4 bytes at a time into a 16 byte buffer. event: (0=HT, 1=TC, 2=IDLE).
event=2, tail=0, head=4
event=1, tail=4, head=8
event=2, tail=8, head=8
event=2, tail=8, head=12
event=0, tail=12, head=16
event=2, tail=16, head=16
event=2, tail=16, head=4
event=1, tail=4, head=8
event=2, tail=8, head=8
event=2, tail=8, head=12
event=0, tail=12, head=16
event=2, tail=16, head=16
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
static uint16_t tail = 0;
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
UNUSED(Size);
HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
HAL_UART_RxEventTypeTypeDef event = HAL_UARTEx_GetRxEventType(huart);
printf("event=%d, tail=%d, head=%d\n", (int)event, (int)tail, (int)Size);
tail = Size;
}
2025-06-06 8:45 AM
@TDK wrote:I tested this on the F4. It works exactly as expected. No IDLE events are missed.
Sending 4 bytes at a time into a 16 byte buffer. event: (0=HT, 1=TC, 2=IDLE).
event=2, tail=0, head=4
event=1, tail=4, head=8
event=2, tail=8, head=8
event=2, tail=8, head=12
event=0, tail=12, head=16
event=2, tail=16, head=16
event=2, tail=16, head=4
event=1, tail=4, head=8
event=2, tail=8, head=8
event=2, tail=8, head=12
event=0, tail=12, head=16
event=2, tail=16, head=16
I noticed your event values didn't match your labeling based off receiving 4 bytes at a time.
You have TC and HT values swapped.
/**
* @brief HAL UART Rx Event type definition
* @note HAL UART Rx Event type value aims to identify which type of Event has occurred
* leading to call of the RxEvent callback.
* This parameter can be a value of @ref UART_RxEvent_Type_Values :
* HAL_UART_RXEVENT_TC = 0x00U,
* HAL_UART_RXEVENT_HT = 0x01U,
* HAL_UART_RXEVENT_IDLE = 0x02U,
*/
typedef uint32_t HAL_UART_RxEventTypeTypeDef;
1
2025-06-06 9:38 AM
Yes, my typo, not HAL's bug. Thanks for catching.
2025-06-10 1:02 AM
Hi, everybody! Sorry for the delay!
Here I tested my driver with different combinations of receive buffer size and received data packet size.
Test program:
#define UART_BUF_LEN (30)
void app_main(void)
{
Drivers::Stm32UartEx& uart1 = Drivers::Stm32UartEx::getInstance(Drivers::Stm32UartEx::Port::UART1);
Drivers::Stm32UartEx::uartConfig_t config = {
.useIt = true,
.useDmaRx = true,
.useDmaTx = true
};
uart1.init(config);
char rxBuf[UART_BUF_LEN];
uart1.setRxBuffer((uint8_t *)rxBuf, UART_BUF_LEN);
uart1.receiveNB(); // Start receiving in non-blocking mode (IT or DMA)
while(true)
{ }
}
Event handler (here I have deliberately separated the processing of the two events):
void Drivers::Stm32UartEx::handleRxEvent(UART_HandleTypeDef* huart, uint16_t size)
{
uint32_t rxEvent = HAL_UARTEx_GetRxEventType(huart);
if (rxEvent == HAL_UART_RXEVENT_TC) {
mRxBufCount = size;
if (mUseDmaRx) {
HAL_UARTEx_ReceiveToIdle_DMA(&mrHuart, mpRxBuf, mRxBufLen);
} else if (mUseIt) {
HAL_UARTEx_ReceiveToIdle_IT(&mrHuart, mpRxBuf, mRxBufLen);
}
printf("TC event! mRxBufCount = %u\r\n", mRxBufCount);
}
if (rxEvent == HAL_UART_RXEVENT_IDLE) {
mRxBufCount = size;
if (mUseDmaRx) {
HAL_UARTEx_ReceiveToIdle_DMA(&mrHuart, mpRxBuf, mRxBufLen);
} else if (mUseIt) {
HAL_UARTEx_ReceiveToIdle_IT(&mrHuart, mpRxBuf, mRxBufLen);
}
printf("IDLE event! mRxBufCount = %u\r\n", mRxBufCount);
}
}
Result when the receive buffer size matches the received packet size:
TC event! mRxBufCount = 30
TC event! mRxBufCount = 30
TC event! mRxBufCount = 30
TC event! mRxBufCount = 30
Result when the buffer size is larger than the received packet size (UART_BUF_LEN (31) :(
IDLE event! mRxBufCount = 30
IDLE event! mRxBufCount = 30
IDLE event! mRxBufCount = 30
IDLE event! mRxBufCount = 30
Hence, we can conclude that the event that occurs first and is passed to the event handler. In this example, if we actually have two events (TC and IDLE), but the TC event occurred a little earlier, then we will see it in the handler. I mean the case when the size of the receiving buffer is equal to the size of the received packet.
In other cases IDLE event occurs.
Thus detecting the end of receiving a packet lies on the main program, not on the UART driver