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

Status
Not open for further replies.

StefanM

Member
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-Using-2-DMA-Channels-for-2-DACs-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();
}
 
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));
}
rume_puls.jpg
 
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.
 
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...
 
Status
Not open for further replies.
Back
Top