simplify code

main
EmaMaker 2021-06-11 22:58:29 +02:00
parent 87b1c51cf0
commit b46cbbdcbf
10 changed files with 175 additions and 252 deletions

View File

@ -8,8 +8,8 @@
{
"name": "PlatformIO",
"includePath": [
"/home/emamaker/Teensy3.5DDS/Firmware/Teensy/include",
"/home/emamaker/Teensy3.5DDS/Firmware/Teensy/src",
"/home/emamaker/Documents/Projects/FunctionGenerator/FunctionGen-Teensy/Teensy3.5-DDS/Firmware/Teensy/include",
"/home/emamaker/Documents/Projects/FunctionGenerator/FunctionGen-Teensy/Teensy3.5-DDS/Firmware/Teensy/src",
"/home/emamaker/.platformio/packages/framework-arduinoteensy/cores/teensy3",
"/home/emamaker/.platformio/packages/framework-arduinoteensy/libraries/ADC",
"/home/emamaker/.platformio/packages/framework-arduinoteensy/libraries/AccelStepper/src",
@ -108,14 +108,13 @@
"/home/emamaker/.platformio/packages/framework-arduinoteensy/libraries/ks0108",
"/home/emamaker/.platformio/packages/framework-arduinoteensy/libraries/ssd1351",
"/home/emamaker/.platformio/packages/framework-arduinoteensy/libraries/x10",
"/home/emamaker/.platformio/packages/tool-unity",
""
],
"browse": {
"limitSymbolsToIncludedHeaders": true,
"path": [
"/home/emamaker/Teensy3.5DDS/Firmware/Teensy/include",
"/home/emamaker/Teensy3.5DDS/Firmware/Teensy/src",
"/home/emamaker/Documents/Projects/FunctionGenerator/FunctionGen-Teensy/Teensy3.5-DDS/Firmware/Teensy/include",
"/home/emamaker/Documents/Projects/FunctionGenerator/FunctionGen-Teensy/Teensy3.5-DDS/Firmware/Teensy/src",
"/home/emamaker/.platformio/packages/framework-arduinoteensy/cores/teensy3",
"/home/emamaker/.platformio/packages/framework-arduinoteensy/libraries/ADC",
"/home/emamaker/.platformio/packages/framework-arduinoteensy/libraries/AccelStepper/src",
@ -214,7 +213,6 @@
"/home/emamaker/.platformio/packages/framework-arduinoteensy/libraries/ks0108",
"/home/emamaker/.platformio/packages/framework-arduinoteensy/libraries/ssd1351",
"/home/emamaker/.platformio/packages/framework-arduinoteensy/libraries/x10",
"/home/emamaker/.platformio/packages/tool-unity",
""
]
},

View File

@ -12,7 +12,7 @@
"type": "platformio-debug",
"request": "launch",
"name": "PIO Debug",
"executable": "/home/emamaker/Teensy3.5DDS/Firmware/Teensy/.pio/build/teensy35/firmware.elf",
"executable": "/home/emamaker/Documents/Projects/FunctionGenerator/FunctionGen-Teensy/Teensy3.5-DDS/Firmware/Teensy/.pio/build/teensy35/firmware.elf",
"projectEnvName": "teensy35",
"toolchainBinDir": "/home/emamaker/.platformio/packages/toolchain-gccarmnoneeabi/bin",
"internalConsoleOptions": "openOnSessionStart",
@ -26,7 +26,7 @@
"type": "platformio-debug",
"request": "launch",
"name": "PIO Debug (skip Pre-Debug)",
"executable": "/home/emamaker/Teensy3.5DDS/Firmware/Teensy/.pio/build/teensy35/firmware.elf",
"executable": "/home/emamaker/Documents/Projects/FunctionGenerator/FunctionGen-Teensy/Teensy3.5-DDS/Firmware/Teensy/.pio/build/teensy35/firmware.elf",
"projectEnvName": "teensy35",
"toolchainBinDir": "/home/emamaker/.platformio/packages/toolchain-gccarmnoneeabi/bin",
"internalConsoleOptions": "openOnSessionStart",

View File

@ -1,13 +0,0 @@
#pragma once
#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 6988800
//Max Freq with good results achievable with Teensy 3.5 DAC
#define MAX_ACHIEVABLE_FREQ 1000000
void generateSine(float);
void setupSine();

View File

@ -1,9 +0,0 @@
#pragma once
#define SQUARE_PIN A22 //DAC1
void setupSquare();
void generateSquare(float, int);
void generateSquareDAC1(float, int);

View File

@ -23,12 +23,31 @@
#define DAC1_SEL 23
#define DAC0_SEL 22
#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 6988800
//Max Freq with good results achievable with Teensy 3.5 DAC
#define MAX_ACHIEVABLE_FREQ 1000000
void calculateSineLookup();
void calculateSquareLookup(int);
void generateSine(float);
void generateSquare(float, int);
void generateWave(float, int*, int);
void selectDAC0();
void selectDAC1();
FASTRUN void startGenerating();
FASTRUN void stopGenerating();
FASTRUN void generateWave();
FASTRUN void delayCycles(unsigned long);
void setupWaves();
extr bool generateWave;
extr bool generating;
/* Generate values for the filters from: https://tools.analog.com/en/filterwizard/*/

View File

@ -1,7 +1,5 @@
#include <Arduino.h>
#include "wave.h"
#include "square.h"
#include "sine.h"
#include "waves.h"
void communicate();
void generate(int, int, int);
@ -20,54 +18,51 @@ void setup() {
attachInterrupt(digitalPinToInterrupt(21), communicate, RISING);
setupWaves();
setupSine();
setupSquare();
}
void loop() {
generateSquareDAC1(100000, 50);
// if(receivingInfo){
if(receivingInfo){
// Serial1.write(42); //The answer to life, universe and everything else
// digitalWriteFast(LED_BUILTIN, HIGH);
Serial1.write(42); //The answer to life, universe and everything else
digitalWriteFast(LED_BUILTIN, HIGH);
// Serial1.flush();
Serial1.flush();
// delay(1000);
// receivingInfo = false;
// valid_flag = false;
delay(1000);
receivingInfo = false;
valid_flag = false;
// while(!valid_flag){
// while(Serial1.available()) s = Serial1.readStringUntil('W');
// Serial.println(s);
// //Check if it's a valid string, it should start with 'w'
// if(!s.startsWith('w')) continue;
while(!valid_flag){
while(Serial1.available()) s = Serial1.readStringUntil('W');
Serial.println(s);
//Check if it's a valid string, it should start with 'w'
if(!s.startsWith('w')) continue;
// // Get type
// tmp_type = s.substring(s.indexOf('t')+1, s.indexOf('T'));
// type = tmp_type.toInt();
// // Get duty
// tmp_duty = s.substring(s.indexOf('d')+1, s.indexOf('D'));
// duty = tmp_duty.toInt();
// // Get frequency
// tmp_frequency = s.substring(s.indexOf('f')+1, s.indexOf('F'));
// frequency = tmp_frequency.toInt();
// Get type
tmp_type = s.substring(s.indexOf('t')+1, s.indexOf('T'));
type = tmp_type.toInt();
// Get duty
tmp_duty = s.substring(s.indexOf('d')+1, s.indexOf('D'));
duty = tmp_duty.toInt();
// Get frequency
tmp_frequency = s.substring(s.indexOf('f')+1, s.indexOf('F'));
frequency = tmp_frequency.toInt();
// for(int i = 0; i < 100; i++) Serial1.write(69);
// valid_flag = true;
for(int i = 0; i < 100; i++) Serial1.write(69);
valid_flag = true;
// valid_flag = true;
// Serial.print("Type: " );
// Serial.println(type);
// Serial.print("Duty: " );
// Serial.println(duty);
// Serial.print("Frequency: " );
// Serial.println(frequency);
valid_flag = true;
Serial.print("Type: " );
Serial.println(type);
Serial.print("Duty: " );
Serial.println(duty);
Serial.print("Frequency: " );
Serial.println(frequency);
// digitalWriteFast(LED_BUILTIN, LOW);
// generate(type, frequency, duty);
// }
// }
digitalWriteFast(LED_BUILTIN, LOW);
generate(type, frequency, duty);
}
}
}
void communicate(){
@ -82,7 +77,7 @@ void generate(int type, int frequency, int duty){
generateSine(frequency);
break;
case 1:
generateSquareDAC1(frequency, duty);
generateSquare(frequency, duty);
break;
}

View File

@ -1,56 +0,0 @@
#include "wave.h"
#include "sine.h"
void calculateSineLookup();
int LUT[LUT_SIZE];
void setupSine(){
calculateSineLookup();
}
/* Calculate a sine lookup table using the analytic formula for a sine wave y=A*sin(wt+phi)
Only the first quarter (quadrant) of the wave is actually getting calculated. This saves up time for calculation
and assures the simmetry of the wave in each quadrant
*/
void calculateSineLookup(){
int LUT_SIZE_QUARTER = LUT_SIZE * 0.25;
int LUT_SIZE_HALF = LUT_SIZE * 0.5;
for (int i = 0; i < LUT_SIZE; i++) {
//For the first quarter of the lut, generate a quarter of a sine wave
if(i >= 0 && i <= LUT_SIZE_QUARTER) LUT[i] = MAX_VALUE_HALF + (MAX_VALUE_HALF-1) * sin((2 * PI * (float)i) / LUT_SIZE);
else if(i > LUT_SIZE_QUARTER && i <= LUT_SIZE_HALF) LUT[i] = LUT[(LUT_SIZE_HALF-i)];
else LUT[i] = MAX_VALUE-LUT[(LUT_SIZE-i)];;
}
}
//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();
digitalWriteFast(DAC0_SEL, HIGH);
digitalWriteFast(DAC1_SEL, LOW);
// Phase accumulator
float phase = 0;
//Constrain frequency
frequency = constrain(frequency, 0, MAX_ACHIEVABLE_FREQ);
// 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

@ -1,86 +0,0 @@
#include "square.h"
#include "wave.h"
void setupSquare(){
pinMode(SQUARE_PIN, OUTPUT);
}
/*Generate a square wave by toggling a digital HIGH and LOW at the correct speed
Count in nano seconds and wait using CPU Cycles for the maximum accuracy on higher frequency waves
Lower frequency waves using nanoseconds is not needed and could actually causes overflows due to the length of the number used, so microseconds can be used instead*/
// Use FASTRUN to run code in RAM
FASTRUN void generateSquare(float frequency, int duty){
digitalWriteFast(DAC0_SEL, LOW);
digitalWriteFast(DAC1_SEL, HIGH);
startGenerating();
if(frequency < 100000){
unsigned long periodMS = (1/ frequency) * pow(10, 6);
unsigned long dutyHigh = periodMS * duty * 0.01;
unsigned long dutyLow = periodMS * duty * 0.01;
while(generateWave){
digitalWriteFast(SQUARE_PIN, HIGH);
delayMicroseconds(dutyHigh);
digitalWriteFast(SQUARE_PIN, LOW);
delayMicroseconds(dutyLow);
}
}else{
unsigned long periodNS = (1/ frequency) * pow(10, 9);
//Duration of the logic HIGH level
unsigned long dutyHigh = periodNS * duty * 0.01;
//Duration of the logic LOW level
unsigned long dutyLow = periodNS - dutyHigh;
unsigned long dutyHighCycles = (unsigned long) (dutyHigh/CLOCK_TO_NS+0.5f);
unsigned long dutyLowCycles = (unsigned long) (dutyLow/CLOCK_TO_NS+0.5f);
while(generateWave){
digitalWriteFast(SQUARE_PIN, HIGH);
delayCycles(dutyHighCycles);
digitalWriteFast(SQUARE_PIN, LOW);
delayCycles(dutyLowCycles);
}
}
}
FASTRUN void generateSquareDAC1(float frequency, int duty){
digitalWriteFast(DAC0_SEL, LOW);
digitalWriteFast(DAC1_SEL, HIGH);
startGenerating();
if(frequency <= 50000){
unsigned long periodMS = (1/ frequency) * pow(10, 6);
unsigned long dutyHigh = periodMS * duty * 0.01;
unsigned long dutyLow = periodMS * duty * 0.01;
while(generateWave){
analogWriteDAC1(MAX_VALUE);
delayMicroseconds(dutyHigh);
analogWriteDAC1(0);
delayMicroseconds(dutyLow);
}
}else{
unsigned long periodNS = (1/ frequency) * pow(10, 9);
//Duration of the logic HIGH level
unsigned long dutyHigh = periodNS * duty * 0.01;
//Duration of the logic LOW level
unsigned long dutyLow = periodNS - dutyHigh;
unsigned long dutyHighCycles = (unsigned long) (dutyHigh/CLOCK_TO_NS+0.5f);
unsigned long dutyLowCycles = (unsigned long) (dutyLow/CLOCK_TO_NS+0.5f);
while(generateWave){
analogWriteDAC1(MAX_VALUE);
delayCycles(dutyHighCycles);
analogWriteDAC1(0);
delayCycles(dutyLowCycles);
}
}
}

View File

@ -1,38 +0,0 @@
#define WAVE_H
#include "Arduino.h"
#include "wave.h"
void setupWaves(){
pinMode(DAC0_SEL, OUTPUT);
pinMode(DAC1_SEL, OUTPUT);
// Info from teensy forum, access cycle counter. This will be needed for square waves in particular
ARM_DEMCR |= ARM_DEMCR_TRCENA;
ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
//Set DACs resolution to 12 bits
analogWriteResolution(12);
// Enable DAC0 and DAC1, from framework's analogWriteDAC0/DAC1, place here from higher speeds
// Reference voltage is 1.2V
SIM_SCGC2 |= SIM_SCGC2_DAC0;
DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS;
SIM_SCGC2 |= SIM_SCGC2_DAC1;
DAC1_C0 = DAC_C0_DACEN | DAC_C0_DACRFS;
}
// Wait time by counting clock cycles
FASTRUN void delayCycles(unsigned long t){
unsigned long begin = ARM_DWT_CYCCNT-CYCLE_OVERHEAD;
while(ARM_DWT_CYCCNT - begin < t) { ; } //wait
}
// This needs to be called from the interrupt triggered by the rotary encoder being pressed
void stopGenerating(){
generateWave = false;
}
FASTRUN void startGenerating(){
generateWave = true;
}

View File

@ -0,0 +1,113 @@
#define WAVE_H
#include "Arduino.h"
#include "waves.h"
int SINE_LUT[LUT_SIZE];
int SQUARE_LUT[LUT_SIZE];
void setupWaves(){
pinMode(DAC0_SEL, OUTPUT);
pinMode(DAC1_SEL, OUTPUT);
// Info from teensy forum, access cycle counter. This will be needed for square waves in particular
ARM_DEMCR |= ARM_DEMCR_TRCENA;
ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
//Set DACs resolution to 12 bits
analogWriteResolution(12);
// Enable DAC0 and DAC1, from framework's analogWriteDAC0/DAC1, place here from higher speeds
// Reference voltage is 1.2V
SIM_SCGC2 |= SIM_SCGC2_DAC0;
DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS;
SIM_SCGC2 |= SIM_SCGC2_DAC1;
DAC1_C0 = DAC_C0_DACEN | DAC_C0_DACRFS;
//This one can be calculated only once
calculateSineLookup();
}
// Wait time by counting clock cycles
FASTRUN void delayCycles(unsigned long t){
unsigned long begin = ARM_DWT_CYCCNT-CYCLE_OVERHEAD;
while(ARM_DWT_CYCCNT - begin < t) { ; } //wait
}
// This needs to be called from the interrupt triggered by the rotary encoder being pressed
void stopGenerating(){
generating = false;
}
FASTRUN void startGenerating(){
generating = true;
}
/* Calculate a sine lookup table using the analytic formula for a sine wave y=A*sin(wt+phi)
Only the first quarter (quadrant) of the wave is actually getting calculated. This saves up time for calculation
and assures the simmetry of the wave in each quadrant
*/
void calculateSineLookup(){
int LUT_SIZE_QUARTER = LUT_SIZE * 0.25;
int LUT_SIZE_HALF = LUT_SIZE * 0.5;
for (int i = 0; i < LUT_SIZE; i++) {
//For the first quarter of the lut, generate a quarter of a sine wave
if(i >= 0 && i <= LUT_SIZE_QUARTER) SINE_LUT[i] = MAX_VALUE_HALF + (MAX_VALUE_HALF-1) * sin((2 * PI * (float)i) / LUT_SIZE);
else if(i > LUT_SIZE_QUARTER && i <= LUT_SIZE_HALF) SINE_LUT[i] = SINE_LUT[(LUT_SIZE_HALF-i)];
else SINE_LUT[i] = MAX_VALUE-SINE_LUT[(LUT_SIZE-i)];;
}
}
void calculateSquareLookup(int duty){
int i_duty = LUT_SIZE*0.01*duty;
for(int i = 0; i < LUT_SIZE; i++) SQUARE_LUT[i] = MAX_VALUE*(i<i_duty);
}
void selectDAC0(){
digitalWriteFast(DAC0_SEL, HIGH);
digitalWriteFast(DAC1_SEL, LOW);
}
void selectDAC1(){
digitalWriteFast(DAC0_SEL, LOW);
digitalWriteFast(DAC1_SEL, HIGH);
}
//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 generateWave(float frequency, int LUT[], int dac){
startGenerating();
// Phase accumulator
float phase = 0;
//Constrain frequency
frequency = constrain(frequency, 0, MAX_ACHIEVABLE_FREQ);
// Phase increment at each step
float delta_phi = frequency / SAMPLE_FREQ * LUT_SIZE;
while(generating){
// increment phase
phase += delta_phi;
// handle wraparound
if (phase >= LUT_SIZE) phase -= LUT_SIZE;
//Write the voltage on the DAC
if(dac == 0) *(volatile aliased_int16_t *)&(DAC0_DAT0L) = LUT[(int)phase];
else *(volatile aliased_int16_t *)&(DAC1_DAT0L) = LUT[(int)phase];
}
}
FASTRUN void generateSine(float frequency){
selectDAC0();
generateWave(frequency, SINE_LUT, 0);
}
FASTRUN void generateSquare(float frequency, int duty){
startGenerating();
calculateSquareLookup(duty);
generateWave(frequency, SQUARE_LUT, 1);
}