cancel
Showing results for 
Search instead for 
Did you mean: 

bug in HAL_UART_Transmit_DMA

MScha.8
Associate II

I wrote an application configuring the USART for DMA transmission. The first call to HAL_UART_Transmit_DMA works correctly and the expected bytes are sent. However, every subsequent call fails with HAL_UART_STATE_BUSY.

It appears that the uart state is not set back to ready when the DMA transmission ends. I added a line in UART_DMATransmitCplt to set the state back to ready (below) and this appears to fix the problem but I wondered if there is a better solution than modifying the provided HAL code.

FWIW, UART_DMAReceiveCplt does set the state back to ready in the non-circular case. It seems like Transmit should do the same.

static void UART_DMATransmitCplt(DMA_HandleTypeDef *hdma)
{
  UART_HandleTypeDef *huart = (UART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
  /* DMA Normal mode*/
  if ((hdma->Instance->CR & DMA_SxCR_CIRC) == 0U)
  {
    huart->TxXferCount = 0x00U;
 
    /* Disable the DMA transfer for transmit request by setting the DMAT bit
       in the UART CR3 register */
    ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT);
 
    /* Enable the UART Transmit Complete Interrupt */
    ATOMIC_SET_BIT(huart->Instance->CR1, USART_CR1_TCIE);
 
    // TODO bug, transmission ends but UART remains in busy state preventing further transmissions
    huart->gState = HAL_UART_STATE_READY;
  }
  /* DMA Circular mode */
  else
  {
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
    /*Call registered Tx complete callback*/
    huart->TxCpltCallback(huart);
#else
    /*Call legacy weak Tx complete callback*/
    HAL_UART_TxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
  }
}

4 REPLIES 4
Pavel A.
Evangelist III

In line 14 it enables UART Transmit Complete Interrupt. The handler of that should set HAL_UART_STATE_READY. There's a time window between moving the last TX byte to the UART and completion of TX.

MScha.8
Associate II

Thanks Pavel.

Configuring the USART for DMA operation in CubeMX does not enable the interrupt. Manually checking the box to enable interrupts fixes the problem and allows  HAL_UART_Transmit_DMA to be called repeatedly.

Maybe CubeMX should automatically enable the interrupt when DMA is used since proper operation seems to require it?

> Maybe CubeMX should automatically enable the interrupt when DMA is used since proper operation seems to require it?

Yes, this would be right thing.

HF.Wang
Associate II

I also encountered the similar problems when the transfer using the DMA and receive use the interrupt or pulling. But there is no data input (actually has data in with the oscilloscope). And trace into the program, find it is to process the FE/ORE and then change the state to ready not in receive mode, so the receive code does not work anymore. (Environment: STM32L412 with the latest STM32CubMx and Lib 1.17.2.)