3 PWM for 3 phase inventer

i want to generate 3 PWM 120 degrees out of phase with arduino mega2560 because i want to control six pluse igbt to control 3 phase motor ( 220v/380v // f=50hz // rpm = 1430 ) and display the frequence in LCD

i use timer 1 and 2 :
timer 1 (controls pin 12, 11)
timer 2 (controls pin 10, 9)

can you help me to fix the code for my arduino mega 2560 because the problem is the frenquence output

#include "avr/pgmspace.h"
#include "avr/io.h"

// 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 sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
int PWM_OUT_1 =11; // PWM output on pin 11
int PWM_OUT_2 =10; // PWM output on pin 10
int PWM_OUT_3 =12; // PWM output on pin 9
int LED_PIN =13; // LED status on pin 13
int TEST_PIN =7; // Scope trigger on pin 7
int POTEN_IN =A0; // Potentiometer on pin 0
int OFFSET_1 =85; // Offset for second-phase
int OFFSET_2 =170; // Offset for third-phase
double dfreq;
const double refclk = 31376.6; // measured
const uint64_t twoTo32 = pow(2, 32); // compute value at startup and use as constant
// variables used inside interrupt service declared as voilatile
volatile uint8_t icnt; // var inside interrupt
volatile uint8_t icnt1; // var inside interrupt
volatile uint8_t c4ms; // counter incremented every 4ms
volatile uint32_t phase_accum; // pahse accumulator
volatile uint32_t tword_m; // dds tuning word m
//******************************************************************
void setup()
{
pinMode(LED_PIN, OUTPUT); // sets the digital pin as output
Serial.begin(115200); // connect to the serial port
Serial.println("DDS Test");

pinMode(TEST_PIN, OUTPUT); // sets the digital pin as output
pinMode(PWM_OUT_1, OUTPUT); // PWM output / frequency output
pinMode(PWM_OUT_2, OUTPUT); // PWM output / frequency output
pinMode(PWM_OUT_3, OUTPUT); // PWM output / frequency output
// Setup the timers
setup_timer1();
setup_timer2();
// disable interrupts to avoid timing distortion
cbi (TIMSK0, TOIE0); // disable Timer0 !!! delay() is now not available
sbi (TIMSK2, TOIE2); // enable Timer2 Interrupt
dfreq = 1000.0; // initial output frequency = 1000.0 Hz
tword_m = twoTo32 * dfreq / refclk; // calulate DDS new tuning word
}
//******************************************************************
void loop()
{
if (c4ms > 250) // timer / wait for a full second
{
c4ms = 0;
dfreq = analogRead(POTEN_IN); // read Poti on analog pin 0 to adjust output frequency from 0..1023 Hz
cbi (TIMSK2, TOIE2); // disble Timer2 Interrupt
tword_m = twoTo32 * dfreq / refclk; // calulate DDS new tuning word
sbi (TIMSK2, TOIE2); // enable Timer2 Interrupt
Serial.print(dfreq);
Serial.print(" ");
Serial.println(tword_m);
}
}
//******************************************************************
// timer1 setup
// set prscaler to 1, PWM mode to phase correct PWM, 16000000/512 = 31.25kHz clock
void setup_timer1(void)
{
// Timer1 Clock Prescaler to : 1
sbi (TCCR1B, CS10);
cbi (TCCR1B, CS11);
cbi (TCCR1B, CS12);
// Timer0 PWM Mode set to Phase Correct PWM
cbi (TCCR1A, COM1A0); // clear Compare Match
sbi (TCCR1A, COM1A1);
cbi (TCCR1A, COM1B0); // clear Compare Match
sbi (TCCR1A, COM1B1);
sbi (TCCR1A, WGM10); // Mode 1 / Phase Correct PWM
cbi (TCCR1A, WGM11);
cbi (TCCR1B, WGM12);
cbi (TCCR1B, WGM13);
}

//******************************************************************
// timer2 setup
// set prscaler to 1, PWM mode to phase correct PWM, 16000000/512 = 31.25kHz 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);
sbi (TCCR2A, WGM20); // Mode 1 / Phase Correct PWM
cbi (TCCR2A, WGM21);
cbi (TCCR2B, WGM22);
}
//******************************************************************
// Timer2 Interrupt Service at 31.25kHz = 32us
// this is the timebase REFCLOCK for the DDS generator
// FOUT = (M (REFCLK)) / (2 exp 32)
// runtime : 8 microseconds ( inclusive push and pop)
ISR(TIMER2_OVF_vect)
{
sbi(PORTD, TEST_PIN); // Test / set PORTD,TEST_PIN high to observe timing with a oscope
phase_accum += tword_m; // soft DDS, phase accu with 32 bits
icnt = phase_accum >> 24; // use upper 8 bits for phase accu as frequency information
OCR2A = pgm_read_byte_near(sine256 + icnt); // read value fron ROM sine table and send to PWM DAC
OCR1A = pgm_read_byte_near(sine256 + (uint8_t)(icnt + OFFSET_1));
OCR1B = pgm_read_byte_near(sine256 + (uint8_t)(icnt + OFFSET_2));
if (icnt1++ == 125) // increment variable c4ms every 4 milliseconds
{
c4ms++;
icnt1 = 0;
}
cbi(PORTD, TEST_PIN); // reset PORTD,TEST_PIN
}


