STM32H7 DMA receive only works if program started with debugger
Hello,
I am running into an issue where I can only receive on UART5 of an STM32H7A3LI if I have been debugging since a power cycle. The code runs normally otherwise after a power cycle, but UART5 cannot receive unless it is debugging.
- Using a JLink Pro, VSCode, arm-none-eabi-gdb-py, STM32H7A3LI on a custom PCB
- I have confirmed data is sent and received regardless of debug state using a logic analzyer, the problem is definitely on the MCU
- I have tried attaching the debugger to an existing session using SEGGER's ozone, the DMA counter gets incremented on the first byte received but the data is just a 0, it is not the actual byte received
- This does not happen on other UARTs or USARTs, I am able to receive normally from other devices connected to other UARTs regardless of whether or not I am debugging
- The Instruction and Data caching has been disabled for the send buffer. It was not needed for any other RX buffer, only the TX buffers had issues with caching. I did try receiving on an RX buffer with caching disabled but this did not fix the problem.
- DMA is initialized before any peripherals. I also changed the order of UART inits, this had no affect as long as DMA was initialized first.
- When not using DMA, and receive stops working regardless of whether or not I am debugging
- The same problem happens on other DMA streams, but not other UARTs
- I am using FreeRTOS
Init code:
static void MX_UART5_Init(void)
{
/* USER CODE BEGIN UART5_Init 0 */
/* USER CODE END UART5_Init 0 */
/* USER CODE BEGIN UART5_Init 1 */
/* USER CODE END UART5_Init 1 */
huart5.Instance = UART5;
huart5.Init.BaudRate = 38400;
huart5.Init.WordLength = UART_WORDLENGTH_8B;
huart5.Init.StopBits = UART_STOPBITS_1;
huart5.Init.Parity = UART_PARITY_NONE;
huart5.Init.Mode = UART_MODE_TX_RX;
huart5.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart5.Init.OverSampling = UART_OVERSAMPLING_16;
huart5.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart5.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart5.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart5) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&huart5, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&huart5, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&huart5) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN UART5_Init 2 */
/* USER CODE END UART5_Init 2 */
}
stm32h7xx_hal_msp.c
else if(huart->Instance==UART5)
{
/* USER CODE BEGIN UART5_MspInit 0 */
/* USER CODE END UART5_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_UART5;
PeriphClkInitStruct.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_D2PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* Peripheral clock enable */
__HAL_RCC_UART5_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/**UART5 GPIO Configuration
PD2 ------> UART5_RX
PC12 ------> UART5_TX
*/
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF8_UART5;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF8_UART5;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* UART5 DMA Init */
/* UART5_RX Init */
hdma_uart5_rx.Instance = DMA1_Stream2;
hdma_uart5_rx.Init.Request = DMA_REQUEST_UART5_RX;
hdma_uart5_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_uart5_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_uart5_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_uart5_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_uart5_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_uart5_rx.Init.Mode = DMA_CIRCULAR;
hdma_uart5_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_uart5_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_uart5_rx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(huart,hdmarx,hdma_uart5_rx);
/* UART5_TX Init */
hdma_uart5_tx.Instance = DMA1_Stream3;
hdma_uart5_tx.Init.Request = DMA_REQUEST_UART5_TX;
hdma_uart5_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_uart5_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_uart5_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_uart5_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_uart5_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_uart5_tx.Init.Mode = DMA_NORMAL;
hdma_uart5_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_uart5_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_uart5_tx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(huart,hdmatx,hdma_uart5_tx);
/* USER CODE BEGIN UART5_MspInit 1 */
/* USER CODE END UART5_MspInit 1 */
}
I use the __HAL_DMA_GET_COUNTER(huart5->hdmarx) macro to check the position of the DMA data pointer, if the counter does not match the previous position, I copy the data into the receive buffer. The code works on several other UARTs for this project and other projects using different MCUs, regardless of whether or not it is being debugged.
Any help would be greatly appreciated, I have been struggling with this for weeks. Please let me know if I am missing any useful information. Thank you!
