Created generic DDS class for tone generation, update AFSK to start the right timers.
This commit is contained in:
		
							parent
							
								
									55c10c503b
								
							
						
					
					
						commit
						1117542411
					
				
							
								
								
									
										28
									
								
								AFSK.cpp
								
								
								
								
							
							
						
						
									
										28
									
								
								AFSK.cpp
								
								
								
								
							| 
						 | 
				
			
			@ -14,6 +14,8 @@
 | 
			
		|||
 | 
			
		||||
#define PPOOL_SIZE 2
 | 
			
		||||
 | 
			
		||||
#define COMPARE_BITS     6
 | 
			
		||||
#define ACCUMULATOR_SIZE 32
 | 
			
		||||
#define ACCUMULATOR_BITS 24 // This is 2^10 bits used from accum
 | 
			
		||||
//#undef PROGMEM
 | 
			
		||||
//#define PROGMEM __attribute__((section(".progmem.data")))
 | 
			
		||||
| 
						 | 
				
			
			@ -44,15 +46,15 @@ volatile unsigned long lastTx = 0;
 | 
			
		|||
volatile unsigned long lastTxEnd = 0;
 | 
			
		||||
volatile unsigned long lastRx = 0;
 | 
			
		||||
 | 
			
		||||
#define REFCLK 9600
 | 
			
		||||
#define REFCLK 38400
 | 
			
		||||
//#define REFCLK 31372.54902
 | 
			
		||||
//#define REFCLK (16000000.0/510.0)
 | 
			
		||||
//#define REFCLK 31200.0
 | 
			
		||||
// 2200Hz = pow(2,32)*2200.0/refclk
 | 
			
		||||
// 1200Hz = pow(2,32)*1200.0/refclk
 | 
			
		||||
