cancel
Showing results for 
Search instead for 
Did you mean: 

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.

christian B.
Associate II

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 ?

5 REPLIES 5

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

christian B.
Associate II

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

Maybe i forgot to say that i need to detect IDLE time...

what if i want to detect when char stream stop sending char ?

GLASS
Senior

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).

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