Merge 11f5e8b733
into d98eafb11a
This commit is contained in:
commit
f8810e357b
250
DDS.cpp
250
DDS.cpp
|
@ -1,41 +1,108 @@
|
|||
#include <Arduino.h>
|
||||
#include "DDS.h"
|
||||
|
||||
#ifdef __SAMD21G18A__
|
||||
|
||||
// The SimpleAudioPlayerZero sample project found at:
|
||||
// https://www.arduino.cc/en/Tutorial/SimpleAudioPlayerZero
|
||||
// is an execellent reference for setting up the Timer/Counter
|
||||
#define TC_ISBUSY() (TC5->COUNT16.STATUS.reg & TC_STATUS_SYNCBUSY)
|
||||
#define TC_WAIT() while (TC_ISBUSY());
|
||||
#define TC_ENABLE() TC5->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE; TC_WAIT();
|
||||
#define TC_RESET() TC5->COUNT16.CTRLA.reg = TC_CTRLA_SWRST; TC_WAIT(); \
|
||||
while (TC5->COUNT16.CTRLA.bit.SWRST);
|
||||
#define TC_DISABLE() TC5->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE; TC_WAIT();
|
||||
|
||||
#endif
|
||||
|
||||
// To start the DDS, we use Timer1, set to the reference clock
|
||||
// We use Timer2 for the PWM output, running as fast as feasible
|
||||
void DDS::start() {
|
||||
|
||||
#ifdef DDS_DEBUG_SERIAL
|
||||
// Print these debug statements (commont to both the AVR and the SAMD21)
|
||||
Serial.print(F("DDS SysClk: "));
|
||||
Serial.println(F_CPU/8);
|
||||
Serial.print(F("DDS RefClk: "));
|
||||
Serial.println(refclk, DEC);
|
||||
#endif
|
||||
|
||||
#ifdef __SAMD21G18A__
|
||||
// SAMD21, like Ardino Zero
|
||||
|
||||
// Enable the Generic Clock Generator 0 and configure for TC4 and TC5.
|
||||
// We only need TC5, but they are configured together
|
||||
GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TC4_TC5)) ;
|
||||
while (GCLK->STATUS.bit.SYNCBUSY);
|
||||
|
||||
TC_RESET();
|
||||
|
||||
// Set TC5 16 bit
|
||||
TC5->COUNT16.CTRLA.reg |= TC_CTRLA_MODE_COUNT16;
|
||||
|
||||
// Set TC5 mode as match frequency
|
||||
TC5->COUNT16.CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ;
|
||||
TC5->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1 | TC_CTRLA_ENABLE;
|
||||
TC5->COUNT16.CC[0].reg = (uint16_t) (SystemCoreClock / DDS_REFCLK_DEFAULT - 1);
|
||||
TC_WAIT()
|
||||
|
||||
// Configure interrupt
|
||||
NVIC_DisableIRQ(TC5_IRQn);
|
||||
NVIC_ClearPendingIRQ(TC5_IRQn);
|
||||
NVIC_SetPriority(TC5_IRQn, 0);
|
||||
NVIC_EnableIRQ(TC5_IRQn);
|
||||
|
||||
// Enable TC5 Interrupt
|
||||
TC5->COUNT16.INTENSET.bit.MC0 = 1;
|
||||
TC_WAIT();
|
||||
|
||||
//Configure the DAC
|
||||
#if COMPARATOR_BITS==6
|
||||
// Not sure why you'd use 6-bit, other than debugging.
|
||||
// Reduced amplitude: clockTick() and getDutyCycle() do not scale the 6 up to 8-bits
|
||||
analogWriteResolution(8);
|
||||
#elif COMPARATOR_BITS == 8 || COMPARATOR_BITS == 10
|
||||
analogWriteResolution(COMPARATOR_BITS);
|
||||
#else
|
||||
#error Unsupported resoltuion for DAC (expected 8 or 10)
|
||||
#endif
|
||||
analogWrite(A0, 0);
|
||||
|
||||
#else
|
||||
// For AVRs
|
||||
|
||||
// Use the clkIO clock rate
|
||||
ASSR &= ~(_BV(EXCLK) | _BV(AS2));
|
||||
|
||||
// First, the timer for the PWM output
|
||||
// Setup the timer to use OC2B (pin 3) in fast PWM mode with a configurable top
|
||||
// Run it without the prescaler
|
||||
#ifdef DDS_PWM_PIN_3
|
||||
TCCR2A = (TCCR2A | _BV(COM2B1)) & ~(_BV(COM2B0) | _BV(COM2A1) | _BV(COM2A0)) |
|
||||
#ifdef DDS_PWM_PIN_3
|
||||
TCCR2A = (TCCR2A | _BV(COM2B1)) & ~(_BV(COM2B0) | _BV(COM2A1) | _BV(COM2A0)) |
|
||||
_BV(WGM21) | _BV(WGM20);
|
||||
TCCR2B = (TCCR2B & ~(_BV(CS22) | _BV(CS21))) | _BV(CS20) | _BV(WGM22);
|
||||
#else
|
||||
TCCR2B = (TCCR2B & ~(_BV(CS22) | _BV(CS21))) | _BV(CS20) | _BV(WGM22);
|
||||
#else
|
||||
// Alternatively, use pin 11
|
||||
// Enable output compare on OC2A, toggle mode
|
||||
TCCR2A = _BV(COM2A1) | _BV(WGM21) | _BV(WGM20);
|
||||
//TCCR2A = (TCCR2A | _BV(COM2A1)) & ~(_BV(COM2A0) | _BV(COM2B1) | _BV(COM2B0)) |
|
||||
// _BV(WGM21) | _BV(WGM20);
|
||||
TCCR2B = _BV(CS20);
|
||||
#endif
|
||||
TCCR2A = _BV(COM2A1) | _BV(WGM21) | _BV(WGM20);
|
||||
//TCCR2A = (TCCR2A | _BV(COM2A1)) & ~(_BV(COM2A0) | _BV(COM2B1) | _BV(COM2B0)) |
|
||||
// _BV(WGM21) | _BV(WGM20);
|
||||
TCCR2B = _BV(CS20);
|
||||
#endif
|
||||
|
||||
// Set the top limit, which will be our duty cycle accuracy.
|
||||
// Setting Comparator Bits smaller will allow for higher frequency PWM,
|
||||
// with the loss of resolution.
|
||||
#ifdef DDS_PWM_PIN_3
|
||||
OCR2A = pow(2,COMPARATOR_BITS)-1;
|
||||
OCR2B = 0;
|
||||
#else
|
||||
OCR2A = 0;
|
||||
#endif
|
||||
#ifdef DDS_PWM_PIN_3
|
||||
OCR2A = DDS_MAX_COMPARATOR-1;
|
||||
OCR2B = 0;
|
||||
#else
|
||||
OCR2A = 0;
|
||||
#endif
|
||||
|
||||
#ifdef DDS_USE_ONLY_TIMER2
|
||||
TIMSK2 |= _BV(TOIE2);
|
||||
#endif
|
||||
#ifdef DDS_USE_ONLY_TIMER2
|
||||
TIMSK2 |= _BV(TOIE2);
|
||||
#endif
|
||||
|
||||
// Second, setup Timer1 to trigger the ADC interrupt
|
||||
// This lets us use decoding functions that run at the same reference
|
||||
|
@ -44,14 +111,10 @@ void DDS::start() {
|
|||
TCCR1B = _BV(CS10) | _BV(WGM13) | _BV(WGM12);
|
||||
TCCR1A = 0;
|
||||
ICR1 = ((F_CPU / 1) / refclk) - 1;
|
||||
#ifdef DDS_DEBUG_SERIAL
|
||||
Serial.print(F("DDS SysClk: "));
|
||||
Serial.println(F_CPU/8);
|
||||
Serial.print(F("DDS RefClk: "));
|
||||
Serial.println(refclk, DEC);
|
||||
Serial.print(F("DDS ICR1: "));
|
||||
Serial.println(ICR1, DEC);
|
||||
#endif
|
||||
#ifdef DDS_DEBUG_SERIAL
|
||||
Serial.print(F("DDS ICR1: "));
|
||||
Serial.println(ICR1, DEC);
|
||||
#endif
|
||||
|
||||
// Configure the ADC here to automatically run and be triggered off Timer1
|
||||
ADMUX = _BV(REFS0) | _BV(ADLAR) | 0; // Channel 0, shift result left (ADCH used)
|
||||
|
@ -60,46 +123,54 @@ void DDS::start() {
|
|||
DIDR0 |= _BV(0);
|
||||
ADCSRB = _BV(ADTS2) | _BV(ADTS1) | _BV(ADTS0);
|
||||
ADCSRA = _BV(ADEN) | _BV(ADSC) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2); // | _BV(ADPS0);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void DDS::stop() {
|
||||
#ifdef __SAMD21G18A__
|
||||
TC_DISABLE();
|
||||
TC_RESET();
|
||||
analogWrite(A0, 0);
|
||||
#else
|
||||
// TODO: Stop the timers.
|
||||
#ifndef DDS_USE_ONLY_TIMER2
|
||||
TCCR1B = 0;
|
||||
#ifndef DDS_USE_ONLY_TIMER2
|
||||
TCCR1B = 0;
|
||||
#endif
|
||||
TCCR2B = 0;
|
||||
#endif
|
||||
TCCR2B = 0;
|
||||
}
|
||||
|
||||
// Set our current sine wave frequency in Hz
|
||||
ddsAccumulator_t DDS::calcFrequency(unsigned short freq) {
|
||||
// Fo = (M*Fc)/2^N
|
||||
// M = (Fo/Fc)*2^N
|
||||
ddsAccumulator_t newStep;
|
||||
|
||||
if(refclk == DDS_REFCLK_DEFAULT) {
|
||||
// Try to use precalculated values if possible
|
||||
if(freq == 2200) {
|
||||
newStep = (2200.0 / (DDS_REFCLK_DEFAULT+DDS_REFCLK_OFFSET)) * pow(2,ACCUMULATOR_BITS);
|
||||
return (2200.0 / (DDS_REFCLK_DEFAULT+DDS_REFCLK_OFFSET)) * DDS_MAX_ACCUMULATOR;
|
||||
} else if (freq == 1200) {
|
||||
newStep = (1200.0 / (DDS_REFCLK_DEFAULT+DDS_REFCLK_OFFSET)) * pow(2,ACCUMULATOR_BITS);
|
||||
return (1200.0 / (DDS_REFCLK_DEFAULT+DDS_REFCLK_OFFSET)) * DDS_MAX_ACCUMULATOR;
|
||||
} else if(freq == 2400) {
|
||||
newStep = (2400.0 / (DDS_REFCLK_DEFAULT+DDS_REFCLK_OFFSET)) * pow(2,ACCUMULATOR_BITS);
|
||||
return (2400.0 / (DDS_REFCLK_DEFAULT+DDS_REFCLK_OFFSET)) * DDS_MAX_ACCUMULATOR;
|
||||
} else if (freq == 1500) {
|
||||
newStep = (1500.0 / (DDS_REFCLK_DEFAULT+DDS_REFCLK_OFFSET)) * pow(2,ACCUMULATOR_BITS);
|
||||
return (1500.0 / (DDS_REFCLK_DEFAULT+DDS_REFCLK_OFFSET)) * DDS_MAX_ACCUMULATOR;
|
||||
} else if (freq == 600) {
|
||||
newStep = (600.0 / (DDS_REFCLK_DEFAULT+DDS_REFCLK_OFFSET)) * pow(2,ACCUMULATOR_BITS);
|
||||
return (600.0 / (DDS_REFCLK_DEFAULT+DDS_REFCLK_OFFSET)) * DDS_MAX_ACCUMULATOR;
|
||||
}
|
||||
} else {
|
||||
newStep = pow(2,ACCUMULATOR_BITS)*freq / (refclk+refclkOffset);
|
||||
}
|
||||
return newStep;
|
||||
|
||||
// Not a pre-calc frequency OR not using default REFCLK
|
||||
return DDS_MAX_ACCUMULATOR * freq / (refclk+refclkOffset);
|
||||
}
|
||||
|
||||
// Degrees should be between -360 and +360 (others don't make much sense)
|
||||
void DDS::setPhaseDeg(int16_t degrees) {
|
||||
accumulator = degrees * (pow(2,ACCUMULATOR_BITS)/360.0);
|
||||
accumulator = degrees * (DDS_MAX_ACCUMULATOR/360.0);
|
||||
}
|
||||
void DDS::changePhaseDeg(int16_t degrees) {
|
||||
accumulator += degrees * (pow(2,ACCUMULATOR_BITS)/360.0);
|
||||
accumulator += degrees * (DDS_MAX_ACCUMULATOR/360.0);
|
||||
}
|
||||
|
||||
// TODO: Clean this up a bit..
|
||||
|
@ -112,64 +183,107 @@ void DDS::clockTick() {
|
|||
if(running) {
|
||||
accumulator += stepRate;
|
||||
if(timeLimited && tickDuration == 0) {
|
||||
#ifndef DDS_PWM_PIN_3
|
||||
#ifdef __SAMD21G18A__
|
||||
#ifdef DDS_IDLE_HIGH
|
||||
analogWrite(A0, DDS_MAX_COMPARATOR/2);
|
||||
#else
|
||||
analogWrite(A0, 0);
|
||||
#endif
|
||||
#else
|
||||
#ifndef DDS_PWM_PIN_3
|
||||
OCR2A = 0;
|
||||
#else
|
||||
#ifdef DDS_IDLE_HIGH
|
||||
#else
|
||||
#ifdef DDS_IDLE_HIGH
|
||||
// Set the duty cycle to 50%
|
||||
OCR2B = pow(2,COMPARATOR_BITS)/2;
|
||||
#else
|
||||
OCR2B = DDS_MAX_COMPARATOR/2;
|
||||
#else
|
||||
// Set duty cycle to 0, effectively off
|
||||
OCR2B = 0;
|
||||
#endif
|
||||
OCR2B = 0;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
running = false;
|
||||
accumulator = 0;
|
||||
} else {
|
||||
#ifdef DDS_PWM_PIN_3
|
||||
OCR2B = getDutyCycle();
|
||||
#ifdef __SAMD21G18A__
|
||||
analogWrite(A0, getDutyCycle());
|
||||
#else
|
||||
#ifdef DDS_PWM_PIN_3
|
||||
OCR2B = getDutyCycle();
|
||||
#else
|
||||
OCR2A = getDutyCycle();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
// Reduce our playback duration by one tick
|
||||
tickDuration--;
|
||||
} else {
|
||||
#ifdef __SAMD21G18A__
|
||||
#ifdef DDS_IDLE_HIGH
|
||||
analogWrite(A0, DDS_MAX_COMPARATOR/2);
|
||||
#else
|
||||
analogWrite(A0, 0);
|
||||
#endif
|
||||
#else
|
||||
// Hold it low
|
||||
#ifndef DDS_PWM_PIN_3
|
||||
#ifndef DDS_PWM_PIN_3
|
||||
OCR2A = 0;
|
||||
#else
|
||||
#ifdef DDS_IDLE_HIGH
|
||||
#else
|
||||
#ifdef DDS_IDLE_HIGH
|
||||
// Set the duty cycle to 50%
|
||||
OCR2B = pow(2,COMPARATOR_BITS)/2;
|
||||
#else
|
||||
// Set duty cycle to 0, effectively off
|
||||
OCR2B = 0;
|
||||
#endif
|
||||
OCR2B = DDS_MAX_COMPARATOR/2;
|
||||
#else
|
||||
// Set duty cycle to 0, effectively off
|
||||
OCR2B = 0;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t DDS::getDutyCycle() {
|
||||
#if ACCUMULATOR_BIT_SHIFT >= 24
|
||||
//TODO: rename this function as it is more than just dutyCycle?
|
||||
//now it powers both a PWM dutyCycle as well as a DAC value on the Zero
|
||||
ddsComparitor_t DDS::getDutyCycle() {
|
||||
#if ACCUMULATOR_BITS - ACCUMULATOR_BIT_SHIFT > 8
|
||||
// For larger sineTables which need more thn 8 bits.
|
||||
uint16_t phAng;
|
||||
#else
|
||||
// For standard sineTables which need 8 bits.
|
||||
uint8_t phAng;
|
||||
#endif
|
||||
|
||||
if(amplitude == 0) // Shortcut out on no amplitude
|
||||
return 128>>(8-COMPARATOR_BITS);
|
||||
return DDS_MAX_COMPARATOR/2;
|
||||
|
||||
// Lookup the value from the sin table.
|
||||
phAng = (accumulator >> ACCUMULATOR_BIT_SHIFT);
|
||||
#if DDS_LOOKUPVALUE_BITS > 8
|
||||
// 16-bit lookup
|
||||
int16_t position = pgm_read_word_near(ddsSineTable + phAng); //>>(8-COMPARATOR_BITS);
|
||||
int32_t scaled = position;
|
||||
#else
|
||||
// 8-bit lookup
|
||||
int8_t position = pgm_read_byte_near(ddsSineTable + phAng); //>>(8-COMPARATOR_BITS);
|
||||
// Apply scaling and return
|
||||
int16_t scaled = position;
|
||||
// output = ((duty * amplitude) / 256) + 128
|
||||
// This keeps amplitudes centered around 50% duty
|
||||
#endif
|
||||
|
||||
// If there's an amplitude, scale it
|
||||
if(amplitude != 255) { // Amplitude is reduced, so do the full math
|
||||
scaled *= amplitude;
|
||||
scaled >>= 8+(8-COMPARATOR_BITS);
|
||||
} else { // Otherwise, only shift for the comparator bits
|
||||
scaled >>= (8-COMPARATOR_BITS);
|
||||
scaled *= amplitude; // multiply by the amplitude, max 255 or an 8-bit shift
|
||||
scaled >>= 8; // bring it back 8 bits devide
|
||||
}
|
||||
scaled += 128>>(8-COMPARATOR_BITS);
|
||||
|
||||
// Scale to the number of bits available
|
||||
#if COMPARATOR_BITS > DDS_LOOKUPVALUE_BITS
|
||||
scaled <<= (COMPARATOR_BITS - DDS_LOOKUPVALUE_BITS);
|
||||
#elif COMPARATOR_BITS < DDS_LOOKUPVALUE_BITS
|
||||
scaled >>= (DDS_LOOKUPVALUE_BITS-COMPARATOR_BITS);
|
||||
#else
|
||||
// COMARATOR_BITS == DDS_LOOKUPVALUE_BITS -- no math needed.
|
||||
#endif
|
||||
|
||||
//Move the sinewave up 1/2 scale into the positive range.
|
||||
scaled += DDS_MAX_COMPARATOR/2;
|
||||
return scaled;
|
||||
}
|
||||
|
||||
|
|
159
DDS.h
159
DDS.h
|
@ -1,19 +1,26 @@
|
|||
#ifndef _DDS_H_
|
||||
#define _DDS_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
// Just a little (useless?) reminder; #warnings are not displayed in Arduino IDE.
|
||||
#ifndef __SAMD21G18A__
|
||||
#warning Experimental support for ArduinoZero. Not yet complete.
|
||||
#endif
|
||||
|
||||
// For AVRs:
|
||||
// Use pin 3 for PWM? If not defined, use pin 11
|
||||
// Quality on pin 3 is higher than on 11, as it can be clocked faster
|
||||
// when the COMPARATOR_BITS value is less than 8
|
||||
#define DDS_PWM_PIN_3
|
||||
// #define DDS_PWM_PIN_3
|
||||
|
||||
// For AVRs:
|
||||
// Normally, we turn on timer2 and timer1, and have ADC sampling as our clock
|
||||
// Define this to only use Timer2, and not start the ADC clock
|
||||
// #define DDS_USE_ONLY_TIMER2
|
||||
|
||||
// Use a short (16 bit) accumulator. Phase accuracy is reduced, but speed
|
||||
// is increased, along with a reduction in memory use.
|
||||
// is increased, along with a reduction in memory use._
|
||||
#define SHORT_ACCUMULATOR
|
||||
|
||||
#ifdef SHORT_ACCUMULATOR
|
||||
|
@ -24,10 +31,15 @@ typedef uint16_t ddsAccumulator_t;
|
|||
typedef uint32_t ddsAccumulator_t;
|
||||
#endif
|
||||
|
||||
// The maximum value of the accumulator based on the number of bits
|
||||
// Macro for code readability.
|
||||
#define DDS_MAX_ACCUMULATOR (pow(2,ACCUMULATOR_BITS))
|
||||
|
||||
// If defined, the timer will idle at 50% duty cycle
|
||||
// This leaves it floating in the centre of the PWM/DAC voltage range
|
||||
#define DDS_IDLE_HIGH
|
||||
|
||||
// For AVRs:
|
||||
// Select how fast the PWM is, at the expense of level accuracy.
|
||||
// A faster PWM rate will make for easier filtering of the output wave,
|
||||
// while a slower one will allow for more accurate voltage level outputs,
|
||||
|
@ -35,19 +47,36 @@ typedef uint32_t ddsAccumulator_t;
|
|||
// 8 = 62.5kHz PWM
|
||||
// 7 = 125kHz PWM
|
||||
// 6 = 250kHz PWM
|
||||
#ifdef DDS_PWM_PIN_3
|
||||
#define COMPARATOR_BITS 6
|
||||
// For SAMD21's -- the resolution of the DAC.
|
||||
|
||||
#ifdef __SAMD21G18A__
|
||||
#define COMPARATOR_BITS 10
|
||||
typedef uint16_t ddsComparitor_t;
|
||||
#elif defined(DDS_PWM_PIN_3)
|
||||
#define COMPARATOR_BITS 6
|
||||
typedef uint8_t ddsComparitor_t;
|
||||
#else // When using pin 11, we always want 8 bits
|
||||
#define COMPARATOR_BITS 8
|
||||
#define COMPARATOR_BITS 8
|
||||
typedef uint8_t ddsComparitor_t;
|
||||
#endif
|
||||
|
||||
// The maximum value of the comparitor based on the number of bits
|
||||
// Macro for code readability.
|
||||
#define DDS_MAX_COMPARATOR pow(2,COMPARATOR_BITS)
|
||||
|
||||
// This is how often we'll perform a phase advance, as well as ADC sampling
|
||||
// rate. The higher this value, the smoother the output wave will be, at the
|
||||
// expense of CPU time. It maxes out around 62000 (TBD)
|
||||
// May be overridden in the sketch to improve performance
|
||||
// expense of CPU time.
|
||||
// For AVRs: It maxes out around 62000 (TBD) May be overridden in the sketch
|
||||
// to improve performance
|
||||
#ifndef DDS_REFCLK_DEFAULT
|
||||
#define DDS_REFCLK_DEFAULT 9600
|
||||
#ifdef __SAMD21G18A__
|
||||
#define DDS_REFCLK_DEFAULT 44100
|
||||
#else
|
||||
#define DDS_REFCLK_DEFAULT 9600
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// As each Arduino crystal is a little different, this can be fine tuned to
|
||||
// provide more accurate frequencies. Adjustments in the range of hundreds
|
||||
// is a good start.
|
||||
|
@ -61,15 +90,77 @@ typedef uint32_t ddsAccumulator_t;
|
|||
#endif
|
||||
|
||||
// Output some of the calculations and information about the DDS over serial
|
||||
//#define DDS_DEBUG_SERIAL
|
||||
#define DDS_DEBUG_SERIAL
|
||||
|
||||
// When defined, use the 1024 element sine lookup table. This improves phase
|
||||
// accuracy, at the cost of more flash and CPU requirements.
|
||||
// #define DDS_TABLE_LARGE
|
||||
|
||||
#ifdef DDS_TABLE_LARGE
|
||||
// How many bits to keep from the accumulator to look up in this table
|
||||
// When defined, use a 10-bit table of short integers. This is wasteful of
|
||||
// flash space as there are 6 bits of each value that are unused.
|
||||
// May improve resolution. When set, "DDS_TABLE_LARGE" is ignored.
|
||||
// #define DDS_TABLE_10BIT
|
||||
|
||||
#ifdef DDS_TABLE_10BIT
|
||||
|
||||
// 10-bit Large SineTable, 1024 values +/-511
|
||||
// Generated using http://www.meraman.com/htmls/en/sinTable.html
|
||||
#define ACCUMULATOR_BIT_SHIFT (ACCUMULATOR_BITS-10)
|
||||
#define DDS_LOOKUPVALUE_BITS 10
|
||||
static const int16_t ddsSineTable[1024] PROGMEM = {0, 3, 6, 9, 13, 16, 19, 22, 25, 28, 31, 34, 38, 41, 44, 47, 50, 53,
|
||||
56, 59, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124, 127, 130, 133, 136,
|
||||
139, 142, 145, 148, 151, 154, 157, 160, 163, 166, 169, 172, 175, 178, 181, 184, 187, 190, 193, 196, 198, 201, 204, 207,
|
||||
210, 213, 216, 218, 221, 224, 227, 230, 233, 235, 238, 241, 244, 246, 249, 252, 255, 257, 260, 263, 265, 268, 271, 273,
|
||||
276, 279, 281, 284, 286, 289, 292, 294, 297, 299, 302, 304, 307, 309, 312, 314, 317, 319, 322, 324, 327, 329, 331, 334,
|
||||
336, 338, 341, 343, 345, 348, 350, 352, 355, 357, 359, 361, 364, 366, 368, 370, 372, 374, 377, 379, 381, 383, 385, 387,
|
||||
389, 391, 393, 395, 397, 399, 401, 403, 405, 407, 409, 410, 412, 414, 416, 418, 420, 421, 423, 425, 427, 428, 430, 432,
|
||||
433, 435, 437, 438, 440, 441, 443, 445, 446, 448, 449, 451, 452, 454, 455, 456, 458, 459, 461, 462, 463, 465, 466, 467,
|
||||
468, 470, 471, 472, 473, 474, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 492,
|
||||
493, 494, 495, 496, 496, 497, 498, 499, 499, 500, 501, 501, 502, 502, 503, 503, 504, 505, 505, 505, 506, 506, 507, 507,
|
||||
508, 508, 508, 509, 509, 509, 509, 510, 510, 510, 510, 510, 511, 511, 511, 511, 511, 511, 511, 511, 511, 511, 511, 511,
|
||||
511, 511, 511, 510, 510, 510, 510, 510, 509, 509, 509, 509, 508, 508, 508, 507, 507, 506, 506, 505, 505, 505, 504, 503,
|
||||
503, 502, 502, 501, 501, 500, 499, 499, 498, 497, 496, 496, 495, 494, 493, 492, 492, 491, 490, 489, 488, 487, 486, 485,
|
||||
484, 483, 482, 481, 480, 479, 478, 477, 476, 474, 473, 472, 471, 470, 468, 467, 466, 465, 463, 462, 461, 459, 458, 456,
|
||||
455, 454, 452, 451, 449, 448, 446, 445, 443, 441, 440, 438, 437, 435, 433, 432, 430, 428, 427, 425, 423, 421, 420, 418,
|
||||
416, 414, 412, 410, 409, 407, 405, 403, 401, 399, 397, 395, 393, 391, 389, 387, 385, 383, 381, 379, 377, 374, 372, 370,
|
||||
368, 366, 364, 361, 359, 357, 355, 352, 350, 348, 345, 343, 341, 338, 336, 334, 331, 329, 327, 324, 322, 319, 317, 314,
|
||||
312, 309, 307, 304, 302, 299, 297, 294, 292, 289, 286, 284, 281, 279, 276, 273, 271, 268, 265, 263, 260, 257, 255, 252,
|
||||
249, 246, 244, 241, 238, 235, 233, 230, 227, 224, 221, 218, 216, 213, 210, 207, 204, 201, 198, 196, 193, 190, 187, 184,
|
||||
181, 178, 175, 172, 169, 166, 163, 160, 157, 154, 151, 148, 145, 142, 139, 136, 133, 130, 127, 124, 121, 118, 115, 112,
|
||||
109, 106, 103, 100, 97, 94, 90, 87, 84, 81, 78, 75, 72, 69, 66, 63, 59, 56, 53, 50, 47, 44, 41, 38, 34, 31, 28, 25, 22,
|
||||
19, 16, 13, 9, 6, 3, 0, -3, -6, -9, -13, -16, -19, -22, -25, -28, -31, -34, -38, -41, -44, -47, -50, -53, -56, -59, -63,
|
||||
-66, -69, -72, -75, -78, -81, -84, -87, -90, -94, -97, -100, -103, -106, -109, -112, -115, -118, -121, -124, -127, -130,
|
||||
-133, -136, -139, -142, -145, -148, -151, -154, -157, -160, -163, -166, -169, -172, -175, -178, -181, -184, -187, -190,
|
||||
-193, -196, -198, -201, -204, -207, -210, -213, -216, -218, -221, -224, -227, -230, -233, -235, -238, -241, -244, -246,
|
||||
-249, -252, -255, -257, -260, -263, -265, -268, -271, -273, -276, -279, -281, -284, -286, -289, -292, -294, -297, -299,
|
||||
-302, -304, -307, -309, -312, -314, -317, -319, -322, -324, -327, -329, -331, -334, -336, -338, -341, -343, -345, -348,
|
||||
-350, -352, -355, -357, -359, -361, -364, -366, -368, -370, -372, -374, -377, -379, -381, -383, -385, -387, -389, -391,
|
||||
-393, -395, -397, -399, -401, -403, -405, -407, -409, -410, -412, -414, -416, -418, -420, -421, -423, -425, -427, -428,
|
||||
-430, -432, -433, -435, -437, -438, -440, -441, -443, -445, -446, -448, -449, -451, -452, -454, -455, -456, -458, -459,
|
||||
-461, -462, -463, -465, -466, -467, -468, -470, -471, -472, -473, -474, -476, -477, -478, -479, -480, -481, -482, -483,
|
||||
-484, -485, -486, -487, -488, -489, -490, -491, -492, -492, -493, -494, -495, -496, -496, -497, -498, -499, -499, -500,
|
||||
-501, -501, -502, -502, -503, -503, -504, -505, -505, -505, -506, -506, -507, -507, -508, -508, -508, -509, -509, -509,
|
||||
-509, -510, -510, -510, -510, -510, -511, -511, -511, -511, -511, -511, -511, -511, -511, -511, -511, -511, -511, -511,
|
||||
-511, -510, -510, -510, -510, -510, -509, -509, -509, -509, -508, -508, -508, -507, -507, -506, -506, -505, -505, -505,
|
||||
-504, -503, -503, -502, -502, -501, -501, -500, -499, -499, -498, -497, -496, -496, -495, -494, -493, -492, -492, -491,
|
||||
-490, -489, -488, -487, -486, -485, -484, -483, -482, -481, -480, -479, -478, -477, -476, -474, -473, -472, -471, -470,
|
||||
-468, -467, -466, -465, -463, -462, -461, -459, -458, -456, -455, -454, -452, -451, -449, -448, -446, -445, -443, -441,
|
||||
-440, -438, -437, -435, -433, -432, -430, -428, -427, -425, -423, -421, -420, -418, -416, -414, -412, -410, -409, -407,
|
||||
-405, -403, -401, -399, -397, -395, -393, -391, -389, -387, -385, -383, -381, -379, -377, -374, -372, -370, -368, -366,
|
||||
-364, -361, -359, -357, -355, -352, -350, -348, -345, -343, -341, -338, -336, -334, -331, -329, -327, -324, -322, -319,
|
||||
-317, -314, -312, -309, -307, -304, -302, -299, -297, -294, -292, -289, -286, -284, -281, -279, -276, -273, -271, -268,
|
||||
-265, -263, -260, -257, -255, -252, -249, -246, -244, -241, -238, -235, -233, -230, -227, -224, -221, -218, -216, -213,
|
||||
-210, -207, -204, -201, -198, -196, -193, -190, -187, -184, -181, -178, -175, -172, -169, -166, -163, -160, -157, -154,
|
||||
-151, -148, -145, -142, -139, -136, -133, -130, -127, -124, -121, -118, -115, -112, -109, -106, -103, -100, -97, -94,
|
||||
-90, -87, -84, -81, -78, -75, -72, -69, -66, -63, -59, -56, -53, -50, -47, -44, -41, -38, -34, -31, -28, -25, -22, -19,
|
||||
-16, -13, -9, -6, -3
|
||||
};
|
||||
|
||||
#elif defined(DDS_TABLE_LARGE)
|
||||
|
||||
// Large SineTable, 1024 values +/-127
|
||||
#define ACCUMULATOR_BIT_SHIFT (ACCUMULATOR_BITS-10) // How many bits to keep from the accumulator to look up in this table
|
||||
#define DDS_LOOKUPVALUE_BITS 8
|
||||
static const int8_t ddsSineTable[1024] PROGMEM = {
|
||||
0, 0, 1, 2, 3, 3, 4, 5, 6, 7, 7, 8, 9, 10, 10, 11, 12, 13, 13, 14, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22, 23, 24,
|
||||
24, 25, 26, 27, 27, 28, 29, 30, 30, 31, 32, 33, 33, 34, 35, 36, 36, 37, 38, 39, 39, 40, 41, 42, 42, 43, 44, 44, 45, 46, 47, 47,
|
||||
|
@ -104,30 +195,26 @@ static const int8_t ddsSineTable[1024] PROGMEM = {
|
|||
-48, -47, -47, -46, -45, -44, -44, -43, -42, -42, -41, -40, -39, -39, -38, -37, -36, -36, -35, -34, -33, -33, -32, -31, -30, -30, -29, -28, -27, -27, -26, -25,
|
||||
-24, -24, -23, -22, -21, -20, -20, -19, -18, -17, -17, -16, -15, -14, -13, -13, -12, -11, -10, -10, -9, -8, -7, -7, -6, -5, -4, -3, -3, -2, -1, 0
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
// Standard SineTable, 256 values +/-127
|
||||
#define ACCUMULATOR_BIT_SHIFT (ACCUMULATOR_BITS-8)
|
||||
static const int8_t ddsSineTable[256] PROGMEM = {
|
||||
0, 3, 6, 9, 12, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, 49,
|
||||
51, 54, 57, 60, 63, 65, 68, 71, 73, 76, 78, 81, 83, 85, 88, 90,
|
||||
92, 94, 96, 98, 100, 102, 104, 106, 107, 109, 111, 112, 113, 115,
|
||||
116, 117, 118, 120, 121, 122, 122, 123, 124, 125, 125, 126, 126,
|
||||
126, 127, 127, 127, 127, 127, 127, 127, 126, 126, 126, 125, 125,
|
||||
124, 123, 122, 122, 121, 120, 118, 117, 116, 115, 113, 112, 111,
|
||||
109, 107, 106, 104, 102, 100, 98, 96, 94, 92, 90, 88, 85, 83, 81,
|
||||
78, 76, 73, 71, 68, 65, 63, 60, 57, 54, 51, 49, 46, 43, 40, 37,
|
||||
34, 31, 28, 25, 22, 19, 16, 12, 9, 6, 3, 0, -3, -6, -9, -12, -16,
|
||||
-19, -22, -25, -28, -31, -34, -37, -40, -43, -46, -49, -51, -54,
|
||||
-57, -60, -63, -65, -68, -71, -73, -76, -78, -81, -83, -85, -88,
|
||||
-90, -92, -94, -96, -98, -100, -102, -104, -106, -107, -109, -111,
|
||||
-112, -113, -115, -116, -117, -118, -120, -121, -122, -122, -123,
|
||||
-124, -125, -125, -126, -126, -126, -127, -127, -127, -127, -127,
|
||||
-127, -127, -126, -126, -126, -125, -125, -124, -123, -122, -122,
|
||||
-121, -120, -118, -117, -116, -115, -113, -112, -111, -109, -107,
|
||||
-106, -104, -102, -100, -98, -96, -94, -92, -90, -88, -85, -83,
|
||||
-81, -78, -76, -73, -71, -68, -65, -63, -60, -57, -54, -51, -49,
|
||||
-46, -43, -40, -37, -34, -31, -28, -25, -22, -19, -16, -12, -9, -6, -3
|
||||
};
|
||||
#endif /* DDS_TABLE_LARGE */
|
||||
#define DDS_LOOKUPVALUE_BITS 8
|
||||
static const int8_t ddsSineTable[256] PROGMEM = {0, 3, 6, 9, 12, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, 49, 51, 54,
|
||||
57, 60, 63, 65, 68, 71, 73, 76, 78, 81, 83, 85, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 107, 109, 111, 112, 113,
|
||||
115, 116, 117, 118, 120, 121, 122, 122, 123, 124, 125, 125, 126, 126, 126, 127, 127, 127, 127, 127, 127, 127, 126, 126,
|
||||
126, 125, 125, 124, 123, 122, 122, 121, 120, 118, 117, 116, 115, 113, 112, 111, 109, 107, 106, 104, 102, 100, 98, 96,
|
||||
94, 92, 90, 88, 85, 83, 81, 78, 76, 73, 71, 68, 65, 63, 60, 57, 54, 51, 49, 46, 43, 40, 37, 34, 31, 28, 25, 22, 19, 16,
|
||||
12, 9, 6, 3, 0, -3, -6, -9, -12, -16, -19, -22, -25, -28, -31, -34, -37, -40, -43, -46, -49, -51, -54, -57, -60, -63,
|
||||
-65, -68, -71, -73, -76, -78, -81, -83, -85, -88, -90, -92, -94, -96, -98, -100, -102, -104, -106, -107, -109, -111,
|
||||
-112, -113, -115, -116, -117, -118, -120, -121, -122, -122, -123, -124, -125, -125, -126, -126, -126, -127, -127, -127,
|
||||
-127, -127, -127, -127, -126, -126, -126, -125, -125, -124, -123, -122, -122, -121, -120, -118, -117, -116, -115, -113,
|
||||
-112, -111, -109, -107, -106, -104, -102, -100, -98, -96, -94, -92, -90, -88, -85, -83, -81, -78, -76, -73, -71, -68,
|
||||
-65, -63, -60, -57, -54, -51, -49, -46, -43, -40, -37, -34, -31, -28, -25, -22, -19, -16, -12, -9, -6, -3
|
||||
};
|
||||
|
||||
#endif /* DDS_TABLE_LARGE, DDS_TABLE_10BIT */
|
||||
|
||||
class DDS {
|
||||
public:
|
||||
|
@ -202,7 +289,7 @@ public:
|
|||
return refclkOffset;
|
||||
}
|
||||
|
||||
uint8_t getDutyCycle();
|
||||
ddsComparitor_t getDutyCycle();
|
||||
|
||||
// Set a scaling factor. To keep things quick, this is a power of 2 value.
|
||||
// Set it with 0 for lowest (which will be off), 8 is highest.
|
||||
|
@ -222,7 +309,7 @@ private:
|
|||
volatile ddsAccumulator_t stepRate;
|
||||
ddsAccumulator_t refclk;
|
||||
int16_t refclkOffset;
|
||||
static DDS *sDDS;
|
||||
//static _DDS *sDDS;
|
||||
};
|
||||
|
||||
#endif /* _DDS_H_ */
|
||||
|
|
|
@ -8,6 +8,12 @@
|
|||
#define RESET_PIN A3
|
||||
#define SWITCH_PIN 2
|
||||
|
||||
#ifdef __SAMD21G18A__
|
||||
// NOTE: this won't really work for the Ardiuno Zero, as it will be playing its tones
|
||||
// out of AO, rather than D3 or D11. Hook up your oscilloscope to A0 to see the waveform.
|
||||
#warning Hamshield may not be compatible with the Arduino Zero.
|
||||
#endif
|
||||
|
||||
HamShield radio;
|
||||
DDS dds;
|
||||
|
||||
|
@ -41,6 +47,31 @@ void loop() {
|
|||
delay(1000);
|
||||
}
|
||||
|
||||
#ifdef __SAMD21G18A__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// ISR for the Arduino Zero Timer/Counter 5
|
||||
// DDS configures this to run at 44100 (default)
|
||||
void DDS_Handler (void) {
|
||||
// Do the thing
|
||||
dds.clockTick();
|
||||
|
||||
// Clear the interrupt
|
||||
TC5->COUNT16.INTFLAG.bit.MC0 = 1;
|
||||
}
|
||||
|
||||
void TC5_Handler (void) __attribute__ ((weak, alias("DDS_Handler")));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
// Standard AVR ISRs
|
||||
|
||||
#ifdef DDS_USE_ONLY_TIMER2
|
||||
ISR(TIMER2_OVF_vect) {
|
||||
dds.clockTick();
|
||||
|
@ -54,4 +85,7 @@ ISR(ADC_vect) {
|
|||
}
|
||||
dds.clockTick();
|
||||
}
|
||||
#endif
|
||||
#endif /* DDS_USE_ONLY_TIMER2 */
|
||||
|
||||
#endif /* __SAMD21G18A__ */
|
||||
|
||||
|
|
Loading…
Reference in New Issue