optimize DAC using calling registers instead of analogWriteDAC0

Take what's needed from framework's analogWriteDAC0
A sine wave of 1MHz can now be generate without any problem
main
EmaMaker 2021-02-13 15:26:30 +01:00
parent e10b4869d8
commit f9f2cbe89b
5 changed files with 32 additions and 50 deletions

View File

@ -1,11 +1,13 @@
#pragma once
#define LUT_SIZE 4096
//DAC sampling time(1428571,428571429), found on the Datasheet
#define SAMPLE_FREQ 1428571
#define LUT_SIZE 512
// Sampling frequency of the DAC
// Since the teensy runs on 168MHz and Fastest + LTO, using the DAC sampling frequency (1428571Hz) from the Datasheet kinda falls apart
#define SAMPLE_FREQ 5316436
//Max Freq with good results achievable with Teensy 3.5 DAC
#define MAX_ACHIEVABLE_FREQ 300000
#define MAX_ACHIEVABLE_FREQ 1000000
void generateSine(float);
void setupSine();

View File

@ -8,8 +8,8 @@
#define extr extern
#endif
#define MAX_VALUE 4096
#define MAX_VALUE_HALF 2048
#define MAX_VALUE 1024
#define MAX_VALUE_HALF 512
//How much time (nanoseconds) is required for an analogWriteDAC0() call
#define ANALOG_WRITE_TIME_NS 477

View File

@ -10,5 +10,5 @@ void setup() {
}
FASTRUN void loop() {
generateSine(1000);
generateSine(1000000);
}

View File

@ -24,54 +24,30 @@ void calculateSineLookup(){
}
}
/*Generate sine wave at the given frequency
Use the classical DDS Phase Accumulator technique
On some lower frequency the maths for the phase accumulator doesn't work (delta_phi becomes too close to zero to be noticed)
and a simpler approach waiting microseconds can be used*/
//Write the DAC with using some parts of framework's Arduino.h, for higher speeds
// Use FASTRUN to run code in RAM
typedef int16_t __attribute__((__may_alias__)) aliased_int16_t;
FASTRUN void generateSine(float frequency){
startGenerating();
if (frequency <= 500){
// Phase accumulator
float phase = 0;
// Period of the wave in microseconds
unsigned long periodMS = 1/frequency * pow (10, 6);
//Constrain frequency
frequency = constrain(frequency, 0, MAX_ACHIEVABLE_FREQ);
//Time to pass between outputting each sample
unsigned long sampleTime = (unsigned long) ((float)periodMS / LUT_SIZE + ANALOG_WRITE_TIME_MS);
int i = 0;
while(generateWave){
//Write the voltage on the DAC. i gets incremented after the call to the function is done
analogWriteDAC0(LUT[i++]);
// handle wraparound
if(i >= LUT_SIZE) i -= LUT_SIZE;
// Wait the needed time
delayMicroseconds(sampleTime);
}
}else{
// Phase accumulator
float phase = 0;
//Constrain frequency
frequency = constrain(frequency, 0, MAX_ACHIEVABLE_FREQ);
// Phase increment at each step
float delta_phi = (int) (frequency / SAMPLE_FREQ * LUT_SIZE);
while(generateWave){
// increment phase
phase += delta_phi;
// handle wraparound
if (phase >= (float)LUT_SIZE) phase -= (float)LUT_SIZE;
//Write the voltage on the DAC
analogWriteDAC0(LUT[(int)phase]);
}
// Phase increment at each step
float delta_phi = frequency / SAMPLE_FREQ * LUT_SIZE;
while(generateWave){
// increment phase
phase += delta_phi;
// handle wraparound
if (phase >= LUT_SIZE) phase -= LUT_SIZE;
//Write the voltage on the DAC
*(volatile aliased_int16_t *)&(DAC0_DAT0L) = LUT[(int)phase];
}
}

View File

@ -10,6 +10,10 @@ void setupWaves(){
//Set DACs resolution to 12 bits
analogWriteResolution(12);
// Enable DAC0, from framework's analogWriteDAC0, place here from higher speeds
SIM_SCGC2 |= SIM_SCGC2_DAC0;
DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS;
}
// Wait time by counting clock cycles