PWM for 3-phase Inverter

Apologies in advance if this is answered elsewhere or posted in the wrong forum.
I would like to drive a 3-phase Inverter with a PWM in a variable duty cycle or fixed duty cycle also. I am using this Inverter for STATCOM (Static Synchronous Compensator) in my project.

I need the PWM output at a frequency of around 1.5 kHz.I would like to be able to change the duty cycle of the PWM across the entire range, from 0% to 100%.

I am using Arduino MEGA 256 for generating PWM. I am new in Programming field and using it.

If you could possibly help me with the code in Arduino MEGA 256, it will be a great help for me.

If I was unclear about something, please let me know and I will clarify.

Thanks..!!

Standard Arduino has a PWM fequency of ~500Hz. If you want another PWM frequency you will need to look at assembly language.

You would be doing yourself a favor if you took some time to learn more about Arduino by spending some time with the sample programs before going into a more involved project.

@kf2q : Thank you for your kind reply...

I know i should take some time to learn more about Arduino by spending some more time but my project is somewhat tougher so did not have much time to get through the programming part. I have only 1 month left for the project so i was asking for help. I have also tried to write a code for PWM myself but i am getting error.

Thank you again :slight_smile:

Hi,

You should be able to set up PWM at whatever frequency you like quite easily using the ATmega's 8-bit TIMER2. The code I'm posting has been used to generate a 38KHz carrier for IR remote control but I have adapted it for use generating much lower frequencies, e.g. your 1.5KHz. This code has been used on the ATmega328P (Arduino Duemilanove) but shouldn't require any modification - it should just work but I can't guarantee anything. I've had a quick look at the ATmega1280 datasheet and everything seems to be the same with regard to this, so hopefully it will work fine on your board - http://www.atmel.com/devices/ATMEGA1280.aspx?tab=documents

The key with using custom PWM frequencies is to work out the correct value for the TOP limit register and the prescaler. Basically, the clock frequency (16MHz) is divided by (TOP limit * prescaler) to give the frequency of the timer. So if you want a frequency of 1500 Hz you'll need

(limit * prescaler) = (16000000 / 1500)

Since the limit has a maximum value of 255 for TIMER2, you'll need a prescaler value that gives you a value for limit less than 256 and ideally as large as possible within that range to allow maximum precision of control. The possible values for the prescaler are given in the datasheet I linked to and the most appropriate for your case appears to be 64. If you use phase correct PWM, which you may need for your application, then the frequency is divided by 2 again (since fast PWM counts up only and phase correct PWM counts both up and down) - there's a good explanation of all this here: http://www.arcfn.com/2009/07/secrets-of-arduino-pwm.html

Any, top stop with the rambling, I think you should be using some code very much like the following:

int pwm_pin = 3;

void setup_pwm()
{
  // Set the pin mode to output and make it low when we're not sending PWM
  pinMode( pwm_pin, OUTPUT );
  digitalWrite( pwm_pin, LOW );

  // Disable all timer 2 interrupts
  TIMSK2 &= ~((1<<OCIE2A) | (1<<OCIE2B) | (1<<TOIE2));
  // Set prescale to 32
  TCCR2B &= ~(1<<CS22);
  TCCR2B |= ((1<<CS20) | (1<<CS21));
  // Set frequency
  OCR2A = 166; // = 16000000 / 1500 / 32 / 2
  // Set duty-cycle to zero initially
  OCR2B = 0;
  // Enable phase correct PWM, TOP at OCR2A (OCR2A determines frequency)
  TCCR2A &= ~(1<<WGM21);
  TCCR2A |= (1<<WGM20);
  TCCR2B |= (1<<WGM22);
  // Disable OC2A output (pin 11)
  TCCR2A &= ~((1<<COM2A0) | (1<<COM2A1));
  // Enable OC2B output (pin 3)
  TCCR2A &= ~(1<<COM2B0);
  TCCR2A |= (1<<COM2B1);
}

After you've done this, writing a value between 0 and 166 to OCR2B should give you between 0% and 100% duty-cycle respectively.

No one has addressed that he requires 3 phase PWM output. That is three separate PWM outputs all using the same duty cycle value but required to be phase shifted precisely by a specific amount of degrees. This in not an easy task and may not even be possible just using arduino software functions without external hardware assistance?

Lefty

1 Like

Hmm, I completely missed the point that the OP was trying to do this for a 3-phase inverter.

I've been digging about myself with regard to solving that problem and I think there's an old post on the forums that addresses it: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1270367757/all. There's a pretty good discussion on there of doing it and a suggestion that I'm going to chase up on tomorrow to have a timer running at 3x the required frequency, catch the interrupt generated by the timer and use that ISR to set the output pins to the desired values for that phase. (This is all in a post by gbulmer about 1/3 of the way down)

1 Like

hi ,
if anyone can help me. my experimet is about inverter 3 phase. i use arduino for generate 3-phase and i connect it with driver IR21362. i can't figure out how to generate pwm 3 phase from my arduino uno.
thanks for ur attention and any help.

kf2qd:
Standard Arduino has a PWM fequency of ~500Hz. If you want another PWM frequency you will need to look at assembly language.

What??? Assembler to program a timer? No need, all the registers are available
to C code.

baso_syahrul:
hi ,
if anyone can help me. my experimet is about inverter 3 phase. i use arduino for generate 3-phase and i connect it with driver IR21362. i can't figure out how to generate pwm 3 phase from my arduino uno.
thanks for ur attention and any help.

3-phase what? sinusoidal or trapezoidal? Frequency range? Does the amplitude
need controlling?

Can you generate a single phase already? If so your code would be handy to see as
a guide to extending it.

sinusoidal. controllable with frequency with range 0-1khz. i've never tried to generate 1 phase.

