Dear forum Members!
I'm in the middle of developing an AC/AC inverter project where 1phase 230VAC will be converted to ~1kVA 3phase 400Hz 115VAC to power some ex-military instrumentation for display purposes. The HW part of the project is almost done/tested, but i'm having some timing/instability trouble with my code running on a mega328p to modulate the 3phase 400Hz sine wave.
The base approach is not a rocket science and looks like the following:
- a 60element sine table was created for each U V W phases and timer OCRxx values (0-255)
- 16bit Timer1 is used in CTC+COMPA interrupt mode to provide timing of the update of the sine PWM registers with a ate of 41.625usec
- 8bit Timer0 and Timer2 are configured to fast PWM mode to output the modulated sine wave on the OC0A, OC0B, OC2A outputs for phases U V W
At first compile everything worked fine. During later on debugging found out that the interrupt for updating the sine-PWM modulation is fluctuating quite a bit and not coming at the desired 41.625usecs resulting in a distorted sine wave.
First of all i was expecting that i'm running out of CPU resources, but later on found that this is not the issue. Realized that if Timer0 and Timer1 are running simultaneously clocked from the Pck Timer1 COMPA interrupt will become instable. If for example Timer1 and Timer2 were running and Timer0 clock was stopped Timer1 COMPA interrupt was a quite stable 41.625usecs. Two scope pics are attached of the proper and improper behaviour of the Timer1 COMPA interrupt.
I know that Timer0/Timer1 shares the same prescaler but don't really understand why i have this strange behaviour when running Timer0 and Timer1 at the same time. Tried to make a timer prescaler reset/syncronization in the GTCCR register but did not help. I'm a bit out of ideas and don't understand the reason why running Timer0/1 at the same time affects the behaviour of my Timer1 COMPA interrupt.
An extract of the PWM modulation/update part of the whole code is attached here:
#include <avr/io.h>
#include <avr/interrupt.h>
int counter = 0;
const int sinet_u[60] = {127,140,153,166,179,191,202,212,221,230,237,243,248,251,253,254,253,251,248,243,237,230,221,212,202,191,179,166,153,140,127,114,101,88,75,64,52,42,33,24,17,11,6,3,1,0,1,3,6,11,17,24,33,42,52,63,75,88,101,114};
const int sinet_v[60] = {17,11,6,3,1,0,1,3,6,11,17,24,33,42,52,64,75,88,101,114,127,140,153,166,179,191,202,212,221,230,237,243,248,251,253,254,253,251,248,243,237,230,221,212,202,191,179,166,153,140,127,114,101,88,75,64,52,42,33,24};
const int sinet_w[60] = {237,230,221,212,202,191,179,166,153,140,127,114,101,88,75,64,52,42,33,24,17,11,6,3,1,0,1,3,6,11,17,24,33,42,52,64,75,88,101,114,127,140,153,166,179,191,202,212,221,230,237,243,248,251,253,254,253,251,248,243};
void setup()
{
cli();
DDRB = 0b00111000; //PB5 pin19 output - Arduino pin13, PB4 pin18 - Arduino pin12, PB3 pin17 output - Arduino pin11
DDRC = 0b00000000; //All set to input for ADC/digital input
DDRD = 0b01100000; //PD6 pin12 output - Arduino pin6, PD5 pin11 output - Arduino pin 5
//Timer1 16bit config to CTC mode for 41,625usec/compare match interrupt
TCCR1A = 0b00000000; //
TCCR1B = 0b00001001; //set CTC mode, Tck=Pck=16M
TCCR1C = 0b00000000; //
OCR1A = 665; //(1/16M)*(665+1)=41.625usec Timer1 COMPA interrupt
TIMSK1 = 0b00000010; //Enable Timer1 COMPA interrupt
//Timer0 8bit config to fast PWM mode
TCCR0A = 0b10100011; //fast PWM mode, OC0A OC0B non-inverting mode
TCCR0B = 0b00000001; //Tck=Pck=16M, fpwm=16M/256=62,5kHz
//Timer2 8bit config to fast PWM mode
TCCR2A = 0b10000011; //fast PWM mode, OC2A non-inverting mode
TCCR2B = 0b00000001; //Tck=Pck=16M, fpwm=16M/256=62,5kHz
/*
Test comments:
T1 = stable interrupt source
T1 + T2 = stable interrupt source
T1 + T0 = instable interrupt source!!
T1 + T0 + T2 = instable interrupt source!!
T0clk: 16M/256 = 62,5kHz
T1clk:
*/
sei();
}
void loop(){}
ISR(TIMER1_COMPA_vect)
{
PORTB |= (1<<PINB5); //set pin high to measure interrupt routine length
OCR0A = sinet_u[counter];
OCR0B = sinet_v[counter];
OCR2A = sinet_w[counter];
if( counter++ >= 59 ){counter = 0;PORTB ^= (1<<PINB4);/*toggle pin on full 400Hz period*/}
PORTB &= ~(1 << PIN5); //set pin low to measure interrupt routine length
}