use Teensy 3.1 DMA to send sine wave to DAC, timed by PDB
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@0:a57be408001f, 2015-10-05 (annotated)
- Committer:
- manitou
- Date:
- Mon Oct 05 14:23:37 2015 +0000
- Revision:
- 0:a57be408001f
use DMA to output sine wave to DAC, timed by PDB
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
manitou | 0:a57be408001f | 1 | // DMA output to DAC controlled by PDB |
manitou | 0:a57be408001f | 2 | // https://forum.pjrc.com/threads/28101-Using-the-DAC-with-DMA-on-Teensy-3-1 |
manitou | 0:a57be408001f | 3 | |
manitou | 0:a57be408001f | 4 | #include "mbed.h" |
manitou | 0:a57be408001f | 5 | #include "USBSerial.h" |
manitou | 0:a57be408001f | 6 | |
manitou | 0:a57be408001f | 7 | #define PRREG(x) pc.printf(#x" 0x%0x\n",x) |
manitou | 0:a57be408001f | 8 | |
manitou | 0:a57be408001f | 9 | USBSerial pc; // Virtual serial port over USB |
manitou | 0:a57be408001f | 10 | |
manitou | 0:a57be408001f | 11 | #define PDB_CONFIG (PDB_SC_TRGSEL(15) | PDB_SC_PDBEN_MASK | PDB_SC_CONT_MASK | PDB_SC_PDBIE_MASK | PDB_SC_DMAEN_MASK) |
manitou | 0:a57be408001f | 12 | // 48mhz bus 128 khz |
manitou | 0:a57be408001f | 13 | #define PDB_PERIOD (375-1) |
manitou | 0:a57be408001f | 14 | |
manitou | 0:a57be408001f | 15 | #define CHNL 0 |
manitou | 0:a57be408001f | 16 | #define DMAMUX_SOURCE_PDB 48 |
manitou | 0:a57be408001f | 17 | |
manitou | 0:a57be408001f | 18 | AnalogIn adc(A0); |
manitou | 0:a57be408001f | 19 | |
manitou | 0:a57be408001f | 20 | |
manitou | 0:a57be408001f | 21 | static volatile uint16_t sinetable[] = { |
manitou | 0:a57be408001f | 22 | 2047, 2147, 2248, 2348, 2447, 2545, 2642, 2737, |
manitou | 0:a57be408001f | 23 | 2831, 2923, 3012, 3100, 3185, 3267, 3346, 3422, |
manitou | 0:a57be408001f | 24 | 3495, 3564, 3630, 3692, 3750, 3804, 3853, 3898, |
manitou | 0:a57be408001f | 25 | 3939, 3975, 4007, 4034, 4056, 4073, 4085, 4093, |
manitou | 0:a57be408001f | 26 | 4095, 4093, 4085, 4073, 4056, 4034, 4007, 3975, |
manitou | 0:a57be408001f | 27 | 3939, 3898, 3853, 3804, 3750, 3692, 3630, 3564, |
manitou | 0:a57be408001f | 28 | 3495, 3422, 3346, 3267, 3185, 3100, 3012, 2923, |
manitou | 0:a57be408001f | 29 | 2831, 2737, 2642, 2545, 2447, 2348, 2248, 2147, |
manitou | 0:a57be408001f | 30 | 2047, 1948, 1847, 1747, 1648, 1550, 1453, 1358, |
manitou | 0:a57be408001f | 31 | 1264, 1172, 1083, 995, 910, 828, 749, 673, |
manitou | 0:a57be408001f | 32 | 600, 531, 465, 403, 345, 291, 242, 197, |
manitou | 0:a57be408001f | 33 | 156, 120, 88, 61, 39, 22, 10, 2, |
manitou | 0:a57be408001f | 34 | 0, 2, 10, 22, 39, 61, 88, 120, |
manitou | 0:a57be408001f | 35 | 156, 197, 242, 291, 345, 403, 465, 531, |
manitou | 0:a57be408001f | 36 | 600, 673, 749, 828, 910, 995, 1083, 1172, |
manitou | 0:a57be408001f | 37 | 1264, 1358, 1453, 1550, 1648, 1747, 1847, 1948, |
manitou | 0:a57be408001f | 38 | }; |
manitou | 0:a57be408001f | 39 | |
manitou | 0:a57be408001f | 40 | int main() { |
manitou | 0:a57be408001f | 41 | wait(2.0); |
manitou | 0:a57be408001f | 42 | pc.printf("SystemCoreClock %d %s %s\n",SystemCoreClock,__TIME__,__DATE__); |
manitou | 0:a57be408001f | 43 | // DAC init |
manitou | 0:a57be408001f | 44 | SIM->SCGC2 |= SIM_SCGC2_DAC0_MASK; // enable DAC clock |
manitou | 0:a57be408001f | 45 | DAC0->C0 = DAC_C0_DACEN_MASK | DAC_C0_DACRFS_MASK; // enable the DAC module, 3.3V reference |
manitou | 0:a57be408001f | 46 | // slowly ramp up to DC voltage, approx 1/4 second |
manitou | 0:a57be408001f | 47 | for (int16_t i=0; i<2048; i+=8) { |
manitou | 0:a57be408001f | 48 | *(int16_t *)&(DAC0->DAT[0]) = i; |
manitou | 0:a57be408001f | 49 | wait(0.001); |
manitou | 0:a57be408001f | 50 | } |
manitou | 0:a57be408001f | 51 | |
manitou | 0:a57be408001f | 52 | // PDB init set the programmable delay block to trigger DMA requests |
manitou | 0:a57be408001f | 53 | SIM->SCGC6 |= SIM_SCGC6_PDB_MASK; // enable PDB clock |
manitou | 0:a57be408001f | 54 | PDB0->IDLY = 0; // interrupt delay register |
manitou | 0:a57be408001f | 55 | PDB0->MOD = PDB_PERIOD; // modulus register, sets period |
manitou | 0:a57be408001f | 56 | PDB0->SC = PDB_CONFIG | PDB_SC_LDOK_MASK; // load registers from buffers |
manitou | 0:a57be408001f | 57 | PDB0->SC = PDB_CONFIG | PDB_SC_SWTRIG_MASK; // reset and restart |
manitou | 0:a57be408001f | 58 | PDB0->CH[0].C1 = 0x0101; // enable PDB |
manitou | 0:a57be408001f | 59 | |
manitou | 0:a57be408001f | 60 | // DMA init continuous loop |
manitou | 0:a57be408001f | 61 | SIM->SCGC7 |= SIM_SCGC7_DMA_MASK; // DMA clock |
manitou | 0:a57be408001f | 62 | SIM->SCGC6 |= SIM_SCGC6_DMAMUX_MASK; // Enable clock to DMA mux |
manitou | 0:a57be408001f | 63 | DMAMUX->CHCFG[CHNL] = DMAMUX_CHCFG_ENBL_MASK | /*DMAMUX_CHCFG_TRIG_MASK |*/ |
manitou | 0:a57be408001f | 64 | DMAMUX_CHCFG_SOURCE(DMAMUX_SOURCE_PDB); // associate DMA channel with PDB trigger |
manitou | 0:a57be408001f | 65 | int bytes = sizeof(sinetable); |
manitou | 0:a57be408001f | 66 | DMA0->CR = DMA_CR_EMLM_MASK | DMA_CR_EDBG_MASK; // ? needed for circular |
manitou | 0:a57be408001f | 67 | DMA0->CERQ = CHNL; //disable channel |
manitou | 0:a57be408001f | 68 | DMA0->CERR = CHNL; // clear errors on channel |
manitou | 0:a57be408001f | 69 | DMA0->TCD[CHNL].SADDR = (uint32_t)sinetable; |
manitou | 0:a57be408001f | 70 | DMA0->TCD[CHNL].SOFF = 2; |
manitou | 0:a57be408001f | 71 | DMA0->TCD[CHNL].ATTR = DMA_ATTR_SSIZE(1) | DMA_ATTR_DSIZE(1); //16-bit |
manitou | 0:a57be408001f | 72 | DMA0->TCD[CHNL].NBYTES_MLNO = 2; |
manitou | 0:a57be408001f | 73 | DMA0->TCD[CHNL].SLAST = -bytes; |
manitou | 0:a57be408001f | 74 | DMA0->TCD[CHNL].DADDR = (uint32_t)&(DAC0->DAT[0]); |
manitou | 0:a57be408001f | 75 | DMA0->TCD[CHNL].DOFF = 0; |
manitou | 0:a57be408001f | 76 | DMA0->TCD[CHNL].CITER_ELINKYES = bytes/2; |
manitou | 0:a57be408001f | 77 | DMA0->TCD[CHNL].DLAST_SGA = 0; |
manitou | 0:a57be408001f | 78 | DMA0->TCD[CHNL].BITER_ELINKYES = bytes/2; |
manitou | 0:a57be408001f | 79 | |
manitou | 0:a57be408001f | 80 | DMA0->SERQ = CHNL; // enable |
manitou | 0:a57be408001f | 81 | #if 0 |
manitou | 0:a57be408001f | 82 | PRREG(SIM->SCGC2); |
manitou | 0:a57be408001f | 83 | PRREG(SIM->SCGC6); |
manitou | 0:a57be408001f | 84 | PRREG(SIM->SCGC7); |
manitou | 0:a57be408001f | 85 | PRREG(PDB0->MOD); |
manitou | 0:a57be408001f | 86 | PRREG(DMAMUX->CHCFG[CHNL]); |
manitou | 0:a57be408001f | 87 | PRREG(DAC0->C0); |
manitou | 0:a57be408001f | 88 | PRREG(DMA0->CR); |
manitou | 0:a57be408001f | 89 | PRREG(DMA0->TCD[CHNL].CSR); |
manitou | 0:a57be408001f | 90 | PRREG(DMA0->TCD[CHNL].ATTR); |
manitou | 0:a57be408001f | 91 | PRREG(DMA0->TCD[CHNL].SOFF); |
manitou | 0:a57be408001f | 92 | PRREG(DMA0->TCD[CHNL].DOFF); |
manitou | 0:a57be408001f | 93 | PRREG(DMA0->TCD[CHNL].NBYTES_MLNO); |
manitou | 0:a57be408001f | 94 | PRREG(DMA0->TCD[CHNL].BITER_ELINKYES); |
manitou | 0:a57be408001f | 95 | PRREG(DMA0->TCD[CHNL].CITER_ELINKYES); |
manitou | 0:a57be408001f | 96 | PRREG(DMA0->TCD[CHNL].SLAST); |
manitou | 0:a57be408001f | 97 | PRREG(DMA0->TCD[CHNL].DLAST_SGA); |
manitou | 0:a57be408001f | 98 | PRREG(DMA0->TCD[CHNL].SADDR); |
manitou | 0:a57be408001f | 99 | PRREG(DMA0->TCD[CHNL].DADDR); |
manitou | 0:a57be408001f | 100 | //while(1); |
manitou | 0:a57be408001f | 101 | #endif |
manitou | 0:a57be408001f | 102 | |
manitou | 0:a57be408001f | 103 | while(1) { |
manitou | 0:a57be408001f | 104 | pc.printf("%d\n",adc.read_u16()); // sample DAC output, jumper DAC to A0 |
manitou | 0:a57be408001f | 105 | } |
manitou | 0:a57be408001f | 106 | } |
manitou | 0:a57be408001f | 107 |