; 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 ; which phase (sequence) of the sine wave, defines VRCON value 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