Author Topic: STM32 with CubeMX: correct establishment order for UART in DMA mode  (Read 1410 times)

0 Members and 1 Guest are viewing this topic.

Offline liteyearTopic starter

  • Regular Contributor
  • *
  • Posts: 69
  • Country: au
Didn't get any bites over at ST, so am seeking your wise counsel.

When initialising a UART using CubeMX generated code, either the receiver or transmitter or both are enabled. Typically that means that before receiving data with the UART for the first time, the RDR register should be cleared (or the RXFRQ function used), to clear out any junk that got read during boot.

But if using DMA RX mode I've discovered an extra consideration - if an error is received before calling HAL_UART_Receive_DMA() for the first time, the error handler will be called. The default HAL_UART_IRQHandler() (at least in stm32u5xx_hal_uart.c) aborts the DMA RX on error (regardless of the DDRE setting). So the user is required to restart if necessary.


This leads to an awkward situation where the error handler (which has to restart DMA RX) can be called before HAL_UART_Receive_DMA() is called for the first time. Rather that handling that strange edge case, it seems prudent to eliminate the undesirable order of operations.


Specifically, is there a sensible way to configure the UART with CubeMX, but then inhibit it (just the receiver part would do, I think) until we're ready to start receiving? I could enable transmit only in CubeMX, which would prevent RE being set. But then HAL_UART_Receive_DMA() doesn't set it, so doing so would be custom.

It seems to me that given the design of the HAL_UART_Receive* interface, that it would never be desirable to have the receiver enabled prior to them being called, so I wonder if there's a more logical way to go about this.
 

Offline eTobey

  • Super Contributor
  • ***
  • Posts: 1293
  • Country: de
  • Virtual Features for the SDS800XHD -> My website
    • Virtual feature script
Re: STM32 with CubeMX: correct establishment order for UART in DMA mode
« Reply #1 on: February 07, 2025, 09:56:28 pm »
Id go with the manual. It gives you the right steps (probably). All that HAL is just a black box in between.

Have you cleared the error before enabling anything DMA / interrupt / receive stuff?

Also you have to initialize the DMA before the peripheral.
"Sometimes, after talking with a person, you want to pet a dog, wave at a monkey, and take off your hat to an elephant."(Maxim Gorki)

SDS800X HD bugs/issues/workarounds (Updated 17. Feb. 2025)
 

Offline liteyearTopic starter

  • Regular Contributor
  • *
  • Posts: 69
  • Country: au
Re: STM32 with CubeMX: correct establishment order for UART in DMA mode
« Reply #2 on: February 09, 2025, 10:45:49 pm »
Yeah, "just bypass the HAL" is a common refrain! I've stayed the HAL course for a couple of decades now and have too much proven-in-use collateral to abandon ship now. Particularly given the extraordinary complexity of the peripherals these days, and the desire to lean on vendors to ensure resistance to change stays low.

Yes, errors are cleared prior to initialisation. The HAL actually does a pretty good job of this, ensuring you don't get interrupts on initialisation. It's the period between initialisation and starting a receive that is no mans land. By then interrupts are already armed to fire, so it's too late to clear anything.

Yes, fortunately that UART-before-DMA initialisation bug has been fixed for a while. This seems to be a deliberate ordering of things, which is why I'm wondering if I've misinterpreted the interface.


FWIW, in the meantime I'm proceeding with the solution I hinted at: in CubeMX I configure all UARTs as Transmit Only. Then, immediately after starting a receive for the first time I manually flip the "receiver enable" bit. Feels a bit crude, but so far so good. Does what you would hope - the peripheral is configured with all the complex intra-peripheral settings you setup in CubeMX, and the Transmit Only setting doesn't seem to inhibit my options. But then no interrupts fire until after you make your first HAL_UART_Receive* call.


PS. Maybe not what you meant, but note the HAL is not a black box. The only reason I've stuck with it for so long is that it's human-readable source code! You can even step through it in the debugger, and I do so regularly. That's essential, and I've abandoned other vendors that have gone the black box route. Now is the intent a black box? Well technical support... varies.
« Last Edit: February 09, 2025, 10:49:12 pm by liteyear »
 

Offline eTobey

  • Super Contributor
  • ***
  • Posts: 1293
  • Country: de
  • Virtual Features for the SDS800XHD -> My website
    • Virtual feature script
Re: STM32 with CubeMX: correct establishment order for UART in DMA mode
« Reply #3 on: February 10, 2025, 07:46:41 am »
Indeed the term i used is wrong in this case. To me its just a "black bocx", that i have never opened.  ;)

