2017-11-28 04:07 AM
MCU: STM32F777II
I am facing a very strange problem with receiving data from a UART where the data reception stops after few minutes like after >10 minutes, where initially it works pretty fine.The RX channel of the UART is configured in DMA mode and the DMA priority for this stream is kept at higher priority as compared to other DMA priorities in the system.
The setting for the UART are:
/* UART7 init function */
void MX_UART7_Init(void) {huart7.Instance = UART7;
huart7.Init.BaudRate = 9600; huart7.Init.WordLength = UART_WORDLENGTH_8B; huart7.Init.StopBits = UART_STOPBITS_1; huart7.Init.Parity = UART_PARITY_NONE; huart7.Init.Mode = UART_MODE_TX_RX; huart7.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart7.Init.OverSampling = UART_OVERSAMPLING_16; huart7.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_ENABLE; huart7.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(&huart7) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); }}
and for the DMA stream:
else if(uartHandle->Instance==UART7)
{ /* USER CODE BEGIN UART7_MspInit 0 *//* USER CODE END UART7_MspInit 0 */
/* UART7 clock enable */ __HAL_RCC_UART7_CLK_ENABLE(); /**UART7 GPIO Configuration PF6 ------> UART7_RX PF7 ------> UART7_TX */ GPIO_InitStruct.Pin = UART7_RX_DOWNSTREAM_Pin|UART7_TX_DOWNSTREAM_Pin; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF8_UART7; HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);/* UART7 DMA Init */
/* UART7_RX Init */ hdma_uart7_rx.Instance = DMA1_Stream3; hdma_uart7_rx.Init.Channel = DMA_CHANNEL_5; hdma_uart7_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_uart7_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_uart7_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_uart7_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_uart7_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;hdma_uart7_rx.Init.Mode = DMA_CIRCULAR;
hdma_uart7_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
hdma_uart7_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; if (HAL_DMA_Init(&hdma_uart7_rx) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); }__HAL_LINKDMA(uartHandle,hdmarx,hdma_uart7_rx);
/* UART7_TX Init */
hdma_uart7_tx.Instance = DMA1_Stream1; hdma_uart7_tx.Init.Channel = DMA_CHANNEL_5; hdma_uart7_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_uart7_tx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_uart7_tx.Init.MemInc = DMA_MINC_ENABLE; hdma_uart7_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_uart7_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_uart7_tx.Init.Mode = DMA_NORMAL; hdma_uart7_tx.Init.Priority = DMA_PRIORITY_LOW; hdma_uart7_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; if (HAL_DMA_Init(&hdma_uart7_tx) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); }__HAL_LINKDMA(uartHandle,hdmatx,hdma_uart7_tx);
/* UART7 interrupt Init */
HAL_NVIC_SetPriority(UART7_IRQn, 5, 0); HAL_NVIC_EnableIRQ(UART7_IRQn); /* USER CODE BEGIN UART7_MspInit 1 *//* USER CODE END UART7_MspInit 1 */
}I have programmed HAL_UART_RxCpltCallback() as:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef* huart)
{ if (huart->Instance == UART7) {// FROM CONFIG APP: Save the command so the worker thread can pick it up
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_14); xQueueSendToBackFromISR(btQueue, huart->pRxBuffPtr, NULL); __HAL_UART_CLEAR_OREFLAG(huart); __HAL_UART_CLEAR_NEFLAG(huart); __HAL_UART_CLEAR_FEFLAG(huart); __HAL_UART_CLEAR_PEFLAG(huart); __HAL_UART_CLEAR_IDLEFLAG(huart); } }And in my main code, I fire up the the DMA for every 1 byte of reception:
uint8_t dmaRXBuffer[1];
HAL_UART_Receive_DMA(&UART_DOWN_USB_TO_SERIAL, dmaRXBuffer, 1);where I tested with and without adding those error flag clear code segments, but it didn't had any effect. As you can see in the above code, I also tried adding a LED toggle code just to check whether the code flow is reaching that are when the UART receives something, and yes for the first few minutes, it works fine as expected but stops after sometime.
Note: Since I am working on FreeRTOS, I ensured that even with other tasks running, there is enough time for the CPU to process anything else, so it is nothing like the CPU is fully loaded or blocked in some task. I verified this using Percepio Tracealyzer.
I am also attaching the UART RX signals captured on my Tektronix 200MHz DSO just for reference:
#stm32-f7 #uart-dma Note: this post was migrated and contained many threaded conversations, some content may be missing.2017-11-28 05:30 AM
Check if the overflow or framing errors, etc are flagging at the time of failure, probably would be visiting callback in those situations.
Hope it is just the scaling on the scope, but the signals look awful.
2017-11-28 06:52 AM
How can I program the mcu not to abort DMA RX on any errors? Is there a way around?
2017-11-28 07:01 AM
Perhaps you can IRQ on the error statuses?
2017-11-28 07:54 AM
How about re-firing the DMA RX on HAL_UART_ErrorCallback() ?, So that I continue to receive even on some random framing errors, etc
void HAL_UART_ErrorCallback(UART_HandleTypeDef* huart)
{ if (huart->Instance == UART7) { /* Restart DMA RX even if we encountered framing error, etc */ HAL_UART_Receive_DMA(&UART_DOWN_USB_TO_SERIAL, huart->pRxBuffPtr, 1); }}2017-11-28 08:29 AM
Not really looking to debug HAL implementations.
Is there some value to using DMA here that can't be solved with exactly the same number of interrupts, and less complexity? The point of using DMA would surely be to provide a deep enough buffering to avoid service latency and overruns?
2017-11-28 09:00 AM
Yes, I am using DMA here to cache the incoming data until the consumer task gets its chance to consume it!
2017-11-28 10:25 AM
As applied this provides zero advantage over USART IRQ, and add significant complexity, perhaps abstracted from view, but still adding burden that brings no benefit.
In these cases I use DMA to provide the buffering and reduce loading.
2017-11-28 11:58 AM
Can u please explain in detail, I didn't get you?