Skip to content

Commit

Permalink
add dds synth
Browse files Browse the repository at this point in the history
  • Loading branch information
robstave committed May 26, 2019
1 parent b9c9378 commit dedffef
Show file tree
Hide file tree
Showing 28 changed files with 7,522 additions and 776 deletions.
119 changes: 119 additions & 0 deletions midisynth/dds_01/dds_01.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@



#include "avr/pgmspace.h"


PROGMEM prog_uchar tri256[] = {0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, 0x80, 0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d, 0x8f, 0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9d, 0x9f, 0xa1, 0xa3, 0xa5, 0xa7, 0xa9, 0xab, 0xad, 0xaf, 0xb1, 0xb3, 0xb5, 0xb7, 0xb9, 0xbb, 0xbd, 0xbf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc9, 0xcb, 0xcd, 0xcf, 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf, 0xe1, 0xe3, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0xff, 0xfd, 0xfb, 0xf9, 0xf7, 0xf5, 0xf3, 0xf1, 0xef, 0xed, 0xeb, 0xe9, 0xe7, 0xe5, 0xe3, 0xe1, 0xdf, 0xdd, 0xdb, 0xd9, 0xd7, 0xd5, 0xd3, 0xd1, 0xcf, 0xcd, 0xcb, 0xc9, 0xc7, 0xc5, 0xc3, 0xc1, 0xbf, 0xbd, 0xbb, 0xb9, 0xb7, 0xb5, 0xb3, 0xb1, 0xaf, 0xad, 0xab, 0xa9, 0xa7, 0xa5, 0xa3, 0xa1, 0x9f, 0x9d, 0x9b, 0x99, 0x97, 0x95, 0x93, 0x91, 0x8f, 0x8d, 0x8b, 0x89, 0x87, 0x85, 0x83, 0x81, 0x80, 0x7e, 0x7c, 0x7a, 0x78, 0x76, 0x74, 0x72, 0x70, 0x6e, 0x6c, 0x6a, 0x68, 0x66, 0x64, 0x62, 0x60, 0x5e, 0x5c, 0x5a, 0x58, 0x56, 0x54, 0x52, 0x50, 0x4e, 0x4c, 0x4a, 0x48, 0x46, 0x44, 0x42, 0x40, 0x3e, 0x3c, 0x3a, 0x38, 0x36, 0x34, 0x32, 0x30, 0x2e, 0x2c, 0x2a, 0x28, 0x26, 0x24, 0x22, 0x20, 0x1e, 0x1c, 0x1a, 0x18, 0x16, 0x14, 0x12, 0x10, 0xe, 0xc, 0xa, 0x8, 0x6, 0x4, 0x2, 0x0};


PROGMEM prog_uchar sine256[] = {
127, 130, 133, 136, 139, 143, 146, 149, 152, 155, 158, 161, 164, 167, 170, 173,
176, 178, 181, 184, 187, 190, 192, 195, 198, 200, 203, 205, 208, 210, 212, 215,
217, 219, 221, 223, 225, 227, 229, 231, 233, 234, 236, 238, 239, 240, 242, 243,
244, 245, 247, 248, 249, 249, 250, 251, 252, 252, 253, 253, 253, 254, 254, 254,

254, 254, 254, 254, 253, 253, 253, 252, 252, 251, 250, 249, 249, 248, 247, 245,
244, 243, 242, 240, 239, 238, 236, 234, 233, 231, 229, 227, 225, 223, 221, 219,
217, 215, 212, 210, 208, 205, 203, 200, 198, 195, 192, 190, 187, 184, 181, 178,
176, 173, 170, 167, 164, 161, 158, 155, 152, 149, 146, 143, 139, 136, 133, 130,

127, 124, 121, 118, 115, 111, 108, 105, 102, 99, 96, 93, 90, 87, 84, 81,
78, 76, 73, 70, 67, 64, 62, 59, 56, 54, 51, 49, 46, 44, 42, 39,
37, 35, 33, 31, 29, 27, 25, 23, 21, 20, 18, 16, 15, 14, 12, 11,
10, 9, 7, 6, 5, 5, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0,

0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 9,
10, 11, 12, 14, 15, 16, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35,
37, 39, 42, 44, 46, 49, 51, 54, 56, 59, 62, 64, 67, 70, 73, 76,
78, 81, 84, 87, 90, 93, 96, 99, 102, 105, 108, 111, 115, 118, 121, 124

};

// Fix Serial for SAMD
#if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL)
// Required for Serial on Zero based boards
#define Serial SERIAL_PORT_USBVIRTUAL
#endif


double dfreq;
const double refclk = 35780; // tweak this number to get a good reference. BAsically, test that you are getting 440 hz

volatile uint32_t phaccu; // phase accumulator
volatile uint32_t tword_m; // dds tuning word m
volatile byte counter; //




void TC4_Handler() // Interrupt Service Routine (ISR) for timer TC4
{
// Check for overflow (OVF) interrupt
if (TC4->COUNT16.INTFLAG.bit.OVF && TC4->COUNT16.INTENSET.bit.OVF)
{
// Put your timer overflow (OVF) code here....


TC4->COUNT16.INTFLAG.reg = TC_INTFLAG_OVF; // Clear the OVF interrupt flag
}
}