To generate 1kHz sine wave you probably want to run your PWM at something like
50kHz.

If you are driving an inverter the output signals are not independent though, and for
sinusoidal is the most complex case. I think with a little care you can use the current
angle within the current 60-degree sector to determine the ratio of time spent in
two active drive states (and the zero drive state).

Think of the 8 inverter drive states as two zero-drives (all phases the same), and
six drive patterns arranged around a hexagon in phasor-space.

The problem this gives is that each PWM period needs to split into 3 parts,
2 different drive patterns and a zero-drive part. This requires at least two PWM
pins if you use the hardware, and you then need to read these pins and convert
the the right pattern (pin-change interrupts can handle that).

50kHz is ambitious, thinking about it, on a 328 based board at least.

There is another approach, hysteresis drive, where you examine the error
on a regular clock tick and change the output pattern based on the error - this
is simpler but needs to run even faster for good smooth sinusoid response.

This can work with actual current feedback from the inverter as well as with
a model of the average

I've been thinking about this some more and looking at what the Arduino
timers can do.

I've realised the Mega has some timers with 3 output pins, and this allows a
clever way to modulate 3 output signals for doing this.

It relies on having an inverter module that takes one input per phase (in
other words it generates its own high/low gate signals with appropriate
dead-time automatically generated - without this you'd need some
circuitry to do this).

Using phase-correct mode you can effectively get two control pulses per
cycle (where the pulses are differential between separate phase outputs).

So here's some test code - it drives pins 6/7/8 which are the pins for timer4.

// For the MEGA!

#define HALF 400
#define PERIOD 800

void setup ()
{
  setup_cosines () ;
  TCCR4A = 0xFE ;  // phase correct (mode 1010)
  TCCR4B = 0x11 ;  // prescale by 1
  TIMSK4 = 0x01 ;  // overflow interrupt
  ICR4  = PERIOD+1 ;    // 100us cycle time, so effectively 50us.
  OCR4A = HALF ;
  OCR4B = HALF ;
  OCR4C = HALF ;
  pinMode (6, OUTPUT) ;  // the OCR4A pin, our U phase
  pinMode (7, OUTPUT) ;  // the OCR4B pin, our V phase
  pinMode (8, OUTPUT) ;  // the OCR4C pin, our W phase
}

// control time values, in units of 62.5ns
volatile int u = HALF ;
volatile int v = HALF ;
volatile int w = HALF ;


// every complete cycle we update the registers.
ISR (TIMER4_OVF_vect)
{
  OCR4A = u ;
  OCR4B = v ;
  OCR4C = w ;
}

// a cosine table, 1024 entries in range +/-127
char cosine [0x400] ;

void setup_cosines ()
{
  for (int i = 0 ; i < 0x400 ; i++)
  {
    float a = PI * i / 0x200 ;
    cosine [i] = round (127.0 * cos (a)) ;
  }
}

int phase = 0 ; // taken modulo 1024
int amplitude = 200 ;  // 201 is maximum value without overflow.

void loop ()
{
  phase ++ ;  // phase increment, normally this would be done by DDS loop
  int newu = (cosine [phase & 0x3FF] * amplitude + 0x1F) >> 6 ;
  int newv = (cosine [(phase + 0x155) & 0x3FF] * amplitude + 0x1F) >> 6 ;
  int neww = - newu - newv ;
  newu += HALF ;
  newv += HALF ;
  neww += HALF ;
  noInterrupts () ;  // interrupt-safe updating of u,v,w
  u = newu ;
  v = newv ;
  w = neww ;
  interrupts () ;
  delay (2) ;
}

[ edited to fix mistake in the ISR ]

can you recommend me a code agree with my problem?

baso_syahrul:
can you recommend me a code agree with my problem?

Well you mentioned the IR21362 which looks like you can strap the HIN and LIN inputs
together per-phase as it has dead-time generation and shoot-through prevention. Then
the technique in my code above would be suitable. You might need to add stronger pull-down
resistors to park the bridge in all-low-side on configuration, needed to charge the bootstrap caps.

[ This link might be useful: Redirect Notice ]

i'm sorry about my PM i've never read your signature. i will try it and thanks. i'll be post the result(works or not).

thx mark i simulate the program ( 2 pics ) but it varying automatique

( work in this topic plz : 3 PWM for 3 phase inventer - Motors, Mechanics, Power and CNC - Arduino Forum )

Have you understood anything about DDS that I mentioned in the other thread?

Does this code not immediately say "DDS sinewave generation":

  phase ++ ;  // phase increment, normally this would be done by DDS loop
  int newu = (cosine [phase & 0x3FF] * amplitude + 0x1F) >> 6 ;
  int newv = (cosine [(phase + 0x155) & 0x3FF] * amplitude + 0x1F) >> 6 ;

Can you not see how to adapt this for different requirements?

MarkT:
Have you understood anything about DDS that I mentioned in the other thread?

Does this code not immediately say "DDS sinewave generation":

  phase ++ ;  // phase increment, normally this would be done by DDS loop

int newu = (cosine [phase & 0x3FF] * amplitude + 0x1F) >> 6 ;
  int newv = (cosine [(phase + 0x155) & 0x3FF] * amplitude + 0x1F) >> 6 ;




Can you not see how to adapt this for different requirements?

thx mark i understand the dds
but here the code it varing varing automatique . can you explain me ?

Well clearly you don't. I'm incrementing a phase variable and recomputing some
cosines. That's DDS and that's why its changing. Its test code to show it working.

MarkT:
Well clearly you don't. I'm incrementing a phase variable and recomputing some
cosines. That's DDS and that's why its changing. Its test code to show it working.

oki mark really thx know i undertand .