For one of my projects I need as much speed out of the DAC as possible.
What is the maximum sample rate both normally clocked and over clocked to 96MHz using Arduino?
2. A small load capacitance (47 pF) can improve the bandwidth performance of the DAC
#include <Audio.h>
#include <Wire.h>
#include <SD.h>
#include <SPI.h>
AudioSynthWaveform osc;
AudioOutputAnalog audioOutput;
AudioConnection c1(osc, audioOutput);
void setup() {
AudioMemory(6);
osc.begin(0.95, 1000, TONE_TYPE_SINE);
audioOutput.analogReference(INTERNAL);
}
void loop() {
}
The main limit to the DAC speed involves the capacitance its analog hardware must drive. Software or DMA can write to the DAC much faster than the analog hardware is capable of settling, so the analog circuitry is the main limiting factor, not the CPU speed.
IntervalTimer timer0;
void setup() {
analogWriteResolution(10);
timer0.begin(timer0_callback, 1.25);
pinMode(A14,OUTPUT);
analogWrite(A14,0);
}
volatile int16_t t = 0;
//http://www.wolframalpha.com/input/?i=table+round%28100%2B412*%28sin%282*pi*t%2F20%29%2B1%29%29+from+0+to+19
int16_t sine_data[20] = {512, 639, 754, 845, 904, 924, 904, 845, 754, 639, 512, 385, 270, 179, 120, 100, 120, 179, 270, 385};
void timer0_callback() {
analogWrite(A14,sine_data[t]);
t=t+1;
if (t >= 20) {
t=0;
}
}
void loop() {
}
If you are using cpu intensive functions like floating point operations with sin(...) for creating the signal, then the cpu seems indeed to be to slow.
That isn't terribly surprising, given the hardware has no support for floating point, and all floating point operations have to be emulated. If you use the float data type, and the float versions of the math functions (i.e. sinf, cosf, etc.), it hopefully should be a bit faster. Paul has dropped hints that the next Teensy 3.x will have hardware support for float, but not double, but since that hasn't been announced yet, it doesn't help you right now.
With precomputing the integer values of the sine function, I got this 40khz signal:
If you do use the DAC much faster, I hope you'll share your results and code?
while (1) {
analogWrite(A21, 0);
delayMicroseconds(1);
analogWrite(A21, 255);
delayMicroseconds(1);
}
// DMA output to DAC clocked by PDB
// https://forum.pjrc.com/threads/28101-Using-the-DAC-with-DMA-on-Teensy-3-1
#include <DMAChannel.h>
// PDB ticks at F_BUS
#define PDB_PERIOD (60-1)
#define PDB_CONFIG (PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | PDB_SC_CONT | PDB_SC_PDBIE | PDB_SC_DMAEN)
DMAChannel dma(false);
static volatile uint16_t sinetable[] = {
2047, 2147, 2248, 2348, 2447, 2545, 2642, 2737,
2831, 2923, 3012, 3100, 3185, 3267, 3346, 3422,
3495, 3564, 3630, 3692, 3750, 3804, 3853, 3898,
3939, 3975, 4007, 4034, 4056, 4073, 4085, 4093,
4095, 4093, 4085, 4073, 4056, 4034, 4007, 3975,
3939, 3898, 3853, 3804, 3750, 3692, 3630, 3564,
3495, 3422, 3346, 3267, 3185, 3100, 3012, 2923,
2831, 2737, 2642, 2545, 2447, 2348, 2248, 2147,
2047, 1948, 1847, 1747, 1648, 1550, 1453, 1358,
1264, 1172, 1083, 995, 910, 828, 749, 673,
600, 531, 465, 403, 345, 291, 242, 197,
156, 120, 88, 61, 39, 22, 10, 2,
0, 2, 10, 22, 39, 61, 88, 120,
156, 197, 242, 291, 345, 403, 465, 531,
600, 673, 749, 828, 910, 995, 1083, 1172,
1264, 1358, 1453, 1550, 1648, 1747, 1847, 1948,
};
void setup() {
dma.begin(true); // allocate the DMA channel first
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 = PDB_PERIOD; // 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?
dma.sourceBuffer(sinetable, sizeof(sinetable));
dma.destination(*(volatile uint16_t *) & (DAC0_DAT0L));
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_PDB);
dma.enable();
}
void loop() {}
inline void writeDAC1(int val) { //modified from PJRC "analogwriteDAC#" from teensy cores analog.c{
//SIM_SCGC2 |= SIM_SCGC2_DAC1;//moved to setup, seems ok so far. saved about 50 cycles!
//DAC1_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V VDDA is DACREF_2
__asm__ ("usat %[value], #12, %[value]\n\t" : [value] "+r" (val)); // 0 <= val <= 4095
*(int16_t *)&(DAC1_DAT0L) = val;
}
inline void writeDAC0(int val) {
// SIM_SCGC2 |= SIM_SCGC2_DAC0;
// DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V VDDA is DACREF_2
__asm__ ("usat %[value], #12, %[value]\n\t" : [value] "+r" (val)); // 0 <= val <= 4095
*(int16_t *)&(DAC0_DAT0L) = val;
}