2021-12-06 6:35 AM
I'm using the NUCLEO-H753ZI dev board and have been testing various tx/rx reception modes using HAL routines with RTOS for all the available uarts. I have them all working well except lpuart1. When I try to receive or transmit in DMA mode I get no interrupts and no data out from the tx pin.
Am I missing something? Does this uart support DMA transfers? I see it uses BDMA instead of DMA, bot I'm not sure what the difference is.
This is the auto generated init code:
static void MX_LPUART1_UART_Init(void)
{
 
  /* USER CODE BEGIN LPUART1_Init 0 */
 
  /* USER CODE END LPUART1_Init 0 */
 
  /* USER CODE BEGIN LPUART1_Init 1 */
 
  /* USER CODE END LPUART1_Init 1 */
  hlpuart1.Instance = LPUART1;
  hlpuart1.Init.BaudRate = 115200;
  hlpuart1.Init.WordLength = UART_WORDLENGTH_8B;
  hlpuart1.Init.StopBits = UART_STOPBITS_1;
  hlpuart1.Init.Parity = UART_PARITY_NONE;
  hlpuart1.Init.Mode = UART_MODE_TX_RX;
  hlpuart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  hlpuart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  hlpuart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
  hlpuart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  hlpuart1.FifoMode = UART_FIFOMODE_DISABLE;
  if (HAL_UART_Init(&hlpuart1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetTxFifoThreshold(&hlpuart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetRxFifoThreshold(&hlpuart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_DisableFifoMode(&hlpuart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN LPUART1_Init 2 */
 
  /* USER CODE END LPUART1_Init 2 */
 
}
 
/**
  * Enable DMA controller clock
  */
static void MX_BDMA_Init(void)
{
 
  /* DMA controller clock enable */
  __HAL_RCC_BDMA_CLK_ENABLE();
 
  /* DMA interrupt init */
  /* BDMA_Channel0_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(BDMA_Channel0_IRQn, 5, 0);
  HAL_NVIC_EnableIRQ(BDMA_Channel0_IRQn);
  /* BDMA_Channel1_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(BDMA_Channel1_IRQn, 5, 0);
  HAL_NVIC_EnableIRQ(BDMA_Channel1_IRQn);
 
}2021-12-06 7:04 AM
UPDATE
When using lpuart1 in DMA mode I get continuous UART_DMAError() errors, tracking through the code it seems to be a transfer error:
hdma->ErrorCode = HAL_DMA_ERROR_TE;
2021-12-06 9:43 AM
I don't really see enough initialization here. CubeMX buries and obfuscates, so makes for bad examples.
Try using SRAM4 in the AHB4 / APB4 / D3 Domain for the memory buffering
2021-12-06 2:26 PM
Hi,
Thanks for your response.
I think you're probably correct in your answer and my DMA buffer should be in the SRAM4 ram. Unfortunately I have no idea how to place this in SRAM4 using CubeIDE.
Any thoughts?
2021-12-06 2:44 PM
Not my tools, but generally GNU/GCC would be via the linker script and __attribute__((section(".sram4"))) type construction
If it's not part of the memory visible to the linker, your could test with a simple pointer assignment.
uint8_t *Buffer4 = (uint8_t *)0x38000000; // 64KB at 0x38000000
2021-12-06 3:46 PM
Ok,
I found this article:
https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices
And now have the DMA working on lpuart1. I added the following to my linker script: STM32H753ZITX_FLASH.ld
  .dma_buffer :
  {
  	*(.dma_buffer)
  } >RAM_D3Then added this definition in my code:
#if defined( __ICCARM__ )
  #define DMA_BUFFER \
      _Pragma("location=\".dma_buffer\"")
#else
  #define DMA_BUFFER \
      __attribute__((section(".dma_buffer")))
#endifThen declared the DMA buffer as follows:
DMA_BUFFER uint8_t	dmaBuff[LPUART_RX_BUFFER];Thanks for pointing me in the right direction!
Now I have a new issue, any overrun error on the UART never seems to get cleared. Any idea what I need to do to clear an overrun? I can ask a new question in the forum but thought you might have an idea.
Cheers.
2021-12-06 4:18 PM
On the H7 series STM32 the Noise, Framing and Overrun have bit level clearing flags. These are for the L0, but think they are the same here
uint32_t isr = USART2->ISR;
if (isr & (USART_ISR_ORE | USART_ISR_NE | USART_ISR_FE))
{
if (isr & USART_ISR_ORE)
USART2->ICR = USART_ICR_ORECF;
if (isr & USART_ISR_NE)
USART2->ICR = USART_ICR_NCF;
if (isr & USART_ISR_FE)
USART2->ICR = USART_ICR_FECF;
}
On the RX DMA side, I tend to prefer a large enough circular buffer that to act as a HW FIFO that I can sweep/harvest periodically. Obviously on M7 watch for cache and write-thru coherency vs DMA
2021-12-07 1:31 AM
Hi,
Well it looks like the UART_ICR_OREF is cleared within the HAL ISR here:
    /* UART Over-Run interrupt occurred -----------------------------------------*/
    if (((isrflags & USART_ISR_ORE) != 0U)
        && (((cr1its & USART_CR1_RXNEIE_RXFNEIE) != 0U) ||
            ((cr3its & (USART_CR3_RXFTIE | USART_CR3_EIE)) != 0U)))
    {
      __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF);
 
      huart->ErrorCode |= HAL_UART_ERROR_ORE;
    }In my ErrorCallback routine I check the uart->ErrorCode and can see it was an ORE, however, the only way I can get things working again is to disable and re-enable the uart.. as below
void HAL_UART_ErrorCallback(UART_HandleTypeDef* huart)
{
	switch(huart->ErrorCode)
	{
	case HAL_UART_ERROR_NONE:
		asm("NOP");
		break;
	case HAL_UART_ERROR_PE:
		asm("NOP");
		break;
	case HAL_UART_ERROR_NE:
		asm("NOP");
		break;
	case HAL_UART_ERROR_FE:
		asm("NOP");
		break;
	case HAL_UART_ERROR_ORE:
		__HAL_UART_DISABLE(&SPEKTRUM_UART);;
		asm("NOP");
		__HAL_UART_ENABLE(&SPEKTRUM_UART);
		break;
	case HAL_UART_ERROR_DMA:
		asm("NOP");
		break;
	case HAL_UART_ERROR_RTO:
		asm("NOP");
		break;
	}
   
  // restart DMA receive..
}I'm completely new to the STM32 processor, so this is a steep learning curve! The DMA circular buffer is exactly what I'm trying to implement although currently using a linear buffer and re-starting DMA reception on completion/timeout. Then I periodically empty the buffer parsing data in my thread.