I have used it in the beginning, but had a few cases where i had to look into that black box. But then i thought it would be better to have a deeper understanding of the hardware, to write a good program. Also its overhead is HUGE, and i am glad that i did not go with HAL at the very beginning, because im gonna need quite a bit of space.

"Yes, errors are cleared prior to initialisation."
Cant you debug where the issue happens exactly? Add some delays maybe in the init. Also sometimes you want to clear errors only exactly before you enable a interrupt.
"Sometimes, after talking with a person, you want to pet a dog, wave at a monkey, and take off your hat to an elephant."(Maxim Gorki)

SDS800X HD bugs/issues/workarounds (Updated 17. Feb. 2025)
 

Offline liteyearTopic starter

  • Regular Contributor
  • *
  • Posts: 69
  • Country: au
Re: STM32 with CubeMX: correct establishment order for UART in DMA mode
« Reply #4 on: February 10, 2025, 10:18:18 pm »
I could be wrong, but I'm pretty sure the issue is clear:

  • CubeMX's MX_UARTn_Init() function configures the peripheral and sets the uart, transmitter, and receiver enable flags.
  • The uart peripheral starts looking for a start bit, and will begin decoding a byte.
  • If a valid byte arrives, the peripheral holds it in the receive buffer (or FIFO if you've enabled it) until you call one of the HAL_UART_Receive* functions. Typically people purge the receive buffer before doing so, so they only get the data they're prepared for.
  • However, if an invalid byte arrives, the interrupt fires and your error handling callback is called. In the special case of a UART configured for DMA RX, DMA is aborted, even if you haven't started it yet with a call to HAL_UART_Receive_DMA().
  • So the error handler is faced with a tricky situation. In normal operation it needs to restart DMA. But because it's called in interrupt context, it can happen before, after, or even during your first call to HAL_UART_Receive_DMA(). That's awkward to manage.

For example, scroll down to "Step #5" here: https://deepbluembedded.com/stm32-uart-dma-receive-transmit-rx-tx-examples/#stm32-uart-dma-receive-rx-example-overview

The author does the traditional thing, not much different to what I'm doing, though much simpler:

Code: [Select]
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
 
HAL_UART_Receive_DMA (&huart1, UART1_rxBuffer, 12);

The problem is that between the call to MX_USART1_UART_Init() and the call to HAL_UART_Receive_DMA(), the receiver is already enabled. DMA isn't, but the UART will still happily receive a byte and throw an error if it detects one.

Doesn't that seem a little back to front?
 

Offline eTobey

  • Super Contributor
  • ***
  • Posts: 1293
  • Country: de
  • Virtual Features for the SDS800XHD -> My website
    • Virtual feature script
Re: STM32 with CubeMX: correct establishment order for UART in DMA mode
« Reply #5 on: February 11, 2025, 11:37:13 am »
I can not answer your question, nor give you a proper advice (in case for the HAL), since its a box that i rather dont want to look into, but since you state:
I could be wrong, but I'm pretty sure the issue is clear:
, to me the solution is clear:

If HAL gives you trouble, get rid of it!

BTW. what is your flash usage? If you are a bit short, then its well worth thinking about getting rid of HAL.
"Sometimes, after talking with a person, you want to pet a dog, wave at a monkey, and take off your hat to an elephant."(Maxim Gorki)

SDS800X HD bugs/issues/workarounds (Updated 17. Feb. 2025)
 

Offline liteyearTopic starter

  • Regular Contributor
  • *
  • Posts: 69
  • Country: au
Re: STM32 with CubeMX: correct establishment order for UART in DMA mode
« Reply #6 on: February 12, 2025, 12:21:54 am »
Okay. There's somewhere north of 10,000 hours of personal investment in the HAL at this point that is paying dividends every day. This issue is a good example - I spent a total of zero hours on developing a DMA enabled UART HAL driver, which I'm now deploying across multiple STM32 families for various clients. Given my familiarity with the HAL I was able to identify and workaround this issue (using the receiver-disabled trick I mentioned) quickly.

If I'm looking for advice on better use of the HAL, you can bet that "stop using the HAL" isn't going to stack up on my cost-benefit analysis  ;)

FWIW, one medium-term project I have open at the moment is at 13% Flash usage for 35000+ lines of application-specific source code, excluding all the HAL and CMSIS stuff, but including the big-bertha stdlib with float support. That's pretty typical. This isn't Zephyr. But yes, if someone is out there looking to save space, it's one thing to consider.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf