cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_UART_Transmit_DMA issues

Posted on June 02, 2015 at 19:39

I am trying a simple test. I want to output a single character to the UART using DMA.

I am using system workbench for stm32 First I tried configuring the DMA in normal mode.

huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart2);
hdma_usart2_tx.Instance = DMA1_Stream6;
hdma_usart2_tx.Init.Channel = DMA_CHANNEL_4;
hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart2_tx.Init.Mode = DMA_NORMAL;
hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_usart2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_usart2_tx);
__HAL_LINKDMA(huart,hdmatx,hdma_usart2_tx);

The only code I have added is this and code to blink LEDs in the while (1) loop:

/* USER CODE BEGIN 2 */
HAL_UART_Transmit_DMA(&huart2,(uint8_t*)
''a''
,1);
HAL_UART_Transmit_DMA(&huart2,(uint8_t*)
''b''
,1);
/* USER CODE END 2 */

In normal mode it outputs the character 'a' once then the lights begin to blink. The character 'b' is never put out to the uart. If I do something like this

char
testMessage[] = 
''test output of a longer string\r\n''
;

HAL_UART_Transmit_DMA(&huart2,(uint8_t*)&testMessage,
sizeof
(testMessage)-1);

HAL_UART_Transmit_DMA(&huart2,(uint8_t*)
''a''
,1);
HAL_UART_Transmit_DMA(&huart2,(uint8_t*)
''b''
,1);

I only get the testMessage array output. 'a' and 'b' are never put out to the uart If I setup my code to use the DMA in circular mode as follows:

huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart2);
hdma_usart2_tx.Instance = DMA1_Stream6;
hdma_usart2_tx.Init.Channel = DMA_CHANNEL_4;
hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart2_tx.Init.Mode = DMA_CIRCULAR;
hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_usart2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_usart2_tx);
__HAL_LINKDMA(huart,hdmatx,hdma_usart2_tx);

Then run the first set out outputs again:

HAL_UART_Transmit_DMA(&huart2,(uint8_t*)
''a''
,1);
HAL_UART_Transmit_DMA(&huart2,(uint8_t*)
''b''
,1);

It outputs a continuous stream of the letter 'a' continuing while the lights are being blinked. 'b' is never output When I output the string as well:

char
testMessage[] = 
''test output of a longer string\r\n''
;
HAL_UART_Transmit_DMA(&huart2,(uint8_t*)&testMessage,
sizeof
(testMessage)-1);
HAL_UART_Transmit_DMA(&huart2,(uint8_t*)
''a''
,1);
HAL_UART_Transmit_DMA(&huart2,(uint8_t*)
''b''
,1);

The testMessage array is sent repeatedly while the leds blink. 'a' and 'b are never output Clearly I am missing something minor here. Reading document UM1725 ''Description of STM32F4xx HAL drivers'' page 846 has this to say about DMA on the uart: ''Send an amount of data in non blocking mode (DMA) using HAL_UART_Transmit_DMA() At transmission end of half transfer HAL_UART_TxHalfCpltCallback is executed and user can add his own code by customization of function pointer HAL_UART_TxHalfCpltCallback At transmission end of transfer HAL_UART_TxCpltCallback is executed and user can add his own code by customization of function pointer HAL_UART_TxCpltCallback'' So what am I missing here? Why does circular mode just keep repeating the output and normal mode simply output once then stop all other outputs? Thank you for your assistance in this matter #dma-uart-usart-hal #hal_uart_transmit_dma
20 REPLIES 20
Posted on December 21, 2015 at 14:55

Hi kauppi.niko,

The version of the firmware package is independent from drivers' versions.

If the firmware is v1.2.0, the driver can have another version.

-Shahrzad-

duybienle
Associate II
Posted on August 01, 2016 at 13:38

Hi shahrzad

I'm facing the same problem. After the first transmitting, UART_Tx keeps being busy. I tried to add the code for handling UART intterupt you provided, but still the same problem occurs.

My code is as follow:

int main(void)

{ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_DMA_Init(); MX_USART2_UART_Init(); // first transmitting if(HAL_UART_Transmit_DMA(&huart2, (uint8_t*)aRxBuffer, 10)!= HAL_OK) { Error_Handler(); } while (HAL_UART_GetState(&huart2) != HAL_UART_STATE_READY) { } // second transmitting

if(HAL_UART_Transmit_DMA(&huart2, (uint8_t*)aRxBuffer, 10)!= HAL_OK)

{ Error_Handler(); } while (HAL_UART_GetState(&huart2) != HAL_UART_STATE_READY) { } while (1) { } } void USARTx_IRQHandler(void) { HAL_UART_IRQHandler(&huart2); } After the first transmitting, the flag

gState

is always set busy. Thanks, Bien
Elwood Downey
Associate II
Posted on August 23, 2016 at 22:16

