Skip to content

Instantly share code, notes, and snippets.

@ednisley
Last active April 21, 2018 12:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ednisley/3dbbf57a5b599e304908a4466b349fe6 to your computer and use it in GitHub Desktop.
Save ednisley/3dbbf57a5b599e304908a4466b349fe6 to your computer and use it in GitHub Desktop.
TeensyDuino source code: FM DDS demo 2 on bare Teensy 3.6 - double float timing
// FM DDS
// Ed Nisley - KE4ZNU
// 2017-04-19 Demo 1
#include <IntervalTimer.h>
#include <ADC.h>
#include <SPI.h>
#define PIN_HEART 14
#define PIN_TIMER 15
#define PIN_ANALOG 16
#define PIN_GLITCH 17
#define PIN_AUDIO A9
#define PIN_DDS_FQUD 10
// data to DDS MOSI0 11
// no data from DDS MISO0 12
// DDS clock on SCK0 13 -- also LED
#define BUILTIN_LED 13
//---------------------
// Useful constants
int SamplePeriod = 25; // microseconds per analog sample
//---------------------
// Globals
ADC *adc = new ADC();
IntervalTimer timer;
volatile int AnalogSample;
volatile int AudioMax = -4096;
volatile int AudioMin = 4096;
typedef struct {
uint8_t Phase;
uint32_t DeltaPhase; // DDS expects MSB first!
} DDS;
DDS DDSBuffer;
double DDSClock = 180.0e6; // nominal DDS oscillator
double CountPerHertz, HertzPerCount; // DDS delta-phase increments
double Crystal = 20.0e6; // nominal DDS frequency
double Deviation = 5.0e3; // nominal FM signal deviation (one-sided)
double TestFreq;
//---------------------
// Handy routines
void FlipPin(int pin) {
digitalWriteFast(pin,!digitalRead(pin));
}
void PulsePin(int p) {
FlipPin(p);
FlipPin(p);
}
//---------------------
// Timer handler
void timer_callback(void) {
digitalWriteFast(PIN_TIMER,HIGH);
digitalWriteFast(PIN_DDS_FQUD,HIGH); // latch previously shifted bits
adc->startSingleRead(PIN_AUDIO, ADC_0); // start ADC conversion
analogWriteDAC0(AnalogSample); // show previous audio sample
digitalWriteFast(PIN_TIMER,LOW);
}
//---------------------
// Analog read handler
void adc0_isr(void) {
int Audio;
digitalWriteFast(PIN_ANALOG,HIGH);
AnalogSample = adc->readSingle(); // fetch just-finished sample
Audio = AnalogSample - 2048; // convert to AC signal
DDSBuffer.Phase = 0;
SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
digitalWriteFast(PIN_DDS_FQUD, LOW);
SPI.transfer(DDSBuffer.Phase);
DDSBuffer.DeltaPhase = (uint32_t)((((double)Audio / 2048.0) * Deviation + Crystal) * CountPerHertz);
SPI.transfer((uint8_t)(DDSBuffer.DeltaPhase >> 24)); // MSB first!
if (Audio > AudioMax) // ignore race conditions
AudioMax = Audio;
if (Audio < AudioMin)
AudioMin = Audio;
SPI.transfer((uint8_t)(DDSBuffer.DeltaPhase >> 16));
SPI.transfer((uint8_t)(DDSBuffer.DeltaPhase >> 8));
SPI.transfer((uint8_t)DDSBuffer.DeltaPhase);
SPI.endTransaction(); // do not raise FQ_UD until next timer tick!
digitalWriteFast(PIN_ANALOG,LOW);
}
//---------------------
// Hardware setup
void setup(void) {
pinMode(BUILTIN_LED,OUTPUT); // will eventually become SCK0
pinMode(PIN_HEART, OUTPUT); // show we arrived
digitalWrite(PIN_HEART,LOW);
PulsePin(PIN_HEART);
PulsePin(PIN_HEART);
pinMode(PIN_TIMER,OUTPUT);
digitalWrite(PIN_TIMER,LOW);
pinMode(PIN_GLITCH,OUTPUT);
digitalWrite(PIN_GLITCH,LOW);
pinMode(PIN_ANALOG,OUTPUT);
digitalWrite(PIN_ANALOG,LOW);
pinMode(PIN_AUDIO,INPUT);
pinMode(PIN_DDS_FQUD,OUTPUT);
digitalWriteFast(PIN_DDS_FQUD,HIGH);
Serial.begin(115200);
int waited = 0;
while (!Serial && waited < 3000) { // fall out after a few seconds
delay(1);
waited++;
if (! (waited % 50))
FlipPin(BUILTIN_LED);
}
Serial.printf("FM Modulated DDS\nEd Nisley KE4ZNU\n");
Serial.printf(" serial wait: %d ms\n\n",waited);
SPI.begin();
SPI.usingInterrupt(255); // attached through analog IRQs
adc->setAveraging(4); // choices: 0, 4, 8, 16, 32
adc->setResolution(12); // choices: 8, 10, 12, 16
adc->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED);
adc->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED);
adc->enableInterrupts(ADC_0);
if (!timer.begin(timer_callback, SamplePeriod)) {
Serial.printf("Timer start failed\n");
while (true) {
FlipPin(BUILTIN_LED);
delay(75);
}
}
CountPerHertz = (1LL << 32) / DDSClock;
HertzPerCount = 1.0 / CountPerHertz;
Serial.printf("DDS clock: %13.3f Hz\n",DDSClock);
Serial.printf("CountPerHertz: %13.3f ct\n",CountPerHertz);
Serial.printf("HertzPerCount: %13.3f Hz\n\n",HertzPerCount);
TestFreq = Crystal;
Serial.printf("Crystal: %13.3f Hz\n",Crystal);
Serial.printf("Deviation: %13.3f Hz\n",Deviation);
Serial.printf("\nSetup done\n");
}
//---------------------
// Do things forever
void loop(void) {
digitalWrite(PIN_HEART,HIGH);
Serial.printf(" %5d to %5d\n",AudioMin,AudioMax);
AudioMax = 99*AudioMax/100; // ignore race conditions
AudioMin = 99*AudioMin/100;
digitalWrite(PIN_HEART,LOW);
delay(500);
}
@ednisley
Copy link
Author

More details on my blog at https://wp.me/poZKh-7tP

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment