/******************************************************************************
  ZJ_SineInverter.c   xtal-locked push-pull sinewave Inverter driver
  Open-source  -  8th Dec 2009  -  www.RomanBlack.com/one_sec.htm
  (Original inspiration by Mike McLaren K8LH).

  PIC 12F675, xtal (see below).
  This manually generates dual inverted sinewave PWM outputs.
  PWM frequency varies from 25kHz to 47kHz depending on the step.
  It will drive push-pull FETs to make a mains inverter;
    10MHz xtal; 50Hz output (same code is used for both)
    12MHz xtal; 60Hz output  
  GP0 - this is push-pull outputA (hi = FET on)
  GP1 - this is push-pull outputB (hi = FET on)
  
_BODEN_OFF _MCLRE_OFF _PWRTE_ON _WDT_OFF _HSOSC
******************************************************************************/

// edit PERIOD to give the freq; PERIOD = (xtal / 4 / (freq*20))
// Note! we need 20 period events per mains cycle, so use (freq * 20)
#define PERIOD 2500   // 10Mhz xtal = 50Hz, 12MHz xtal = 60Hz. (don't edit)
#define PERHI (PERIOD / 256)          // don't edit this!
#define PERLO (PERIOD - (PERHI*256))  // don't edit this!

unsigned char step;     // sequences each of the 20 PWM steps

#define PHASEA 0b00000001;  // push-pull outputA on
#define PHASEB 0b00000010;  // push-pull outputB on

//=============================================================================
void interrupt()
{
  // TMR1 interrupt. This is a very simple zero-error TMR1 correction.
  // It generates an interrupt every 2500 PIC instructions.
  // (this code was hardware tested to exact cycle accuracy)
  TMR1L -= (PERLO - 2);   // fix TMR1, retain error for next period
  TMR1H -= (PERHI + 1);
  step++;
  PIR1.TMR1IF = 0;
}

//=============================================================================
void Delay10(void)
{
  // gives a total delay of 10 PIC instructions
  asm goto $+1;   // 2 insts each
  asm goto $+1;
  asm goto $+1;
}
//=============================================================================
void Delay20(void)
{
  // gives a total delay of 20 PIC instructions
  asm goto $+1;   // 2 insts each
  asm goto $+1;
  asm goto $+1;
  asm goto $+1;
  asm goto $+1;
  asm goto $+1;
  asm goto $+1;
  asm goto $+1;
}

