LPUART eDMA: Efficient asynch reception of bursty data with DMA

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

LPUART eDMA: Efficient asynch reception of bursty data with DMA

Jump to solution
1,261 Views
davenadler
Senior Contributor I

Background

For high-speed serial communications, what we do not want to do is take interrupts for every serial character received and chew up large amounts of CPU (and derange caches each interrupt). Thus, a common need for high-performance async reception is to receive data via DMA until one of:

  1. a buffer fills up, or
  2. the incoming line goes idle, or
  3. a specific end-of-line character is received (CR, LF, etc), or
  4. an infrequent higher-level poll requests whatever is available (this use case less common).

Example use-cases here are a GPS that blasts a stream of data then pauses, input streams delimited by CR/LF, and an RS485 9-bit slave node (yes I've read the RS-485 app note and software, doesn't seem to cover the GPS use case). When the line goes idle, collect any data already received without race conditions. The line-idle situation can be handled several ways:

  1. The DMA system can support the line-inactivity interrupt, for example generate a DMA completion interrupt on line-idle (with a bytes received count) and toggle to an alternate (ping-pong) buffer. But maybe the hardware can't do that...
  2. The DMA activity is never suspended and remains active indefinitely with ping-pong buffers. On line-idle interrupt the application takes any data received, and keeps track of how much it's received from the current buffer. Requires reading the DMA transfer count without too-bad race conditions (some DMA controllers don't reflect DMA count from controller to CPU registers while running).
  3. DMA is stopped on line inactivity interrupt (and immediately restarted using an alternate buffer). The application gets the count of data received from the suspended DMA action. Prone to both hardware and software race conditions (though I've had to do this a few times in past).

The iMXRT LPUART can generate a line-idle interrupt, but I don't see how it can be connected to the DMA system to force a transfer completion, so...

Question

What is the recommended approach for iMXRT (I'm using RT1024)?

Can any of these approaches be implemented using the LPUART and eDMA FSL libraries?

Thanks in advance for any guidance!
Best Regards, Dave

Labels (1)
Tags (3)
0 Kudos
1 Solution
1,095 Views
davenadler
Senior Contributor I

With LPUART and eDMA, the DMA system is not so easy to pause/resume or toggle. However it is still possible to get interrupts for line-idle or character-match even while the DMA is still active. So, I took the approach of taking those interrupts and returning what was already received via DMA, and leaving the DMA active. On DMA completion, skip returning any data already returned.

This is relatively simple and avoids any CPU overhead until there is interesting data to return, except in the case of DMA completion (buffer filled). Works great.

I wrapped this in an OS-agnostic class:

  • configurable LPUART, DMA channels and priority.
  • configurable match characters (I'm using LF for a couple peripheral streams).

A second FreeRTOS-specific class wraps the above with blocking until transmit is available.

If anyone is interested in the code, please find it attached...
Hope that helps,
Best Regards, Dave

View solution in original post

0 Kudos
5 Replies
1,096 Views
davenadler
Senior Contributor I

With LPUART and eDMA, the DMA system is not so easy to pause/resume or toggle. However it is still possible to get interrupts for line-idle or character-match even while the DMA is still active. So, I took the approach of taking those interrupts and returning what was already received via DMA, and leaving the DMA active. On DMA completion, skip returning any data already returned.

This is relatively simple and avoids any CPU overhead until there is interesting data to return, except in the case of DMA completion (buffer filled). Works great.

I wrapped this in an OS-agnostic class:

  • configurable LPUART, DMA channels and priority.
  • configurable match characters (I'm using LF for a couple peripheral streams).

A second FreeRTOS-specific class wraps the above with blocking until transmit is available.

If anyone is interested in the code, please find it attached...
Hope that helps,
Best Regards, Dave

0 Kudos
568 Views
alonbl
Contributor III

Hello @davenadler ,

I also need to solve the idle issue of LPUART during DMA transfer, amazing this was not considered while implementing the DMA hardware.

I would love if you can share your solution.

Thanks,

0 Kudos
534 Views
davenadler
Senior Contributor I

@alonbl- I've updated the solution to include the code.
Hope that helps you and other folks!
Happy 2024,
Best Regards, Dave

PS: Don't forget to click Kudos if this is helpful

0 Kudos
521 Views
alonbl
Contributor III

Happy new year @davenadler ,

 

Thank you so  much for your code!

 

I ended up taking a different approach.

 

I created two TCD that point to each other, then sample the TCDs in constant interval (so I won't get dynamic # of wakeups per remote behavior), I process the TCDs in FreeRTOS task including the partial one that is currently active.

This enables me to be deterministic and handle idle tail using eDMA without using the non-efficient NXP transfer implementation and adhere to the priority of the FreeRTOS task.

 

Regards,

0 Kudos
1,217 Views
Miguel04
NXP TechSupport
NXP TechSupport

Hi @davenadler 

I recommend you to look into chapter 6.4 from the RT1024 reference manual, specially the 6.4.1 DMA initialization, 6.4.2 programming errors, 6.4.4 transfer examples and 6.4.8 suspend/resume DMA channel, this chapters could give you some approaches to use the DMA. Also, the SDK has numerous examples using the DMA. 

Best Regards, Miguel.

0 Kudos