cancel
Showing results for 
Search instead for 
Did you mean: 

Is this a bug? - STM32L4, HAL, USART DMA handler

steve239955_st
Associate II
Posted on October 02, 2015 at 14:39

Using HAL, I have configured DMA1_CH2 and USART3_TX such that once in a while, a block of bytes will be copied from memory to peripheral, in NORMAL, i.e. non-circular mode.

Now, my handler, HAL_USART_TxCpltCallback, never gets called - but the one for the half complete does get called.

In file stm32L4xx_hal_usart.c, function USART_DMATransmitCplt, the HAL_USART_TxCpltCallback is called.

BUT: only when the DMA is in circular mode.

Is this a bug, or does this somehow make sense and I have misunderstood how to use this feature?

This HAL-internal handler does get called, so my configuration basically works I guess.

For my USART Transmission in normal mode, I don't care for the half-completed callback, I only need to know when it's done.

How is it supposed to be done?

Thanks in advance
3 REPLIES 3
Amel NASRI
ST Employee
Posted on October 02, 2015 at 17:44

Hi kledtke.steve.002,

When using DMA for UART transmission in normal mode, the UART Transmit Complete Interrupt is enabled with the call of UART_DMATransmitCplt.

If you check the UART_IRQHandler, at the end of transmission, UART_EndTransmit_IT is called. At this level, UART state is set to ready and HAL_UART_TxCpltCallback is used.

So in your code, pay attention to enable UART IRQ Handler in your it.c file.

-Mayla-

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

steve239955_st
Associate II
Posted on October 05, 2015 at 15:45

Hello,

the handler for the DMA channel is active in ..._it.c file, calling: HAL_DMA_IRQHandler( husart3.hdmatx ); In the USART_DMATransmitCplt function, the user-implemented handler is only called in the block titled ''circular mode''. See below. In USART_EndTransmit_IT, the user-provided handler, HAL_USART_TxCpltCallback,is indeed called. But according to the comments in the source file, that HAL_USART_IRQHandler, where USART_EndTransmit_IT is called,is only for the interrupt-based non-blocking mode, as when HAL_USART_Transmit_IT iscalled - not for DMA mode, i.e. when HAL_USART_Transmit_DMA is called. So I still don't understand how this is supposed to work. Have I overlooked something? Thanks,

/* 
(#) Non-Blocking mode API's with Interrupt are : 
(++) HAL_USART_Transmit_IT()in simplex mode 
(++) HAL_USART_Receive_IT() in full duplex receive only 
(++) HAL_USART_TransmitReceive_IT()in full duplex mode 
(++) HAL_USART_IRQHandler() 
(#) No-Blocking mode API's with DMA are : 
(++) HAL_USART_Transmit_DMA()in simplex mode 
(++) HAL_USART_Receive_DMA() in full duplex receive only 
(++) HAL_USART_TransmitReceive_DMA() in full duplex mode 
(++) HAL_USART_DMAPause() 
(++) HAL_USART_DMAResume() 
(++) HAL_USART_DMAStop() 
*/
static
void
USART_DMATransmitCplt(DMA_HandleTypeDef *hdma) 
{ 
USART_HandleTypeDef* husart = ( USART_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent; 
/* DMA Normal mode */
if
( HAL_IS_BIT_CLR(hdma->Instance->CCR, DMA_CCR_CIRC) ) 
{ 
husart->TxXferCount = 0; 
if
(husart->State == HAL_USART_STATE_BUSY_TX) 
{ 
/* Disable the DMA transfer for transmit request by resetting the DMAT bit 
in the USART CR3 register */
husart->Instance->CR3 &= ~(USART_CR3_DMAT); 
/* Enable the USART Transmit Complete Interrupt */
__HAL_USART_ENABLE_IT(husart, USART_IT_TC); 
// TEST: has this been forgotten, is this a bug? 
//HAL_USART_TxCpltCallback(husart); 
} 
} 
/* DMA Circular mode */
else
{ 
if
(husart->State == HAL_USART_STATE_BUSY_TX) 
{ 
HAL_USART_TxCpltCallback(husart); 
} 
} 
} 

Hikledtke.steve.002,

When using DMA for UART transmission in normal mode, the UART Transmit Complete Interrupt is enabled with the call ofUART_DMATransmitCplt. If you check the UART_IRQHandler, at the end of transmission,UART_EndTransmit_IT is called. At this level, UART state is set to ready andHAL_UART_TxCpltCallback is used. So in your code, pay attention to enable UART IRQ Handler in your it.c file. -Mayla-
Amel NASRI
ST Employee
Posted on October 08, 2015 at 13:26

Hikledtke.steve.002,

In the file stm32l4xx_it.c, you have to add:

void

USARTx_IRQHandler(

void

)

{

HAL_UART_IRQHandler(&UartHandle);

}

The explanation: when using DMA, you will have ''UART_DMATransmitCplt'' called.

If you are in DMA Normal mode, the UART Transmit Complete Interrupt will be enabled:

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);

}

/* DMA Circular mode */

else

{

HAL_UART_TxCpltCallback(huart);

}

}

This interrupt has to be managed with the UART IRQ handler. That is why I suggested to add it.

-Mayla-

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.