Pages: [1]   Go Down
Author Topic: DDS - 3phase signals 120 degrees out of phase  (Read 3466 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 2
Posts: 21
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi

I just completed a project of mine that generates 3 Sine waves 120 degrees out of phase. It took my hours to understand how to generate the sine tables and so forth. Thus I commented in as much detail as possible for future programmers to understand and grasp the idea quicker.

Code:

Code:
/*
 *
 * DDS Sine Generator mit ATMEGS 328
 * Timer2 generates the  31250 KHz Clock Interrupt
 * Use Timer2 Interrupt to change duty cycle for the output PWM signals
 * D. Tolken
 * 120 degress out of phase signals for 3 phase BLDC motor controller
 * CPUT, South Africa


a Huge thumbs up and thanks must be given to Martin Nawrath for the developement of the original code to generate a sine wave using PWM and a LPF.
Link:
                                         http://interface.khm.de/index.php/lab/experiments/arduino-dds-sinewave-generator/
*/

#include "avr/pgmspace.h" //Store data in flash (program) memory instead of SRAM

// Look Up table of a single sine period divied up into 256 values. Refer to PWM to sine.xls on how the values was calculated
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

};
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) //define a bit to have the properties of a clear bit operator
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))//define a bit to have the properties of a set bit operator

int PWM1= 11;// PWM1 output, phase 1
int PWM2 = 3; //[WM2 ouput, phase 2
int PWM3 = 10; //PWM3 output, phase 3
int offset_1 = 85; //offset 1 is 120 degrees out of phase with previous phase, Refer to PWM to sine.xls
int offset_2 = 170; //offset 2 is 120 degrees out of phase with offset 1. Refer to PWM to sine.xls
int program_exec_time = 6; //monitor how quickly the interrupt trigger
int ISR_exec_time = 7; //monitor how long the interrupt takes

double dfreq;
const double refclk=31376.6;      // measured output frequency

// variables used inside interrupt service declared as voilatile
volatile byte current_count;              // Keep track of where the current count is in sine 256 array
volatile byte ms4_delay;             //variable used to generate a 4ms delay
volatile byte c4ms;              // after every 4ms this variable is incremented, its used to create a delay of 1 second
volatile unsigned long phase_accumulator;   // pahse accumulator
volatile unsigned long tword_m;  // dds tuning word m, refer to DDS_calculator (from Martin Nawrath) for explination.

void setup()
{
  pinMode(PWM1, OUTPUT);      //sets the digital pin as output
  pinMode(PWM2, OUTPUT);      //sets the digital pin as output
  pinMode(PWM3, OUTPUT);      //sets the digital pin as output
  pinMode(program_exec_time, OUTPUT);      //sets the digital pin as output
  pinMode(9, OUTPUT);         //sets the digital pin as output
  sbi(PORTD,program_exec_time); //Sets the pin
  Setup_timer1();
  Setup_timer2();
 
  //Disable Timer 1 interrupt to avoid any timing delays
  cbi (TIMSK0,TOIE0);              //disable Timer0 !!! delay() is now not available
  sbi (TIMSK2,TOIE2);              //enable Timer2 Interrupt

  dfreq=1000.0;                    //initial output frequency = 1000.o Hz
  tword_m=pow(2,32)*dfreq/refclk;  //calulate DDS new tuning word

}
void loop()
{
  while(1)
  {
      sbi(PORTD,program_exec_time); //Sets the pin
      if (c4ms > 250) // c4ms = 4ms, thus 4ms *250 = 1 second delay
       {                 
        c4ms=0;                          //Reset c4ms
        dfreq=analogRead(0);             //Read voltage on analog 1 to see desired output frequency, 0V = 0Hz, 5V = 1.023kHz
        cbi (TIMSK2,TOIE2);              //Disable Timer2 Interrupt
        tword_m=pow(2,32)*dfreq/refclk;  //Calulate DDS new tuning word
        sbi (TIMSK2,TOIE2);              //Enable Timer2 Interrupt
      }
  }
}

//Timer 1 setup
//Set prscaler to 1, PWM mode to phase correct PWM,  16000000/510 = 31372.55 Hz clock
void Setup_timer1(void)
{
  // Timer1 Clock Prescaler to : 1
  sbi (TCCR1B, CS10);
  cbi (TCCR1B, CS11);
  cbi (TCCR1B, CS12);
 
  // Timer1 PWM Mode set to Phase Correct PWM
  cbi (TCCR1A, COM1A0);
  sbi (TCCR1A, COM1A1);
  cbi (TCCR1A, COM1B0);
  sbi (TCCR1A, COM1B1);

  // Mode 1 / Phase Correct PWM
  sbi (TCCR1A, WGM10);
  cbi (TCCR1A, WGM11);
  cbi (TCCR1B, WGM12);
  cbi (TCCR1B, WGM13);
}

