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:
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:
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
Solved! Go to Solution.
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:
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
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:
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
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,
@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
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,
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.