I think the assumption of your first sentence is basically wrong. When doing a 3 phase drive, the PWM frequency will be much higher than the commutation frequency (in order to obtain good current control, especially with non-constant current per commutation) therefore there is no need for any phase difference in the PWM signals.

For a 50Hz motor, the commutation frequency is 50Hz but the PWM will be a few kHz.

If you're trying to generate three sine waves from PWM with a phase offset, that's totally reasonable. You just have three different indices into your sine table, offset by 1/3 of the table's length. You basically have it with OFFSET_1 etc but you didn't wrap the values so you're reading off the end of the sine table. Do something like this instead:

pwm1=sine256[icnt];
pwm2=sine256[(icnt+OFFSET_1)&0xFF];
pwm3=sine256[(icnt+OFFSET_2)&0xFF]

The PWM signals will all be mostly in phase but that doesn't matter; the sine waves will be out of phase. In fact if you zoom out on your waveform view, you might find that you are very close already.

Its more complex that this, you have 3 currents you want to independently control,
to get sinusoids, the three PWM signals have to coordinate to achieve this. I don't
think this is possible using the hardware PWM units.

You should perhaps consider trapezoidal drive which only drives two of the phase-
wires at once - easier to do at the expense of torque ripple.

I'd recommend looking at this which I came across a while back:

(in particular look for the section "Delta friendly")

polyglot:
I think the assumption of your first sentence is basically wrong. When doing a 3 phase drive, the PWM frequency will be much higher than the commutation frequency (in order to obtain good current control, especially with non-constant current per commutation) therefore there is no need for any phase difference in the PWM signals.

For a 50Hz motor, the commutation frequency is 50Hz but the PWM will be a few kHz.

If you're trying to generate three sine waves from PWM with a phase offset, that's totally reasonable. You just have three different indices into your sine table, offset by 1/3 of the table's length. You basically have it with OFFSET_1 etc but you didn't wrap the values so you're reading off the end of the sine table. Do something like this instead:

pwm1=sine256[icnt];

pwm2=sine256[(icnt+OFFSET_1)&0xFF];
pwm3=sine256[(icnt+OFFSET_2)&0xFF]




The PWM signals will all be mostly in phase but that doesn't matter; the sine waves will be out of phase. In fact if you zoom out on your waveform view, you might find that you are very close already.

thx but can you explain more what i can do in program

the 3 tables of sine wave

 int sinus0[]={0,10,20,31,41,51,61,71,81,91,101,110,119,128,137,146,154,163,
              170,178,185,192,199,205,211,217,222,227,231,236,239,243,246,248,250,252,
              253,254,254,254,254,253,252,250,248,246,243,239,236,231,227,222,217,211,
              205,199,192,185,178,170,163,154,146,137,128,119,110,101,91,81,71,61,
              51,41,31,20,10,0};
