Lunch
Lunch

Reputation: 55

Checking a char buffer from UART - what is the best practice?

Which of the following is better practice (or please suggest better alternatives) when using a global buffer with DMA with UART on an STM32 embedded application (no RTOS):

Option 1: When entering the ISR after a DMA to Idle event on the UART I have a global buffer that has been filled with characters. I set a flag in the ISR and exit quickly. In main loop I check the flag and process the contents of the global array. I then reset the flag at the end of processing.

Possible Advantages

Possible Disadvantages

Option 2: When entering the ISR after a DMA to Idle event on the UART I have a global buffer that has been filled with characters. I process the characters within the ISR and then set a flag according to what output is necessary.

Possible Advantages

Possible Disadvantages

Or, does anyone have any other alternatives, e.g. setting a flag and then copying the buffer immediately in the main loop to a local variable, and then processing that local variable itself?

Grateful for any advice and comments.

Upvotes: 1

Views: 95

Answers (3)

chux
chux

Reputation: 154173

I process the characters within the ISR

#2 is a weak choice. ISRs are not meant for long execution time. Get in, get out.

incoming UART characters could change the array contents as I'm processing it?

Avoid a race condition of data arriving while processing the buffer in option #1.

Option 3: use 2 buffers. Let the DMA fill the one that is not being processed. The ISR, after filling one buffer, simple swaps which buffer to use. Now the processing is done in the foreground with the proviso that it must be done before the alternate buffer is filled, else the ISR should whine with setting a buffer overflow error flag.

Could use more than 2 buffers is processing is sluggish/jerky, yet fast enough over a long period. Yet I suspect 2 will work fine for OP.

Upvotes: 3

0___________
0___________

Reputation: 67835

Global buffer is a bad idea.

I have plenty systems using DMA UART at the high speeds (up to 8M).

  1. Use memory pools (I will call them chunks).
  2. Set the DMA to chunk memory.
  3. When it is full or you receive idle interrupt post its reference to the processing task queue. Allocate new chunk, sed DMA etc

It is clean fast and reliable.

Upvotes: 3

Lundin
Lundin

Reputation: 214770

It all boils down to real-time requirements. How fast is the data coming in and how frequently. Size of the data in relation to the DMA buffer. How busy your program is doing other things. How important is the UART communication in relation to other things. What possibilities the DMA offers when it comes to early warning flags and swapping buffers. And so on - there is no general solution fitting every application.

Also, processing data directly in the DMA buffer is probably not recommended, unless you know you have plenty of time to do so. Otherwise copying to another buffer is faster than processing. Either way you have to make sure that the data stays protected from getting overwritten while sitting in the DMA buffer.

So one sensible way of implementing it could be:

  • DMA writes data to the buffer.
  • From DMA ISR, set a flag.
  • The background program is known to be fast enough to execute the code grabbing data from the DMA buffer until x amounts of DMA events have occurred threatening to overwrite the data.
  • Have the background program copy the data from the DMA buffer to a local store (double-buffering).
  • Process.

There's also a law of physics here: if the background program isn't fast enough to process the data in time, then no DMA driver design or queue system will salvage that situation. You have to either live with packet losses or find a way to speed up the background program.

Upvotes: 0

Related Questions