Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 5 of 5

Thread: 2 DMA channels with 2 DACs and variable output for electric fish bait

  1. #1
    Junior Member
    Join Date
    Apr 2019
    Posts
    3

    2 DMA channels with 2 DACs and variable output for electric fish bait

    Hello everybody,
    I'm using both DACs of the teensy 3.5 to emit short biphasic pulses. These pulses are recorded signals from weakly electric fish and are pretty fast (ca. 0.5ms duration). I want to build a little battery-driven playback device that emits these signals to lure weakly electric fish into minnow traps in the swamp

    To extend the output voltage range, I split the positive and negative phase of the pulse, stored them in arrays and feed them to the DACs (currently at 100 kHz) for 5 seconds and then put the teensy to deepSleep for 5 seconds to save battery life. Also, I use the teensy 3.5 at CPU speed of 24 mHz to save energy.
    I would like to make the playback more variable, e.g. vary the amplitude and intervals between pulses. I'm still learning a lot about programming and the code that I use is honestly mostly copy-pasted from this post: https://forum.pjrc.com/threads/48457...-on-Teensy-3-6

    I would like to ask for advice, how to best achieve a variable output at min. 100kHz. I thought that I probably needed a dynamic buffer in which I store the variable pulses (e.g. pulseArray * someFactor) and append a pause (Array with zeroes) that will be fed to the DACs but I don't know yet how to best do this.

    Here is the code that I use:
    Code:
    #include <Snooze.h>
    #include <SnoozeBlock.h>
    #define ARM_MATH_CM4
    #include <DMAChannel.h>
    #define PDB_CONFIG     (PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | PDB_SC_PDBIE | PDB_SC_CONT | PDB_SC_DMAEN)
    
    //configure snooze driver and install it
    SnoozeTimer timer;
    SnoozeBlock config(timer);
    
    static volatile uint16_t posphase[] = {
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
      0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 2, 4, 4, 6, 6, 10, 10, 10, 12, 16, 16, 18, 18, 22, 26, 28, 28, 32, 38, 42, 46, 50, 58, 64, 74, 78, 88, 98, 110, 120, 134, 148, 
      168, 186, 208, 232, 262, 296, 332, 372, 416, 468, 522, 582, 648, 720, 798, 880, 966, 1058, 1158, 1260, 1368, 1498, 1666, 1890, 2180, 2516, 2832, 3048, 3114, 
      3026, 2816, 2490, 2052, 1470,
    };
    
    static volatile uint16_t negphase[] = {
      270, 1292, 2250, 3032, 3582, 3918, 4078, 4095, 3984, 3752, 3412, 2984, 2508, 2024, 1570, 1182, 872, 640, 466, 338, 244, 180, 134, 100, 72, 52, 38, 30, 18, 10, 
      6, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    };
    
    
    
    // DMA for ADC
    DMAChannel dma1(false);
    DMAChannel dma2(false);
    
    // Set fs - the sampling frequency at 100kHz
    const uint32_t pdb_freq = 100000; 
    
    // Setup PDB at pdb_freq
    void setup_pdb() {
      uint32_t mod = (F_BUS / pdb_freq);
        
      PDB0_MOD = (uint16_t)(mod-1);  
      PDB0_IDLY = 0;
      PDB0_SC = PDB_CONFIG | PDB_SC_LDOK;
      PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG;
      PDB0_CH0C1 = 0x0101;
    }
    
    // Setup DMA for DAC transfer - ref sin 
    void setup_dma1() {
      dma1.disable();
      dma1.sourceBuffer(posphase, sizeof(posphase));
      dma1.destination(*(volatile uint16_t *)&(DAC0_DAT0L));
      dma1.triggerAtHardwareEvent(DMAMUX_SOURCE_PDB);
      }
    
    void setup_dma2() {
      dma2.disable();
      dma2.sourceBuffer(negphase, sizeof(negphase));
      dma2.destination(*(volatile uint16_t *)&(DAC1_DAT0L));
      dma2.triggerAtCompletionOf(dma1);
      dma2.triggerAtTransfersOf(dma1);  
    }
    
    void setup() {
      timer.setTimer(5000);   // sleep duration between signal playback
      
      // setup DAC 
      SIM_SCGC2 |= SIM_SCGC2_DAC0 | SIM_SCGC2_DAC1;
      DAC0_C0 = DAC_C0_DACEN; // 1.2V VDDA is DACREF_2
      DAC0_C0 |= DAC_C0_DACRFS; // 3.3V
      
      DAC1_C0 = DAC_C0_DACEN; // 1.2V VDDA is DACREF_2
      DAC1_C0 |= DAC_C0_DACRFS; // 3.3V
    
      // slowly ramp up to DC voltage, approx 1/4 second
      for (int16_t i=0; i<=2048; i+=8) {
        *(int16_t *)&(DAC0_DAT0L) = i;
        *(int16_t *)&(DAC1_DAT0L) = i;
        delay(1);
      }
    
      // allocate the dma channels
      dma1.begin(true);
      dma2.begin(true);
    
      
      setup_dma1();
      setup_dma2();
    
      SIM_SCGC6 |= SIM_SCGC6_PDB;   // enable PDB clock
      setup_pdb();
    
    
    }
    
    void loop() {
      int who = Snooze.deepSleep( config ); // return module that woke processor
      for (int16_t i=0; i<=2048; i+=8) {
        *(int16_t *)&(DAC0_DAT0L) = i;
        *(int16_t *)&(DAC1_DAT0L) = i;
        delay(1);
      }
      dma1.enable();
      dma2.enable();
      delay(5000);
      dma1.disable();
      dma2.disable();
    }

  2. #2
    Junior Member
    Join Date
    Apr 2019
    Posts
    3
    Hey everybody, I know that this is an old-ish post and probably not very exciting to most of you. Still, if anybody is interested, I have a slightly further developed version of the sketch that I tested in the wild. I still use primitive LUTs and random intervals between pulses and would really like to play e.g. pulses from raw files on an SD card. I looked at some examples from the audio lib but - as great as it is - I don't know where to start to adapt the code to my application (2 coordinated DACs with sampling rates up to 500 kHz) because it seems to me that most is happening under the hood of library functions that wrap up the technical details. And I have to say that I'm not as profficient a programmer to fully grasp everthing that happens e.g. when using DMAs (e.g. how to change settings in the TCD).
    Anyways, here's the sketch and a picture of a fish pulse recorded at 500 kHz. I'm happy for any input.
    Code:
    #include <Snooze.h>
    #include <SnoozeBlock.h>
    #define ARM_MATH_CM4
    #include <DMAChannel.h>
    #define PDB_CONFIG     (PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | PDB_SC_PDBIE | PDB_SC_CONT | PDB_SC_DMAEN)
    
    // Configure snooze driver and install it
    // The timer controls the interval between single pulses (Teensy goes into sleep mode between pulses to save energy)
    SnoozeTimer timer;
    SnoozeBlock config(timer);
    
    // Simple vectors with measured values from a pulse (M. rume 500 kHz) - positive and 
    // negative phase of pulse are in one vector each and are sent to different outputs
    static volatile uint16_t pos_phase[] = {
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,11,2,5,10,2,0,0,6,10,0,1,6,1,3,
      2,0,11,4,2,6,2,3,3,2,13,14,0,4,7,4,3,0,12,17,3,10,13,0,6,4,11,18,4,9,10,10,13,9,3,24,
      17,9,9,14,12,12,7,26,16,8,15,17,14,13,9,23,28,16,21,19,13,22,16,19,34,23,19,26,21,25,
      20,18,42,27,23,29,24,25,28,23,39,37,28,33,34,29,32,25,36,47,41,36,40,39,47,39,36,51,
      46,42,47,49,44,48,47,65,57,46,59,59,52,60,55,66,76,65,69,69,64,71,65,75,86,79,75,88,
      86,87,84,85,104,99,92,109,103,102,110,107,125,127,119,126,128,128,142,129,147,163,154,
      157,166,168,170,175,189,210,197,203,221,224,229,237,243,269,274,279,291,300,316,335,
      341,369,386,393,416,439,454,471,489,527,559,569,599,631,649,680,705,741,777,804,831,
      868,896,927,961,986,1034,1065,1085,1117,1156,1183,1219,1240,1285,1319,1337,1366,1403,
      1424,1456,1488,1526,1566,1585,1617,1653,1680,1718,1754,1776,1838,1870,1900,1946,1981,
      2025,2066,2096,2153,2186,2213,2253,2285,2309,2335,2344,2363,2373,2359,2348,2337,2300,
      2272,2228,2174,2119,2034,1944,1851,1731,1614,1465,1308,1163,980,778,583,367,147,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,1,0,2,0,2,2,6,5,3,5,5,6,
      8,7,13,11,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    };
    static volatile uint16_t neg_phase[] = {
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,8,0,0,0,0,0,0,2,7,0,0,2,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,3,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,85,325,546,794,1044,1272,1503,1738,1956,2168,2368,2550,2746,2919,3078,3225,3354,
      3480,3589,3669,3761,3839,3892,3945,3992,4028,4058,4062,4079,4095,4091,4088,4083,4068,
      4061,4037,4012,3995,3970,3944,3917,3887,3860,3825,3780,3751,3726,3684,3649,3619,3581,
      3549,3497,3464,3433,3392,3354,3322,3284,3255,3206,3172,3144,3104,3068,3034,2997,2970,
      2930,2890,2864,2831,2797,2764,2737,2706,2672,2631,2613,2580,2547,2521,2489,2461,2437,
      2400,2374,2348,2321,2295,2268,2241,2218,2185,2159,2132,2107,2086,2064,2035,2018,1990,
      1964,1942,1917,1896,1874,1851,1834,1810,1787,1766,1747,1725,1706,1685,1665,1647,1622,
      1607,1588,1569,1552,1530,1513,1497,1476,1456,1444,1425,1410,1392,1376,1361,1343,1324,
      1307,1298,1281,1270,1255,1238,1223,1207,1193,1182,1164,1155,1143,1127,1117,1099,1086,
      1079,1063,1051,1039,1030,1018,1002,991,986,971,957,950,939,928,917,905,899,885,876,
      867,857,847,839,822,819,809,802,792,783,775,770,755,746,739,728,723,717,706,703,690,
      682,676,668,661,654,643,639,631,623,615,610,599,596,586,583,576,566,558,554,550,542,
      534,527,524,515,509,505,501,493,487,482,478,467,457,456,452,449,445,436,430,425,418,
      414,407,403,400,399,390,387,378,372,369,362,362,354,350,349,342,335,335,330,324,320,
      314,311,306,301,297,296,289,286,281,278,274,265,263,265,260,257,251,248,247,239,235,
      232,229,226,226,220,218,210,208,208,201,199,201,196,191,189,182,183,177,173,176,169,
      168,165,160,160,157,153,152,148,147,146,139,139,138,134,132,131,125,124,120,117,117,
      118,115,112,109,111,107,99,102,99,96,95,93,92,93,85,88,83,83,79,79,77,81,73,71,73,69,
      67,68,63,66,64,60,59,59,56,56,53,51,53,47,47,47,47,48,42,43,45,37,38,40,35,35,35,35,
      36,30,28,28,30,25,28,26,26,24,19,22,21,17,18,18,16,18,12,14,14,13,10,13,8,10,8,7,6,6,
      7,6,4,5,0,0,3,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,
    };
    
    // Set the sampling frequency at 500kHz
    const uint32_t pdb_freq = 500000; 
    
    // Amplification factor
    int amp_factor = 1;
    
    // Adjust the amplification factor in case it creates too high values (>4095) and multiply every array element with it
    int pos_phase_length;
    int neg_phase_length;
    
    void adjust_amp() {
      pos_phase_length = sizeof pos_phase / sizeof pos_phase[0];
      neg_phase_length = sizeof neg_phase / sizeof neg_phase[0];
      int max_pos = 0;
      int max_neg = 0;
      for(int i = 0; i < pos_phase_length; i++){
        if(pos_phase[i] > max_pos){
          max_pos = pos_phase[i];
        }
      }
      for(int i = 0; i < neg_phase_length; i++){
        if(neg_phase[i] > max_neg){
          max_neg = neg_phase[i];
        }
      }
      int max_both = max(max_pos, max_neg);
      if(max_both*amp_factor > 4095){
        int max_val = max_both*amp_factor;
        amp_factor = amp_factor/(max_val/4095);
      }
      for(int i = 0; i < pos_phase_length; i++){
        pos_phase[i] = round(pos_phase[i]*amp_factor);
      }
      for(int i = 0; i < neg_phase_length; i++){
        neg_phase[i] = round(neg_phase[i]*amp_factor);
      }
    }
    
    // DMA for ADC
    DMAChannel dma1(false);
    DMAChannel dma2(false);
    
    // Setup PDB at pdb_freq
    void setup_pdb() {
      uint32_t mod = (F_BUS / pdb_freq);
      PDB0_MOD = (uint16_t)(mod-1);  
      PDB0_IDLY = 0;
      PDB0_SC = PDB_CONFIG | PDB_SC_LDOK;
      PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG;
      PDB0_CH0C1 = 0x0101;
    }
    
    // Setup DMA for DAC transfer from the pulse LUTs
    void setup_dma1() {
      dma1.disable();
      dma1.sourceBuffer(pos_phase, sizeof(pos_phase));
      dma1.transferSize(2);
      dma1.destination(*(volatile uint16_t *)&(DAC0_DAT0L));
      dma1.triggerAtHardwareEvent(DMAMUX_SOURCE_PDB);
      dma1.disableOnCompletion();
    }
    
    void setup_dma2() {
      dma2.disable();
      dma2.sourceBuffer(neg_phase, sizeof(neg_phase));
      dma2.transferSize(2);
      dma2.destination(*(volatile uint16_t *)&(DAC1_DAT0L));
      dma2.triggerAtTransfersOf(dma1);  
      dma2.disableOnCompletion();
    }
    
    void setup() {
      adjust_amp();
      timer.setTimer(5000);// milliseconds
      // setup DAC 
      SIM_SCGC2 |= SIM_SCGC2_DAC0 | SIM_SCGC2_DAC1;
      DAC0_C0 = DAC_C0_DACEN; // 1.2V VDDA is DACREF_2
      DAC0_C0 |= DAC_C0_DACRFS; // 3.3V
      DAC1_C0 = DAC_C0_DACEN; // 1.2V VDDA is DACREF_2
      DAC1_C0 |= DAC_C0_DACRFS; // 3.3V
    
      // allocate the dma channels
      dma1.begin(true);
      dma2.begin(true);
      setup_dma1();
      setup_dma2();
      
      SIM_SCGC6 |= SIM_SCGC6_PDB; // enable PDB clock
      setup_pdb();
    }
    
    void loop() {
      int who = Snooze.deepSleep( config );// return module that woke processor
      dma1.enable();
      delay(round((pos_phase_length/pdb_freq)*1000));
      *(int16_t *)&(DAC0_DAT0L) = 0;
      *(int16_t *)&(DAC1_DAT0L) = 0;
      timer.setTimer(random(10,1000));
    }
    Click image for larger version. 

Name:	rume_puls.jpg 
Views:	18 
Size:	18.9 KB 
ID:	19126

  3. #3
    Senior Member
    Join Date
    Feb 2015
    Posts
    217
    The Audio library is locked to 44.1KHz so the approach you're taking makes a lot of sense. There's no reason you couldn't load the samples off an SD card into RAM, but due to your high sample rate, I would just make sure the whole thing was in RAM before trying to play it.

    By the way, the 'volatile' keyword is usually only needed for variables which are modified inside an interrupt service routine (ISR) and used elsewhere. It tells the compiler "don't trust the last value of this variable, reload it every time it's referenced". So there's probably no need to have your sample arrays marked as volatile.

  4. #4
    Junior Member
    Join Date
    Apr 2019
    Posts
    3
    Now I understand, why it's called volatile as it might change while being used... Thank you for the explanation! I changed the sketch accordingly...

  5. #5
    thanks for posting this project! It is very interesting dor me and might be a template for my goal.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •