cancel
Showing results for 
Search instead for 
Did you mean: 

UART TX/RX with DMA in Normal mode

Davood_Kesha
Associate III

Dear ST experts,

I have configured UART (both RX and TX) in Normal DMA mode. I want to send a small data packet every 500 ms with using HAL_UART_Transmit_DMA (&huart, buffer, 10). But I noticed that only one shot is triggered. What is the problem? Should I do something in HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) callback?

Best,
Davood.

1 ACCEPTED SOLUTION

Accepted Solutions

Yes, you need to enable the UART global interrupt in STM32CubeMX. Go to your UART :

NVIC Settings → USARTx global interrupt → Enable

In Normal DMA mode, the HAL uses the UART TC (Transmission Complete) interrupt to reset the UART state to READY after each transfer. Without it, the state stays BUSY and every next HAL_UART_Transmit_DMA() call silently fails with HAL_BUSY.

In Circular mode this interrupt isn't needed because the DMA never stops.

You need both enabled: DMA stream interrupt & UART global interrupt

 

Br 

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.

View solution in original post

4 REPLIES 4
MOBEJ
ST Employee

Hello @Davood_Kesha ,
In DMA Normal mode, the DMA performs exactly one transfer and stops this is by design, not a bug. The HAL marks the UART state as READY and waits. It will not automatically re-trigger.

Yes, you must re-call HAL_UART_Transmit_DMA() to send again. The correct place is from HAL_UART_TxCpltCallback, combined with a timing mechanism:

volatile uint8_t txDone = 1; // start ready

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    txDone = 1; // transfer finished, ready for next
}

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_DMA_Init();
    MX_USART1_UART_Init();

    while (1)
    {
        if (txDone)
        {
            txDone = 0;
            HAL_UART_Transmit_DMA(&huart1, buffer, 10);
        }
        HAL_Delay(500);
    }
}

 Br

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.

Hello,
I am recalling HAL_UART_Transmit_DMA (&huart, buffer, 10) every 500 ms. But it does not work.
Should I activate the global interrupt of uart in stm32cubemx? In circular mode global interrupt is not needed. 

Yes, you need to enable the UART global interrupt in STM32CubeMX. Go to your UART :

NVIC Settings → USARTx global interrupt → Enable

In Normal DMA mode, the HAL uses the UART TC (Transmission Complete) interrupt to reset the UART state to READY after each transfer. Without it, the state stays BUSY and every next HAL_UART_Transmit_DMA() call silently fails with HAL_BUSY.

In Circular mode this interrupt isn't needed because the DMA never stops.

You need both enabled: DMA stream interrupt & UART global interrupt

 

Br 

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.

@MOBEJ wrote:

HAL_UART_Transmit_DMA() call silently (sic) fails with HAL_BUSY.


If it gives an error code, then it's not a silent failure.

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.