cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 problem with UART RX throught DMA

Smark
Associate II

Hello,

I am implementing the use of the DMA for receiving data from the UART on a board with an STM32G491 that is constantly receiving data at 19200 baud.


The DMA is configured in normal mode, and the receive buffer is currently of 50 bytes.


Each time the buffer fills up, in the HAL_UART_RxCpltCallback interrupt I enable a flag to handle data in the main loop and in the same interrupt I call HAL_UART_Receive_DMA to re-enable reception.


The problem comes when in this call returns HAL_BUSY because the DMA reception is blocked waiting for HAL_UART_Receive_DMA to be called again to restart the reception.

I don't understand why I get this response (HAL_BUSY), nor how to deal with it.

If I configure the DMA in circular mode I always receive the HAL_BUSY response and therefore the reception does not work.

Any idea what I can be doing wrong?

Thanks in advance,

 

 

9 REPLIES 9
Karl Yamashita
Lead III

The problem comes when in this call returns HAL_BUSY because the DMA reception is blocked waiting for HAL_UART_Receive_DMA to be called again to restart the reception.

I don't understand why I get this response (HAL_BUSY), nor how to deal with it.


Always show your code so we know exactly what you're doing.

If the status returns HAL_BUSY, you try again. Just because you can't re-enable the interrupt in the IRQ, doesn't mean you can't enable it outside of the IRQ. 

See this project on how using a flag can re-enable the interrupt outside of the IRQ.

https://github.com/karlyamashita/Nucleo-G431RB_Three_UART

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.
Imen.D
ST Employee

Hello @Smark ,

Make sure that the UART and DMA are properly initialized before starting the reception (for UART parameters and the DMA channels).

You may need to reset the DMA controller. This can be done by calling the HAL_DMA_Abort function to abort the current DMA transfer and then reinitializing the DMA.

I recommend you follow the examples and steps described in these articles :

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
Guenael Cadier
ST Employee

Hi @Smark 

If your DMA channel is configured in Circular mode, no need to recall HAL_UART_Receive_DMA(), as reception is not stopped when reaching the Receive Complete event (reception will go on and new received characters will be stored starting again from rx buffer start).

 

If your DMA is not in Circular mode, then UART Handle Rx state is reset to HAL_UART_STATE_READY prior executing the HAL_UART_RxCpltCallback() callback, so you should be able to restart a new reception with a new call to HAL_UART_Receive_DMA(). If this new call returns HAL_BUSY, then it means a reception is still ongoing, or has been already restarted.

If you are in case on a continuous reception, and want to transfer received data from reception buffer to somewhere else, one option could be to use a Circular DMA, and :

- retrieve data from 0 to 24 on Half Reception => HAL_UART_RxHalfCpltCallback()

- retrieve data from 25 to 49 on Complete reception => HAL_UART_RxCpltCallback()

- and then, repeat this endlessly
In this case, no need to call again HAL_UART_Receive_DMA() in callbacks, reception will remain active until you abort it.

 

Hope this helps.

Hi Guenael,

For now the UART is not configured in circular mode, although I don't know if this is the best option for the application I am developing.

The question is that I can not understand why the UART Handle Rx state is not reset and sometimes I get HAL_BUSY.

As Karl Yamashita has commented, I recall  HAL_UART_Receive_DMA out of the IRQ when recived HAL_BUSY, but my goal is to try to understand why this situation occurs and correct it so that frames are not lost. 

This system is composed of two cards that send data to each other continuously, in the card I am talking about, the DMA has been implemented for reading the UART and also for sending data. The reading has priority over the reading. The output frames are correct, but in reception the response HAL_BUSY causes some frames to be lost.

 

Best regards,

Cube/HAL is open source, so simply debug it as your own code.

How exactly do you check the return value from HAL_UART_Receive_DMA()?

What is the value of huart->RxState?

JW

Yes, perhaps look if it depends on the callback completing and returning. Or there's some broken exit path.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Now I am doing this to debug the errors

debug.png

Variable errorDMA_UART4 has the value HAL_BUSY

In the function HAL_UART_Receive_DMA it entries into the conditional sentence:

        if (huart->RxState == HAL_UART_STATE_READY)

and it seems it returns HAL_BUSY in the line: 

        return (UART_Start_Receive_DMA(huart, pData, Size));

Because it does not stop in other call to return. But looking into the code, UART_Start_Receive_DMA returns nothing but HAL_ERROR or HAL_OK.

> UART_Start_Receive_DMA returns nothing but HAL_ERROR or HAL_OK.

You don't check for HAL_BUSY anyway, you check for HAL_OK. So UART_Start_Receive_DMA() returns HAL_ERROR. Find out, why.

JW

Thank you for your quick response.

It is returning HAL_BUSY. I has been checking if NOT HAL_OK since I detected the loss of data frames and I didn´t know what was happening. As I am debugging I know that always it entries in the NOT HAL_OK condition is because it returns HAL_BUSY.

Thank you