2022-02-03 01:41 AM
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
}
2022-02-03 04:14 AM
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.
2022-02-04 03:02 AM
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?