diff --git a/FunctionGen-Teensy/software/Teensy3.5DDS/.gitignore b/.gitignore similarity index 100% rename from FunctionGen-Teensy/software/Teensy3.5DDS/.gitignore rename to .gitignore diff --git a/FunctionGen-Teensy/software/tests/Test/.gitignore b/Firmware/.gitignore similarity index 100% rename from FunctionGen-Teensy/software/tests/Test/.gitignore rename to Firmware/.gitignore diff --git a/FunctionGen-Teensy/software/Teensy3.5DDS/.vscode/extensions.json b/Firmware/.vscode/extensions.json similarity index 100% rename from FunctionGen-Teensy/software/Teensy3.5DDS/.vscode/extensions.json rename to Firmware/.vscode/extensions.json diff --git a/FunctionGen-Teensy/software/Teensy3.5DDS/include/sine.h b/Firmware/include/sine.h similarity index 100% rename from FunctionGen-Teensy/software/Teensy3.5DDS/include/sine.h rename to Firmware/include/sine.h diff --git a/FunctionGen-Teensy/software/Teensy3.5DDS/include/square.h b/Firmware/include/square.h similarity index 100% rename from FunctionGen-Teensy/software/Teensy3.5DDS/include/square.h rename to Firmware/include/square.h diff --git a/FunctionGen-Teensy/software/Teensy3.5DDS/include/wave.h b/Firmware/include/wave.h similarity index 100% rename from FunctionGen-Teensy/software/Teensy3.5DDS/include/wave.h rename to Firmware/include/wave.h diff --git a/FunctionGen-Teensy/software/Teensy3.5DDS/lib/README b/Firmware/lib/README similarity index 100% rename from FunctionGen-Teensy/software/Teensy3.5DDS/lib/README rename to Firmware/lib/README diff --git a/FunctionGen-Teensy/software/Teensy3.5DDS/platformio.ini b/Firmware/platformio.ini similarity index 100% rename from FunctionGen-Teensy/software/Teensy3.5DDS/platformio.ini rename to Firmware/platformio.ini diff --git a/FunctionGen-Teensy/software/Teensy3.5DDS/src/main.cpp b/Firmware/src/main.cpp similarity index 100% rename from FunctionGen-Teensy/software/Teensy3.5DDS/src/main.cpp rename to Firmware/src/main.cpp diff --git a/FunctionGen-Teensy/software/Teensy3.5DDS/src/sine.cpp b/Firmware/src/sine.cpp similarity index 100% rename from FunctionGen-Teensy/software/Teensy3.5DDS/src/sine.cpp rename to Firmware/src/sine.cpp diff --git a/FunctionGen-Teensy/software/Teensy3.5DDS/src/square.cpp b/Firmware/src/square.cpp similarity index 100% rename from FunctionGen-Teensy/software/Teensy3.5DDS/src/square.cpp rename to Firmware/src/square.cpp diff --git a/FunctionGen-Teensy/software/Teensy3.5DDS/src/wave.cpp b/Firmware/src/wave.cpp similarity index 96% rename from FunctionGen-Teensy/software/Teensy3.5DDS/src/wave.cpp rename to Firmware/src/wave.cpp index 224b098..445af30 100644 --- a/FunctionGen-Teensy/software/Teensy3.5DDS/src/wave.cpp +++ b/Firmware/src/wave.cpp @@ -12,6 +12,7 @@ void setupWaves(){ analogWriteResolution(12); // Enable DAC0, from framework's analogWriteDAC0, place here from higher speeds + // Reference voltage is 1.2V SIM_SCGC2 |= SIM_SCGC2_DAC0; DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; } diff --git a/FunctionGen-Teensy/software/Teensy3.5DDS/test/README b/Firmware/test/README similarity index 100% rename from FunctionGen-Teensy/software/Teensy3.5DDS/test/README rename to Firmware/test/README diff --git a/FunctionGen-Teensy/software/Teensy3.5DDS/include/README b/FunctionGen-Teensy/software/Teensy3.5DDS/include/README deleted file mode 100644 index 194dcd4..0000000 --- a/FunctionGen-Teensy/software/Teensy3.5DDS/include/README +++ /dev/null @@ -1,39 +0,0 @@ - -This directory is intended for project header files. - -A header file is a file containing C declarations and macro definitions -to be shared between several project source files. You request the use of a -header file in your project source file (C, C++, etc) located in `src` folder -by including it, with the C preprocessing directive `#include'. - -```src/main.c - -#include "header.h" - -int main (void) -{ - ... -} -``` - -Including a header file produces the same results as copying the header file -into each source file that needs it. Such copying would be time-consuming -and error-prone. With a header file, the related declarations appear -in only one place. If they need to be changed, they can be changed in one -place, and programs that include the header file will automatically use the -new version when next recompiled. The header file eliminates the labor of -finding and changing all the copies as well as the risk that a failure to -find one copy will result in inconsistencies within a program. - -In C, the usual convention is to give header files names that end with `.h'. -It is most portable to use only letters, digits, dashes, and underscores in -header file names, and at most one dot. - -Read more about using header files in official GCC documentation: - -* Include Syntax -* Include Operation -* Once-Only Headers -* Computed Includes - -https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/FunctionGen-Teensy/software/tests/Test/.vscode/extensions.json b/FunctionGen-Teensy/software/tests/Test/.vscode/extensions.json deleted file mode 100644 index 0f0d740..0000000 --- a/FunctionGen-Teensy/software/tests/Test/.vscode/extensions.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - // See http://go.microsoft.com/fwlink/?LinkId=827846 - // for the documentation about the extensions.json format - "recommendations": [ - "platformio.platformio-ide" - ] -} diff --git a/FunctionGen-Teensy/software/tests/Test/include/README b/FunctionGen-Teensy/software/tests/Test/include/README deleted file mode 100644 index 194dcd4..0000000 --- a/FunctionGen-Teensy/software/tests/Test/include/README +++ /dev/null @@ -1,39 +0,0 @@ - -This directory is intended for project header files. - -A header file is a file containing C declarations and macro definitions -to be shared between several project source files. You request the use of a -header file in your project source file (C, C++, etc) located in `src` folder -by including it, with the C preprocessing directive `#include'. - -```src/main.c - -#include "header.h" - -int main (void) -{ - ... -} -``` - -Including a header file produces the same results as copying the header file -into each source file that needs it. Such copying would be time-consuming -and error-prone. With a header file, the related declarations appear -in only one place. If they need to be changed, they can be changed in one -place, and programs that include the header file will automatically use the -new version when next recompiled. The header file eliminates the labor of -finding and changing all the copies as well as the risk that a failure to -find one copy will result in inconsistencies within a program. - -In C, the usual convention is to give header files names that end with `.h'. -It is most portable to use only letters, digits, dashes, and underscores in -header file names, and at most one dot. - -Read more about using header files in official GCC documentation: - -* Include Syntax -* Include Operation -* Once-Only Headers -* Computed Includes - -https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/FunctionGen-Teensy/software/tests/Test/lib/README b/FunctionGen-Teensy/software/tests/Test/lib/README deleted file mode 100644 index 6debab1..0000000 --- a/FunctionGen-Teensy/software/tests/Test/lib/README +++ /dev/null @@ -1,46 +0,0 @@ - -This directory is intended for project specific (private) libraries. -PlatformIO will compile them to static libraries and link into executable file. - -The source code of each library should be placed in a an own separate directory -("lib/your_library_name/[here are source files]"). - -For example, see a structure of the following two libraries `Foo` and `Bar`: - -|--lib -| | -| |--Bar -| | |--docs -| | |--examples -| | |--src -| | |- Bar.c -| | |- Bar.h -| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html -| | -| |--Foo -| | |- Foo.c -| | |- Foo.h -| | -| |- README --> THIS FILE -| -|- platformio.ini -|--src - |- main.c - -and a contents of `src/main.c`: -``` -#include -#include - -int main (void) -{ - ... -} - -``` - -PlatformIO Library Dependency Finder will find automatically dependent -libraries scanning project source files. - -More information about PlatformIO Library Dependency Finder -- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/FunctionGen-Teensy/software/tests/Test/platformio.ini b/FunctionGen-Teensy/software/tests/Test/platformio.ini deleted file mode 100644 index ae5443d..0000000 --- a/FunctionGen-Teensy/software/tests/Test/platformio.ini +++ /dev/null @@ -1,14 +0,0 @@ -; PlatformIO Project Configuration File -; -; Build options: build flags, source filter -; Upload options: custom upload port, speed and extra flags -; Library options: dependencies, extra library storages -; Advanced options: extra scripting -; -; Please visit documentation for the other options and examples -; https://docs.platformio.org/page/projectconf.html - -[env:teensy35] -platform = teensy -board = teensy35 -framework = arduino diff --git a/FunctionGen-Teensy/software/tests/Test/src/lookup_tables.h b/FunctionGen-Teensy/software/tests/Test/src/lookup_tables.h deleted file mode 100644 index f751e99..0000000 --- a/FunctionGen-Teensy/software/tests/Test/src/lookup_tables.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -//From: https://github.com/jameskeaveney/Teensy-SineWaveGenerator - -#define maxSamplesNum 512 // 12-bit - -static int waveformsTable[maxSamplesNum] = { - // Sin wave - 0x800,0x819,0x832,0x84c,0x865,0x87e,0x897,0x8b0,0x8c9,0x8e2,0x8fb,0x914, -0x92d,0x946,0x95f,0x978,0x990,0x9a9,0x9c2,0x9da,0x9f3,0xa0b,0xa23,0xa3b, -0xa54,0xa6c,0xa84,0xa9b,0xab3,0xacb,0xae2,0xafa,0xb11,0xb28,0xb3f,0xb56, -0xb6d,0xb84,0xb9a,0xbb1,0xbc7,0xbdd,0xbf3,0xc09,0xc1f,0xc34,0xc4a,0xc5f, -0xc74,0xc89,0xc9d,0xcb2,0xcc6,0xcda,0xcee,0xd02,0xd15,0xd29,0xd3c,0xd4f, -0xd62,0xd74,0xd86,0xd98,0xdaa,0xdbc,0xdcd,0xddf,0xdf0,0xe00,0xe11,0xe21, -0xe31,0xe41,0xe51,0xe60,0xe6f,0xe7e,0xe8d,0xe9b,0xea9,0xeb7,0xec4,0xed2, -0xedf,0xeec,0xef8,0xf04,0xf10,0xf1c,0xf27,0xf32,0xf3d,0xf48,0xf52,0xf5c, -0xf66,0xf6f,0xf78,0xf81,0xf8a,0xf92,0xf9a,0xfa2,0xfa9,0xfb0,0xfb7,0xfbe, -0xfc4,0xfca,0xfcf,0xfd5,0xfda,0xfde,0xfe3,0xfe7,0xfeb,0xfee,0xff1,0xff4, -0xff7,0xff9,0xffb,0xffd,0xffe,0xfff,0x1000,0x1000,0x1000,0x1000,0xfff,0xffe, -0xffd,0xffc,0xffa,0xff8,0xff5,0xff3,0xff0,0xfec,0xfe9,0xfe5,0xfe1,0xfdc, -0xfd7,0xfd2,0xfcd,0xfc7,0xfc1,0xfba,0xfb4,0xfad,0xfa6,0xf9e,0xf96,0xf8e, -0xf86,0xf7d,0xf74,0xf6b,0xf61,0xf57,0xf4d,0xf43,0xf38,0xf2d,0xf22,0xf16, -0xf0a,0xefe,0xef2,0xee5,0xed8,0xecb,0xebe,0xeb0,0xea2,0xe94,0xe85,0xe77, -0xe68,0xe58,0xe49,0xe39,0xe29,0xe19,0xe09,0xdf8,0xde7,0xdd6,0xdc5,0xdb3, -0xda1,0xd8f,0xd7d,0xd6b,0xd58,0xd45,0xd32,0xd1f,0xd0c,0xcf8,0xce4,0xcd0, -0xcbc,0xca8,0xc93,0xc7e,0xc69,0xc54,0xc3f,0xc2a,0xc14,0xbfe,0xbe8,0xbd2, -0xbbc,0xba6,0xb8f,0xb79,0xb62,0xb4b,0xb34,0xb1d,0xb06,0xaee,0xad7,0xabf, -0xaa7,0xa90,0xa78,0xa60,0xa48,0xa2f,0xa17,0x9ff,0x9e6,0x9ce,0x9b5,0x99d, -0x984,0x96b,0x952,0x93a,0x921,0x908,0x8ef,0x8d6,0x8bd,0x8a4,0x88a,0x871, -0x858,0x83f,0x826,0x80d,0x7f3,0x7da,0x7c1,0x7a8,0x78f,0x776,0x75c,0x743, -0x72a,0x711,0x6f8,0x6df,0x6c6,0x6ae,0x695,0x67c,0x663,0x64b,0x632,0x61a, -0x601,0x5e9,0x5d1,0x5b8,0x5a0,0x588,0x570,0x559,0x541,0x529,0x512,0x4fa, -0x4e3,0x4cc,0x4b5,0x49e,0x487,0x471,0x45a,0x444,0x42e,0x418,0x402,0x3ec, -0x3d6,0x3c1,0x3ac,0x397,0x382,0x36d,0x358,0x344,0x330,0x31c,0x308,0x2f4, -0x2e1,0x2ce,0x2bb,0x2a8,0x295,0x283,0x271,0x25f,0x24d,0x23b,0x22a,0x219, -0x208,0x1f7,0x1e7,0x1d7,0x1c7,0x1b7,0x1a8,0x198,0x189,0x17b,0x16c,0x15e, -0x150,0x142,0x135,0x128,0x11b,0x10e,0x102,0xf6,0xea,0xde,0xd3,0xc8, -0xbd,0xb3,0xa9,0x9f,0x95,0x8c,0x83,0x7a,0x72,0x6a,0x62,0x5a, -0x53,0x4c,0x46,0x3f,0x39,0x33,0x2e,0x29,0x24,0x1f,0x1b,0x17, -0x14,0x10,0xd,0xb,0x8,0x6,0x4,0x3,0x2,0x1,0x0,0x0, -0x0,0x0,0x1,0x2,0x3,0x5,0x7,0x9,0xc,0xf,0x12,0x15, -0x19,0x1d,0x22,0x26,0x2b,0x31,0x36,0x3c,0x42,0x49,0x50,0x57, -0x5e,0x66,0x6e,0x76,0x7f,0x88,0x91,0x9a,0xa4,0xae,0xb8,0xc3, -0xce,0xd9,0xe4,0xf0,0xfc,0x108,0x114,0x121,0x12e,0x13c,0x149,0x157, -0x165,0x173,0x182,0x191,0x1a0,0x1af,0x1bf,0x1cf,0x1df,0x1ef,0x200,0x210, -0x221,0x233,0x244,0x256,0x268,0x27a,0x28c,0x29e,0x2b1,0x2c4,0x2d7,0x2eb, -0x2fe,0x312,0x326,0x33a,0x34e,0x363,0x377,0x38c,0x3a1,0x3b6,0x3cc,0x3e1, -0x3f7,0x40d,0x423,0x439,0x44f,0x466,0x47c,0x493,0x4aa,0x4c1,0x4d8,0x4ef, -0x506,0x51e,0x535,0x54d,0x565,0x57c,0x594,0x5ac,0x5c5,0x5dd,0x5f5,0x60d, -0x626,0x63e,0x657,0x670,0x688,0x6a1,0x6ba,0x6d3,0x6ec,0x705,0x71e,0x737, -0x750,0x769,0x782,0x79b,0x7b4,0x7ce,0x7e7,0x800 -}; \ No newline at end of file diff --git a/FunctionGen-Teensy/software/tests/Test/src/teensy_audiolibrary.cpp b/FunctionGen-Teensy/software/tests/Test/src/teensy_audiolibrary.cpp deleted file mode 100644 index fe68cc2..0000000 --- a/FunctionGen-Teensy/software/tests/Test/src/teensy_audiolibrary.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "test.h" - -#ifdef TEST6 - -#include "Audio.h" -#include "" - -AudioSynthWaveformSine sine1; -AudioSynthWaveformSine sine2; -AudioOutputAnalog dac1(0); -AudioOutputAnalog dac2(1); -AudioConnection patchCord1(sine1, dac1); -AudioConnection patchCord1(sine2, dac2); - -void setup (void) { - AudioMemory(12); - sine1.amplitude(1.0); - sine1.frequency(100); - sine2.amplitude(2.0); - sine2.frequency(200); -} - -void loop (void) { -} - -#endif \ No newline at end of file diff --git a/FunctionGen-Teensy/software/tests/Test/src/test.cpp b/FunctionGen-Teensy/software/tests/Test/src/test.cpp deleted file mode 100644 index 64fb016..0000000 --- a/FunctionGen-Teensy/software/tests/Test/src/test.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "test.h" -#ifdef TEST1 - -//The analogWrite function takes an int as argument. The DAC is 12 bit. So max int value we can use is 2^16 -//Precalculate it, don't use a define -int MAX_VALUE = pow(2, 12); -int MAX_VALUE_HALF = MAX_VALUE / 2; - -//DAC voltage value goes from 0V (analogWrite(0)) to 3.3V (analogWrite(pow(2,12))) - -//Function declaration -void sineWave(); -void resetSineWave(); -void sawTooth(boolean); -float sineApprox(float); - -float freq = 1000; //Hertz - -void setup() -{ - //Set DACs resolution to 12 bits - analogWriteResolution(12); - - Serial.begin(9600); - - resetSineWave(); -} - -float amplitude = 1; - -void loop() -{ - sineWave(); -} - -float t = 0; -float omega = freq * 2 * PI; - -int oldValue = 0; -unsigned long lastTime = 0; -unsigned long time = 0; - -//This is not frequency accurate. Frequency changes by changing the t value, which is totally not correct -void sineWave() -{ - int y1 = MAX_VALUE_HALF + MAX_VALUE_HALF * sin(omega + t ); - - analogWriteDAC0(y1); - - t += 0.26; - -} - -void resetSineWave() -{ - t = 0; -} - -void sawTooth(boolean delay_) -{ - //Sawthoot wave - for (int i = 0; i < MAX_VALUE; i++) - { - analogWriteDAC0(i); - analogWriteDAC1(i); - if (delay_) - delay(100); - } -} - -//Sine approximation function https://en.wikipedia.org/wiki/Bhaskara_I%27s_sine_approximation_formula -float sineApprox(float x) -{ - return (16 * x * (PI - x) / (5 * PI * PI - 4 * x * (PI - x))); -} -#endif \ No newline at end of file diff --git a/FunctionGen-Teensy/software/tests/Test/src/test.h b/FunctionGen-Teensy/software/tests/Test/src/test.h deleted file mode 100644 index 565954f..0000000 --- a/FunctionGen-Teensy/software/tests/Test/src/test.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -#define TEST6 - -#include \ No newline at end of file diff --git a/FunctionGen-Teensy/software/tests/Test/src/test_customlookup.cpp b/FunctionGen-Teensy/software/tests/Test/src/test_customlookup.cpp deleted file mode 100644 index 9e62367..0000000 --- a/FunctionGen-Teensy/software/tests/Test/src/test_customlookup.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "test.h" - -#ifdef TEST3 -//Lookup table test - -//Use a lookup table to generate the sine wave. This works well and generates a good 0-3.3V sine wave -//After playing around with the sampling freq, this is good enough but still has some artifacts on the wave, probably due to the phase accumulator wraparound. But definitely the way to go here -//Above a certain value (like 130khz) linear interpolation is NEEDED to smooth out the wave, probably due to the sampling rate of the DAC - -//Next-day note: the artifacts on the wave definetely were because of the phase wraparound, changing the way the DAC was driven and the phase accumulated this now works fine -//Linear interpolation is still needed though - -//The analogWrite function takes an int as argument. The DAC is 12 bit. So max int value we can use is 2^12 -//Precalculate it, don't use a define - -int MAX_VALUE = pow(2, 12); -int MAX_VALUE_HALF = MAX_VALUE / 2; - -//How many samples of the wave we want -#define LUT_SIZE 1024 -int LUT[LUT_SIZE]; - -const int BUFF_SIZE = 1024; // size of output buffer (samples) -int16_t buff[BUFF_SIZE]; // output buffer - -//DAC voltage value goes from 0V (analogWrite(0)) to 3.3V (analogWrite(pow(2,12))) - -void calculateLookupTable(); - -FASTRUN void setup() { - //Set DACs resolution to 12 bits - analogWriteResolution(12); - - //Disable interrupts for extra speed - noInterrupts(); - - calculateLookupTable(); -} - -long sampleFreq = 1818181; //DAC sampling time(1428571,428571429), then i played around with it - -const int f = 50000; // frequency we want to generate (Hz) -const float delta_phi = (float)f / sampleFreq * LUT_SIZE; // phase increment -int phase = 0.0f; // phase accumulator - -FASTRUN void loop() { - - // generate buffer of output - for (int i = 0; i < BUFF_SIZE; ++i) { - buff[i] = LUT[phase]; // get sample value from LUT - phase = (phase + delta_phi) % LUT_SIZE; // increment phase - if (phase >= (float)LUT_SIZE) // handle wraparound - phase -= (float)LUT_SIZE; - - analogWriteDAC0(buff[i]); // write the selected waveform on DAC - } -} - -//Using the analitic formula for a sine wave, calculate the lookup table -void calculateLookupTable() { - for (int i = 0; i < LUT_SIZE; i++) { - LUT[i] = MAX_VALUE_HALF + MAX_VALUE_HALF * sin((2 * PI * (float)i) / LUT_SIZE); - } -} -#endif \ No newline at end of file diff --git a/FunctionGen-Teensy/software/tests/Test/src/test_lookup.cpp b/FunctionGen-Teensy/software/tests/Test/src/test_lookup.cpp deleted file mode 100644 index ace1c50..0000000 --- a/FunctionGen-Teensy/software/tests/Test/src/test_lookup.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "test.h" - -#ifdef TEST2 -//Lookup table test - -//Use a lookup table to generate the sine wave. This works well and generates a good 0-3.3V sine wave -//Frequency is modulated using "samplerate", which waits a defined time between outputting a point and another. -//The digital oscilloscope reports the frequency to be in a range 10-100 hertz from the defined requency (drifting higher the higher the frequency) -//Frequency caps at 1.5kHz, but it's stabler the lower it goes -//delay functions in teensy take long as arguments, eliminating the decimal part and giving us less numbers to use (samplerate becomes lower and lower the higher the frequency) -//Approximation errors errors cap the frequency and make it less accurate - -//The analogWrite function takes an int as argument. The DAC is 12 bit. So max int value we can use is 2^12 -//Precalculate it, don't use a define - -int MAX_VALUE = pow(2, 12); -int MAX_VALUE_HALF = MAX_VALUE / 2; - -//DAC voltage value goes from 0V (analogWrite(0)) to 3.3V (analogWrite(pow(2,12))) - -volatile int i = 0; - -float freq = 100; //Hertz - -FASTRUN void setup() { - //Set DACs resolution to 12 bits - analogWriteResolution(12); - - //Disable interrupts for extra speed - noInterrupts(); -} - -//This is how much time can pass between two points -//We wait micros (10^-6) to mult by 10^6 -float samplerate = ((1/freq)/maxSamplesNum)*pow(10, 6); - -FASTRUN void loop() { - analogWriteDAC0(waveformsTable[i]); // write the selected waveform on DAC - i = (i+1)%maxSamplesNum; - - //Using delay instead of micros() produces defined waves that don't wobble because of the approximation errors, since delayMicroseconds takes a long and not a float as argument - delayMicroseconds(samplerate); -} -#endif \ No newline at end of file diff --git a/FunctionGen-Teensy/software/tests/Test/src/test_quarterlookup.cpp b/FunctionGen-Teensy/software/tests/Test/src/test_quarterlookup.cpp deleted file mode 100644 index 565121b..0000000 --- a/FunctionGen-Teensy/software/tests/Test/src/test_quarterlookup.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "test.h" - -#ifdef TEST4 -//Lookup table test - -//Use a lookup table to generate a quarter of a sine sine wave. This eliminates asimmetries and random frequency shiftings (very slight but noticeable enough) -//It is also a faster algo -//This however has some problems in the zones when a quarter if shifted, giving some artifacts that point to MAX_VALUE_HALF, like if there was MAX_VALUE_HALF in the table at that point - -//The analogWrite function takes an int as argument. The DAC is 12 bit. So max int value we can use is 2^12 -//Precalculate it, don't use a define - -int MAX_VALUE = pow(2, 12); -int MAX_VALUE_HALF = MAX_VALUE / 2; - -//How many samples of the wave we want -#define LUT_SIZE 1024 -int LUT[LUT_SIZE]; - -const int BUFF_SIZE = 4096; // size of output buffer (samples) -int16_t buff[BUFF_SIZE]; // output buffer - -//DAC voltage value goes from 0V (analogWrite(0)) to 3.3V (analogWrite(pow(2,12))) - -void calculateLookupTable(); - -FASTRUN void setup() { - //Set DACs resolution to 12 bits - analogWriteResolution(12); - - //Disable interrupts for extra speed - noInterrupts(); - - calculateLookupTable(); - - Serial.begin(115200); -} - -long sampleFreq = 1428571; //DAC sampling time(1428571,428571429), then i played around with it - -const int f = 10000; // frequency we want to generate (Hz) -const float delta_phi = (float)f / sampleFreq * (LUT_SIZE*4); // phase increment -int phase = 0.0f; // phase accumulator - -int LUT_SIZE_QUARTER = LUT_SIZE * 2; -int LUT_SIZE_HALF = LUT_SIZE * 3; -int LUT_SIZE_3QUARTERS = LUT_SIZE * 4; - -FASTRUN void loop() { - - // generate buffer of output - for (int i = 0; i < BUFF_SIZE; ++i) { - - phase += delta_phi; // increment phase - - int phase_i = (int)phase; // get integer part of our phase - - //For the first quarter of the lut, generate a quarter of a sine wave - - if(phase >= 0 && phase < LUT_SIZE) buff[i] = LUT[phase_i]; - else if(phase >= LUT_SIZE && phase < LUT_SIZE*2) buff[i] = LUT[(2*LUT_SIZE-phase_i)%LUT_SIZE]; - else if(phase >= LUT_SIZE*2 && phase < LUT_SIZE*3) buff[i] = MAX_VALUE-LUT[(2*LUT_SIZE+phase_i)%LUT_SIZE]; - else if(phase >= LUT_SIZE*3 && phase <= LUT_SIZE*4) buff[i] = MAX_VALUE-LUT[(4*LUT_SIZE-phase_i)%LUT_SIZE]; - else if (phase > (float)LUT_SIZE*4) phase -= (float)(LUT_SIZE*4); // handle wraparound - - //This is a very ugly fix to the spikes that sometimes happed when changing quadrant - // if (abs(oldValue-buff[i]) >= MAX_VALUE_HALF*0.65) buff[i] = oldValue; - // else oldValue = buff[i] - - - analogWriteDAC0(buff[i]); - } -} - -//Calculate the lookup table for a quarter (pi/2) of the sinewave -void calculateLookupTable() { - for (int i = 0; i < LUT_SIZE; i++) { - LUT[i] = MAX_VALUE_HALF + MAX_VALUE_HALF * sin((PI/2) * i / LUT_SIZE); - } -} -#endif \ No newline at end of file diff --git a/FunctionGen-Teensy/software/tests/Test/src/test_quarterlookup_2.cpp b/FunctionGen-Teensy/software/tests/Test/src/test_quarterlookup_2.cpp deleted file mode 100644 index a8e46a1..0000000 --- a/FunctionGen-Teensy/software/tests/Test/src/test_quarterlookup_2.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "test.h" - -#ifdef TEST5 -//Lookup table test - -//Generate a full lookup table by using simmetries of the first quarter. Works fine, i'd use this as the base for the complete project. -//Usual artifacts from 100kHz on, but i think it just needs to switch from analogWrite to the use of registers, to drive the DAC as fast as possible. - -int MAX_VALUE = pow(2, 12); -int MAX_VALUE_HALF = MAX_VALUE / 2; - -//How many samples of the wave we want -#define LUT_SIZE 1024 -int LUT[LUT_SIZE]; - -const int BUFF_SIZE = 4096; // size of output buffer (samples) -int16_t buff[BUFF_SIZE]; // output buffer - -//DAC voltage value goes from 0V (analogWrite(0)) to 3.3V (analogWrite(pow(2,12))) - -void calculateLookupTable(); - -FASTRUN void setup() { - //Set DACs resolution to 12 bits - analogWriteResolution(12); - - //Disable interrupts for extra speed - noInterrupts(); - - calculateLookupTable(); -} - -long sampleFreq = 1817571; //DAC sampling time(1428571,428571429), then i played around with it - -const int f = 250075; // frequency we want to generate (Hz) -const float delta_phi = (float)f / sampleFreq * (LUT_SIZE); // phase increment -float phase = 0.0f; // phase accumulator - -int oldValue; - -FASTRUN void loop() { - - // generate buffer of output - for (int i = 0; i < BUFF_SIZE; ++i) { - int phase_i = (int)phase; // get integer part of our phase - buff[i] = LUT[phase_i]; // get sample value from LUT - phase += delta_phi; // increment phase - if (phase >= (float)LUT_SIZE) // handle wraparound - phase -= (float)LUT_SIZE; - - analogWriteDAC0(buff[i]); // write the selected waveform on DAC - } -} - -//Calculate a quarter of a sine wave, the other three quadrants are simmetris of it -void calculateLookupTable() { - 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 * 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)];; - } -} - - -#endif \ No newline at end of file diff --git a/FunctionGen-Teensy/software/tests/Test/test/README b/FunctionGen-Teensy/software/tests/Test/test/README deleted file mode 100644 index b94d089..0000000 --- a/FunctionGen-Teensy/software/tests/Test/test/README +++ /dev/null @@ -1,11 +0,0 @@ - -This directory is intended for PlatformIO Unit Testing and project tests. - -Unit Testing is a software testing method by which individual units of -source code, sets of one or more MCU program modules together with associated -control data, usage procedures, and operating procedures, are tested to -determine whether they are fit for use. Unit testing finds problems early -in the development cycle. - -More information about PlatformIO Unit Testing: -- https://docs.platformio.org/page/plus/unit-testing.html diff --git a/README.md b/README.md new file mode 100644 index 0000000..2d4c462 --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +# Teensy 3.5 DDS Function Generator +Using a Teensy 3.5 and the integrated DAC to generate arbitrary periodic waveforms
+ +## How it works +The [Teensy 3.5](https://www.pjrc.com/store/teensy35.html) is a powerful Arduino-compatible microcontroller running an ARM Cortex-M4 at 120 MHz
+For the purpose of this project, it has been overclocked to 168MHz, running with the Fastest Pure Code+LTO optimizer
+It has two integrated DACs whose output can vary between 0v and 3.3V
+Using classical techniques from DDS (Direct Digital Synthesis) the Teensy can become a fully functional function generator
+In particular, the technique used here is the classic Phase Accumulator, together with a Lookup Table. This allows to precompute arbitrary periodic waveforms and then output them at the wanted frequency.
+Square waves of variable duty cycles can be generated by simply toggling a digital pin high and low and the correct time +Despite both sine and square wave being output by the teensy are quite clean and seem to have low noise and spurs levels at naked eye, advanced filtering techniques, like Chebyshev, Butterworth or Bessel filters with multiple stages are required. +The desired waveform, frequency and duty cycle can be selected using the I2C LCD Display and an incremental encoder with pushbutton + + +## Amplification and offset +Sill WIP + + +## Filters +Still WIP + + +## Credits +A lot of choices come from following this Degree dissertation paper (Direct Digital Synthesizers: Theory, Design and Applications by Jouko Vankka, Helsinki University of Technology, November 2000): http://lib.tkk.fi/Diss/2000/isbn9512253186/isbn9512253186.pdf
+
Analog Devices offers a lot of cool guides and papers about DDS, this is one of them: https://www.analog.com/media/en/training-seminars/design-handbooks/Technical-Tutorial-DDS/Section8.pdf
+
The website [ZipCPU](zipcpu.com) offers a variety of articles about sine wave generation using FPGAs
+- https://zipcpu.com/dsp/2017/08/26/quarterwave.html
+- https://zipcpu.com/dsp/2017/07/11/simplest-sinewave-generator.html + +
Stackoverflow and the rest of the internet of course
+- https://stackoverflow.com/questions/13466623/how-to-look-up-sine-of-different-frequencies-from-a-fixed-sized-lookup-table
+- https://stackoverflow.com/questions/16889426/fm-synthesis-using-phase-accumulator
+- https://electronics.stackexchange.com/questions/438935/how-to-calculate-sampling-rate-for-dac-from-its-data-sheet
+- https://www.daycounter.com/Calculators/Sine-Generator-Calculator.phtml
diff --git a/Useful_links_and_notes.txt b/Useful_links_and_notes.txt deleted file mode 100644 index d1bd888..0000000 --- a/Useful_links_and_notes.txt +++ /dev/null @@ -1,20 +0,0 @@ -From my current research, using the analitic formula for the sine wave in not frequency-accurate and frequency changes by changing the incremental step factor t -Where y=A*sin(wt+q) - -Apparently using a lookup table is much easier, since the wave gets precomputed and stored in an array, and then it can be modulated in amplitude and frequency - -https://www.daycounter.com/Calculators/Sine-Generator-Calculator.phtml - -https://en.wikipedia.org/wiki/Numerically-controlled_oscillator - -But how to modulate in frequency? -Apparently phase accumulator is the answer: -https://stackoverflow.com/questions/13466623/how-to-look-up-sine-of-different-frequencies-from-a-fixed-sized-lookup-table (First answer works but i can't understand how the sample rate is involved) -https://stackoverflow.com/questions/16889426/fm-synthesis-using-phase-accumulator -https://zipcpu.com/dsp/2017/07/11/simplest-sinewave-generator.html - -And this is how you calculate the sample rate (of the DAC). Look at teensy's uC datasheet. Then just play around with it to suit your needs -https://electronics.stackexchange.com/questions/438935/how-to-calculate-sampling-rate-for-dac-from-its-data-sheet - -Even better than using a normal lookup table, is using a lookup table that stores only a quarter of a sine wave (0 to 90°), and then getting the other 3/4 by simmetry -https://zipcpu.com/dsp/2017/08/26/quarterwave.html