Using PDB to time DMA transfers

Status
Not open for further replies.

mborgerson

Well-known member
In a different thread I asked about sending a DMA transfer > 32K bytes---which doesn't seem to be supported by the DMAChannel object.
I postponed investigation of large transfers and switched to sending my video frame line-by line using an intervaltimer to send a new line each 64 microseconds. To get a clean display on my video monitor, I need to send the video with consistent timing at about 6MHz.

I solved the timing problem by using the PDB to trigger the DMA transfers. There are some other examples out there, but they mainly concern the use of the PDB for transfer to a DAC or from an ADC. Setting those things up adds a lot of complexity to the PDB setup.
I wrote a simple sketch that uses the PDB to transfer a buffer of bytes to the low byte of GPIOD using a dmachannel.


View attachment PDB_Test_clean.ino
 
I could have sworn that I gave you some suggestions on how to setup a DMA transfer > 32K
That is you want to output something like 110,040 bytes, which won't fit into 32768... but you can chain the settings...

For example: You have: DMAChannel dma0;

What you might need is something like:
Code:
 DMAChannel dma0;
 DMASetting DMASettings[4];  // need to split to 4 settings...

  dma0.disable();

 // Setup to do the first set.
  #define CNT_PER_SETTING 27510
  DMASettings[0].sourceBuffer(&dmabuff[0*CNT_PER_SETTING ], CNT_PER_SETTING );
  DMASettings[0].destination(GPIOD_PDORBL); 
  DMASettings[0].replaceSettinsOnCompletion(&DMASettings[1]);

  DMASettings[1].sourceBuffer(&dmabuff[1*CNT_PER_SETTING ], CNT_PER_SETTING );
  DMASettings[1].destination(GPIOD_PDORBL); 
  DMASettings[1].replaceSettinsOnCompletion(&DMASettings[2]);

  DMASettings[2].sourceBuffer(&dmabuff[2*CNT_PER_SETTING ], CNT_PER_SETTING );
  DMASettings[2].destination(GPIOD_PDORBL); 
  DMASettings[2].replaceSettinsOnCompletion(&DMASettings[3]);

  DMASettings[3].sourceBuffer(&dmabuff[3*CNT_PER_SETTING ], CNT_PER_SETTING );
  DMASettings[3].destination(GPIOD_PDORBL); 
  DMASettings[3].replaceSettinsOnCompletion(&DMASettings[0]);
  DMASettings[3].disableOnCompletion();

  dma0 = DMASettings[0];

  // Use the PDB to trigger each DMA transfer
  dma0.triggerAtHardwareEvent(DMAMUX_SOURCE_PDB);
  dma0.enable();

Note: typed in (including cut/paste) so could be things missing or mistyped, but hopefully shows you how it can be done...

Or another alternative, was to just have the DMA stuff output some of it, add in a interruptOnCompletion and have your interrupt handler set it self up to continue and then restart the dma...
 
I'm trying to keep my code as simple as possible---and that means doing the DMA with one transaction. The eventual goal is to continuously output data from a video frame buffer as is done in the DMA DAC video example. From my reading of the KINETIS manual, it seems that dma output >32K should be possible when there is no minor loop. However, the dmaChannel object does not allow that option. It simply returns with no action if the request is larger than 32K---without checking to see if there is a minor loop or not. I'll be out of town for about 10 days, but will continue investigating when I return.

Since I'm sending NTSC video, I can't arbitrarily interrupt the data stream in the middle of a frame without video glitches, so the idea of using an interrupt handler to trigger DMA at an arbitrary point in the buffer may be problematic. I have successfully output video by using an IntervalTimer with high priority triggering DMA at the start of line of video. The PDB is used as the DMA trigger.
 
Good luck. Hope it works for you.

Kurt

FYI - The posting I did in #2 does doe the whole thing in one DMA transaction... It is simply using the scatter/gather part of the DMA engine.
That is it is setting up the DMA_TCDn_DLASTSGA ... (register is defined in 24.3.29)... The above setup is setting up the chain of TCDs for the transfer, and setting up the DMA to start off using the contents of the first TCD. When the DMA engine completes the transfers as described in the TCD, if the DLASTSGA value is set, the DMA engine internally replaces the current TCD with the value in that register and continues, all internal to the DMA engine....
 
Status
Not open for further replies.
Back
Top