//=============================================================================
void main ()
{
  //-----------------------------------------------------
  // PIC 12F675  setup ports
  ANSEL = 0;            // ADC off
  CMCON = 0x07;         // comparators off
  GPIO =   0b00000000;  // clear GPIO
  TRISIO = 0b00000000;  // All outputs
  //-----------------------------------------------------
  // timer setup etc
  OPTION_REG = 0b00001000;  // TMR0 on, 1:1 prescale
  T1CON  = 0b00000001;  // TMR1 on, 1:1 prescale
  INTCON = 0b11000000;  // GIE on, PEIE on 
  PIE1 =   0b00000001;  // TMR1 int ON
  //-----------------------------------------------------
  // 20 sine PWM values provided by Mike McLaren K8LH;
  // (I have tweaked these slightly in code below)
  // sine[] = { 49,64,78,89,96,99,96,89,78,64,
  //             49,34,20,9,2,0,2,9,20,34 };
  //-----------------------------------------------------
  // main run loop here
  while(1)
  {
    //---------------------------------
    // 50% PWM
    sinestep0:
      step = 0;
    sinestep0b:
      GPIO = PHASEA;
      if(step == 1) goto sinestep1;
      Delay20();
      GPIO = PHASEB;
      Delay20();
      asm goto $+1;
      asm goto $+1;
      goto sinestep0b;

    //---------------------------------
    // 64% PWM
    sinestep1:
      GPIO = PHASEA;
      if(step == 2) goto sinestep2;
      Delay20();
      asm goto $+1;
      asm goto $+1;
      asm goto $+1;
      asm goto $+1;
      asm goto $+1;
      asm goto $+1;
      asm nop;
      GPIO = PHASEB;
      Delay20();
      goto sinestep1;

    //---------------------------------
    // 78% PWM
    sinestep2:
      GPIO = PHASEA;
      if(step == 3) goto sinestep3;
      Delay20();
      Delay10();
      asm goto $+1;
      asm goto $+1;
      asm nop;
      GPIO = PHASEB;
      Delay10();
      goto sinestep2;

    //---------------------------------
    // 89% PWM
    sinestep3:
      GPIO = PHASEA;
      if(step == 4) goto sinestep4;
      Delay20();
      Delay20();
      asm goto $+1;
      asm goto $+1;
      GPIO = PHASEB;
      asm goto $+1;
      asm goto $+1;
      goto sinestep3;

    //---------------------------------
    // 96% PWM
    sinestep4:
      GPIO = PHASEA;
      if(step == 5) goto sinestep5;
      Delay20();
      Delay20();
      Delay20();
      Delay20();
      asm goto $+1;
      asm goto $+1;
      GPIO = PHASEB;
      asm goto $+1;
      goto sinestep4;

    //---------------------------------
    // 100% PWM
    sinestep5:
      GPIO = PHASEA;
      if(step == 6) goto sinestep6;
      goto sinestep5;

    //---------------------------------
    // 96% PWM
    sinestep6:
      GPIO = PHASEA;
      if(step == 7) goto sinestep7;
      Delay20();
      Delay20();
      Delay20();
      Delay20();
      asm goto $+1;
      asm goto $+1;
      GPIO = PHASEB;
      asm goto $+1;
      goto sinestep6;

    //---------------------------------
    // 89% PWM
    sinestep7:
      GPIO = PHASEA;
      if(step == 8) goto sinestep8;
      Delay20();
      Delay20();
      asm goto $+1;
      asm goto $+1;
      GPIO = PHASEB;
      asm goto $+1;
      asm goto $+1;
      goto sinestep7;

    //---------------------------------
    // 78% PWM
    sinestep8:
      GPIO = PHASEA;
      if(step == 9) goto sinestep9;
      Delay20();
      Delay10();
      asm goto $+1;
      asm goto $+1;
      asm nop;
      GPIO = PHASEB;
      Delay10();
      goto sinestep8;

    //---------------------------------
    // 64% PWM
    sinestep9:
      GPIO = PHASEA;
      if(step == 10) goto sinestep10;
      Delay20();
      asm goto $+1;
      asm goto $+1;
      asm goto $+1;
      asm goto $+1;
      asm goto $+1;
      asm goto $+1;
      asm nop;
      GPIO = PHASEB;
      Delay20();
      goto sinestep9;

    //---------------------------------
    // 50% PWM
    sinestep10:
      GPIO = PHASEA;
      if(step == 11) goto sinestep11;
      Delay20();
      GPIO = PHASEB;
      Delay20();
      asm goto $+1;
      asm goto $+1;
      goto sinestep10;

    //---------------------------------
    // 64% PWM inv
    sinestep11:
      GPIO = PHASEB;
      if(step == 12) goto sinestep12;
      Delay20();
      asm goto $+1;
      asm goto $+1;
      asm goto $+1;
      asm goto $+1;
      asm goto $+1;
      asm goto $+1;
      asm nop;
      GPIO = PHASEA;
      Delay20();
      goto sinestep11;

    //---------------------------------
    // 78% PWM inv
    sinestep12:
      GPIO = PHASEB;
      if(step == 13) goto sinestep13;
      Delay20();
      Delay10();
      asm goto $+1;
      asm goto $+1;
      asm nop;
      GPIO = PHASEA;
      Delay10();
      goto sinestep12;

    //---------------------------------
    // 89% PWM inv
    sinestep13:
      GPIO = PHASEB;
      if(step == 14) goto sinestep14;
      Delay20();
      Delay20();
      asm goto $+1;
      asm goto $+1;
      GPIO = PHASEA;
      asm goto $+1;
      asm goto $+1;
      goto sinestep13;

    //---------------------------------
    // 96% PWM inv
    sinestep14:
      GPIO = PHASEB;
      if(step == 15) goto sinestep15;
      Delay20();
      Delay20();
      Delay20();
      Delay20();
      asm goto $+1;
      asm goto $+1;
      GPIO = PHASEA;
      asm goto $+1;
      goto sinestep14;

    //---------------------------------
    // 100% PWM inv
    sinestep15:
      GPIO = PHASEB;
      if(step == 16) goto sinestep16;
      goto sinestep15;

    //---------------------------------
    // 96% PWM inv
    sinestep16:
      GPIO = PHASEB;
      if(step == 17) goto sinestep17;
      Delay20();
      Delay20();
      Delay20();
      Delay20();
      asm goto $+1;
      asm goto $+1;
      GPIO = PHASEA;
      asm goto $+1;
      goto sinestep16;

    //---------------------------------
    // 89% PWM inv
    sinestep17:
      GPIO = PHASEB;
      if(step == 18) goto sinestep18;
      Delay20();
      Delay20();
      asm goto $+1;
      asm goto $+1;
      GPIO = PHASEA;
      asm goto $+1;
      asm goto $+1;
      goto sinestep17;

    //---------------------------------
    // 78% PWM inv
    sinestep18:
      GPIO = PHASEB;
      if(step == 19) goto sinestep19;
      Delay20();
      Delay10();
      asm goto $+1;
      asm goto $+1;
      asm nop;
      GPIO = PHASEA;
      Delay10();
      goto sinestep18;

    //---------------------------------
    // 64% PWM inv
    sinestep19:
      GPIO = PHASEB;
      if(step == 20) goto sinestep0;
      Delay20();
      asm goto $+1;
      asm goto $+1;
      asm goto $+1;
      asm goto $+1;
      asm goto $+1;
      asm goto $+1;
      asm nop;
      GPIO = PHASEA;
      Delay20();
      goto sinestep19;
  }
}
//-----------------------------------------------------------------------------