/*
High Frequency Interrupt
This is the interrupt that controls the actual signal
*/

void TC5_Handler() // Interrupt Service Routine (ISR) for timer TC4
{
// Check for overflow (OVF) interrupt
if (TC5->COUNT16.INTFLAG.bit.OVF && TC5->COUNT16.INTENSET.bit.OVF)
{

phaccu = phaccu + tword_m; // soft DDS, phase accu with 32 bits
uint32_t icnt = phaccu >> 24; // use upper 8 bits for phase accu as frequency information
// read value fron ROM sine table and send to PWM DAC

uint32_t value = pgm_read_byte_near(sine256 + icnt);

// value = value << 1;


analogWrite(A0, value);


counter++;
if (counter % 2 == 0) {
digitalWrite(A2, true);
} else {
digitalWrite(A2, false);
}



TC5->COUNT16.INTFLAG.reg = TC_INTFLAG_OVF; // Clear the OVF interrupt flag

}
}

void setup() {

Serial.begin(115200);
Serial.println("Setting up");
analogWriteResolution(10);
dfreq = 440.0; // initial output frequency = 440 Hz
tword_m = pow(2, 32) * dfreq / refclk; // calulate DDS new tuning word

counter = 0;

setupTimer4_5();

}

void loop() {

Serial.println("Enter Loop:");
while (true) { }
}
57 changes: 57 additions & 0 deletions midisynth/dds_01/setTimers.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

// Set timer TC4 and TC5

// TC4 is set up with a prescaler of 1024 : 48MHz/1024 = 46.875kHz
// The CC0 is set to 100 so ultimately this timer is happening every 469 HZ

// TC5 is much faster at
// 48MHz/64 = 750kHz
// 750kHz/20 = 37,500


