; Grid Tie Inverter with PWM and H-bridge drive for iron core transformer (toroid) for use with 50 Hz mains
; Filename: pwm_gti.asm
; Contact: pic@polonai.se Polonaise PIC Projects
; v0.0 190802 New project: sine wave with VRCON, test with PWM and SENSE ports
; v0.1 190803 CMCON interrupt doesn't work. Lose VRCON and CMIE
; v0.2 190803 Impossible to generate PWM without glitches. 16F628A instead of 12F629. No 8-pin PWM capable MCU in my tray.
; v0.3 190804 Play first and last sequence from lookup table twice
; v0.4 190804 Fix PWM resolution (CCP1X & Y)
; v0.5 190805 Sync with mains frequency (50 Hz)
; v0.6 190805 Driveon for H-bridge supply voltage to prevent latchup at poweron and sanity check for mains frequency
; v0.7 190807 Tweaked PHASE at RB0 interrupt (6->9) because of added optocoupler filter. Fix for spurious firing and running without mains
; v0.8 190808 MAINSOK flag for valid mains frequency to test if mains power disconnected
; v0.9 190811 Changed lookup table for 99% duty cycle
; v1.0 190812 Release
LIST P=16F628A, F=INHX8M
#include <p16f628a.inc>
__CONFIG _INTRC_OSC_NOCLKOUT & _WDT_OFF & _LVP_OFF & _CP_OFF
; Equates
RESET_V EQU 0x00 ; Address of RESET Vector
OSC_FREQ EQU D'4000000' ; Internal RC Oscillator Frequency is 4.0 MHz
; Registers
FLAGS EQU 0x20
PHASE EQU 0x21 ; Sequence number of the (quarter) sine wave
TEMP EQU 0x23 ; Temporary variable used for setting PWM
; Ports
; RB0 has no name defined (SYNC)
; RB3 also has no name defined (PWM), drive for PWM MOSFET
#define HPOS PORTA,1 ; H-bridge positive period (low is on)
#define HNEG PORTA,0 ; H-bridge negative period (low is on)
#define DRIVEON PORTA,7 ; Switch on power to MOSFET gates at poweron
#define UPDN FLAGS,0 ; 1 is up, 0 is down for sine wave generator
#define NEWPHASE1 FLAGS,1 ; Needed to play the first sample of the sine wave twice
#define NEWPHASE2 FLAGS,2 ; Needed to play the last sample of the sine wave twice
#define POSPHASE FLAGS,3 ; Needed to re-enable RB0 interrupt again (H-bridge control, PWM is always active)
#define FREQVALID FLAGS,4 ; Make sure the H-bridge is off with no mains
#define MAINSOK FLAGS,5 ; Make double sure the H-bridge is off with no mains
ORG 0x00
GOTO START
ORG 0x04
; Interrupt handlers
; RB0 interrupt
BTFSC INTCON,INTF
GOTO SYNCSINE
; TMR0 interrupt
BTFSC INTCON,T0IF
GOTO PHASEHANDLER
JIC
RETFIE ; Just In Case
SYNCSINE ; Only used to sync internal sine wave generator
BCF INTCON,INTF ; Clear RB0 interrupt flag
BCF INTCON,INTE ; Disable RB0 interrupt
BTFSS MAINSOK ; Mains OK?
GOTO CONTSYNC ; No
MOVFW PHASE ; Test for...
SUBLW 0x04 ; (1/4)
BTFSC STATUS,C ; Phase <= 0x04?
GOTO MAINSFAIL ; Yes
MOVLW 0x08 ; (2/4)
SUBWF PHASE,W ; Test for...
BTFSC STATUS,C ; Phase >= 0x08?
GOTO MAINSFAIL ; Yes
BTFSS UPDN ; In first quadrant?
GOTO MAINSFAIL ; No
BTFSS POSPHASE ; Positive phase?
GOTO MAINSFAIL ; No
BSF FREQVALID ; We have a valid period so next period we can actually start delivering power to the grid
MOVLW 0x06 ; (3/4) Adjust for response delay optocoupler OC5 (might need tweaking!)
MOVWF PHASE
RETFIE
MAINSFAIL
BCF MAINSOK
BCF FREQVALID
BSF HPOS
BSF HNEG
RETFIE
CONTSYNC
MOVLW 0x06 ; (4/4) Adjust for response delay optocoupler OC5 (might need tweaking!)
MOVWF PHASE
BSF UPDN
BSF HPOS
BSF HNEG
BSF POSPHASE
BSF DRIVEON ; Power up drive voltage for H-bridge gates
BSF MAINSOK
RETFIE
PHASEHANDLER
BCF INTCON,T0IF ; Clear interrupt source
MOVLW 0x44 ; Restore 0.20 ms count timer0
MOVWF TMR0
BTFSS UPDN ; Going up?
GOTO Q2 ; No
BTFSS NEWPHASE1 ; Is this the first sample?
GOTO CONTPHASE1 ; No
BCF NEWPHASE1 ; Yes, clear the flag
BTFSS POSPHASE ; Did we just start a new positive phase?
GOTO CONTPHASE3 ; Yes
BCF POSPHASE ; No, start negative phase
BTFSC FREQVALID ; Mains OK?
BCF HNEG ; Yes
BSF HPOS ; No
GOTO CONTPHASE ; play seq 0 twice (PHASE is still zero)
CONTPHASE3
BSF POSPHASE ; We just started a new positive phase
BTFSC FREQVALID ; Mains OK?
BCF HPOS ; Yes
BSF HNEG ; Set H-bridge for positive phase
BCF FREQVALID ; This should be set again at the next RB0 interrupt
BSF INTCON,INTE ; Enable RB0 interrupt which should arrive in about 0.6 ms
GOTO CONTPHASE
CONTPHASE1
INCF PHASE,F ; Yes, still doing the first quarter of the sine wave (0-90°)
MOVLW 0x18
SUBWF PHASE,W ; Check if phase has ended (store back in W)
BTFSS STATUS,Z ; Zero bit set because PHASE is at 0x18?
GOTO CONTPHASE
BCF UPDN
BSF NEWPHASE2 ; play last sample twice
GOTO CONTPHASE
Q2 ; Handles the second quarter of the sine wave (90-180°)
BTFSS NEWPHASE2 ; Is this the last sample?
GOTO CONTPHASE2 ; No
BCF NEWPHASE2 ; Yes, clear the flag
GOTO CONTPHASE ; and get the last sample
CONTPHASE2
DECFSZ PHASE,F ; End of second quarter?
GOTO CONTPHASE ; No
BSF UPDN ; Yes, start first quarter again
BSF NEWPHASE1 ; and skip the first sample from the lookup table (H-bridge drive)
BSF HPOS
BSF HNEG ; Switch off H-bridge in any polarity
CONTPHASE
MOVFW PHASE
CALL PHASETABLE ; Get value of timer0
MOVWF TEMP ; Load PWM MSB
BCF CCP1CON,CCP1X ; Clear PWM bit 1:0
BCF CCP1CON,CCP1Y
RRF TEMP,F
BTFSC STATUS,C ; Carry set?
BSF CCP1CON,CCP1X ; Yes, set PWM bit 1
RRF TEMP,F
BTFSC STATUS,C ; Carry set?
BSF CCP1CON,CCP1Y ; Yes, set PWM bit 0
MOVLW 0x3F ; Clear two MSBs of PWM (from RRF)
ANDWF TEMP,W ; and store in W
MOVWF CCPR1L ; Load PWM bit 9:2
RETFIE
START
CLRF STATUS ; Do initialization, Select bank 0
CLRF INTCON ; Clear int-flags, Disable interrupts
CLRF PCLATH ; Keep in lower 2KByte
CLRF PORTA
CLRF PORTB
CLRF FLAGS
CLRF PHASE
BANKSEL TRISA
MOVLW B'00001000' ; Prescaler to WDT, 1 µs per count. 0.20 ms is 0x100-0xC8=0x38, weak pullups
MOVWF OPTION_REG
MOVLW B'00011000' ; Port RA0-2,5-7 outputs, RA3,4 inputs
MOVWF TRISA ;
MOVLW B'00000001' ; Port RB0 input, RB1-7 outputs
MOVWF TRISB ;
CLRF PIE1 ; Disable all peripheral interrupts
MOVLW 0x31 ; PWM period 50 us
MOVWF PR2
BANKSEL T1CON
CLRF T1CON
MOVLW B'00000100' ; Timer2 enabled, pre/postscaler 1:1
MOVWF T2CON
MOVLW B'00000111' ; Comparators off
MOVWF CMCON
MOVLW B'00001111' ; PWM mode, LSBs clear
MOVWF CCP1CON
BSF HPOS ; and H-bridge MOSFETS
BSF HNEG
BSF UPDN ; First quarter of sine wave
MOVLW 0x44 ; 0.20 ms
MOVWF TMR0
MOVLW B'10110000' ; Enable global interrupts, Timer0, RB0, falling edge (INTEDG clear)
MOVWF INTCON
MAIN
GOTO MAIN
PHASETABLE ; Lookup table for timer for sine phase (PWM duty cycle)
ADDWF PCL,1
RETLW 0xBD ; seq 0 0 ms (actually 0.10 ms)
RETLW 0xB1 ; seq 1 0.20 ms
RETLW 0xA5 ; seq 2 0.40 ms
RETLW 0x99 ; seq 3 0.60 ms
RETLW 0x8D ; seq 4 0.80 ms
RETLW 0x82 ; seq 5 1.0 ms
RETLW 0x76 ; seq 6 1.2 ms
RETLW 0x6B ; seq 7 1.4 ms
RETLW 0x61 ; seq 8 1.6 ms
RETLW 0x56 ; seq 9 1.8 ms
RETLW 0x4D ; seq 10 2.0 ms
RETLW 0x43 ; seq 11 2.2 ms
RETLW 0x3A ; seq 12 2.4 ms
RETLW 0x32 ; seq 13 2.6 ms
RETLW 0x2A ; seq 14 2.8 ms
RETLW 0x23 ; seq 15 3.0 ms
RETLW 0x1D ; seq 16 3.2 ms
RETLW 0x17 ; seq 17 3.4 ms
RETLW 0x11 ; seq 18 3.6 ms
RETLW 0x0D ; seq 19 3.8 ms
RETLW 0x09 ; seq 20 4.0 ms
RETLW 0x06 ; seq 21 4.2 ms
RETLW 0x04 ; seq 22 4.4 ms
RETLW 0x02 ; seq 23 4.6 ms
RETLW 0x02 ; seq 24 4.8 ms (Duty cycle 99%)
END