Skip to main content
steve239955_st
Associate II
October 2, 2015
Question

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

  • October 2, 2015
  • 3 replies
  • 939 views
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
    This topic has been closed for replies.

    3 replies

    Amel NASRI
    ST Technical Moderator
    October 2, 2015
    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 "Best Answer" on the reply which solved your issue or answered your question.
    steve239955_st
    Associate II
    October 5, 2015
    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 Technical Moderator
    October 8, 2015
    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 "Best Answer" on the reply which solved your issue or answered your question.