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-12-21 05:55 AM
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-2016-08-01 04:38 AM
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 transmittingif(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 flaggState
is always set busy.
Thanks,
Bien
2016-08-23 01:16 PM
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.
2016-10-10 10:22 PM
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); }}----------------------2017-01-05 01:10 AM
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.
2017-02-20 12:58 PM
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.
2017-02-20 03:25 PM
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;} }}�?�?�?�?�?�?�?�?�?�?
2018-02-25 08:44 AM
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
2023-10-26 02:39 PM
stm32l432 still impacted by this bug in late 2023 :\
huart->gState=HAL_UART_STATE_READY;
Thank you very much for your post!
2023-10-26
03:53 PM
- last edited on
2023-11-09
01:04 AM
by
Lina_DABASINSKA
The HAL is full of such bugs...