use Teensy 3.1 DMA to send sine wave to DAC, timed by PDB

Dependencies:   USBDevice mbed

Example of using Teensy 3.1 DMA to send sine wave value to DAC timed by PDB, based on https://forum.pjrc.com/threads/28101-Using-the-DAC-with-DMA-on-Teensy-3-1

you can jumper DAC to A0 and sample the output or view with scope.

main.cpp

Committer:
manitou
Date:
2015-10-05
Revision:
0:a57be408001f

File content as of revision 0:a57be408001f:

// DMA output to DAC controlled by PDB   
// https://forum.pjrc.com/threads/28101-Using-the-DAC-with-DMA-on-Teensy-3-1

#include "mbed.h"
#include "USBSerial.h"

#define PRREG(x) pc.printf(#x" 0x%0x\n",x)

USBSerial  pc;          // Virtual serial port over USB

#define PDB_CONFIG (PDB_SC_TRGSEL(15) | PDB_SC_PDBEN_MASK | PDB_SC_CONT_MASK | PDB_SC_PDBIE_MASK | PDB_SC_DMAEN_MASK)
// 48mhz bus   128 khz
#define PDB_PERIOD (375-1)

#define CHNL 0
#define DMAMUX_SOURCE_PDB       48

AnalogIn adc(A0);


static volatile uint16_t sinetable[] = {
   2047,    2147,    2248,    2348,    2447,    2545,    2642,    2737,
   2831,    2923,    3012,    3100,    3185,    3267,    3346,    3422,
   3495,    3564,    3630,    3692,    3750,    3804,    3853,    3898,
   3939,    3975,    4007,    4034,    4056,    4073,    4085,    4093,
   4095,    4093,    4085,    4073,    4056,    4034,    4007,    3975,
   3939,    3898,    3853,    3804,    3750,    3692,    3630,    3564,
   3495,    3422,    3346,    3267,    3185,    3100,    3012,    2923,
   2831,    2737,    2642,    2545,    2447,    2348,    2248,    2147,
   2047,    1948,    1847,    1747,    1648,    1550,    1453,    1358,
   1264,    1172,    1083,     995,     910,     828,     749,     673,
    600,     531,     465,     403,     345,     291,     242,     197,
    156,     120,      88,      61,      39,      22,      10,       2,
      0,       2,      10,      22,      39,      61,      88,     120,
    156,     197,     242,     291,     345,     403,     465,     531,
    600,     673,     749,     828,     910,     995,    1083,    1172,
   1264,    1358,    1453,    1550,    1648,    1747,    1847,    1948,
};

int main() {
    wait(2.0);
    pc.printf("SystemCoreClock %d  %s %s\n",SystemCoreClock,__TIME__,__DATE__);
  // DAC init
  SIM->SCGC2 |= SIM_SCGC2_DAC0_MASK; // enable DAC clock
  DAC0->C0 = DAC_C0_DACEN_MASK | DAC_C0_DACRFS_MASK; // enable the DAC module, 3.3V reference
  // slowly ramp up to DC voltage, approx 1/4 second
  for (int16_t i=0; i<2048; i+=8) {
    *(int16_t *)&(DAC0->DAT[0]) = i;  
    wait(0.001);
  }
  
  // PDB init  set the programmable delay block to trigger DMA requests
  SIM->SCGC6 |= SIM_SCGC6_PDB_MASK; // enable PDB clock
  PDB0->IDLY = 0; // interrupt delay register
  PDB0->MOD = PDB_PERIOD; // modulus register, sets period
  PDB0->SC = PDB_CONFIG | PDB_SC_LDOK_MASK; // load registers from buffers
  PDB0->SC = PDB_CONFIG | PDB_SC_SWTRIG_MASK; // reset and restart
  PDB0->CH[0].C1 = 0x0101; // enable PDB

  // DMA init  continuous loop
  SIM->SCGC7 |= SIM_SCGC7_DMA_MASK;       // DMA clock
  SIM->SCGC6 |= SIM_SCGC6_DMAMUX_MASK;    // Enable clock to DMA mux
  DMAMUX->CHCFG[CHNL] = DMAMUX_CHCFG_ENBL_MASK | /*DMAMUX_CHCFG_TRIG_MASK |*/
    DMAMUX_CHCFG_SOURCE(DMAMUX_SOURCE_PDB);  // associate DMA channel with PDB trigger
  int bytes = sizeof(sinetable);
  DMA0->CR = DMA_CR_EMLM_MASK | DMA_CR_EDBG_MASK;  // ? needed for circular
  DMA0->CERQ = CHNL;   //disable channel
  DMA0->CERR = CHNL;    // clear errors on channel
  DMA0->TCD[CHNL].SADDR = (uint32_t)sinetable;
  DMA0->TCD[CHNL].SOFF = 2;
  DMA0->TCD[CHNL].ATTR = DMA_ATTR_SSIZE(1) | DMA_ATTR_DSIZE(1);  //16-bit
  DMA0->TCD[CHNL].NBYTES_MLNO = 2;
  DMA0->TCD[CHNL].SLAST = -bytes;
  DMA0->TCD[CHNL].DADDR = (uint32_t)&(DAC0->DAT[0]);
  DMA0->TCD[CHNL].DOFF = 0;
  DMA0->TCD[CHNL].CITER_ELINKYES = bytes/2;
  DMA0->TCD[CHNL].DLAST_SGA = 0;
  DMA0->TCD[CHNL].BITER_ELINKYES = bytes/2;

  DMA0->SERQ = CHNL;  // enable
#if 0
  PRREG(SIM->SCGC2);
  PRREG(SIM->SCGC6);
  PRREG(SIM->SCGC7);
  PRREG(PDB0->MOD);
  PRREG(DMAMUX->CHCFG[CHNL]);
  PRREG(DAC0->C0);
  PRREG(DMA0->CR);
  PRREG(DMA0->TCD[CHNL].CSR);
  PRREG(DMA0->TCD[CHNL].ATTR);
  PRREG(DMA0->TCD[CHNL].SOFF);
  PRREG(DMA0->TCD[CHNL].DOFF);
  PRREG(DMA0->TCD[CHNL].NBYTES_MLNO);
  PRREG(DMA0->TCD[CHNL].BITER_ELINKYES);
  PRREG(DMA0->TCD[CHNL].CITER_ELINKYES);
  PRREG(DMA0->TCD[CHNL].SLAST);
  PRREG(DMA0->TCD[CHNL].DLAST_SGA);
  PRREG(DMA0->TCD[CHNL].SADDR);
  PRREG(DMA0->TCD[CHNL].DADDR);
  //while(1);
#endif

  while(1) {
      pc.printf("%d\n",adc.read_u16());  // sample DAC output, jumper DAC to A0
  }
}