Hi,
i've been using a modified version of the dac/dma sample from (https://forum.pjrc.com/threads/28101-Using-the-DAC-with-DMA-on-Teensy-3-1) to generate arbitrary waveforms with a teensy 3.1/3.2 using different lookuptables, changing the frequency of the waveform by modifying the PDB0_Mod at runtime, and was pretty happy with that.
However, i do need to change the DAC's output from the waveform to a simple 4095 on the DAC0, thus have a simple constant voltage output for a set time period.
But i did face some trouble handling the change of the dma.sourceBuffer at runtime. I might be doing a simple conversion error, maybe i do have another problem. The trouble is that i'm not very fluent in arduino with handling data conversions.
The concept is: serial input delivers a number for a frequency, this frequency is applied via setFreq(uint16_t freq) by means of changing PDB0_Mod, and if the serial reads a 0 as input, it triggers setDc to change the dma.sourceBuffer from the sinetable32 to dclut[], which is a simple high for the DAC. I was hoping this would be a convenient way of changing the waveform or, in this case, to apply a 100% Vref Voltage to the DAC0.
The code compiles fine and of course works fine until i trigger the change of the lookup-table via a zero on the serial input. It then seems to successfully disable the DMA resulting in a 50% Vref output on the DAC0 and does neither set the correct output level, nor change the dma.sourceBuffer to something that works (at all).
The trouble i'm facing is that setting the dma.sourceBuffer at complile-time requires a different input than doing it at runtime (outside of the setup()-scope).
All suggestions are welcome!
Thank you!
i've been using a modified version of the dac/dma sample from (https://forum.pjrc.com/threads/28101-Using-the-DAC-with-DMA-on-Teensy-3-1) to generate arbitrary waveforms with a teensy 3.1/3.2 using different lookuptables, changing the frequency of the waveform by modifying the PDB0_Mod at runtime, and was pretty happy with that.
However, i do need to change the DAC's output from the waveform to a simple 4095 on the DAC0, thus have a simple constant voltage output for a set time period.
But i did face some trouble handling the change of the dma.sourceBuffer at runtime. I might be doing a simple conversion error, maybe i do have another problem. The trouble is that i'm not very fluent in arduino with handling data conversions.
The concept is: serial input delivers a number for a frequency, this frequency is applied via setFreq(uint16_t freq) by means of changing PDB0_Mod, and if the serial reads a 0 as input, it triggers setDc to change the dma.sourceBuffer from the sinetable32 to dclut[], which is a simple high for the DAC. I was hoping this would be a convenient way of changing the waveform or, in this case, to apply a 100% Vref Voltage to the DAC0.
The code compiles fine and of course works fine until i trigger the change of the lookup-table via a zero on the serial input. It then seems to successfully disable the DMA resulting in a 50% Vref output on the DAC0 and does neither set the correct output level, nor change the dma.sourceBuffer to something that works (at all).
The trouble i'm facing is that setting the dma.sourceBuffer at complile-time requires a different input than doing it at runtime (outside of the setup()-scope).
All suggestions are welcome!
Thank you!
Code:
#include <DMAChannel.h>
#include "pdb.h"
DMAChannel dma(false);
char buf[80] = {};
int readline(int readch, char *buffer, int len) {
static int pos = 0;
int rpos;
if (readch > 0) {
switch (readch) {
case '\r': // Ignore CR
break;
case '\n': // Return on new-line
rpos = pos;
pos = 0; // Reset position index ready for next time
return rpos;
default:
if (pos < len - 1) {
buffer[pos++] = readch;
buffer[pos] = 0;
}
}
}
return 0;
}
static volatile uint16_t sinetable32[] = {
2047, 2459, 2854, 3217, 3531, 3785, 3967, 4071, 4092, 4029, 3885, 3666, 3381, 3041, 2660, 2254,
1840, 1434, 1053, 713, 428, 209, 65, 2, 23, 127, 309, 563, 877, 1240, 1635, 2047,
};
static volatile uint16_t sinetable32_o[] = { // offset by +1000
2547, 2859, 3157, 3431, 3669, 3860, 3998, 4077, 4093, 4045, 3936, 3771, 3555, 3298, 3010, 2704,
2390, 2084, 1796, 1539, 1323, 1158, 1049, 1001, 1017, 1096, 1234, 1425, 1663, 1937, 2235, 2547,
};
static volatile uint16_t dclut[] = {
4095,
};
static void setFreq(uint16_t freq) { //should work for 1...65KHz
change_sr(F_BUS / (freq * 32)); //32 for LUT32
}
static void change_sr(uint16_t srate) {
PDB0_MOD = srate - 1;
PDB0_SC = PDB_CONFIG | PDB_SC_LDOK; // load registers from buffers
}
static void setDc(DMAChannel dma) {
changeLUT(dclut, dma);
delay(5);
changeLUT(sinetable32, dma);
}
static void changeLUT(volatile uint16_t *lut, DMAChannel dma) {
dma.disable();
dma.sourceBuffer(lut, sizeof(lut));
dma.enable();
}
void setup() {
dma.begin(true); // allocate the DMA channel first
Serial.begin(115200);
SIM_SCGC2 |= SIM_SCGC2_DAC0; // enable DAC clock
DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 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_DAT0L) = i;
delay(1);
}
// set the programmable delay block to trigger DMA requests
SIM_SCGC6 |= SIM_SCGC6_PDB; // enable PDB clock
PDB0_IDLY = 0; // interrupt delay register
PDB0_MOD = 1499; // modulus register, sets period
PDB0_SC = PDB_CONFIG | PDB_SC_LDOK; // load registers from buffers
PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG; // reset and restart
// PDB0_CH0C1 = 0x0101; // channel n control register-> Back to back enable, pre trigger output select to bypass, pre trigger enable
PDB0_CH0C1 = 0x0100; // channel n control register-> Back to back enable, pre trigger output select to bypass, pre trigger disable
dma.sourceBuffer(sinetable32, sizeof(sinetable32)); //32 is the best LUT
dma.destination(*(volatile uint16_t *) & (DAC0_DAT0L));
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_PDB);
dma.enable();
}
void loop() {
if (readline(Serial.read(), buf, 80) > 0) {
if (atoi(buf) == 0) {
setDc(dma);
}
setFreq(atoi(buf));
Serial.println("setFreq to: ");
Serial.println(atoi(buf), DEC);
}
}