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
tm3341
Associate II
Posted on June 02, 2015 at 20:38

You have to check what these functions returns to you.

Because DMA do some work and when you call DMA transmit first time, DMA is ready, but when you do it second time, DMA is not ready yet and you probably get an error back.

Set some delay betweem statements for transmit, for example 10ms for testing to see if it will work.

PS: Larger string/array you wanna send, more time you need to wait before next transmission will be ready.

I hope you understand how DMA works.

Check return values from Transmit_DMA functions.

stigmablu
Associate II
Posted on June 02, 2015 at 23:09 From cubemx examples:

/*##-2- Start the transmission process #####################################*/
if
(HAL_UART_Transmit_DMA(&UartHandle, (uint8_t*)aTxBuffer, TXBUFFERSIZE)!= HAL_OK)
{
Error_Handler();
}
/*##-3- Wait for the end of the transfer ###################################*/
while
(UartReady != SET)
{
}
/* Reset transmission flag */
UartReady = RESET;

since DMA transmissions are non-blocking you need to check that previous send has been completed.
eng239955
Associate II
Posted on July 03, 2015 at 21:15 i have the same problem but after a long tracing i found that at the end of dma trans farecompletion the ''hal'' didn't set the state to ''HAL_UART_STATE_READY'' so i set the state to ''HAL_UART_STATE_READY'' at the end ofUART_DMATransmitCplt function in stm32f1xx_hal_uart.c line :1547 and it work


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 setting the DMAT bit

in the UART CR3 register */

CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT);



/* Enable the UART Transmit Complete Interrupt */

__HAL_UART_ENABLE_IT(huart, UART_IT_TC);

huart->State=HAL_UART_STATE_READY; 
//<--- i add this line to solve the //problem 

}

/* DMA Circular mode */

else

{

HAL_UART_TxCpltCallback(huart);

}

}

/////////////////////////////////////////// if there any other solution please feedback
romanovda
Associate
Posted on July 28, 2015 at 00:53

Hi!

I confirm the issue. If I set UART DMA in Normal mode without interrupts, HAL_UART_Transmit_DMA always returns HAL_BUSY after the first use. Another way to solve this is to enable USART global interrupt. Looks like after the interrupt called by the line:

HAL_UART_ENABLE_IT(huart, UART_IT_TC);

the flag is set correctly.
Posted on July 28, 2015 at 14:26

Hi romanov.dmitry.001,

Could you precise in which HAL library you have found the issue. So, we can verify it.

-Shahrzad-

jean-pierre
Associate II
Posted on September 22, 2015 at 16:21

Hi Dmitry

I am facing the same issue with the 

HAL_UART_Transmit_DMA function.

The communication seems ok when a delay* is inserted between two calls.

(* the delay have to be proportionnal to the number of bytes transmitted).

I can't explain the origin of this phenomena.

Could you please give more precisions about the issue you confirm in your post?

Best regards,

Jean-Pierre

Posted on September 29, 2015 at 13:07

Hi fortune.jean_pierre,

Could you precise which HAL are you using and which version? You should add the function that handles USART interrupts.

/** 
* @brief This function handles USARTx interrupt request. 
* @param None 
* @retval None 
*/ 
void USARTx_IRQHandler(void) 
{ 
HAL_UART_IRQHandler(&UartHandle); 
}

Indeed, the function ''HAL_UART_IRQHandler()'' calls ''UART_Transmit_IT()'' function that sets the USART state to ''HAL_UART_STATE_READY''. -Shahrzad-
jean-pierre
Associate II
Posted on October 09, 2015 at 12:34

Hi Shahrzad,

Thanks for your response. Here is what is on top of file :

* @file stm32l4xx_hal_uart.c
* @author MCD Application Team
* @version V1.0.0
* @date 26-June-2015

May be a newer is available, nevertheless we already have a call to

HAL_UART_IRQHandler from the ISR handler.

Best regards, -- Jean-Pierre
niko40
Associate
Posted on December 21, 2015 at 03:00

This is exactly what I needed. Thanks for the tip. :)

I got newest version of CubeF1 ( 1.2.0 in CubeMX ) and it's still happening in there.

stm32f1xx_hal_uart.c header says:

  * @version V1.0.1

  * @date    31-July-2015