DMA Libraries for Teensy?

clinker8

Well-known member
I've used ZeroDMA from Adafruit before on an M4 chip.

Are there any DMA libraries for Teensy's? If so, what is the name? Didn't see anything with DMA in the name in the /teensy/avr/libraries area. I'm thinking about running the ADC fast and using DMA for it.
Got any resources on this? Thanks. My use would be for T4.1, since that is what I have.
 
Built into core is the building block for DMA. Or at least the one I use.
There are files: DMAChannel.h and .cpp in both the teensy3 and teensy4 directories.

As @defragster mentioned, there is a lot of information in that thread.

There is/was a DMA library setup for SPI ( https://github.com/crteensy/DmaSpi)
But I don't believe it was ever updated to run with T4.x and last change to it, was like 5 years ago.

Note: the SPI library has examples using the DMAChannel stuff with the asynchronous version of the transfer.
Likewise, many of our display libraries have code in them using this.

As for more specific help, might help to know things like: From what to what? for example is it from/to SPI from memory? Or some other device, or memory to memory?
How much?

Do you want it be continuous or one shot? Do you want interrupts? And if so in what cases.
 
More examples of DMA usage in libraries Audio, SmartMatrix, OctoWS2811, WS2812Serial, ST7735_t3, ILI9488_t3.

If you want your code or library to work together with others that also use DMA, it's important to create an instance of DMAChannel to allocate the which of the 32 channels you will actually use. You can use the DMAChannel convenience functions (look at comments in DMAChannel.h for docs) or you can directly control the TCD registers. Use of the TCD registers gives you full control over the hardware's capabilities. If you look at the various DMA-based libraries, you'll see many of them do this. But all create an instance of DMAChannel to get the pointer to the TCD registers, which prevents conflicts between libraries which could otherwise attempt to use the same channel.
 
Built into core is the building block for DMA. Or at least the one I use.
There are files: DMAChannel.h and .cpp in both the teensy3 and teensy4 directories.

As @defragster mentioned, there is a lot of information in that thread.

There is/was a DMA library setup for SPI ( https://github.com/crteensy/DmaSpi)
But I don't believe it was ever updated to run with T4.x and last change to it, was like 5 years ago.

Note: the SPI library has examples using the DMAChannel stuff with the asynchronous version of the transfer.
Likewise, many of our display libraries have code in them using this.

As for more specific help, might help to know things like: From what to what? for example is it from/to SPI from memory? Or some other device, or memory to memory?
How much?

Do you want it be continuous or one shot? Do you want interrupts? And if so in what cases.

I don't have any of the Teensy 3.X's for which this would be really nice, due to the better ADC than in the 4.1, but was thinking of something similar to the following:
Set up internal ADC to sample at a known rate, oh, how about 60 KHz. Have the DMA get triggered by a timer and transfer 1K samples to a buffer. After the buffer was filled, a second channel would be triggered, which moves 1K samples to a different buffer, basically forming a ping pong buffer. The ADC would run continuously at 60KHz, depositing data in the alternate buffers.

Ideally, I need to know which buffer is getting filled, and optionally, how much time is left before the switch. I think if the DMA were chained, I would just need to know when the block of 1K samples started (or more likely, when the block completed). So one interrupt per block transfer. So while one buffer was filling, the other buffer could be processed. Kind of simple, because at least for me, simple allows me to finish it!
 
More examples of DMA usage in libraries Audio, SmartMatrix, OctoWS2811, WS2812Serial, ST7735_t3, ILI9488_t3.

If you want your code or library to work together with others that also use DMA, it's important to create an instance of DMAChannel to allocate the which of the 32 channels you will actually use. You can use the DMAChannel convenience functions (look at comments in DMAChannel.h for docs) or you can directly control the TCD registers. Use of the TCD registers gives you full control over the hardware's capabilities. If you look at the various DMA-based libraries, you'll see many of them do this. But all create an instance of DMAChannel to get the pointer to the TCD registers, which prevents conflicts between libraries which could otherwise attempt to use the same channel.

Yes, thanks. Definitely want to create an instance of DMAChannel. DMA is hard enough to get it to run, without stomping on someone else's registers! I managed to get this sort of thing to work on an Adafruit M4 based system, but would like to get one going on a Teensy. The nomenclature in the NxP docs is quite hard to follow. Glad to have at least a couple of examples to look at.
 
I don't have any of the Teensy 3.X's for which this would be really nice, due to the better ADC than in the 4.1, but was thinking of something similar to the following:
Set up internal ADC to sample at a known rate, oh, how about 60 KHz. Have the DMA get triggered by a timer and transfer 1K samples to a buffer. After the buffer was filled, a second channel would be triggered, which moves 1K samples to a different buffer, basically forming a ping pong buffer. The ADC would run continuously at 60KHz, depositing data in the alternate buffers.

Ideally, I need to know which buffer is getting filled, and optionally, how much time is left before the switch. I think if the DMA were chained, I would just need to know when the block of 1K samples started (or more likely, when the block completed). So one interrupt per block transfer. So while one buffer was filling, the other buffer could be processed. Kind of simple, because at least for me, simple allows me to finish it!
Two examples both using the ADC library:

The one I wrote when we were helping to port the ADC library to run on T4.x.
examples->ADC->adc_timer_dma

That each DMA operation is triggered by a timer, for example it is setup to do 3000 reads per second on each of the two ADCs.

Second place I played around with, was a well monitoring system that I will never complete. When the well is working right, I don't feel a need for it, and when it breaks, I get started on it again ;)
https://github.com/kurte/wellmonitor

In this program, I have 4 passive-current sensors (https://www.sparkfun.com/products/11005) which I have the coils around 4 circuits in my pump house. one each to the two Wells, 3rd one to pressure pump, and 4th to heater. I was simply trying compute how power (actually more like if in power) was going to each of these circuits and log it.

In the currentSensor code, I have it use an IntervalTimer to start up a DMA read on both ADCs for two of the circuits.
I believe I do something like 3000 reads on each channel, and then on the next next interval, I change the DMA memory buffer and which pins to look at and start it up again
and process the data retrieved by the previous operation.

Not sure if either of these are exactly what you are looking for, but hopefully gives you some ideas.
 
Set up internal ADC to sample at a known rate, oh, how about 60 KHz. Have the DMA get triggered by a timer and transfer 1K samples to a buffer. After the buffer was filled, a second channel would be triggered, which moves 1K samples to a different buffer, basically forming a ping pong buffer. The ADC would run continuously at 60KHz, depositing data in the alternate buffers.

ADC support for Teensy 4 in the Audio library does essentially this, but at 176.4 kHz, and with a FIR filter low-pass filter to decimate down to 44.1 kHz. Lots of useful code in there, probably most of what you need.

Instead of ping-ping between 2 buffers, the DMA is configured for interrupt at half and complete full on a buffer twice the size of data processed on each interrupt, which achieves the same thing as ping-ping but more efficiently. Many of the other libraries using DMA also use that half full interrupt to implement the equivalent of 2 buffer ping-pong.
 
ADC support for Teensy 4 in the Audio library does essentially this, but at 176.4 kHz, and with a FIR filter low-pass filter to decimate down to 44.1 kHz. Lots of useful code in there, probably most of what you need.

Instead of ping-ping between 2 buffers, the DMA is configured for interrupt at half and complete full on a buffer twice the size of data processed on each interrupt, which achieves the same thing as ping-ping but more efficiently. Many of the other libraries using DMA also use that half full interrupt to implement the equivalent of 2 buffer ping-pong.

Thanks again. Have a lot of reading to do! I used a ping pong with chained DMAs in the past, worked out ok. The buffers were adjacent anyways, so sort of equivalent. I will read through the library and hope that enough of it sticks so I can give it a go.
 
Back
Top