Skip to main content
MStei.4
Associate II
February 3, 2022
Question

HAL DMA USART RX Character > Buffer Size Problem

  • February 3, 2022
  • 2 replies
  • 1328 views

Sure it's a small thing but I just can't get on with the UART RX via DMA. I want to use the HAL in my project and execute the following.

Precondition:

- UART2 initialized

- DMA GPDMA1 Channel 3 Mode: normal

- RX Buffer 5Bytes

- character match Interrupt is configured to "\n"

- GPDMA1_Channel3_IRQHandler reports _HAL_DMA_GET_FLAG(&handle_GPDMA1_Channel3, DMA_FLAG_IDLE ) to application to clear RX buffer

Sequence:

1. HAL_UART_Receive_DMA() waits for RX

2. RX (ASCII) 6Bytes!: "abcdef" , in RX buffer is "abcde"

3. GPDMA1_Channel3_IRQHandler is called and deletes immediately the DMA_FLAG_IDLE

4. HAL_UART_RxCpltCallback() is called and sett HAL_UART_DMAStop() für UART2 Handle

5. delete RX buffer (\0)

6. HAL_UART_Receive_DMA() and wait for next RX

7. RX (ASCII): " 1\n", in RX buffer is: "f1\n"

Why is the byte from the last RX now the first one in the RX buffer at 7. Expected is only "1\n" . It is as if the DMA index was not yet reset to 0. I have already tried to influence this with the functions, but unfortunately without success. 

__HAL_DMA_SET_COUNTER(&handle_GPDMA1_Channel3, 0);

HAL_UART_AbortReceive(&handle);

Here is my DMA configuration:

/** Initializes the peripherals clock
 */
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2;
PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_HSI;
 if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
 {
 printf("HAL_RCCEx_PeriphCLKConfig"); ///< todo Error_Handler(), message sent to debug uart
 }
 
 /* Peripheral clock enable */
 __HAL_RCC_USART2_CLK_ENABLE();
 __HAL_RCC_GPIOD_CLK_ENABLE();
 
 /**USART2 GPIO Configuration from BSP_GPIO.h */
 GPIO_InitStruct.Pin = USART2_DE_PIN|USART2_TX_PIN|USART2_RX_PIN;
 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
 GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
 HAL_GPIO_Init(USART2_GPIO_PORT, &GPIO_InitStruct);
 
 /* USART2 DMA Init */
 /* GPDMA1_REQUEST_USART2_RX Init */
 handle_GPDMA1_Channel3.Instance = GPDMA1_Channel3;
 handle_GPDMA1_Channel3.Init.Request = GPDMA1_REQUEST_USART2_RX;
 handle_GPDMA1_Channel3.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
 handle_GPDMA1_Channel3.Init.Direction = DMA_PERIPH_TO_MEMORY;
 handle_GPDMA1_Channel3.Init.SrcInc = DMA_SINC_FIXED;
 handle_GPDMA1_Channel3.Init.DestInc = DMA_DINC_INCREMENTED;
 handle_GPDMA1_Channel3.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
 handle_GPDMA1_Channel3.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
 handle_GPDMA1_Channel3.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
 handle_GPDMA1_Channel3.Init.SrcBurstLength = 1;
 handle_GPDMA1_Channel3.Init.DestBurstLength = 1;
 handle_GPDMA1_Channel3.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT1;
 handle_GPDMA1_Channel3.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
 handle_GPDMA1_Channel3.Init.Mode = DMA_NORMAL;
 if (HAL_DMA_Init(&handle_GPDMA1_Channel3) != HAL_OK)
 {
 printf("HAL_DMA_Init"); ///< todo Error_Handler(), message sent to debug uart
 }

This topic has been closed for replies.

2 replies

LCE
Principal II
February 3, 2022

The UART RX input register (Receive data register (USART_RDR)?) is not the DMA buffer, so when you tell the DMA to complete after 5 bytes, but you send 6, the 6th byte will still be in the Receive data register (USART_RDR), and then be shifted into the DMA buffer when DMA is enabled again.

5 bytes are not that many... anyway, you need some RX buffer overflow handling.

MStei.4
MStei.4Author
Associate II
February 4, 2022

5 Bytes buffer size I just chose to easier test the overflow. In the USART_RDR I can see the last byte that is received, but how can that help me with the overflow handling?

If RX = "abcdefg" as in sequence above, the next RX puts two characters "fg" in the buffer before adding the new received:

[ 0 ] 'f'
[ 1 ] 'g'
[ 2 ] '\1' -> position of second RX
[ 3 ] '\n'
[ 4 ] '\0'

(first RX: abcdefg, second RX: 1\n)

For my scenario I would like to skip such frames that are too long. How can I reset this buffer position or is there a good example/description about that?