cancel
Showing results for 
Search instead for 
Did you mean: 

HAL DMA USART RX Character > Buffer Size Problem

MStei.4
Associate III

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
  }

2 REPLIES 2
LCE
Principal

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
Associate III

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?