I try to implement UART DMA reception in circular buffer with reception with idle in STM32F429 Discovery with MCU Package for STM32F4 in Rev 1.27.0 . IDLE event is not called when number of recived char rise DMA_TC.
What i expect is that my interrupt callback (HAL_UARTEx_RxEventCallback) will be called with those event :
DMA_Half_Transfert Complete -> OK
DMA_Transfert_Complete -> OK
IDLE_Event -> OK
All interrupt work individually but...
1) Receive buffer is empty
I send a number of char equal to the half buffer size
Call back is called a first time for half transfert complete with Size parameter = half buffer size
Call back is called a second time with the same Size parameter
first time it is called with DMA HT complete then it is called a second time with the idle event, this is PERFECT for me
2) Receive buffer is empty
I send a number of char equal to the buffer size
CallBack is called with half transfert complete with size = half buffer size -> Ok for me
CallBack is called with Dma transfert complete with Size = buffer size -> OK for me
But what i expect is that idle is called after that as we will not detect idle line in this case
The root of this behavior is in : stm32f4xx_hal_uart.c
line 2487 to 2505 :
/* Check current reception Mode :
If Reception till IDLE event has been selected : */
if ((huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
&& ((isrflags & USART_SR_IDLE) != 0U)
&& ((cr1its & USART_SR_IDLE) != 0U))
{
__HAL_UART_CLEAR_IDLEFLAG(huart);
/* Check if DMA mode is enabled in UART */
if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
{
/* DMA mode enabled */
/* Check received length : If all expected data are received, do nothing,
(DMA cplt callback will be called).
Otherwise, if at least one data has already been received, IDLE event is to be notified to user */
uint16_t nb_remaining_rx_data = (uint16_t) __HAL_DMA_GET_COUNTER(huart->hdmarx);
if ((nb_remaining_rx_data > 0U)
&& (nb_remaining_rx_data < huart->RxXferSize))
{The test on nb_remainning_data forbid the call of the callback.
i capture the different event for a 8 byte circular buffer :
example based on 1)
debug_size[0] struct debug_size_trace {...}
num_event uint8_t 0 '\0'
debug_size unsigned int 4
debug_size[1] struct debug_size_trace {...}
num_event uint8_t 1 '\001'
debug_size unsigned int 4
debug_size[2] struct debug_size_trace {...}
num_event uint8_t 0 '\0'
debug_size unsigned int 0
debug_size[3] struct debug_size_trace {...}
num_event uint8_t 0 '\0'
debug_size unsigned int 0 example based on 2
debug_size[0] struct debug_size_trace {...}
num_event uint8_t 0 '\0'
debug_size unsigned int 4
debug_size[1] struct debug_size_trace {...}
num_event uint8_t 1 '\001'
debug_size unsigned int 8
debug_size[2] struct debug_size_trace {...}
num_event uint8_t 0 '\0'
debug_size unsigned int 0
debug_size[3] struct debug_size_trace {...}
num_event uint8_t 0 '\0'
debug_size unsigned int 0 No IDLE event detected !!
if i modify test condition in line 2504 (i hate modifying HAL :( )
&& (nb_remaining_rx_data <= huart->RxXferSize))i have replaced < by <=
i got :
debug_size[0] struct debug_size_trace {...}
num_event uint8_t 0 '\0'
debug_size unsigned int 4
debug_size[1] struct debug_size_trace {...}
num_event uint8_t 1 '\001'
debug_size unsigned int 8
debug_size[2] struct debug_size_trace {...}
num_event uint8_t 2 '\002'
debug_size unsigned int 0
debug_size[3] struct debug_size_trace {...}
num_event uint8_t 0 '\0'
debug_size unsigned int 0 Event number 2 is called with a Size 0 and is the idle event.
and if i send 16 char (so i got a dual full circular buffer done) :
debug_size[0] struct debug_size_trace {...}
num_event uint8_t 0 '\0'
debug_size unsigned int 4
debug_size[1] struct debug_size_trace {...}
num_event uint8_t 1 '\001'
debug_size unsigned int 8
debug_size[2] struct debug_size_trace {...}
num_event uint8_t 2 '\002'
debug_size unsigned int 4
debug_size[3] struct debug_size_trace {...}
num_event uint8_t 3 '\003'
debug_size unsigned int 8
debug_size[4] struct debug_size_trace {...}
num_event uint8_t 4 '\004'
debug_size unsigned int 0
debug_size[5] struct debug_size_trace {...}
num_event uint8_t 0 '\0'
debug_size unsigned int 0 Is there a better way to implement IDLE detection when DMA_TC complete is rise by the last char received ?