//Timer 1 setup
//Set prscaler to 1, PWM mode to phase correct PWM,  16000000/510 = 31372.55 Hz clock
void Setup_timer2()
{
  // Timer2 Clock Prescaler to : 1
  sbi (TCCR2B, CS20);
  cbi (TCCR2B, CS21);
  cbi (TCCR2B, CS22);

  // Timer2 PWM Mode set to Phase Correct PWM
  cbi (TCCR2A, COM2A0);  // clear Compare Match
  sbi (TCCR2A, COM2A1);
  cbi (TCCR2A, COM2B0);
  sbi (TCCR2A, COM2B1);
 
  // Mode 1  / Phase Correct PWM
  sbi (TCCR2A, WGM20); 
  cbi (TCCR2A, WGM21);
  cbi (TCCR2B, WGM22);
}


//Timer2 Interrupt Service at 31372,550 KHz = 32uSec
//This is the timebase REFCLOCK for the DDS generator
//FOUT = (M (REFCLK)) / (2 exp 32)
//Runtime : 8 microseconds
ISR(TIMER2_OVF_vect)
{
  cbi(PORTD,program_exec_time); //Clear the pin
  sbi(PORTD,ISR_exec_time);          // Sets the pin

  phase_accumulator=phase_accumulator+tword_m; //Adds tuning M word to previoud phase accumulator. refer to DDS_calculator (from Martin Nawrath) for explination.
  current_count=phase_accumulator >> 24;     // use upper 8 bits of phase_accumulator as frequency information                     
 
  OCR2A=pgm_read_byte_near(sine256 + current_count); // read value fron ROM sine table and send to PWM
  OCR2B=pgm_read_byte_near(sine256 + (uint8_t)(current_count + offset_1)); // read value fron ROM sine table and send to PWM, 120 Degree out of phase of PWM1
 
  OCR1A = pgm_read_byte_near(sine256 + (uint8_t)(current_count + offset_2));// read value fron ROM sine table and send to PWM, 120 Degree out of phase of PWM2
  OCR1B = pgm_read_byte_near(sine256 + (uint8_t)(current_count + offset_2));// read value fron ROM sine table and send to PWM, 120 Degree out of phase of PWM2
 
  //increment variable ms4_delay every 4mS/125 =  milliseconds 32uS
  if(ms4_delay++ == 125)
  { 
    c4ms++;
    ms4_delay=0; //reset count
   }   

 cbi(PORTD,ISR_exec_time);            //Clear the pin
}

Sine wave table calculater: PWM to sine.xlsx
DDS Frequency Calc (Not My Document, helps to explain): dds_calc.xls
Circuit Diagram (Fritz): Breadboard
Measured Results: Output.bmp

Feel free to comment/ask questions

Cheers smiley

* dds_calc.xls (8 KB - downloaded 89 times.)
* PWM to sine.xlsx (44.02 KB - downloaded 99 times.)
* Breadboard.fzz (13.93 KB - downloaded 87 times.)

* Output.BMP (219.43 KB, 320x234 - viewed 188 times.)
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 309
Posts: 26528
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I suspect your phase accumulator handling in the ISR could be improved, if the compiler hasn't already done it for you.
That 24 place shift will probably be slow, so extracting the eight bit integer part of the fixed-point accumulator might be quicker.
Might be worth a peek at the generated code.
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Dubai, UAE
Offline Offline
Edison Member
*
Karma: 22
Posts: 1675
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
That 24 place shift will probably be slow, so extracting the eight bit integer part of the fixed-point accumulator might be quicker.

Good idea, I have a few spots that might benefit from a union in a similar application.

Duane B

rcarduino.blogspot.com
Logged


USA
Offline Offline
Sr. Member
****
Karma: 17
Posts: 391
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If we're looking for ways to save time, I'll suggest declaring ISR_exec_time and program_exec_time as const.  It's surprising how many cycles it takes to do a cbi() or sbi() with a variable bit number.  With a const bit number, those collapse to single-byte cbi and sbi instructions.

I think there could be additional improvement - but maybe not much - from declaring current_count to be local to the ISR.  It's not used outside the ISR.  It's volatile, so it has to be read or stored each time it's used; if it was a local variable, it might just stay in regsiters, and never make it to memory at all.
Logged

Rome
Offline Offline
God Member
*****
Karma: 1
Posts: 643
La mia prima bromografata!!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
//Disable Timer 1 interrupt to avoid any timing delays
  cbi (TIMSK0,TOIE0);              //disable Timer0 !!! delay() is now not available
  sbi (TIMSK2,TOIE2);              //enable Timer2 Interrupt

what did you mean here?

Quote
//Timer 1 setup
//Set prscaler to 1, PWM mode to phase correct PWM,  16000000/510 = 31372.55 Hz clock
void Setup_timer2()
{
  // Timer2 Clock Prescaler to : 1
It seems like there's the need of some code-cleaning..

of course, other than that, that's very interesting!!
« Last Edit: September 16, 2012, 06:13:41 am by dab77 » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

i want to generate 6 sine wave because i want o fire six pluse igbt so how can i do that?? 
Logged

Pages: [1]   Go Up
Jump to: