2015-06-02 10:39 AM
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
2015-06-02 11:38 AM
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.2015-06-02 02:09 PM
/*##-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.
2015-07-03 12:15 PM
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
2015-07-27 03:53 PM
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.
2015-07-28 05:26 AM
Hi romanov.dmitry.001,
Could you precise in which HAL library you have found the issue. So, we can verify it. -Shahrzad-2015-09-22 07:21 AM
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-Pierre2015-09-29 04:07 AM
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-
2015-10-09 03:34 AM
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-Pierre2015-12-20 06:00 PM
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