/*******************************************************************************
* � 2011 Microchip Technology Inc.
*
* SOFTWARE LICENSE AGREEMENT:
* Microchip Technology Incorporated ("Microchip") retains all ownership and
* intellectual property rights in the code accompanying this message and in all
* derivatives hereto. You may use this code, and any derivatives created by
* any person or entity by or on your behalf, exclusively with Microchip's
* proprietary products. Your acceptance and/or use of this code constitutes
* agreement to the terms and conditions of this notice.
*
* CODE ACCOMPANYING THIS MESSAGE IS SUPPLIED BY MICROCHIP "AS IS". NO
* WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
* TO, IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE APPLY TO THIS CODE, ITS INTERACTION WITH MICROCHIP'S
* PRODUCTS, COMBINATION WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION.
*
* YOU ACKNOWLEDGE AND AGREE THAT, IN NO EVENT, SHALL MICROCHIP BE LIABLE,
* WHETHER IN CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE OR BREACH OF
* STATUTORY DUTY), STRICT LIABILITY, INDEMNITY, CONTRIBUTION, OR OTHERWISE, FOR
* ANY INDIRECT, SPECIAL, PUNITIVE, EXEMPLARY, INCIDENTAL OR CONSEQUENTIAL LOSS,
* DAMAGE, FOR COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE CODE,
* HOWSOEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE
* DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT ALLOWABLE BY LAW, MICROCHIP'S
* TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS CODE, SHALL NOT
* EXCEED THE PRICE YOU PAID DIRECTLY TO MICROCHIP SPECIFICALLY TO HAVE THIS
* CODE DEVELOPED.
*
* You agree that you are solely responsible for testing the code and
* determining its suitability. Microchip has no obligation to modify, test,
* certify, or support the code.
*
*
*******************************************************************************/
#include <p33FJ16GS504.h>
#include "PVInverter_defines.h" // Include #defines
#include "PVInverter_Variable.h" // Include Variables
#include "SineTable512.h"
void __attribute__((interrupt, no_auto_psv)) _ADCP0Interrupt()
{
// Measure FlyBack Current and PV Voltage in Q15 format
pvCellCurrent2 = (ADCBUF0 << 5); // Read PV cell Current at Flyback leg1
pvCellVoltage = (ADCBUF1 << 5); // Read PV cell Voltage
pvCellCurrent1 = (ADCBUF2 << 5); // Read PV cell Current at Flyback leg2
// Read inverter output voltage, output current, and grid voltage
// Need to subtract off the DC Offset (1.65V), 522*32(Q15) ~ 16383 to read just AC quantity
pvInverterOutputVoltage = (ADCBUF3 << 5) - 16334; // Read Single Phase Inverter output voltage
if(systemState == SYSTEM_STARTUP)
{
ACCurrentOffset = (ADCBUF4 << 5); // Measure actual offset before system is operating
}
pvInverterOutputCurrent = (ADCBUF4 << 5) - ACCurrentOffset; // Change offset to match present hardware offset
gridVoltage = (ADCBUF5 << 5) - 16250; // Read Single Phase grid voltage
// Check for Over Current Condition (Input)
if((pvCellCurrent1 > PVCELL_MAX_CURRENT)||(pvCellCurrent2 > PVCELL_MAX_CURRENT))
{
PTCONbits.PTEN = 0; // Disable PWM
IEC0bits.T2IE = 0; // Disable Timer2 interrupt
IEC6bits.ADCP0IE = 0; // Disable the ADC Pair0 Interrupt
systemStartFlag = 2;
systemState = SYSTEM_ERROR;
errorState = FLYBACK_OVERCURRENT;
}
// Check for Over Current condition on the ouput
if(pvInverterOutputCurrent >= 0)
{
rectifiedIacQ15 = pvInverterOutputCurrent;
}
else
{
rectifiedIacQ15 = (-pvInverterOutputCurrent);
}
if(rectifiedIacQ15 > INVERTER_OUTPUTCURRENT_MAX)
{
PTCONbits.PTEN = 0; // Disable PWM
IEC0bits.T2IE = 0; // Disable Timer2 interrupt
IEC6bits.ADCP0IE = 0; // Disable ADC Pair0 Interrupt
systemStartFlag = 2;
systemState = SYSTEM_ERROR;
errorState = GRID_OVERCURRENT;
}
// To eliminate glitches at the ZC detection only look for a zero cross
// when gridPeriodCounter is greater then 300
if((gridZeroCross == 0) && (gridPeriodCounter > 300))
{
// Detect the zero crossing at the 1st Quadrant
if ((prevGridVoltage < 0) && (gridVoltage >= 0))
{
if ((gridVoltage - prevGridVoltage) > 30)
{
gridZeroCross = 1;
firstQuadrantDetectedFlag = 1;
firstQuadrantFlag = 1;
// Load counter to Grid Period to check grid frequency
gridPeriod = gridPeriodCounter;
gridPeriodCounter = 0;
// Store accumulated voltage/current sum and counter for avg (avg calculated in T2ISR)
// The average is calculated every 3rd +ve zero cross event
zeroCrossCount++;
if (zeroCrossCount == 1)
{
numberofSamples = 0;
}
// gridPeriod is only half cycle so add prevGridPeriod
numberofSamples = numberofSamples + gridPeriod + prevGridPeriod;
if(zeroCrossCount >= 3)
{
zeroCrossCount = 0;
finalInputVoltageSum = inputVoltageSum;
finalInputCurrentSum = inputCurrentSum;
avgInputDataReadyFlag = 1;
inputVoltageSum = 0;
inputCurrentSum = 0;
}
}
}
// Detect the zero crossing at the 3rd Quadrant
else if ((prevGridVoltage >= 0) && (gridVoltage < 0))
{
if ((gridVoltage - prevGridVoltage) < -30)
{
// We must start with Zero Crossing at 1st Quadrant
if (firstQuadrantDetectedFlag == 1)
{
gridZeroCross = 1;
firstQuadrantFlag = 0;
// Load counter to Grid Period to check grid frequency
gridPeriod = gridPeriodCounter;
gridPeriodCounter = 0;
}
}
}
}
// Counter for verifying the Grid Frequency (number of ADC interrupts per grid half cycle)
// variable gets reset when finding the zero crossing event
if(firstQuadrantDetectedFlag == 1)
{
gridPeriodCounter++;
// At the start of the first detected zero crossing event start accumulating samples
// for the Average Calculation
inputCurrentSum = inputCurrentSum + pvCellCurrent1 + pvCellCurrent2;
inputVoltageSum = inputVoltageSum + pvCellVoltage;
}
// Store current grid voltage to compare with next sample for ZCD
prevGridVoltage = gridVoltage;
if(gridZeroCross == 1)
{
gridZeroCross = 0;
if(systemStartFlag == 1)
{
ZCDcount ++;
}
// After 100 consecutive zero crossings, remove the PWM Override
if((ZCDcount > 100) && (systemStartFlag == 1) && (firstQuadrantFlag == 1))
{
FLYBACKDUTY1 = 0;
FLYBACKDUTY2 = 0;
IOCON1bits.OVRENH = 0; // Remove Override to start PWM output
IOCON1bits.OVRENL = 0;
IOCON2bits.OVRENH = 0;
IOCON2bits.OVRENL = 0;
// Workaround for Errata #32
IOCON1bits.PENH = 1; // PWM controls the PWM1H pin
IOCON1bits.PENL = 1; // PWM controls the PWM1L pin
IOCON2bits.PENH = 1; // PWM controls the PWM2H pin
IOCON2bits.PENL = 1; // PWM controls the PWM2L pin
IOCON3bits.PENL = 1; // PWM controls the PWM3L pin
IOCON3bits.PENH = 1; // PWM controls the PWM3H pin
SCRState = SCR_INACTIVE_4TH_QUADRANT;
systemStartFlag = 0;
mpptStartFlag = 1;
Ioutput = 0;
ZCDcount = 0;
}
//Continuously Verify that Grid Frequency is okay
if ((gridPeriod > gridPeriodMin ) && (gridPeriod < gridPeriodMax))
{
if(gridFrequencyErrorFlag == 1)
{
// Hysteresis for the frequency once a fault has been detected
if((gridPeriod > (gridPeriodMin + 20)) && (gridPeriod < (gridPeriodMax - 20)))
{
gridFrequencyState = GRID_FREQUENCY_OK;
gridFrequencyErrorFlag = 0;
}
}