int sinus1[]={220,225,230,234,238,242,245,247,250,251,253,254,254,254,254,254,252,251,
              249,246,244,240,237,233,228,224,219,213,207,201,194,188,180,173,165,157,
              149,140,131,122,113,104,94,85,75,65,55,44,34,24,13,3,6,17,
              27,38,48,58,68,78,88,98,107,116,126,134,143,152,160,168,175,183,
              190,197,203,209,215,220};
 int sinus2[]={220,215,209,203,197,190,183,175,168,160,151,143,134,125,116,107,97,88,
               78,68,58,48,37,27,17,6,3,14,24,34,45,55,65,75,85,94,
               104,113,123,132,140,149,157,165,173,181,188,195,201,207,213,219,224,229,
               233,237,241,244,247,249,251,252,254,254,255,254,254,253,251,250,247,245,
               242,238,234,230,225,220};

MarkT: the 50Hz reference and use of sines makes me believe this is an AC machine, not a PM BLDC.

adelo14: you only need one sine table. You read from it at different offsets as per the code snippet I posted. Your code is mostly there, though you will want to increase your PWM frequency somewhat in order to get a clean sine.

he make me crazy , can anyone help to fix it ?

polyglot:
MarkT: the 50Hz reference and use of sines makes me believe this is an AC machine, not a PM BLDC.

They are different names for the same motor. Some are optimized for sinusoidal
drive and some for trapezoidal, but they will both work with either.

for my 3 signals it's oki but the problem is i can't varier the frequence .

i use this lowpass

can you help me to fix it

i found this doc can you explain me this to fix the output frequence in 2khz

dds_calc.xls (8 KB)

DDS can be used to synthesize a sine wave, but you need a PWM scheme, for which
a master clock is needed that's digital, not analog. DDS can still do this but jitter
may be a concern if the DDS isn't running fast enough (ie isn't hardware based).

Can you explain more what you are intending to do?