// http://forum.arduino.cc/index.php?topic=599151.0
void setupTimer4_5() {
// Feed GCLK0 to TC4 and TC5
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Enable GCLK0 to TC4 and TC5
GCLK_CLKCTRL_GEN_GCLK0 | // Select GCLK0
GCLK_CLKCTRL_ID_TC4_TC5; // Feed the GCLK0 to TC4 and TC5
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization

TC4->COUNT16.CC[0].reg = 100; // Set the TC4 CC0 register as the TOP value in match frequency mode
while (TC4->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization

NVIC_SetPriority(TC4_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for TC4 to 0 (highest)
NVIC_EnableIRQ(TC4_IRQn); // Connect TC4 to Nested Vector Interrupt Controller (NVIC)

TC4->COUNT16.INTFLAG.reg |= TC_INTFLAG_OVF; // Clear the interrupt flags
TC4->COUNT16.INTENSET.reg = TC_INTENSET_OVF; // Enable TC4 interrupts

TC4->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCSYNC_PRESC | // Reset timer on the next prescaler clock
TC_CTRLA_PRESCALER_DIV1024 | // Set prescaler to 1024, 48MHz/1024 = 46.875kHz
TC_CTRLA_WAVEGEN_MFRQ | // Put the timer TC4 into match frequency (MFRQ) mode
TC_CTRLA_MODE_COUNT16; // Set the timer to 16-bit mode
while (TC4->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization

TC4->COUNT16.CTRLA.bit.ENABLE = 1; // Enable TC4
while (TC4->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization



TC5->COUNT16.CC[0].reg = 20; // Set the TC5 CC0 register as the TOP value in match frequency mode
while (TC5->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization

NVIC_SetPriority(TC5_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for TC5 to 0 (highest)
NVIC_EnableIRQ(TC5_IRQn); // Connect TC4 to Nested Vector Interrupt Controller (NVIC)

TC5->COUNT16.INTFLAG.reg |= TC_INTFLAG_OVF; // Clear the interrupt flags
TC5->COUNT16.INTENSET.reg = TC_INTENSET_OVF; // Enable TC5 interrupts

TC5->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCSYNC_PRESC | // Reset timer on the next prescaler clock
TC_CTRLA_PRESCALER_DIV64 | // Set prescaler to 64, 48MHz/64 = 750 kHz
TC_CTRLA_WAVEGEN_MFRQ | // Put the timer TC5 into match frequency (MFRQ) mode
TC_CTRLA_MODE_COUNT16; // Set the timer to 16-bit mode
while (TC5->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization

TC5->COUNT16.CTRLA.bit.ENABLE = 1; // Enable TC5
while (TC5->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization
}
86 changes: 86 additions & 0 deletions midisynth/dds_02/dds_02.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@

#include "avr/pgmspace.h"
#include "tables.h"


// Plays random sine wave notes

// Fix Serial for SAMD
#if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL)
// Required for Serial on Zero based boards
#define Serial SERIAL_PORT_USBVIRTUAL
#endif


const double refclk = 35780;
volatile uint32_t phaccu; // pahse accumulator
volatile uint32_t tword_m; // dds tuning word m
volatile byte counter; //

volatile int lf_counter; //
volatile int lf_counter_compare; //


void TC4_Handler() // Interrupt Service Routine (ISR) for timer TC4
{
// Check for overflow (OVF) interrupt
if (TC4->COUNT16.INTFLAG.bit.OVF && TC4->COUNT16.INTENSET.bit.OVF)
{
// Put your timer overflow (OVF) code here....

if ( lf_counter > lf_counter_compare) {
lf_counter = 0;

double dfreq = random(200, 1000); // initial output frequency = 440 Hz
tword_m = pow(2, 32) * dfreq / refclk; // calulate DDS new tuning word

}
lf_counter++;


TC4->COUNT16.INTFLAG.reg = TC_INTFLAG_OVF; // Clear the OVF interrupt flag
}
}

/*
High Frequency Interrupt
This is the interrupt that controls the actual signal
*/

void TC5_Handler() // Interrupt Service Routine (ISR) for timer TC4
{
// Check for overflow (OVF) interrupt
if (TC5->COUNT16.INTFLAG.bit.OVF && TC5->COUNT16.INTENSET.bit.OVF)
{

phaccu = phaccu + tword_m; // soft DDS, phase accu with 32 bits
uint32_t icnt = phaccu >> 24; // use upper 8 bits for phase accu as frequency information
// read value fron ROM sine table and send to PWM DAC

uint32_t value = (signed char)pgm_read_byte_near(SinTable + icnt)*4 + 512;

analogWrite(A0, value);

TC5->COUNT16.INTFLAG.reg = TC_INTFLAG_OVF; // Clear the OVF interrupt flag

}
}

void setup() {

Serial.begin(115200);
Serial.println("Setting up");
//By setting the write resolution to 10, you can use analogWrite()
// with values between 0 and 1023 to exploit the full DAC resolution
analogWriteResolution(10);
lf_counter_compare = 200; // increase for longer notes
double dfreq = 440.0; // initial output frequency = 440 Hz
tword_m = pow(2, 32) * dfreq / refclk; // calulate DDS new tuning word
setupTimer4_5();
}

void loop() {

Serial.println("Enter Loop:");
while (true) { }
}
57 changes: 57 additions & 0 deletions midisynth/dds_02/setTimers.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

// Set timer TC4 and TC5

// TC4 is set up with a prescaler of 1024 : 48MHz/1024 = 46.875kHz
// The CC0 is set to 100 so ultimately this timer is happening every 469 HZ

// TC5 is much faster at
// 48MHz/64 = 750kHz
// 750kHz/20 = 37,500


// http://forum.arduino.cc/index.php?topic=599151.0
void setupTimer4_5() {
// Feed GCLK0 to TC4 and TC5
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Enable GCLK0 to TC4 and TC5
GCLK_CLKCTRL_GEN_GCLK0 | // Select GCLK0
GCLK_CLKCTRL_ID_TC4_TC5; // Feed the GCLK0 to TC4 and TC5
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization

TC4->COUNT16.CC[0].reg = 100; // Set the TC4 CC0 register as the TOP value in match frequency mode
while (TC4->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization

NVIC_SetPriority(TC4_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for TC4 to 0 (highest)
NVIC_EnableIRQ(TC4_IRQn); // Connect TC4 to Nested Vector Interrupt Controller (NVIC)

TC4->COUNT16.INTFLAG.reg |= TC_INTFLAG_OVF; // Clear the interrupt flags
TC4->COUNT16.INTENSET.reg = TC_INTENSET_OVF; // Enable TC4 interrupts

TC4->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCSYNC_PRESC | // Reset timer on the next prescaler clock
TC_CTRLA_PRESCALER_DIV1024 | // Set prescaler to 1024, 48MHz/1024 = 46.875kHz
TC_CTRLA_WAVEGEN_MFRQ | // Put the timer TC4 into match frequency (MFRQ) mode
TC_CTRLA_MODE_COUNT16; // Set the timer to 16-bit mode
while (TC4->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization

TC4->COUNT16.CTRLA.bit.ENABLE = 1; // Enable TC4
while (TC4->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization



TC5->COUNT16.CC[0].reg = 20; // Set the TC5 CC0 register as the TOP value in match frequency mode
while (TC5->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization

NVIC_SetPriority(TC5_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for TC5 to 0 (highest)
NVIC_EnableIRQ(TC5_IRQn); // Connect TC4 to Nested Vector Interrupt Controller (NVIC)

TC5->COUNT16.INTFLAG.reg |= TC_INTFLAG_OVF; // Clear the interrupt flags
TC5->COUNT16.INTENSET.reg = TC_INTENSET_OVF; // Enable TC5 interrupts

TC5->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCSYNC_PRESC | // Reset timer on the next prescaler clock
TC_CTRLA_PRESCALER_DIV64 | // Set prescaler to 64, 48MHz/64 = 750 kHz
TC_CTRLA_WAVEGEN_MFRQ | // Put the timer TC5 into match frequency (MFRQ) mode
TC_CTRLA_MODE_COUNT16; // Set the timer to 16-bit mode
while (TC5->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization

TC5->COUNT16.CTRLA.bit.ENABLE = 1; // Enable TC5
while (TC5->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization
}
Loading

0 comments on commit dedffef

Please sign in to comment.