static const unsigned long toneStep[2] = {
 | 
			
		||||
  pow(2,32)*2200.0/REFCLK,
 | 
			
		||||
  pow(2,32)*1200.0/REFCLK
 | 
			
		||||
  (2200.0/REFCLK)*pow(2,ACCUMULATOR_SIZE),
 | 
			
		||||
  (1200.0/REFCLK)*pow(2,ACCUMULATOR_SIZE)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Set to an arbitrary frequency
 | 
			
		||||
| 
						 | 
				
			
			@ -143,12 +145,7 @@ void AFSK::Encoder::process() {
 | 
			
		|||
 | 
			
		||||
  accumulator += toneStep[currentTone];
 | 
			
		||||
  uint8_t phAng = (accumulator >> ACCUMULATOR_BITS);
 | 
			
		||||
  /*if(toneVolume[currentTone] != 255) {
 | 
			
		||||
  OCR2B = pwm * toneVolume[currentTone] / 255;
 | 
			
		||||
  } else {*/
 | 
			
		||||
  // No volume scaling required
 | 
			
		||||
  OCR2B = pgm_read_byte_near(sinetable + phAng);
 | 
			
		||||
  /*}*/
 | 
			
		||||
  OCR2B = pgm_read_byte_near(sinetable + phAng)>>(8-COMPARE_BITS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AFSK::Encoder::start() {
 | 
			
		||||
| 
						 | 
				
			
			@ -368,6 +365,19 @@ bool AFSK::Decoder::read() {
 | 
			
		|||
void AFSK::Decoder::start() {
 | 
			
		||||
  // Do this in start to allocate our first packet
 | 
			
		||||
  currentPacket = pBuf.makePacket(PACKET_MAX_LEN);
 | 
			
		||||
  ASSR &= ~(_BV(EXCLK) | _BV(AS2));
 | 
			
		||||
 | 
			
		||||
  // Do non-inverting PWM on pin OC2B (arduino pin 3) (p.159).
 | 
			
		||||
  // OC2A (arduino pin 11) stays in normal port operation:
 | 
			
		||||
  // COM2B1=1, COM2B0=0, COM2A1=0, COM2A0=0
 | 
			
		||||
  // Mode 1 - Phase correct PWM
 | 
			
		||||
  TCCR2A = (TCCR2A | _BV(COM2B1)) & ~(_BV(COM2B0) | _BV(COM2A1) | _BV(COM2A0)) |
 | 
			
		||||
           _BV(WGM21) | _BV(WGM20);
 | 
			
		||||
  // No prescaler (p.162)
 | 
			
		||||
  TCCR2B = (TCCR2B & ~(_BV(CS22) | _BV(CS21))) | _BV(CS20) | _BV(WGM22);
 | 
			
		||||
  
 | 
			
		||||
  OCR2A = pow(2,COMPARE_BITS)-1;
 | 
			
		||||
  OCR2B = 0;
 | 
			
		||||
  // Configure the ADC and Timer1 to trigger automatic interrupts
 | 
			
		||||
  TCCR1A = 0;
 | 
			
		||||
  TCCR1B = _BV(CS11) | _BV(WGM13) | _BV(WGM12);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,82 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
#include "DDS.h"
 | 
			
		||||
 | 
			
		||||
// 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() {
 | 
			
		||||
  // 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
 | 
			
		||||
  TCCR2A = (TCCR2A | _BV(COM2B1)) & ~(_BV(COM2B0) | _BV(COM2A1) | _BV(COM2A0)) |
 | 
			
		||||
         _BV(WGM21) | _BV(WGM20);
 | 
			
		||||
  TCCR2B = (TCCR2B & ~(_BV(CS22) | _BV(CS21))) | _BV(CS20) | _BV(WGM22);
 | 
			
		||||
 | 
			
		||||
  // 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.
 | 
			
		||||
  OCR2A = pow(2,COMPARATOR_BITS)-1;
 | 
			
		||||
  OCR2B = 0;
 | 
			
		||||
  
 | 
			
		||||
  // Second, setup Timer1 to trigger the ADC interrupt
 | 
			
		||||
  // This lets us use decoding functions that run at the same reference
 | 
			
		||||
  // clock as the DDS.
 | 
			
		||||
  TCCR1B = _BV(CS11) | _BV(WGM13) | _BV(WGM12);
 | 
			
		||||
  TCCR1A = 0;
 | 
			
		||||
  ICR1 = ((F_CPU / 8) / DDS_REFCLK_DEAULT) - 1;
 | 
			
		||||
 | 
			
		||||
  // 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)
 | 
			
		||||
  DDRC &= ~_BV(0);
 | 
			
		||||
  PORTC &= ~_BV(0);
 | 
			
		||||
  DIDR0 |= _BV(0);
 | 
			
		||||
  ADCSRB = _BV(ADTS2) | _BV(ADTS1) | _BV(ADTS0);
 | 
			
		||||
  ADCSRA = _BV(ADEN) | _BV(ADSC) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2); // | _BV(ADPS0);    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DDS::stop() {
 | 
			
		||||
  // TODO: Stop the timers.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set our current sine wave frequency in Hz
 | 
			
		||||
void DDS::setFrequency(unsigned short freq) {
 | 
			
		||||
  // Fo = (M*Fc)/2^N
 | 
			
		||||
  // M = (Fo/Fc)*2^N
 | 
			
		||||
  if(refclk == DDS_REFCLK_DEAULT) {
 | 
			
		||||
    // Try to use precalculated values if possible
 | 
			
		||||
    if(freq == 2200) {
 | 
			
		||||
      stepRate = (2200.0 / DDS_REFCLK_DEAULT) * pow(2,ACCUMULATOR_BITS);
 | 
			
		||||
    } else if (freq == 1200) {
 | 
			
		||||
      stepRate = (1200.0 / DDS_REFCLK_DEAULT) * pow(2,ACCUMULATOR_BITS);      
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    // Do the actual math instead.
 | 
			
		||||
    stepRate = (freq / refclk) * pow(2,ACCUMULATOR_BITS);    
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DDS::clockTick() {
 | 
			
		||||
  accumulator += stepRate;
 | 
			
		||||
  if(running) {
 | 
			
		||||
    if(tickDuration == 0) {
 | 
			
		||||
      OCR2B = 0;
 | 
			
		||||
      running = false;
 | 
			
		||||
    } else {
 | 
			
		||||
      OCR2B = getPhaseAngle();
 | 
			
		||||
    }
 | 
			
		||||
    // Reduce our playback duration by one tick
 | 
			
		||||
    tickDuration--;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t DDS::getPhaseAngle() {
 | 
			
		||||
#if ACCUMULATOR_BIT_SHIFT >= 24
 | 
			
		||||
  uint16_t phAng;
 | 
			
		||||
#else
 | 
			
		||||
  uint8_t phAng;
 | 
			
		||||
#endif
 | 
			
		||||
  phAng = (accumulator >> ACCUMULATOR_BIT_SHIFT);
 | 
			
		||||
  return pgm_read_byte_near(ddsSineTable + phAng)>>(8-COMPARATOR_BITS);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,171 @@
 | 
			
		|||
#ifndef _DDS_H_
 | 
			
		||||
#define _DDS_H_
 | 
			
		||||
 | 
			
		||||
#include <avr/pgmspace.h>
 | 
			
		||||
 | 
			
		||||
#define SHORT_ACCUMULATOR
 | 
			
		||||
 | 
			
		||||
#ifdef SHORT_ACCUMULATOR
 | 
			
		||||
#define ACCUMULATOR_BITS      16
 | 
			
		||||
#else
 | 
			
		||||
#define ACCUMULATOR_BITS      32
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define COMPARATOR_BITS       6
 | 
			
		||||
 | 
			
		||||
#define DDS_REFCLK_DEAULT     38400
 | 
			
		||||
 | 
			
		||||
#define DDS_TABLE_LARGE
 | 
			
		||||
 | 
			
		||||
#ifdef DDS_TABLE_LARGE
 | 
			
		||||
#define ACCUMULATOR_BIT_SHIFT (ACCUMULATOR_BITS-10)
 | 
			
		||||
static const uint8_t ddsSineTable[1024] PROGMEM = {
 | 
			
		||||
  128,128,129,130,131,131,132,133,134,135,135,136,137,138,138,139,
 | 
			
		||||
  140,141,142,142,143,144,145,145,146,147,148,149,149,150,151,152,
 | 
			
		||||
  152,153,154,155,155,156,157,158,158,159,160,161,162,162,163,164,
 | 
			
		||||
  165,165,166,167,167,168,169,170,170,171,172,173,173,174,175,176,
 | 
			
		||||
  176,177,178,178,179,180,181,181,182,183,183,184,185,186,186,187,
 | 
			
		||||
  188,188,189,190,190,191,192,192,193,194,194,195,196,196,197,198,
 | 
			
		||||
  198,199,200,200,201,202,202,203,203,204,205,205,206,207,207,208,
 | 
			
		||||
  208,209,210,210,211,211,212,213,213,214,214,215,215,216,217,217,
 | 
			
		||||
  218,218,219,219,220,220,221,221,222,222,223,224,224,225,225,226,
 | 
			
		||||
  226,227,227,228,228,228,229,229,230,230,231,231,232,232,233,233,
 | 
			
		||||
  234,234,234,235,235,236,236,236,237,237,238,238,238,239,239,240,
 | 
			
		||||
  240,240,241,241,241,242,242,242,243,243,243,244,244,244,245,245,
 | 
			
		||||
  245,246,246,246,246,247,247,247,248,248,248,248,249,249,249,249,
 | 
			
		||||
  250,250,250,250,250,251,251,251,251,251,252,252,252,252,252,252,
 | 
			
		||||
  253,253,253,253,253,253,253,254,254,254,254,254,254,254,254,254,
 | 
			
		||||
  254,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 | 
			
		||||
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,254,
 | 
			
		||||
  254,254,254,254,254,254,254,254,254,254,253,253,253,253,253,253,
 | 
			
		||||
  253,252,252,252,252,252,252,251,251,251,251,251,250,250,250,250,
 | 
			
		||||
  250,249,249,249,249,248,248,248,248,247,247,247,246,246,246,246,
 | 
			
		||||
  245,245,245,244,244,244,243,243,243,242,242,242,241,241,241,240,
 | 
			
		||||
  240,240,239,239,238,238,238,237,237,236,236,236,235,235,234,234,
 | 
			
		||||
  234,233,233,232,232,231,231,230,230,229,229,228,228,228,227,227,
 | 
			
		||||
  226,226,225,225,224,224,223,222,222,221,221,220,220,219,219,218,
 | 
			
		||||
  218,217,217,216,215,215,214,214,213,213,212,211,211,210,210,209,
 | 
			
		||||
  208,208,207,207,206,205,205,204,203,203,202,202,201,200,200,199,
 | 
			
		||||
  198,198,197,196,196,195,194,194,193,192,192,191,190,190,189,188,
 | 
			
		||||
  188,187,186,186,185,184,183,183,182,181,181,180,179,178,178,177,
 | 
			
		||||
  176,176,175,174,173,173,172,171,170,170,169,168,167,167,166,165,
 | 
			
		||||
  165,164,163,162,162,161,160,159,158,158,157,156,155,155,154,153,
 | 
			
		||||
  152,152,151,150,149,149,148,147,146,145,145,144,143,142,142,141,
 | 
			
		||||
  140,139,138,138,137,136,135,135,134,133,132,131,131,130,129,128,
 | 
			
		||||
  128,127,126,125,124,124,123,122,121,120,120,119,118,117,117,116,
 | 
			
		||||
  115,114,113,113,112,111,110,110,109,108,107,106,106,105,104,103,
 | 
			
		||||
  103,102,101,100,100,99,98,97,97,96,95,94,93,93,92,91,
 | 
			
		||||
  90,90,89,88,88,87,86,85,85,84,83,82,82,81,80,79,
 | 
			
		||||
  79,78,77,77,76,75,74,74,73,72,72,71,70,69,69,68,
 | 
			
		||||
  67,67,66,65,65,64,63,63,62,61,61,60,59,59,58,57,
 | 
			
		||||
  57,56,55,55,54,53,53,52,52,51,50,50,49,48,48,47,
 | 
			
		||||
  47,46,45,45,44,44,43,42,42,41,41,40,40,39,38,38,
 | 
			
		||||
  37,37,36,36,35,35,34,34,33,33,32,31,31,30,30,29,
 | 
			
		||||
  29,28,28,27,27,27,26,26,25,25,24,24,23,23,22,22,
 | 
			
		||||
  21,21,21,20,20,19,19,19,18,18,17,17,17,16,16,15,
 | 
			
		||||
  15,15,14,14,14,13,13,13,12,12,12,11,11,11,10,10,
 | 
			
		||||
  10,9,9,9,9,8,8,8,7,7,7,7,6,6,6,6,
 | 
			
		||||
  5,5,5,5,5,4,4,4,4,4,3,3,3,3,3,3,
 | 
			
		||||
  2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,
 | 
			
		||||
  1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 | 
			
		||||
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
 | 
			
		||||
  1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,
 | 
			
		||||
  2,3,3,3,3,3,3,4,4,4,4,4,5,5,5,5,
 | 
			
		||||
  5,6,6,6,6,7,7,7,7,8,8,8,9,9,9,9,
 | 
			
		||||
  10,10,10,11,11,11,12,12,12,13,13,13,14,14,14,15,
 | 
			
		||||
  15,15,16,16,17,17,17,18,18,19,19,19,20,20,21,21,
 | 
			
		||||
  21,22,22,23,23,24,24,25,25,26,26,27,27,27,28,28,
 | 
			
		||||
  29,29,30,30,31,31,32,33,33,34,34,35,35,36,36,37,
 | 
			
		||||
  37,38,38,39,40,40,41,41,42,42,43,44,44,45,45,46,
 | 
			
		||||
  47,47,48,48,49,50,50,51,52,52,53,53,54,55,55,56,
 | 
			
		||||
  57,57,58,59,59,60,61,61,62,63,63,64,65,65,66,67,
 | 
			
		||||
  67,68,69,69,70,71,72,72,73,74,74,75,76,77,77,78,
 | 
			
		||||
  79,79,80,81,82,82,83,84,85,85,86,87,88,88,89,90,
 | 
			
		||||
  90,91,92,93,93,94,95,96,97,97,98,99,100,100,101,102,
 | 
			
		||||
  103,103,104,105,106,106,107,108,109,110,110,111,112,113,113,114,
 | 
			
		||||
  115,116,117,117,118,119,120,120,121,122,123,124,124,125,126,127
 | 
			
		||||
};
 | 
			
		||||
#else
 | 
			
		||||
#define ACCUMULATOR_BIT_SHIFT (ACCUMULATOR_BITS-8)
 | 
			
		||||
static const uint8_t ddsSineTable[256] PROGMEM = {
 | 
			
		||||
  128,131,134,137,140,143,146,149,152,155,158,162,165,167,170,173,
 | 
			
		||||
  176,179,182,185,188,190,193,196,198,201,203,206,208,211,213,215,
 | 
			
		||||
  218,220,222,224,226,228,230,232,234,235,237,238,240,241,243,244,
 | 
			
		||||
  245,246,248,249,250,250,251,252,253,253,254,254,254,255,255,255,
 | 
			
		||||
  255,255,255,255,254,254,254,253,253,252,251,250,250,249,248,246,
 | 
			
		||||
  245,244,243,241,240,238,237,235,234,232,230,228,226,224,222,220,
 | 
			
		||||
  218,215,213,211,208,206,203,201,198,196,193,190,188,185,182,179,
 | 
			
		||||
  176,173,170,167,165,162,158,155,152,149,146,143,140,137,134,131,
 | 
			
		||||
  128,124,121,118,115,112,109,106,103,100,97,93,90,88,85,82,
 | 
			
		||||
  79,76,73,70,67,65,62,59,57,54,52,49,47,44,42,40,
 | 
			
		||||
  37,35,33,31,29,27,25,23,21,20,18,17,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,17,18,20,21,23,25,27,29,31,33,35,
 | 
			
		||||
  37,40,42,44,47,49,52,54,57,59,62,65,67,70,73,76,
 | 
			
		||||
  79,82,85,88,90,93,97,100,103,106,109,112,115,118,121,124
 | 
			
		||||
};
 | 
			
		||||
#endif /* DDS_TABLE_LARGE */
 | 
			
		||||
 | 
			
		||||
class DDS {
 | 
			
		||||
public:
 | 
			
		||||
  DDS(): refclk(DDS_REFCLK_DEAULT), accumulator(0), running(false) {};
 | 
			
		||||
 | 
			
		||||
  void start();
 | 
			
		||||
  const bool isRunning() { return running; };
 | 
			
		||||
  void stop();
 | 
			
		||||
  
 | 
			
		||||
  // Start the PWM output, or stop it
 | 
			
		||||
  void on() {
 | 
			
		||||
    running = true;
 | 
			
		||||
  }
 | 
			
		||||
  // Provide a duration in ms for the tone
 | 
			
		||||
  void on(unsigned short duration) {
 | 
			
		||||
    // Duration in ticks from milliseconds is:
 | 
			
		||||
    // t = (1/refclk)
 | 
			
		||||
    tickDuration = duration / (1000.0/refclk);
 | 
			
		||||
    running = true;
 | 
			
		||||
  }
 | 
			
		||||
  void off() {
 | 
			
		||||
    running = false;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  // Generate a tone for a specific amount of time
 | 
			
		||||
  void play(unsigned short freq, unsigned short duration) {
 | 
			
		||||
    setFrequency(freq);
 | 
			
		||||
    on(duration);
 | 
			
		||||
  }
 | 
			
		||||
  // Blocking version
 | 
			
		||||
  void playWait(unsigned short freq, unsigned short duration) {
 | 
			
		||||
    setFrequency(freq);
 | 
			
		||||
    on(duration);
 | 
			
		||||
    delay(duration * 1000);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  // Our maximum clock isn't very high, so our highest
 | 
			
		||||
  // frequency supported will fit in a short.
 | 
			
		||||
  void setFrequency(unsigned short freq);
 | 
			
		||||
  
 | 
			
		||||
  // Adjustable reference clock
 | 
			
		||||
  void setReferenceClock(unsigned long ref);
 | 
			
		||||
 | 
			
		||||
  uint8_t getPhaseAngle();
 | 
			
		||||
 | 
			
		||||
  void clockTick();
 | 
			
		||||
  
 | 
			
		||||
private:
 | 
			
		||||
  bool running;
 | 
			
		||||
  unsigned long tickDuration;
 | 
			
		||||
#ifdef SHORT_ACCUMULATOR
 | 
			
		||||
  unsigned short accumulator;
 | 
			
		||||
  unsigned short stepRate;
 | 
			
		||||
  unsigned short refclk;
 | 
			
		||||
#else
 | 
			
		||||
  unsigned long accumulator;
 | 
			
		||||
  unsigned long stepRate;
 | 
			
		||||
  unsigned long refclk;
 | 
			
		||||
#endif
 | 
			
		||||
  static DDS *sDDS;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* _DDS_H_ */
 | 
			
		||||
		Loading…
	
		Reference in New Issue