As an alternative to DDS this code shows a way to generate 3 phase sine PWM using a recursion equation rather than a lookup table. Because computation is slower than a lookup table it cannot go as high as 1KHz for the sine output. I have tested it to 500Hz and it can probably go a little higher.
// Generates three equally spaced phases of a PWM sine signal
// on an Arduino Mega
#include <TimerOne.h>
#define phase0 11 // Timer1 sets pwm on 11, 12, and 13 on Mega (9 and 10 on Uno)
#define phase1 12
#define phase2 13
#define delayPin 10 // use this optional signal for info on compute time
const float pi = 3.14159 ;
float T = 150 ; // sample time in microseconds
volatile float freq = 50 ; // frequency of tone in hertz
float omega = 2*pi*freq ;
float A = 490 ; // amplitude
float omegaT = omega*T/1000000.0 ;
// next line initializes oscillation with amplitude A
volatile float a[]={0.0, A*sin(omegaT),0.0};
float bb0 = A*sin(2.0*pi/3.0);
float bb1 = A*sin(omegaT + 2.0*pi/3.0);
float cc0 = A*sin(4.0*pi/3.0);
float cc1 = A*sin(omegaT + 4.0*pi/3.0);
volatile float b[]={bb0, bb1 ,0.0};
volatile float c[]={cc0, cc1 ,0.0};
// c1 is the difference equation coefficient
float c1 = (8.0 - 2.0*pow(omegaT,2))/(4.0+pow(omegaT,2));
void setup()
{
Timer1.initialize(T); // set sample time for discrete tone signal
Timer1.pwm(phase0, 0,T);
Timer1.pwm(phase1, 0,T);
Timer1.pwm(phase2, 0,T);
Timer1.attachInterrupt(compute);
pinMode(delayPin, OUTPUT);
}
void loop()
{
delay(1000);
changeFreq(10);
delay(1000);
changeFreq(50);
delay(1000);
changeFreq(200);
}
void compute() // called by Timer Interrupt
{
digitalWrite(delayPin, HIGH);
a[2] = c1*a[1] - a[0] ; // recursion equation
a[0] = a[1] ; // shift
a[1] = a[2] ;
b[2] = c1*b[1] - b[0] ; // recursion equation
b[0] = b[1] ;
b[1] = b[2] ;
c[2] = c1*c[1] - c[0] ; // recursion equation
c[0] = c[1] ;
c[1] = c[2] ;
Timer1.setPwmDuty(phase0, int(a[2])+512);
Timer1.setPwmDuty(phase1, int(b[2])+512);
Timer1.setPwmDuty(phase2, int(c[2])+512);
digitalWrite(delayPin, LOW);
}
void changeFreq(float _freq){ // changes frequency
noInterrupts();
freq = _freq;
omega = 2*pi*freq ;
omegaT = omega*T/1000000.0 ;
a[0] = 0.0 ;
a[1] = A*sin(omegaT);
b[0] = A*sin(2.0*pi/3.0);
b[1] = A*sin(omegaT + 2.0*pi/3.0);
c[0] = A*sin(4.0*pi/3.0);
c[1] = A*sin(omegaT + 4.0*pi/3.0);
c1 = (8.0 - 2.0*pow(omegaT,2))/(4.0+pow(omegaT,2));
interrupts();
}