STM: this bug is still here and this is still the only solution that works for me. I have V1.5.1. Please fix. I wasted almost two days tracking this down.

vdevram
Associate
Posted on October 11, 2016 at 07:22

Thank you for this post. This still exists, I ran into it today (Oct10, 2016) with latest cube MX code on STM32 F303 board. 

Set 

huart->gState=HAL_UART_STATE_READY 

at the end of UART_DMATransmitCplt function in stm32f3xx_hal_uart.c, right after line 1804 and it worked.

Code snippet:

----------------------

static void UART_DMATransmitCplt(DMA_HandleTypeDef *hdma)

{

  UART_HandleTypeDef* huart = ( UART_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;

  

  /* DMA Normal mode */

  if ( HAL_IS_BIT_CLR(hdma->Instance->CCR, DMA_CCR_CIRC) )

  {  

    huart->TxXferCount = 0;

  

    /* Disable the DMA transfer for transmit request by resetting the DMAT bit

    in the UART CR3 register */

    huart->Instance->CR3 &= (uint32_t)~((uint32_t)USART_CR3_DMAT);

    /* Enable the UART Transmit Complete Interrupt */

    __HAL_UART_ENABLE_IT(huart, UART_IT_TC);

    /* fix to enable multiple msgs to be transmitted */

    huart->gState=HAL_UART_STATE_READY; 

  }

  /* DMA Circular mode */

  else

  {

    HAL_UART_TxCpltCallback(huart);

  }

}

----------------------

abotha
Associate III
Posted on January 05, 2017 at 10:10

This worked for me too, STM32F072 with HAL MX Cube F0 v1.7.0.

I have noticed that none of my Callbacks are firing, so I suspect that this workaround works for incorrect implementation with the callbacks. I will come back to this when I understand the implementation of callbacks a bit better.

MDS
Associate III
Posted on February 20, 2017 at 20:58

If you are not going to immediately disable the UART transmitter or the UART, this fix will work. It appears that the HAL is assuming that the user is going to shut down the UART after each transmission. As the last character is still in the transmitter shift register, disabling the transmitter would corrupt it.

You should also comment out the preceding line that enables the UART Transmit Complete Interrupt as you don't need it. This will save come code and time, and you will no longer need to enable the UART interrupt when DMA is used.

T J
Lead
Posted on February 21, 2017 at 00:25

this code will send any number of bytes after the UartDMA has been initialised:

void MX_USART1_UART_Init(void){
 huart1.Instance = USART1; huart1.Init.BaudRate = 460800; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); }
}
void CheckTxDMABufferProgress(void){ if ( DMABufHasData ){ char uartState = HAL_UART_GetState(&huart1); if ((uartState == HAL_UART_STATE_READY) || (uartState == HAL_UART_STATE_BUSY_RX)) { DMABufHasData = false; // sending now if (HAL_UART_Transmit_DMA(&huart1, (uint8_t *)Usart1TxDMABuffer + U1TxBufferPtrOUT ,U1TxBufferPtrIN - U1TxBufferPtrOUT) == HAL_OK){
 HAL_UART_Transmit_DMA_Status = UartDMAsuccess;
 U1TxBufferPtrOUT = U1TxBufferPtrIN; } else{ /* Transfer error in transmission process */ HAL_UART_Transmit_DMA_Status = UartDMAfailed; }// }else { // sprintf(string,'HAL_UART_GetState gave %02x 

',uartState);// puts(string); } //use this in main loop.... //if ( HAL_UART_Transmit_DMA_Status == UartDMAfailed ) {ProcessFailure();HAL_UART_Transmit_DMA_Status = PreviousUartDMAfailed;} //if ( HAL_UART_Transmit_DMA_Status == UartDMAsuccess ) {ProcessSuccess();HAL_UART_Transmit_DMA_Status = PreviousUartDMAsucceeded;} }}�?�?�?�?�?�?�?�?�?�?

Roberto Roman
Associate II
Posted on February 25, 2018 at 17:44

Hello all, thank you for your help

On the other hand I would like add a comment. 

On this implementation the interruption never call a callback when the DMA finish to send all buffer

/*********************************************************/

    /* fix to enable multiple msgs to be transmitted */

    huart->gState=HAL_UART_STATE_READY; 

  }

  /* DMA Circular mode */

  else

  {

    HAL_UART_TxCpltCallback(huart);

  }

/*********************************************************/

As a improvement I changed the implementation as follow:

/*********************************************************/

    /* fix to enable multiple msgs to be transmitted */

    huart->gState=HAL_UART_STATE_READY; 

  }

 

/* DMA Circular mode  and Normal */

  HAL_UART_TxCpltCallback(huart);

/*********************************************************/

Currently I'm using freeRtos and is really helpful

to have this callback to send a notification at the task in charge to print by UART

stm32l432 still impacted by this bug in late 2023 :\

huart->gState=HAL_UART_STATE_READY;

Thank you very much for your post!