2022-06-23 03:29 AM
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 ?
2022-06-23 03:55 AM
UART Idle interrupt is not bound to DMA naturally, it's the matter of library you are using. If it does not suit your purpose, simply don't use it.
JW
2022-06-23 03:55 AM
I forgot to join my RX_Event_Callback for capturing trace :
struct debug_size_trace{
uint8_t num_event;
unsigned int debug_size;
};
#define DEBUG_TRACE_SIZE 16
struct debug_size_trace debug_size[DEBUG_TRACE_SIZE] = {0};
uint8_t Rx_Event = 0;
void RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){
debug_size[Rx_Event % DEBUG_TRACE_SIZE].num_event = Rx_Event;
debug_size[Rx_Event % DEBUG_TRACE_SIZE].debug_size = Size;
Rx_Event++;
....
What i do with received data is not important
2022-06-23 04:05 AM
Maybe i forgot to say that i need to detect IDLE time...
what if i want to detect when char stream stop sending char ?
2022-06-23 07:16 AM
Hello,
I'm totally agree with @christian B. .
When we use HAL_UARTEx_ReceiveToIdle_DMA(), we expect that each time an idle occur in UART side, the HAL must always trigger the callback.
The proposed HAL correction allow to be signaled each time the IDLE is triggered by UART(no more filtered for the particular case when nb_remaining_rx_data == huart->RxXferSize).
So the application can manage particular condition on "IDLE" (when "size" returned value == 0).
2022-06-23 07:28 AM
I repeat, IDLE interrupt is by no means bound to DMA. So just don't use the Cube/HAL "combo" function, and handle it independently.
Cube/HAL, as any other "library", inevitably implements a miniscule subset of what the hardware allows and includes only functionality which is deemed "typical" by the "library"'s authors. It may not fit your particular purpose.
I understand that others may benefit from your proposal being implemented, but I recommend you not holding your breath.
JW