i want to generate 3 PWM 120 degrees out of phase with arduino mega2560 because i want to control six pluse igbt to control 3 phase motor ( 220v/380v // f=50hz // rpm = 1430 ) and display the frequence in LCD

No, with DDS and details of your waveform generation, I meant!

how I can do it ?

want to generate 3 PWM 120 degrees out of phase with arduino mega2560 because i want to control six pluse igbt to control 3 phase motor ( 220v/380v // f=50hz // rpm = 1430 ) and display the frequence in LCD

i use timer 1 and 2 :
timer 1 (controls pin 12, 11)
timer 2 (controls pin 10, 9)

can you help me to fix the code for my arduino mega 2560 because the problem is the frenquence output

#include "avr/pgmspace.h"
#include "avr/io.h"

// 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 sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
int PWM_OUT_1 =11; // PWM output on pin 11
int PWM_OUT_2 =10; // PWM output on pin 10
int PWM_OUT_3 =12; // PWM output on pin 9
int LED_PIN =13; // LED status on pin 13
int TEST_PIN =7; // Scope trigger on pin 7
int POTEN_IN =A0; // Potentiometer on pin 0
int OFFSET_1 =85; // Offset for second-phase
int OFFSET_2 =170; // Offset for third-phase
double dfreq;
const double refclk = 31376.6; // measured
const uint64_t twoTo32 = pow(2, 32); // compute value at startup and use as constant
// variables used inside interrupt service declared as voilatile
volatile uint8_t icnt; // var inside interrupt
volatile uint8_t icnt1; // var inside interrupt
volatile uint8_t c4ms; // counter incremented every 4ms
volatile uint32_t phase_accum; // pahse accumulator
volatile uint32_t tword_m; // dds tuning word m
//******************************************************************
void setup()
{
pinMode(LED_PIN, OUTPUT); // sets the digital pin as output
Serial.begin(115200); // connect to the serial port
Serial.println("DDS Test");

pinMode(TEST_PIN, OUTPUT); // sets the digital pin as output
pinMode(PWM_OUT_1, OUTPUT); // PWM output / frequency output
pinMode(PWM_OUT_2, OUTPUT); // PWM output / frequency output
pinMode(PWM_OUT_3, OUTPUT); // PWM output / frequency output
// Setup the timers
setup_timer1();
setup_timer2();
// disable interrupts to avoid timing distortion
cbi (TIMSK0, TOIE0); // disable Timer0 !!! delay() is now not available
sbi (TIMSK2, TOIE2); // enable Timer2 Interrupt
dfreq = 1000.0; // initial output frequency = 1000.0 Hz
tword_m = twoTo32 * dfreq / refclk; // calulate DDS new tuning word
}
//******************************************************************
void loop()
{
if (c4ms > 250) // timer / wait for a full second
{
c4ms = 0;
dfreq = analogRead(POTEN_IN); // read Poti on analog pin 0 to adjust output frequency from 0..1023 Hz
cbi (TIMSK2, TOIE2); // disble Timer2 Interrupt
tword_m = twoTo32 * dfreq / refclk; // calulate DDS new tuning word
sbi (TIMSK2, TOIE2); // enable Timer2 Interrupt
Serial.print(dfreq);
Serial.print(" ");
Serial.println(tword_m);
}
}
//******************************************************************
// timer1 setup
// set prscaler to 1, PWM mode to phase correct PWM, 16000000/512 = 31.25kHz clock
void setup_timer1(void)
{
// Timer1 Clock Prescaler to : 1
sbi (TCCR1B, CS10);
cbi (TCCR1B, CS11);
cbi (TCCR1B, CS12);
// Timer0 PWM Mode set to Phase Correct PWM
cbi (TCCR1A, COM1A0); // clear Compare Match
sbi (TCCR1A, COM1A1);
cbi (TCCR1A, COM1B0); // clear Compare Match
sbi (TCCR1A, COM1B1);
sbi (TCCR1A, WGM10); // Mode 1 / Phase Correct PWM
cbi (TCCR1A, WGM11);
cbi (TCCR1B, WGM12);
cbi (TCCR1B, WGM13);
}

//******************************************************************
// timer2 setup
// set prscaler to 1, PWM mode to phase correct PWM, 16000000/512 = 31.25kHz 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);
sbi (TCCR2A, WGM20); // Mode 1 / Phase Correct PWM
cbi (TCCR2A, WGM21);
cbi (TCCR2B, WGM22);
}
//******************************************************************
// Timer2 Interrupt Service at 31.25kHz = 32us
// this is the timebase REFCLOCK for the DDS generator
// FOUT = (M (REFCLK)) / (2 exp 32)
// runtime : 8 microseconds ( inclusive push and pop)
ISR(TIMER2_OVF_vect)
{
sbi(PORTD, TEST_PIN); // Test / set PORTD,TEST_PIN high to observe timing with a oscope
phase_accum += tword_m; // soft DDS, phase accu with 32 bits
icnt = phase_accum >> 24; // use upper 8 bits for phase accu as frequency information
OCR2A = pgm_read_byte_near(sine256 + icnt); // read value fron ROM sine table and send to PWM DAC
OCR1A = pgm_read_byte_near(sine256 + (uint8_t)(icnt + OFFSET_1));
OCR1B = pgm_read_byte_near(sine256 + (uint8_t)(icnt + OFFSET_2));
if (icnt1++ == 125) // increment variable c4ms every 4 milliseconds
{
c4ms++;
icnt1 = 0;
}
cbi(PORTD, TEST_PIN); // reset PORTD,TEST_PIN
}

Change your post title to 3-Phase AC motor controller

raschemmel:
Change your post title to 3-Phase AC motor controller

ok thanks

What is your power source?

this is my power source

What's the Peak to Peak voltage at the output ?

raschemmel:
What's the Peak to Peak voltage at the output ?

i don't know