PWM for 3-phase Inverter

MarkT:
That means the load is intrinsically balanced and there is a lot of inductance
(meaning a lower PWM frequency is feasible).

BTW I've worked out how to synchronize timer1 and timer2 on the Uno, another
sample sketch provided:

// For the UNO et al.

#define PERIOD 250   // 250 cycles = 15.625us for each half of waveform, 32kHz
#define HALF 125     // half the period is the default PWM threshold - gives square wave.
#define MAXAMP 31
 
void setup_timers ()
{
 TCCR1A = 0xF2 ;  // phase correct (mode 1010, ICR1 controls period)
 TCCR1B = 0x11 ;  // prescale by 1, change to 0x12 for prescale by 8
 TIMSK1 = 0x01 ;  // overflow interrupt
 TCCR2A = 0x31 ;  // phase correct (mode 101, OCR2A controls period)
 TCCR2B = 0x09 ; // prescale by 1, change to 0x0A for prescale by 8
 
 ICR1  = PERIOD ;    // 31.25us cycle time, 32kHz PWM but 64kHz drive pulses (differential)
 OCR2A = PERIOD ;
 
 OCR1A = HALF-100 ;    // example U drive
 OCR1B = HALF ;
 OCR2B = HALF+100 ;    // example W drive
 
 GTCCR = 0x83 ; // clear and halt prescalers
 TCNT1 = 0xFFFF ;  // synchronize counters exactly.
 TCNT2 = 0 ;
 GTCCR = 0x00 ; // allow prescalers to fly
}

void setup ()
{
 setup_cosines () ;
 setup_timers () ;

pinMode (9, OUTPUT) ; // OC1A pin = U drive
 pinMode (10, OUTPUT) ; // OC1B pin = V drive
 pinMode (3, OUTPUT) ; // OC2B pin = W drive
}

volatile byte u = HALF ;
volatile byte v = HALF ;
volatile byte w = HALF ;

ISR (TIMER1_OVF_vect)   // overflow triggers at BOTTOM, update all the compare regs, which are sampled at TOP
{
 OCR1A = u ;
 OCR1B = v ;
 OCR2B = w ;
}

#define  DEG_360  0x200
#define  DEG_120  0x0AB

char cosine_tab [DEG_360+1] ;  // fails to work if less than 0x202.

void setup_cosines ()
{
 for (int i = 0 ; i < 0x202 ; i++)
 {
   float a = i * 6.283185 / 0x200 ;
   if (i <= DEG_360)
     cosine_tab [i] = round (127.0 * cos (a)) ;
 }
}

unsigned int phase = 0 ;
int freq  = 1 ;
int amplitude = MAXAMP ;

int my_cosine (int ph)
{
 ph &= DEG_360-1 ;
 int res = cosine_tab [ph] ;
 res *= amplitude ;
 return (res + 0x0F) >> 5 ;
}

void loop ()
{
 phase += freq ;
 int newu = my_cosine (phase) ;
 int newv = my_cosine (phase - DEG_120) ;
 int neww = - newu - newv ;
 newu += HALF ;
 newv += HALF ;
 neww += HALF ;
 u = newu ;  // no masking of interrupts needed as u,v,w variables are single byte each.
 v = newv ;
 w = neww ;
 delayMicroseconds (1000) ;
}

HI MarkT,

I have been going over this code very carefully:
You very carefully synchronize the timers so the PWM are all in sync.
You use interrupts to update the PWM registers at appropriate times.
You carefully use volatile byte for u, v and w.

Now the dumb question:
Why are updating your phase word in the loop() part of the code? Shouldn't the variable "phase" be carefully clocked so that the frequency is as accurate as your crystal? As far as I understand loop() runs asynchronously and may take longer or shorter depending on if an interrupt occurs. (You just set up Timer 2 to control the updating of the PWM registers...) Isn't your frequency going to fluctuate because the period of updating phase varies. I believe delayMicroseconds() waits for exactly 1000us and doesn't consider the overhead of the code in loop() as well as the interrupts that may occur.

Second dumb question:
Hypothetically, what if an ISR interrupt occurs between setting u but before v and w are set. The three phase will have a new value for u but old values for v and w. What prevents that from happening?