Here I'm trying to generate two sin waveforms of two different frequencies on the two DACs available in teensy 3.6. I'm using two DMA Channels to transfer data from two look up tables (LUT) to the DACs. Both the DMA transfers are triggered by a PDB running at 200KHz.
To my surprise, the frequency the the generated sine waveform on DAC1 is doubled! It seems that that the DMA associated with it misses one data from LUT out of each two data. I suspect there is a collision between the two DMA channels or something.
As the size of the two LUTs are different so I think I can't use one DMA channel to transfer data from the LUT to DAC as Paul did in out_dacs in the audio library. Please suggest me some workaround.
Here is the source code:
To my surprise, the frequency the the generated sine waveform on DAC1 is doubled! It seems that that the DMA associated with it misses one data from LUT out of each two data. I suspect there is a collision between the two DMA channels or something.
As the size of the two LUTs are different so I think I can't use one DMA channel to transfer data from the LUT to DAC as Paul did in out_dacs in the audio library. Please suggest me some workaround.
Here is the source code:
Code:
#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)
// DMA for ADC
DMAChannel dma1(false);
DMAChannel dma2(false);
// Set fs - the sampling frequency at 200KHz
const uint32_t pdb_freq = 200000;
// 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;
}
uint lut_size1;
uint lut_size2;
static uint16_t lut1[256];
static uint16_t lut2[256];
// Setup DMA for DAC transfer - ref sin
void setup_dma1() {
dma1.disable();
dma1.sourceBuffer(lut1, lut_size1*sizeof(uint16_t));
dma1.transferSize(2);
dma1.destination(*(volatile uint16_t *)&(DAC0_DAT0L));
dma1.triggerAtHardwareEvent(DMAMUX_SOURCE_PDB);
//dma_dac.transferCount(lut_size/3);
//dma_dac_ref.interruptAtCompletion();
//dma_dac.interruptAtHalf();
dma1.enable();
//dma_dac_ref1.attachInterrupt(dma_dac_ref_isr);
}
void setup_dma2() {
dma2.disable();
dma2.sourceBuffer(lut2, lut_size2*sizeof(uint16_t));
dma2.transferSize(2);
dma2.destination(*(volatile uint16_t *)&(DAC1_DAT0L));
dma2.triggerAtHardwareEvent(DMAMUX_SOURCE_PDB);
//dma_dac.transferCount(lut_size/3);
//dma_dac_ref.interruptAtCompletion();
//dma_dac.interruptAtHalf();
dma2.enable();
//dma_dac_ref1.attachInterrupt(dma_dac_ref_isr);
}
void setup_lut(uint target_freq1, uint target_freq2) {
//lut1
lut_size1 = uint(pdb_freq/target_freq1);
Serial.printf("pdb_freq = %d\ntarget_freq1 = %d\nlut_size1 = %d\n", pdb_freq,target_freq1,lut_size1);
for(uint i=0; i<lut_size1; i++) {
lut1[i] = 2047 + 2000*sin(2.0*M_PI*i/lut_size1);
}
Serial.printf("True freq1 = %f\n", pdb_freq/float(lut_size1));
// lut2
lut_size2 = uint(pdb_freq/target_freq2);
Serial.printf("pdb_freq = %d\ntarget_freq2 = %d\nlut_size2 = %d\n", pdb_freq,target_freq2,lut_size2);
for(uint i=0; i<lut_size2; i++) {
lut2[i] = 2047 + 2000*sin(2.0*M_PI*i/lut_size2);
}
Serial.printf("True freq2 = %f\n", pdb_freq/float(lut_size2));
}
void setup() {
// 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_lut(1000,2000);
setup_dma1();
setup_dma2();
SIM_SCGC6 |= SIM_SCGC6_PDB; // enable PDB clock
setup_pdb();
}
void loop() {
}