Max DMA Buffer Size ?

Status
Not open for further replies.

Jp3141

Well-known member
I am trying to build an arbitrary waveform generator by using DMA to drive the DAC diretly from a table in (flash) memory. I need at least 50,000 points. My code works with < 32767 points, but not more. I can't quite understand in the Kinetis docs if this is a limitation of the DMA engine, or just the DMA library in Teensy.

For reference, here's my code:

Code:
#include <DMAChannel.h>
// DAC on pin A14 
#define LED 13
#include "kinetis.h"

#include "wave.h"

// Multiple input & output objects use the Programmable Delay Block
// to set their sample rate.  They must all configure the same
// period to avoid chaos.

#define PDB_CONFIG (PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | PDB_SC_CONT | PDB_SC_PDBIE | PDB_SC_DMAEN)

// 128 samples; PDB_Period = F_BUS/(128*1kHz)
#if F_BUS == 6*1000*10000
  #define PDB_PERIOD (468-1)
#elif F_BUS == 56*1000*1000
  #define PDB_PERIOD (437-1)
#elif F_BUS == 48*1000*1000
  #define PDB_PERIOD (375-1)
#elif F_BUS == 36*1000*1000
  #define PDB_PERIOD (281-1)
#elif F_BUS == 24*1000*1000
 #define PDB_PERIOD (187-1)
#elif F_BUS == 16*1000*1000
  #define PDB_PERIOD (125-1)
#else
  #error "Unsupported F_BUS speed"
#endif

DMAChannel dma(false);

// not much point in updating the DAC faster than 1 us
#define FSTEP (1*1000*1000)

void setup() {
  Serial.begin(0);  
  while (!Serial);
  pinMode(0, OUTPUT);
  Serial.println(__FILE__ " " __DATE__ " " __TIME__);
  Serial.printf("Arbitrary Wave Generator, Step F = %i\n\n", FSTEP);
  
  dma.begin(true); // allocate the DMA channel first
  pinMode(LED, OUTPUT);  
  SIM_SCGC2 |= SIM_SCGC2_DAC0; // enable DAC clock
  DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // enable the DAC module, 3.3V reference
 
  // set the programmable delay block to trigger DMA requests
  SIM_SCGC6 |= SIM_SCGC6_PDB; // enable PDB clock
  PDB0_IDLY = 0; // interrupt delay register
  PDB0_MOD = F_BUS/FSTEP-1; // modulus register, sets period

  Serial.printf("FBUS = %6i, PDB0_MOD = %6i (+1)\n", F_BUS, F_BUS/FSTEP-1);

  PDB0_SC = PDB_CONFIG | PDB_SC_LDOK; // load registers from buffers
  PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG; // reset and restart
  PDB0_CH0C1 = 0x0101; // channel n control register?
[U]//  dma.sourceBuffer(WiringWave, sizeof(WiringWave));  // Doesn't work if > 65534
  dma.sourceBuffer(WiringWave, 65534);[/U]
  Serial.printf("Waveform size = %i\n", sizeof(WiringWave));
  dma.destination(*(volatile uint16_t *)&(DAC0_DAT0L));
  dma.triggerAtHardwareEvent(DMAMUX_SOURCE_PDB);
  digitalWrite(LED, HIGH);
  dma.enable();
}




void loop() {
}

andf the waveform is defined like this:

Code:
static const uint16_t WiringWave[] = {
1780,
1755,
1727,
1696,
1666,
.
.  // for ~ 50,000 total samples
.
.

1635,
1608,
1582,
1030};
 
The DAC has a ring buffer which can hold up to 16 words. It allows to trigger 1 DMA request to fill the lower half while the upper half is read and vice versa. This would allow to organize the lookup table as arrays[8] und thus reduce the # of table elements to <7000. Another thing is that transferring 8 words with one single DMA request is ways more efficient than transferring a single word at onc.
 
Thanks. With 16 word loops, does this still pump data to the DAC at a uniform and constant rate, or does it go in bursts ?
 
I am trying to build an arbitrary waveform generator by using DMA to drive the DAC diretly from a table in (flash) memory. I need at least 50,000 points. My code works with < 32767 points, but not more. I can't quite understand in the Kinetis docs if this is a limitation of the DMA engine, or just the DMA library in Teensy.

AFAIK, general DMA buffers are in RAM, which is rather limited (RAM inT3.1 is also smaller than T3.2).
I would for constant waveform DAC hack the DMAChannel library and pass Flash memory as source buffer.

(obviously you cannot use Flash for destination buffers, but you could Flash for source buffers)
 
Thanks. With 16 word loops, does this still pump data to the DAC at a uniform and constant rate, or does it go in bursts ?
The approach is slightly different. You use the PDB to directly trigger the DAC output at constant rate. Its hardware ring buffer does then (if the appropriate flags are set) raise either interrupts or DMA requests (your choice) when the read pointer of the ring buffer reaches specific values. When it reaches for example the top position, a DMA request will refill the 8 bottom words, and when it reaches the Watermark position (configurable from 1 to 4 away from the bottom position) another DMA request will refill the top 8 words.
 
Status
Not open for further replies.
Back
Top