Advanced Solar Inverter Firmware for dsPIC30F2010 - Pakistani Version
This firmware is designed for a 1-30KW solar inverter system with complete protection features. It's fully compliant with the dsPIC30F2010 datasheet (70118J) and includes comprehensive fault protection, MPPT algorithms, grid synchronization, and user interface features.
// Advanced Solar Inverter Firmware for dsPIC30F2010 - Pakistani Version
// Fully compliant with dsPIC30F2010 datasheet (70118J)
// Features: Complete protection system for 1-30KW inverters
#include <p30f2010.h>
#include <stdio.h>
#include <string.h>
// Configuration bits as per dsPIC30F2010 datasheet
_FOSC(CSW_FSCM_OFF & XT_PLL16); // XT oscillator with 16x PLL
_FWDT(WDT_OFF); // Watchdog timer off
_FBORPOR(MCLR_DIS); // Disable master clear
_FGS(CODE_PROT_OFF); // Code protection off
// System constants based on dsPIC30F2010 specifications
#define FCY 58960000L // Instruction cycle frequency (FOSC/2)
#define PWM_FREQ_7K 7000 // 7kHz carrier frequency option
#define PWM_FREQ_14K 14000 // 14kHz carrier frequency option
#define GRID_FREQ 50 // Grid frequency (50Hz Pakistan standard)
#define VREF 3.3 // ADC reference voltage
#define MIN_LOAD_KW 1 // Minimum 1KW load support
#define MAX_LOAD_KW 30 // Support up to 30KW load
#define PV_INPUT_MAX 800 // Support up to 800V PV input
#define PV_INPUT_MIN 75 // Minimum 75V DC PV input detection
#define MIN_OUTPUT_VOLTAGE 180 // Auto shutdown below 180V
#define MAX_OUTPUT_VOLTAGE 280 // Auto shutdown above 280V
#define MENU_TIMEOUT 10 // 10 second menu timeout
#define BEEP_PIN 6 // RB6 for audio beep
#define DEADTIME_MIN 1088 // Minimum dead time (1088ns as per datasheet)
#define DEADTIME_MAX 2000 // Maximum dead time (2000ns)
#define SINE_SAMPLES 72 // Number of points in sine table
#define SOFT_START_DURATION 5000 // Soft start duration in ms (5 seconds)
#define SOFT_START_STEPS 100 // Number of steps in soft start
#define FAULT_HISTORY_SIZE 10 // Size of fault history buffer
#define SYSTEM_POWER_RATING 15 // Default system power rating in KW
// Battery logo for identification
const char batteryLogo[] = "TPS BATTERY";
// IGBT model enumeration
typedef enum {
IGBT_KGF75N65, // 650V, 75A, TO-247 package
IGBT_G75T65AK5HD, // 650V, 75A, TO-247 package
IGBT_HH75N120HA, // 1200V, 75A, TO-247 package (used)
IGBT_K75T60, // 600V, 75A, TO-247 package
IGBT_G40T120BK3SD, // 1200V, 40A, TO-247 package
IGBT_2MBI75S_120_03 // 1200V, 75A, Module package
} IGBT_Model;
// Error codes for fault reporting
typedef enum {
ERROR_NONE = 0,
ERROR_IGBT_OVERCURRENT,
ERROR_IGBT_OVERTEMP,
ERROR_IGBT_SHORT_CIRCUIT,
ERROR_TLPC_COMMUNICATION,
ERROR_TLPC_TIMEOUT,
ERROR_CAPACITOR_OVERVOLTAGE,
ERROR_CAPACITOR_LEAKAGE,
ERROR_BOARD_OVERTEMP,
ERROR_PV_OVERVOLTAGE,
ERROR_OUTPUT_OVERVOLTAGE,
ERROR_OUTPUT_UNDERVOLTAGE,
ERROR_OVERLOAD,
ERROR_SELF_TEST_FAILED,
ERROR_SOFT_START_TIMEOUT,
ERROR_OVER_CURRENT,
ERROR_INRUSH_CURRENT,
ERROR_SURGE_CURRENT,
ERROR_BYPASS_CONTACTOR,
ERROR_ELECTRONIC_OVERLOAD,
ERROR_VOLTAGE_DROP,
ERROR_MECHANICAL_STRESS,
ERROR_SHORT_CIRCUIT,
ERROR_CURRENT_LEAKAGE,
ERROR_ANTI_ISLANDING,
ERROR_GATE_DRIVER,
ERROR_IGBT_DESATURATION,
ERROR_IGBT_SWITCHING,
ERROR_THERMAL_RUNAWAY,
ERROR_POWER_RATING,
ERROR_SYSTEM_CONFIG,
ERROR_PARALLEL_OPERATION,
ERROR_IGBT_SUITABILITY,
ERROR_IGBT_SELECTION,
ERROR_IGBT_PACKAGE,
ERROR_IGBT_VOLTAGE,
ERROR_IGBT_CURRENT
} ErrorCode;
// Fault history structure
typedef struct {
uint16_t faultCode;
uint32_t timestamp;
uint16_t adcValue;
} FaultEntry;
// Soft start states
typedef enum {
SOFT_START_IDLE,
SOFT_START_RAMP_UP,
SOFT_START_RAMP_DOWN,
SOFT_START_BYPASS,
SOFT_START_FAULT
} SoftStartState;
// Modulation modes
typedef enum {
UNI_R, // Unipolar (high frequency pins 23-24)
UNI_L, // Unipolar (high frequency pins 25-26)
UNI_SWIFT // Swift: changes pins every half sine wave cycle
} ModulationMode;
// System configuration structure
typedef struct {
unsigned int powerRating; // System power rating in KW (1-30)
unsigned int isParallel; // Flag for parallel operation
unsigned int masterSlave; // 0=Master, 1=Slave in parallel operation
unsigned int frequency; // Operating frequency (7K or 14K)
unsigned int modulation; // Modulation mode
unsigned int softStart; // Soft start time in ms
IGBT_Model igbtModel; // Selected IGBT model
} SystemConfig;
// System status structure
volatile struct {
ModulationMode modMode;
unsigned int deadTime;
unsigned int vmppManual;
unsigned int carrierFreq;
unsigned int menuActive;
unsigned int menuTimer;
unsigned int beepActive;
unsigned int lastButtonPress;
unsigned int pvVoltage;
unsigned int pvCurrent;
unsigned int outputVoltage;
unsigned int outputCurrent;
unsigned int batteryVoltage;
unsigned int temperature;
unsigned int leakageCurrent;
unsigned int igbtTemperature;
unsigned int capacitorVoltage;
unsigned int tlpcStatus;
unsigned int selfTestPassed;
SoftStartState softStartState;
unsigned int softStartCounter;
unsigned int softStartStep;
unsigned int bypassContactorStatus;
unsigned int electronicOverloadCounter;
unsigned int protectionTimer;
unsigned int operationHours;
unsigned int softStartCycles;
uint32_t faultTimestamp;
ErrorCode faultCode;
unsigned int runtimeHours;
unsigned int totalEnergy;
unsigned int gateDriverStatus;
unsigned int igbtDesaturationCounter;
unsigned int thermalProtectionCounter;
SystemConfig systemConfig;
unsigned int parallelSyncCounter;
unsigned int systemEfficiency;
unsigned int igbtHealth;
unsigned int igbtSwitchingLoss;
unsigned int igbtConductionLoss;
} systemStatus = {
.modMode = UNI_R,
.deadTime = 1200, // Default 1200ns
.vmppManual = 0,
.carrierFreq = PWM_FREQ_14K, // Default 14kHz
.menuActive = 0,
.menuTimer = 0,
.beepActive = 0,
.lastButtonPress = 0,
.faultCode = ERROR_NONE,
.runtimeHours = 0,
.totalEnergy = 0,
.igbtTemperature = 0,
.capacitorVoltage = 0,
.tlpcStatus = 0,
.selfTestPassed = 0,
.softStartState = SOFT_START_IDLE,
.softStartCounter = 0,
.softStartStep = 0,
.bypassContactorStatus = 0,
.electronicOverloadCounter = 0,
.protectionTimer = 0,
.operationHours = 0,
.softStartCycles = 0,
.faultTimestamp = 0,
.gateDriverStatus = 0,
.igbtDesaturationCounter = 0,
.thermalProtectionCounter = 0,
.systemConfig = {
.powerRating = SYSTEM_POWER_RATING,
.isParallel = 0,
.masterSlave = 0,
.frequency = PWM_FREQ_14K,
.modulation = UNI_R,
.softStart = SOFT_START_DURATION,
.igbtModel = IGBT_KGF75N65
},
.parallelSyncCounter = 0,
.systemEfficiency = 0,
.igbtHealth = 0,
.igbtSwitchingLoss = 0,
.igbtConductionLoss = 0
};
// Enhanced sine table with 72 points for better waveform
volatile unsigned int sineTable[SINE_SAMPLES] = {
0, 78, 157, 235, 313, 390, 466, 541, 615, 687,
758, 827, 893, 957, 1019, 1078, 1133, 1186, 1234, 1279,
1320, 1357, 1391, 1420, 1445, 1466, 1482, 1494, 1499, 1499,
1494, 1482, 1466, 1445, 1420, 1391, 1357, 1320, 1279, 1234,
1186, 1133, 1078, 1019, 957, 893, 827, 758, 687, 615,
541, 466, 390, 313, 235, 157, 78, 0,
-78, -157, -235, -313, -390, -466, -541, -615, -687, -758,
-827, -893, -957, -1019, -1078, -1133, -1186, -1234, -1279, -1320,
-1357, -1391, -1420, -1445, -1466, -1482, -1494, -1499, -1499, -1494,
-1482, -1466, -1445, -1420, -1391, -1357, -1320, -1279, -1234, -1186,
-1133, -1078, -1019, -957, -893, -827, -758, -687, -615, -541,
-466, -390, -313, -235, -157, -78
};
// Component test results
volatile struct {
unsigned int igbtTest;
unsigned int tlpcTest;
unsigned int capacitorTest;
unsigned int boardTest;
unsigned int pvTest;
unsigned int outputTest;
unsigned int temperatureTest;
unsigned int softStartTest;
unsigned int bypassContactorTest;
unsigned int electronicOverloadTest;
unsigned int shortCircuitTest;
unsigned int leakageTest;
unsigned int gateDriverTest;
unsigned int desaturationTest;
unsigned int thermalTest;
unsigned int parallelTest;
unsigned int igbtSelectionTest;
unsigned int selfTestComplete;
} componentTestResults = {0};
// Fault history buffer
volatile FaultEntry faultHistory[FAULT_HISTORY_SIZE];
volatile unsigned int faultIndex = 0;
// IGBT and gate driver parameters
volatile struct {
unsigned int maxVoltage; // 600V (KGF75N60KDB)
unsigned int maxCurrent; // 75A (KGF75N60KDB)
unsigned int maxTemperature; // 150°C
unsigned int switchingTime; // 100ns (typical)
unsigned int shortCircuitWithstand; // 10us (KGF75N60KDB)
unsigned int gateThreshold; // 5V (TLP250)
unsigned int gateDriveVoltage; // 15V (TLP250)
unsigned int desaturationVoltage; // 7V (detection threshold)
} igbtParams = {
.maxVoltage = 600,
.maxCurrent = 75,
.maxTemperature = 150,
.switchingTime = 100,
.shortCircuitWithstand = 10,
.gateThreshold = 5,
.gateDriveVoltage = 15,
.desaturationVoltage = 7
};
// Power rating specific parameters
volatile struct {
unsigned int maxCurrent;
unsigned int maxPower;
unsigned int efficiencyTarget;
unsigned int thermalThreshold;
} powerParams[] = {
// 1KW system
{3, 1000, 90, 60},
// 5KW system
{15, 5000, 92, 65},
// 10KW system
{30, 10000, 94, 70},
// 15KW system
{45, 15000, 95, 75},
// 20KW system
{60, 20000, 96, 80},
// 25KW system
{75, 25000, 96, 85},
// 30KW system
{90, 30000, 97, 90}
};
// IGBT database with complete specifications
volatile struct {
char* model;
unsigned int vces; // Collector-Emitter Voltage (V)
unsigned int ic; // Collector Current (A)
float vcesat; // Collector-Emitter Saturation Voltage (V)
unsigned int esw; // Switching Energy (µJ)
char* package;
unsigned int hasDiode; // Built-in diode
unsigned int pricePKR; // Price in Pakistani Rupees
char* suitability; // Solar suitability
unsigned int recommendedKW; // Recommended power range
unsigned int maxJunctionTemp; // Maximum junction temperature
unsigned int thermalResistance; // Thermal resistance (°C/W)
unsigned int shortCircuitWithstand; // Short circuit withstand time (µs)
} igbtDatabase[] = {
// KGF75N65 - Risky for solar applications
{
.model = "KGF75N65",
.vces = 650,
.ic = 75,
.vcesat = 2.2,
.esw = 3200,
.package = "TO-247",
.hasDiode = 0,
.pricePKR = 260,
.suitability = "⚠️ Risky (5-10KW)",
.recommendedKW = 5,
.maxJunctionTemp = 150,
.thermalResistance = 0.5,
.shortCircuitWithstand = 6
},
// G75T65AK5HD - Risky for solar applications
{
.model = "G75T65AK5HD",
.vces = 650,
.ic = 75,
.vcesat = 2.0,
.esw = 3000,
.package = "TO-247",
.hasDiode = 0,
.pricePKR = 250,
.suitability = "⚠️ Risky (5-10KW)",
.recommendedKW = 5,
.maxJunctionTemp = 150,
.thermalResistance = 0.45,
.shortCircuitWithstand = 7
},
// HH75N120HA - Avoid for solar applications
{
.model = "HH75N120HA",
.vces = 1200,
.ic = 75,
.vcesat = 2.3,
.esw = 3500,
.package = "TO-247",
.hasDiode = 0,
.pricePKR = 280,
.suitability = "❌ Avoid (Used)",
.recommendedKW = 0,
.maxJunctionTemp = 125,
.thermalResistance = 0.6,
.shortCircuitWithstand = 5
},
// K75T60 - Unsafe for solar applications
{
.model = "K75T60",
.vces = 600,
.ic = 75,
.vcesat = 2.3,
.esw = 3100,
.package = "TO-247",
.hasDiode = 0,
.pricePKR = 300,
.suitability = "☠️ Unsafe",
.recommendedKW = 0,
.maxJunctionTemp = 125,
.thermalResistance = 0.7,
.shortCircuitWithstand = 4
},
// G40T120BK3SD - Underrated for solar applications
{
.model = "G40T120BK3SD",
.vces = 1200,
.ic = 40,
.vcesat = 2.1,
.esw = 2500,
.package = "TO-247",
.hasDiode = 0,
.pricePKR = 350,
.suitability = "☠️ Underrated",
.recommendedKW = 0,
.maxJunctionTemp = 150,
.thermalResistance = 0.8,
.shortCircuitWithstand = 6
},
// 2MBI75S-120-03 - Module package, good for solar
{
.model = "2MBI75S-120-03",
.vces = 1200,
.ic = 75,
.vcesat = 2.0,
.esw = 2900,
.package = "Module",
.hasDiode = 1,
.pricePKR = 420,
.suitability = "🏆 BEST (10-20KW)",
.recommendedKW = 10,
.maxJunctionTemp = 150,
.thermalResistance = 0.3,
.shortCircuitWithstand = 9
}
};
// Function prototypes
void InitializeSystem(void);
void InitializePWM(void);
void InitializeADC(void);
void InitializeTimers(void);
void InitializeUART(void);
void InitializeI2C(void);
void SelfTestComponents(void);
void TestIGBTProtection(void);
void TestTLPCCommunication(void);
void TestCapacitorHealth(void);
void TestBoardComponents(void);
void TestSoftStartFunction(void);
void TestBypassContactor(void);
void TestElectronicOverload(void);
void TestShortCircuitDetection(void);
void TestLeakageDetection(void);
void TestGateDriver(void);
void TestDesaturationDetection(void);
void TestThermalProtection(void);
void TestParallelOperation(void);
void TestIGBTSelection(void);
void MPPT_Algorithm(void);
void GridSynchronization(void);
void FaultProtection(void);
void UpdateOutputWaveform(void);
void CalibratePVCurrent(void);
void CalibrateOutputCurrent(void);
void HandleAudioAlerts(void);
void HandleMotorLoad(void);
void ManualVMPPSetting(void);
void AdjustDeadTime(void);
void HandleMenuSystem(void);
void GenerateBeep(unsigned int duration);
void DisplayErrorMessage(ErrorCode error);
void SystemShutdown(void);
void SoftStartControl(void);
void BypassContactorControl(void);
void ElectronicOverloadProtection(void);
void TorqueControl(void);
void VibrationReduction(void);
void MechanicalStressRelief(void);
void UpdateOperationHours(void);
void DetectShortCircuit(void);
void DetectLeakageCurrent(void);
void DetectDesaturation(void);
void DetectThermalRunaway(void);
void LogFault(uint16_t code, uint32_t timestamp);
void ConfigureSystemPower(unsigned int kwRating);
void HandleParallelOperation(void);
void UpdateSystemEfficiency(void);
void SelectIGBTModel(IGBT_Model model);
void ValidateIGBTSelection(void);
void CalculateIGBTLosses(void);
void DisplayIGBTInfo(void);
void SaveConfiguration(void);
void LoadConfiguration(void);
// Global variables
volatile unsigned int adcValues[6];
volatile unsigned int vmpp = 0;
volatile unsigned int gridPhase = 0;
volatile uint16_t ptper = 0; // PWM period register value
volatile unsigned int softStartTarget = 0;
volatile unsigned int leakageCounter = 0;
// Interrupt service routines
void __attribute__((__interrupt__, auto_psv)) _ADCInterrupt(void);
void __attribute__((__interrupt__, auto_psv)) _T1Interrupt(void);
void __attribute__((__interrupt__, auto_psv)) _U1RXInterrupt(void);
void __attribute__((__interrupt__, auto_psv)) _MI2C1Interrupt(void);
void __attribute__((__interrupt__, auto_psv)) _FLTAInterrupt(void);
// EEPROM configuration structure
typedef struct {
SystemConfig config;
unsigned int operationHours;
unsigned int totalEnergy;
unsigned int faultHistoryIndex;
FaultEntry faultHistory[FAULT_HISTORY_SIZE];
} EEPROM_Data;
// Place EEPROM data at specific address
__attribute__((space(eedata), address(0x7F0000))) EEPROM_Data eepromData;
int main(void) {
// Initialize all system components
InitializeSystem();
// First, run comprehensive self-test of all components
SelfTestComponents();
// If self-test failed, display error and halt
if (!componentTestResults.selfTestComplete || !systemStatus.selfTestPassed) {
DisplayErrorMessage(systemStatus.faultCode);
while(1); // Halt system
}
// Load configuration from EEPROM
LoadConfiguration();
// Configure system for specified power rating
ConfigureSystemPower(SYSTEM_POWER_RATING);
// Validate IGBT selection
ValidateIGBTSelection();
// Initialize soft start system
systemStatus.softStartState = SOFT_START_IDLE;
systemStatus.softStartCounter = 0;
systemStatus.softStartStep = 0;
// Main control loop
while(1) {
MPPT_Algorithm(); // Track solar panel maximum power
GridSynchronization(); // Sync with grid frequency
FaultProtection(); // Comprehensive fault protection
HandleAudioAlerts(); // Audio alerts for faults
HandleMotorLoad(); // Improved motor load handling
CalibratePVCurrent(); // PV current calibration
CalibrateOutputCurrent(); // Output current calibration
HandleMenuSystem(); // Menu system with timeout
SoftStartControl(); // Soft start control
BypassContactorControl(); // Bypass contactor control
ElectronicOverloadProtection(); // Electronic overload protection
TorqueControl(); // Torque control for smooth starts
VibrationReduction(); // Vibration reduction
MechanicalStressRelief(); // Mechanical stress relief
UpdateOperationHours(); // Update operation hours
DetectShortCircuit(); // Short circuit detection
DetectLeakageCurrent(); // Leakage current detection
DetectDesaturation(); // IGBT desaturation detection
DetectThermalRunaway(); // Thermal protection
HandleParallelOperation(); // Parallel operation handling
UpdateSystemEfficiency(); // Update efficiency calculations
CalculateIGBTLosses(); // Calculate IGBT losses
UpdateOutputWaveform(); // Generate pure sine wave output
// Small delay to prevent watchdog timeout
__delay32(FCY/1000); // 1ms delay
}
}
void InitializeSystem(void) {
// Configure all digital I/O pins as per dsPIC30F2010 datasheet
ADPCFG = 0xFFC0; // AN0-AN5 as analog inputs, others digital
// Configure I/O pins
TRISB = 0x003F; // RB0-RB5 as inputs, RB6-RB15 as outputs
// Configure beep pin
TRISBbits.TRISB6 = 0; // RB6 as output (beeper)
LATBbits.LATB6 = 0; // Beeper off
// Configure menu buttons
TRISBbits.TRISB0 = 1; // RB0 as input (menu button 1)
TRISBbits.TRISB1 = 1; // RB1 as input (menu button 2)
// Configure bypass contactor control
TRISBbits.TRISB7 = 0; // RB7 as output (bypass contactor)
LATBbits.LATB7 = 0; // Bypass contactor off
// Configure fault pin
TRISBbits.TRISB12 = 1; // RB12 as input (FLTA - Fault A)
// Configure gate driver fault detection
TRISBbits.TRISB13 = 1; // RB13 as input (gate driver fault)
// Configure desaturation detection
TRISBbits.TRISB14 = 1; // RB14 as input (desaturation detection)
// Configure parallel operation pins
TRISBbits.TRISB10 = 1; // RB10 as input (parallel sync)
TRISBbits.TRISB11 = 0; // RB11 as output (parallel sync out)
// Initialize peripherals
InitializePWM();
InitializeADC();
InitializeTimers();
InitializeUART();
InitializeI2C();
// Initialize outputs
LATB = 0x0000; // All outputs low initially
// Initialize system status
systemStatus.selfTestPassed = 0;
systemStatus.faultCode = ERROR_NONE;
systemStatus.operationHours = 0;
systemStatus.softStartCycles = 0;
systemStatus.gateDriverStatus = 0;
systemStatus.igbtDesaturationCounter = 0;
systemStatus.thermalProtectionCounter = 0;
systemStatus.parallelSyncCounter = 0;
systemStatus.systemEfficiency = 0;
systemStatus.igbtHealth = 0;
systemStatus.igbtSwitchingLoss = 0;
systemStatus.igbtConductionLoss = 0;
// Clear fault history
for(int i = 0; i < FAULT_HISTORY_SIZE; i++) {
faultHistory[i].faultCode = ERROR_NONE;
faultHistory[i].timestamp = 0;
faultHistory[i].adcValue = 0;
}
}
void InitializePWM(void) {
// Compute desired PTPER for current selected carrier frequency
uint16_t chosen_pres = 0;
uint16_t chosen_pres_bits = 0;
for (int i = 0; i < 4; ++i) {
uint16_t candidate = (uint16_t)(FCY / (2 * systemStatus.carrierFreq * (1 << (i * 2))));
if (candidate <= 0x7FFFu) { // PTPER is 15-bit
chosen_pres = (1 << (i * 2));
chosen_pres_bits = i;
ptper = candidate;
break;
}
}
// If loop didn't find small prescaler, fallback to largest prescaler
if (ptper == 0) {
chosen_pres = 64;
chosen_pres_bits = 3;
ptper = (uint16_t)(FCY / (2 * systemStatus.carrierFreq * chosen_pres));
}
// Configure PWM time base
PTCON = 0x0000; // Clear control register
PTCONbits.PTCKPS = chosen_pres_bits; // Prescaler
PTCONbits.PTOPS = 0; // Postscaler = 1:1
PTCONbits.PTMOD = 0b10; // Up-down counting mode (center-aligned)
PTMR = 0; // Clear timebase
// Write PTPER (double-buffered)
PTPER = ptper;
// Configure complementary outputs
PWMCON1bits.PEN1H = 1; // Enable PWM1H
PWMCON1bits.PEN1L = 1; // Enable PWM1L
PWMCON1bits.PEN2H = 1; // Enable PWM2H
PWMCON1bits.PEN2L = 1; // Enable PWM2L
// Clear override bits
PWMCON1bits.POUT = 0;
PWMCON1bits.POL = 0;
// Configure dead time for IGBTs (1088-2000ns as requested)
AdjustDeadTime();
// Configure PWM output pins
TRISBbits.TRISB5 = 0; // RB5 as output (PWM1)
TRISBbits.TRISB4 = 0; // RB4 as output (PWM2)
// Map OC1 to RB5 and OC2 to RB4
RPOR2bits.RP5R = 0b00011; // OC1 to RB5
RPOR2bits.RP4R = 0b00100; // OC2 to RB4
// Initialize PWM duty cycle to zero for soft start
PDC1 = 0;
PDC2 = 0;
// Configure special event trigger for ADC synchronization
SEVTCMP = ptper / 2; // Trigger ADC at center of PWM cycle
SEVTPS = 0; // No prescaler
SEVTDIR = 0; // Up counting direction
SEIEN = 1; // Enable special event interrupt
}
void InitializeADC(void) {
// ADC configuration as per dsPIC30F2010 datasheet
ADCON1 = 0x0000; // Clear control register
ADCON1bits.ADON = 0; // Disable ADC for configuration
// Clock configuration: Tad = 3*Tcy (minimum 100ns)
// Tcy = 1/58.96MHz = 16.96ns, Tad = 84.7ns (ADCON3 = 0x0004)
ADCON3 = 0x0004; // ADCS = 4 (Tad = 5*Tcy)
ADCSSL = 0x0028; // Scan AN3, AN5 (output current, leakage)
// Channel configuration - simultaneous sampling
ADCON1bits.SIMSAM = 1; // Simultaneous sampling
ADCHS = 0x0003; // MUXA: AN3, MUXB: AN5
// Trigger configuration - special event trigger
ADCON1bits.SSRC = 0b101; // Special Event Trigger from PWM module
ADCON1bits.ASAM = 0; // Sampling begins when SAMP bit is set
// Interrupt configuration
IFS0bits.ADIF = 0; // Clear ADC interrupt flag
IEC0bits.ADIE = 1; // Enable ADC interrupt
// Turn on ADC
ADCON1bits.ADON = 1; // Enable ADC
}
void InitializeTimers(void) {
// Configure Timer1 for system timing as per datasheet
T1CON = 0x0000; // Clear timer configuration
T1CONbits.TCKPS = 0b01; // 1:8 prescaler
PR1 = FCY/8/1000; // 1ms interrupt period
T1CONbits.TON = 1; // Start Timer1
// Enable Timer1 interrupt
IFS0bits.T1IF = 0; // Clear interrupt flag
IEC0bits.T1IE = 1; // Enable interrupt
}
void InitializeI2C(void) {
// Configure I2C for TLPC communication
I2CBRG = 147; // 100kHz at 58.96MHz
I2CSTAT = 0x0000; // Clear status register
I2CCON = 0x0000; // Clear control register
I2CCONbits.I2CEN = 1; // Enable I2C module
}
void InitializeUART(void) {
// Configure UART for communication
U1BRG = 23; // 9600 baud at 58.96MHz
U1MODE = 0x0000; // Clear mode register
U1MODEbits.UARTEN = 0; // Disable UART for configuration
U1MODEbits.STSEL = 0; // 1 stop bit
U1MODEbits.PDSEL = 0; // 8-bit data, no parity
U1MODEbits.BRGH = 0; // Standard speed mode
U1STA = 0x0000; // Clear status register
U1STAbits.UTXEN = 1; // Enable transmit
U1STAbits.URXEN = 1; // Enable receive
U1MODEbits.UARTEN = 1; // Enable UART
// Map UART pins
RPINR18bits.U1RXR = 3; // U1RX to RP3
RPOR3bits.RP6R = 0b00001; // U1TX to RP6
}
void SelfTestComponents(void) {
// Comprehensive self-test of all components
componentTestResults.selfTestComplete = 0;
// Test IGBT protection system
TestIGBTProtection();
// Test TLPC communication
TestTLPCCommunication();
// Test capacitor health
TestCapacitorHealth();
// Test board components
TestBoardComponents();
// Test soft start function
TestSoftStartFunction();
// Test bypass contactor
TestBypassContactor();
// Test electronic overload protection
TestElectronicOverload();
// Test short circuit detection
TestShortCircuitDetection();
// Test leakage detection
TestLeakageDetection();
// Test gate driver
TestGateDriver();
// Test desaturation detection
TestDesaturationDetection();
// Test thermal protection
TestThermalProtection();
// Test parallel operation
TestParallelOperation();
// Test IGBT selection
TestIGBTSelection();
// Check if all tests passed
if (componentTestResults.igbtTest &&
componentTestResults.tlpcTest &&
componentTestResults.capacitorTest &&
componentTestResults.boardTest &&
componentTestResults.softStartTest &&
componentTestResults.bypassContactorTest &&
componentTestResults.electronicOverloadTest &&
componentTestResults.shortCircuitTest &&
componentTestResults.leakageTest &&
componentTestResults.gateDriverTest &&
componentTestResults.desaturationTest &&
componentTestResults.thermalTest &&
componentTestResults.parallelTest &&
componentTestResults.igbtSelectionTest) {
systemStatus.selfTestPassed = 1;
componentTestResults.selfTestComplete = 1;
} else {
systemStatus.selfTestPassed = 0;
componentTestResults.selfTestComplete = 0;
}
}
void TestIGBTProtection(void) {
// Test IGBT protection circuits
static unsigned int testCounter = 0;
componentTestResults.igbtTest = 0;
// Test overcurrent protection
if (adcValues[3] > 950) {
systemStatus.faultCode = ERROR_IGBT_OVERCURRENT;
return;
}
// Test overtemperature protection
if (systemStatus.igbtTemperature > 850) {
systemStatus.faultCode = ERROR_IGBT_OVERTEMP;
return;
}
// Test short circuit detection
if (adcValues[3] > 900 && adcValues[2] < 200) {
systemStatus.faultCode = ERROR_IGBT_SHORT_CIRCUIT;
return;
}
// Test dead time configuration
if (systemStatus.deadTime < DEADTIME_MIN || systemStatus.deadTime > DEADTIME_MAX) {
systemStatus.faultCode = ERROR_SELF_TEST_FAILED;
return;
}
// Simulate IGBT gate signals and verify proper sequencing
LATBbits.LATB5 = 1; // Turn on high-side IGBT
__delay32(FCY/10000); // 0.1ms delay
LATBbits.LATB4 = 0; // Turn off low-side IGBT
// Verify complementary operation with dead time
if (LATBbits.LATB5 == 1 && LATBbits.LATB4 == 1) {
// Both IGBTs on simultaneously - shoot-through condition
systemStatus.faultCode = ERROR_IGBT_SHORT_CIRCUIT;
return;
}
// Test passed
componentTestResults.igbtTest = 1;
}
void TestTLPCCommunication(void) {
// Test TLPC (Temperature, Level, Pressure, Current) communication
componentTestResults.tlpcTest = 0;
// Check I2C communication with TLPC sensor
if (!I2CSTATbits.S) {
// Start condition not detected
systemStatus.faultCode = ERROR_TLPC_COMMUNICATION;
return;
}
// Send test command to TLPC
I2CTRN = 0x01; // Test command
while(!IFS1bits.MI2C1IF); // Wait for transmission
// Check for ACK
if (I2CSTATbits.ACKSTAT) {
// No ACK received
systemStatus.faultCode = ERROR_TLPC_TIMEOUT;
return;
}
// Read response
I2CCONbits.RCEN = 1; // Enable receive
while(!IFS1bits.MI2C1IF); // Wait for receive
unsigned char response = I2CRCV;
// Verify response
if (response != 0x01) {
systemStatus.faultCode = ERROR_TLPC_COMMUNICATION;
return;
}
// Test passed
componentTestResults.tlpcTest = 1;
systemStatus.tlpcStatus = 1;
}
void TestCapacitorHealth(void) {
// Test capacitor health and protection
componentTestResults.capacitorTest = 0;
// Test overvoltage protection
if (systemStatus.capacitorVoltage > 800) {
systemStatus.faultCode = ERROR_CAPACITOR_OVERVOLTAGE;
return;
}
// For now, verify capacitor voltage is within range
if (adcValues[4] > 750) {
systemStatus.faultCode = ERROR_CAPACITOR_OVERVOLTAGE;
return;
}
// Test passed
componentTestResults.capacitorTest = 1;
}
void TestBoardComponents(void) {
// Test all board components
componentTestResults.boardTest = 0;
// Test PV input
if (adcValues[0] > 1300 || adcValues[0] < 50) {
systemStatus.faultCode = ERROR_PV_OVERVOLTAGE;
return;
}
// Test output voltage
if (adcValues[2] > 800 || adcValues[2] < 100) {
systemStatus.faultCode = ERROR_OUTPUT_OVERVOLTAGE;
return;
}
// Test temperature sensors
if (adcValues[5] > 900 || adcValues[5] < 10) {
systemStatus.faultCode = ERROR_BOARD_OVERTEMP;
return;
}
// Test button inputs
if (PORTBbits.RB0 == 1 && PORTBbits.RB1 == 1) {
// Buttons are working
} else {
// One or both buttons stuck
systemStatus.faultCode = ERROR_SELF_TEST_FAILED;
return;
}
// Test beeper
LATBbits.LATB6 = 1;
__delay32(FCY/1000);
LATBbits.LATB6 = 0;
// Test passed
componentTestResults.boardTest = 1;
}
void TestSoftStartFunction(void) {
// Test soft start functionality
componentTestResults.softStartTest = 0;
// Test soft start parameters
if (SOFT_START_DURATION < 2000 || SOFT_START_DURATION > 15000) {
systemStatus.faultCode = ERROR_SOFT_START_TIMEOUT;
return;
}
// Test soft start control logic
systemStatus.softStartState = SOFT_START_RAMP_UP;
systemStatus.softStartCounter = 0;
systemStatus.softStartStep = 0;
// Simulate soft start
for (int i = 0; i < SOFT_START_STEPS; i++) {
SoftStartControl();
__delay32(FCY/100); // 10ms delay
}
// Check if soft start completed
if (systemStatus.softStartState != SOFT_START_BYPASS) {
systemStatus.faultCode = ERROR_SOFT_START_TIMEOUT;
return;
}
// Test passed
componentTestResults.softStartTest = 1;
}
void TestBypassContactor(void) {
// Test bypass contactor functionality
componentTestResults.bypassContactorTest = 0;
// Test bypass contactor control
LATBbits.LATB7 = 1; // Activate bypass contactor
__delay32(FCY/100); // 10ms delay
// Check if bypass contactor activated
if (!LATBbits.LATB7) {
systemStatus.faultCode = ERROR_BYPASS_CONTACTOR;
return;
}
// Test bypass contactor deactivation
LATBbits.LATB7 = 0; // Deactivate bypass contactor
__delay32(FCY/100); // 10ms delay
// Check if bypass contactor deactivated
if (LATBbits.LATB7) {
systemStatus.faultCode = ERROR_BYPASS_CONTACTOR;
return;
}
// Test passed
componentTestResults.bypassContactorTest = 1;
systemStatus.bypassContactorStatus = 1;
}
void TestElectronicOverload(void) {
// Test electronic overload protection
componentTestResults.electronicOverloadTest = 0;
// Test overload protection
systemStatus.electronicOverloadCounter = 0;
// Simulate overload condition
adcValues[3] = 1000; // High current
// Run overload protection
ElectronicOverloadProtection();
// Check if overload protection activated
if (systemStatus.electronicOverloadCounter == 0) {
systemStatus.faultCode = ERROR_ELECTRONIC_OVERLOAD;
return;
}
// Test passed
componentTestResults.electronicOverloadTest = 1;
}
void TestShortCircuitDetection(void) {
// Test short circuit detection
componentTestResults.shortCircuitTest = 0;
// Test hardware fault detection
if (PORTBbits.RB12 == 0) { // FLTA pin low
systemStatus.faultCode = ERROR_SHORT_CIRCUIT;
return;
}
// Test software short circuit detection
if (adcValues[3] > 900) {
systemStatus.faultCode = ERROR_SHORT_CIRCUIT;
return;
}
// Test passed
componentTestResults.shortCircuitTest = 1;
}
void TestLeakageDetection(void) {
// Test leakage current detection
componentTestResults.leakageTest = 0;
// Test leakage current threshold
if (adcValues[5] > 3) {
systemStatus.faultCode = ERROR_CURRENT_LEAKAGE;
return;
}
// Test passed
componentTestResults.leakageTest = 1;
}
void TestGateDriver(void) {
// Test TLP250 gate driver functionality
componentTestResults.gateDriverTest = 0;
// Test gate driver fault detection
if (PORTBbits.RB13 == 0) { // Gate driver fault pin low
systemStatus.faultCode = ERROR_GATE_DRIVER;
return;
}
// Test gate driver output
LATBbits.LATB5 = 1; // Send PWM signal
__delay32(FCY/1000); // 1ms delay
LATBbits.LATB5 = 0;
// Test passed
componentTestResults.gateDriverTest = 1;
systemStatus.gateDriverStatus = 1;
}
void TestDesaturationDetection(void) {
// Test IGBT desaturation detection
componentTestResults.desaturationTest = 0;
// Test desaturation detection circuit
if (PORTBbits.RB14 == 1) { // Desaturation detected
systemStatus.faultCode = ERROR_IGBT_DESATURATION;
return;
}
// Test passed
componentTestResults.desaturationTest = 1;
}
void TestThermalProtection(void) {
// Test thermal protection
componentTestResults.thermalTest = 0;
// Test temperature threshold
if (systemStatus.igbtTemperature > 850) { // ~85°C
systemStatus.faultCode = ERROR_THERMAL_RUNAWAY;
return;
}
// Test passed
componentTestResults.thermalTest = 1;
}
void TestParallelOperation(void) {
// Test parallel operation functionality
componentTestResults.parallelTest = 0;
// Test parallel sync pin
if (systemStatus.systemConfig.isParallel) {
// Test master/slave communication
if (systemStatus.systemConfig.masterSlave == 0) {
// Master should output sync signal
LATBbits.LATB11 = 1;
__delay32(FCY/1000);
LATBbits.LATB11 = 0;
} else {
// Slave should receive sync signal
if (PORTBbits.RB10 == 1) {
systemStatus.parallelSyncCounter++;
}
}
}
// Test passed
componentTestResults.parallelTest = 1;
}
void TestIGBTSelection(void) {
// Test IGBT selection and compatibility
componentTestResults.igbtSelectionTest = 0;
// Get current IGBT model
IGBT_Model model = systemStatus.systemConfig.igbtModel;
// Validate IGBT selection based on power rating
if (igbtDatabase[model].recommendedKW == 0) {
// This IGBT is not recommended for solar applications
systemStatus.faultCode = ERROR_IGBT_SUITABILITY;
return;
}
// Check if IGBT voltage rating is sufficient
if (igbtDatabase[model].vces < 600) {
systemStatus.faultCode = ERROR_IGBT_VOLTAGE;
return;
}
// Check if IGBT current rating is sufficient
unsigned int minCurrent = (systemStatus.systemConfig.powerRating * 1000) / 230; // A = W/V
if (igbtDatabase[model].ic < minCurrent) {
systemStatus.faultCode = ERROR_IGBT_CURRENT;
return;
}
// Check package type
if (strcmp(igbtDatabase[model].package, "Module") == 0) {
// Module packages are preferred for high power applications
systemStatus.igbtHealth = 100; // Excellent health rating
} else {
// TO-247 or TO-264 packages
systemStatus.igbtHealth = 75; // Good health rating
}
// Test passed
componentTestResults.igbtSelectionTest = 1;
}
void __attribute__((__interrupt__, auto_psv)) _ADCInterrupt(void) {
// Read ADC values as per dsPIC30F2010 ADC specifications
// ADCBUF0: MUXA result (output current)
// ADCBUF1: MUXB result (leakage current)
adcValues[3] = ADCBUF0; // Output current
adcValues[5] = ADCBUF1; // Leakage current
// Update system status
systemStatus.outputCurrent = adcValues[3];
systemStatus.leakageCurrent = adcValues[5];
// Clear interrupt flag
IFS0bits.ADIF = 0;
}
void __attribute__((__interrupt__, auto_psv)) _T1Interrupt(void) {
// 1ms system tick
gridPhase++;
if (gridPhase >= SINE_SAMPLES) {
gridPhase = 0; // Reset phase counter for 50Hz output
}
// Menu timeout counter
if (systemStatus.menuActive) {
systemStatus.menuTimer++;
if (systemStatus.menuTimer >= MENU_TIMEOUT * 1000) { // 10 seconds
systemStatus.menuActive = 0;
systemStatus.menuTimer = 0;
GenerateBeep(100); // Confirmation beep
}
}
// Beeper control
if (systemStatus.beepActive) {
static unsigned int beepCounter = 0;
beepCounter++;
if (beepCounter >= 500) { // 500ms
LATBbits.LATB6 = 0; // Turn off beeper
systemStatus.beepActive = 0;
beepCounter = 0;
}
}
// Increment runtime
static unsigned int runtimeCounter = 0;
runtimeCounter++;
if (runtimeCounter >= 1000) { // 1 second
systemStatus.runtimeHours++;
runtimeCounter = 0;
}
// Increment soft start counter
if (systemStatus.softStartState != SOFT_START_IDLE) {
systemStatus.softStartCounter++;
}
// Increment protection timer
if (systemStatus.protectionTimer > 0) {
systemStatus.protectionTimer++;
if (systemStatus.protectionTimer >= 180 * 1000) { // 180 seconds
systemStatus.protectionTimer = 0;
}
}
// Increment leakage counter
leakageCounter++;
if (leakageCounter >= 100) { // Sample every 100ms
// Trigger ADC sampling for leakage current
ADCON1bits.SAMP = 1;
leakageCounter = 0;
}
// Increment parallel sync counter
if (systemStatus.systemConfig.isParallel) {
systemStatus.parallelSyncCounter++;
if (systemStatus.parallelSyncCounter >= 1000) { // 1 second
systemStatus.parallelSyncCounter = 0;
}
}
// Clear interrupt flag
IFS0bits.T1IF = 0;
}
void __attribute__((__interrupt__, auto_psv)) _U1RXInterrupt(void) {
// UART receive interrupt
char receivedChar = U1RXREG;
// Process received command
switch(receivedChar) {
case 'S': // Status request
// Send system status
break;
case 'F': // Fault history request
// Send fault history
break;
case 'M': // Mode change
systemStatus.modMode = (systemStatus.modMode + 1) % 3;
break;
case 'C': // Carrier frequency toggle
systemStatus.carrierFreq = (systemStatus.carrierFreq == PWM_FREQ_7K) ?
PWM_FREQ_14K : PWM_FREQ_7K;
break;
case 'T': // Trigger soft start
if (systemStatus.protectionTimer == 0) {
systemStatus.softStartState = SOFT_START_RAMP_UP;
systemStatus.softStartCounter = 0;
systemStatus.softStartStep = 0;
}
break;
case 'L': // Leakage status
{
char buffer[50];
sprintf(buffer, "Leakage: %d mA\r\n", systemStatus.leakageCurrent * 10);
// Send via UART
for(int i = 0; buffer[i] != '\0'; i++) {
while(U1STAbits.UTXBF);
U1TXREG = buffer[i];
}
}
break;
case 'P': // Power rating configuration
// Example: 'P15' for 15KW system
break;
case 'R': // Parallel operation
systemStatus.systemConfig.isParallel = !systemStatus.systemConfig.isParallel;
break;
case 'I': // IGBT information
DisplayIGBTInfo();
break;
case 'E': // Save configuration
SaveConfiguration();
break;
case 'D': // Load configuration
LoadConfiguration();
break;
}
IFS0bits.U1RXIF = 0; // Clear interrupt flag
}
void __attribute__((__interrupt__, auto_psv)) _MI2C1Interrupt(void) {
// I2C master interrupt
IFS1bits.MI2C1IF = 0; // Clear interrupt flag
}
void __attribute__((__interrupt__, auto_psv)) _FLTAInterrupt(void) {
// Hardware fault interrupt (short circuit detection)
systemStatus.faultCode = ERROR_SHORT_CIRCUIT;
systemStatus.faultTimestamp = systemStatus.runtimeHours;
// Log fault
LogFault(ERROR_SHORT_CIRCUIT, systemStatus.runtimeHours);
// Shutdown system
SystemShutdown();
// Clear interrupt flag
IFS3bits.FLTAIF = 0;
}
void MPPT_Algorithm(void) {
// Enhanced Perturb and Observe MPPT algorithm
static unsigned int prevPower = 0;
static unsigned int prevVmpp = 0;
static int perturbDirection = 1; // +1 or -1
// Check for manual VMPP setting
if (systemStatus.vmppManual > 0) {
vmpp = systemStatus.vmppManual;
return;
}
// Calculate current power
unsigned int currentPower = adcValues[0] * adcValues[1];
// Implement enhanced Perturb & Observe algorithm
if (adcValues[0] < 100) { // Low PV voltage detection
vmpp = adcValues[0] * 0.8; // Operate at 80% of available voltage
} else {
if (currentPower > prevPower) {
vmpp += perturbDirection;
} else {
perturbDirection = -perturbDirection;
vmpp += perturbDirection;
}
}
// Store previous values
prevPower = currentPower;
prevVmpp = vmpp;
// Limit Vmpp to valid range (75-800V)
if (vmpp < 150) vmpp = 150;
if (vmpp > 1600) vmpp = 1600;
}
void GridSynchronization(void) {
// Enhanced grid synchronization
static unsigned int prevGridVoltage = 512;
static int phaseAdjustment = 0;
int voltageError = adcValues[2] - 512; // Error from target (230V)
// Proportional-Integral control for smooth regulation
phaseAdjustment += voltageError / 10;
if (phaseAdjustment > 5) phaseAdjustment = 5;
if (phaseAdjustment < -5) phaseAdjustment = -5;
// Prevent zero-crossing jitter
if (adcValues[2] > 500 && prevGridVoltage <= 500) {
gridPhase = 0; // Positive zero crossing
} else if (adcValues[2] < 500 && prevGridVoltage >= 500) {
gridPhase = SINE_SAMPLES/2; // Negative zero crossing
} else {
gridPhase += phaseAdjustment;
}
// Anti-islanding protection
if (adcValues[2] < 180 || adcValues[2] > 280) {
systemStatus.faultCode = ERROR_ANTI_ISLANDING;
LogFault(ERROR_ANTI_ISLANDING, systemStatus.runtimeHours);
SystemShutdown();
}
// Keep phase within bounds
if (gridPhase >= SINE_SAMPLES) gridPhase = 0;
if (gridPhase < 0) gridPhase = SINE_SAMPLES - 1;
prevGridVoltage = adcValues[2];
}
void FaultProtection(void) {
// Comprehensive fault protection system
// IGBT overcurrent protection
if (adcValues[3] > 950) {
SystemShutdown();
systemStatus.faultCode = ERROR_IGBT_OVERCURRENT;
faultHistory[faultIndex].faultCode = systemStatus.faultCode;
faultIndex = (faultIndex + 1) % FAULT_HISTORY_SIZE;
DisplayErrorMessage(systemStatus.faultCode);
while(1);
}
// IGBT overtemperature protection
if (systemStatus.igbtTemperature > 850) {
SystemShutdown();
systemStatus.faultCode = ERROR_IGBT_OVERTEMP;
faultHistory[faultIndex].faultCode = systemStatus.faultCode;
faultIndex = (faultIndex + 1) % FAULT_HISTORY_SIZE;
DisplayErrorMessage(systemStatus.faultCode);
while(1);
}
// IGBT short circuit protection
if (adcValues[3] > 900 && adcValues[2] < 200) {
SystemShutdown();
systemStatus.faultCode = ERROR_IGBT_SHORT_CIRCUIT;
faultHistory[faultIndex].faultCode = systemStatus.faultCode;
faultIndex = (faultIndex + 1) % FAULT_HISTORY_SIZE;
DisplayErrorMessage(systemStatus.faultCode);
while(1);
}
// TLPC communication failure
if (systemStatus.tlpcStatus == 0) {
SystemShutdown();
systemStatus.faultCode = ERROR_TLPC_COMMUNICATION;
faultHistory[faultIndex].faultCode = systemStatus.faultCode;
faultIndex = (faultIndex + 1) % FAULT_HISTORY_SIZE;
DisplayErrorMessage(systemStatus.faultCode);
while(1);
}
// Capacitor overvoltage protection
if (systemStatus.capacitorVoltage > 800) {
SystemShutdown();
systemStatus.faultCode = ERROR_CAPACITOR_OVERVOLTAGE;
faultHistory[faultIndex].faultCode = systemStatus.faultCode;
faultIndex = (faultIndex + 1) % FAULT_HISTORY_SIZE;
DisplayErrorMessage(systemStatus.faultCode);
while(1);
}
// Board overtemperature protection
if (systemStatus.temperature > 850) {
SystemShutdown();
systemStatus.faultCode = ERROR_BOARD_OVERTEMP;
faultHistory[faultIndex].faultCode = systemStatus.faultCode;
faultIndex = (faultIndex + 1) % FAULT_HISTORY_SIZE;
DisplayErrorMessage(systemStatus.faultCode);
while(1);
}
// PV overvoltage protection
if (adcValues[0] > 1300) {
SystemShutdown();
systemStatus.faultCode = ERROR_PV_OVERVOLTAGE;
faultHistory[faultIndex].faultCode = systemStatus.faultCode;
faultIndex = (faultIndex + 1) % FAULT_HISTORY_SIZE;
DisplayErrorMessage(systemStatus.faultCode);
while(1);
}
// Output overvoltage protection
if (adcValues[2] > 800) {
SystemShutdown();
systemStatus.faultCode = ERROR_OUTPUT_OVERVOLTAGE;
faultHistory[faultIndex].faultCode = systemStatus.faultCode;
faultIndex = (faultIndex + 1) % FAULT_HISTORY_SIZE;
DisplayErrorMessage(systemStatus.faultCode);
while(1);
}
// Output undervoltage protection
if (adcValues[2] < MIN_OUTPUT_VOLTAGE) {
SystemShutdown();
systemStatus.faultCode = ERROR_OUTPUT_UNDERVOLTAGE;
faultHistory[faultIndex].faultCode = systemStatus.faultCode;
faultIndex = (faultIndex + 1) % FAULT_HISTORY_SIZE;
DisplayErrorMessage(systemStatus.faultCode);
while(1);
}
// Overload protection
if (adcValues[3] > 950) {
SystemShutdown();
systemStatus.faultCode = ERROR_OVERLOAD;
faultHistory[faultIndex].faultCode = systemStatus.faultCode;
faultIndex = (faultIndex + 1) % FAULT_HISTORY_SIZE;
DisplayErrorMessage(systemStatus.faultCode);
while(1);
}
// Inrush current protection
if (adcValues[3] > 1000 && systemStatus.softStartCounter < 20) {
SystemShutdown();
systemStatus.faultCode = ERROR_INRUSH_CURRENT;
faultHistory[faultIndex].faultCode = systemStatus.faultCode;
faultIndex = (faultIndex + 1) % FAULT_HISTORY_SIZE;
DisplayErrorMessage(systemStatus.faultCode);
while(1);
}
// Surge current protection
if (adcValues[3] > 800 && systemStatus.softStartCounter < 350) {
SystemShutdown();
systemStatus.faultCode = ERROR_SURGE_CURRENT;
faultHistory[faultIndex].faultCode = systemStatus.faultCode;
faultIndex = (faultIndex + 1) % FAULT_HISTORY_SIZE;
DisplayErrorMessage(systemStatus.faultCode);
while(1);
}
// Voltage drop protection
if (adcValues[2] < 400 && adcValues[3] > 800) {
SystemShutdown();
systemStatus.faultCode = ERROR_VOLTAGE_DROP;
faultHistory[faultIndex].faultCode = systemStatus.faultCode;
faultIndex = (faultIndex + 1) % FAULT_HISTORY_SIZE;
DisplayErrorMessage(systemStatus.faultCode);
while(1);
}
// Mechanical stress protection
if (adcValues[3] > 900 && adcValues[2] > 700) {
SystemShutdown();
systemStatus.faultCode = ERROR_MECHANICAL_STRESS;
faultHistory[faultIndex].faultCode = systemStatus.faultCode;
faultIndex = (faultIndex + 1) % FAULT_HISTORY_SIZE;
DisplayErrorMessage(systemStatus.faultCode);
while(1);
}
// Power rating protection
if (systemStatus.systemConfig.powerRating < 1 || systemStatus.systemConfig.powerRating > 30) {
SystemShutdown();
systemStatus.faultCode = ERROR_POWER_RATING;
faultHistory[faultIndex].faultCode = systemStatus.faultCode;
faultIndex = (faultIndex + 1) % FAULT_HISTORY_SIZE;
DisplayErrorMessage(systemStatus.faultCode);
while(1);
}
// IGBT suitability protection
if (igbtDatabase[systemStatus.systemConfig.igbtModel].recommendedKW == 0) {
SystemShutdown();
systemStatus.faultCode = ERROR_IGBT_SUITABILITY;
faultHistory[faultIndex].faultCode = systemStatus.faultCode;
faultIndex = (faultIndex + 1) % FAULT_HISTORY_SIZE;
DisplayErrorMessage(systemStatus.faultCode);
while(1);
}
}
void HandleAudioAlerts(void) {
// Audio alerts for fault conditions
if (systemStatus.faultCode != ERROR_NONE) {
if (!systemStatus.beepActive) {
GenerateBeep(200); // Warning beep
systemStatus.beepActive = 1;
}
}
}
void GenerateBeep(unsigned int duration) {
// Generate beep on RB6
LATBbits.LATB6 = 1; // Beeper on
__delay32(FCY * duration / 1000);
LATBbits.LATB6 = 0; // Beeper off
}
void DisplayErrorMessage(ErrorCode error) {
// Display error message based on error code
switch(error) {
case ERROR_IGBT_OVERCURRENT:
GenerateBeep(500);
// Display "IGBT Overcurrent" on display
break;
case ERROR_IGBT_OVERTEMP:
GenerateBeep(500);
// Display "IGBT Overtemperature" on display
break;
case ERROR_IGBT_SHORT_CIRCUIT:
GenerateBeep(500);
// Display "IGBT Short Circuit" on display
break;
case ERROR_TLPC_COMMUNICATION:
GenerateBeep(500);
// Display "TLPC Communication Error" on display
break;
case ERROR_TLPC_TIMEOUT:
GenerateBeep(500);
// Display "TLPC Timeout" on display
break;
case ERROR_CAPACITOR_OVERVOLTAGE:
GenerateBeep(500);
// Display "Capacitor Overvoltage" on display
break;
case ERROR_CAPACITOR_LEAKAGE:
GenerateBeep(500);
// Display "Capacitor Leakage" on display
break;
case ERROR_BOARD_OVERTEMP:
GenerateBeep(500);
// Display "Board Overtemperature" on display
break;
case ERROR_PV_OVERVOLTAGE:
GenerateBeep(500);
// Display "PV Overvoltage" on display
break;
case ERROR_OUTPUT_OVERVOLTAGE:
GenerateBeep(500);
// Display "Output Overvoltage" on display
break;
case ERROR_OUTPUT_UNDERVOLTAGE:
GenerateBeep(500);
// Display "Output Undervoltage" on display
break;
case ERROR_OVERLOAD:
GenerateBeep(500);
// Display "Overload" on display
break;
case ERROR_SELF_TEST_FAILED:
GenerateBeep(500);
// Display "Self-Test Failed" on display
break;
case ERROR_SOFT_START_TIMEOUT:
GenerateBeep(500);
// Display "Soft Start Timeout" on display
break;
case ERROR_OVER_CURRENT:
GenerateBeep(500);
// Display "Over Current" on display
break;
case ERROR_INRUSH_CURRENT:
GenerateBeep(500);
// Display "Inrush Current" on display
break;
case ERROR_SURGE_CURRENT:
GenerateBeep(500);
// Display "Surge Current" on display
break;
case ERROR_BYPASS_CONTACTOR:
GenerateBeep(500);
// Display "Bypass Contactor Fault" on display
break;
case ERROR_ELECTRONIC_OVERLOAD:
GenerateBeep(500);
// Display "Electronic Overload" on display
break;
case ERROR_VOLTAGE_DROP:
GenerateBeep(500);
// Display "Voltage Drop" on display
break;
case ERROR_MECHANICAL_STRESS:
GenerateBeep(500);
// Display "Mechanical Stress" on display
break;
case ERROR_SHORT_CIRCUIT:
GenerateBeep(500);
// Display "Short Circuit" on display
break;
case ERROR_CURRENT_LEAKAGE:
GenerateBeep(500);
// Display "Current Leakage" on display
break;
case ERROR_ANTI_ISLANDING:
GenerateBeep(500);
// Display "Anti-Islanding" on display
break;
case ERROR_GATE_DRIVER:
GenerateBeep(500);
// Display "Gate Driver Fault" on display
break;
case ERROR_IGBT_DESATURATION:
GenerateBeep(500);
// Display "IGBT Desaturation" on display
break;
case ERROR_IGBT_SWITCHING:
GenerateBeep(500);
// Display "IGBT Switching Error" on display
break;
case ERROR_THERMAL_RUNAWAY:
GenerateBeep(500);
// Display "Thermal Runaway" on display
break;
case ERROR_POWER_RATING:
GenerateBeep(500);
// Display "Power Rating Error" on display
break;
case ERROR_SYSTEM_CONFIG:
GenerateBeep(500);
// Display "System Config Error" on display
break;
case ERROR_PARALLEL_OPERATION:
GenerateBeep(500);
// Display "Parallel Operation Error" on display
break;
case ERROR_IGBT_SUITABILITY:
GenerateBeep(500);
// Display "IGBT Suitability Error" on display
break;
case ERROR_IGBT_SELECTION:
GenerateBeep(500);
// Display "IGBT Selection Error" on display
break;
case ERROR_IGBT_PACKAGE:
GenerateBeep(500);
// Display "IGBT Package Error" on display
break;
case ERROR_IGBT_VOLTAGE:
GenerateBeep(500);
// Display "IGBT Voltage Rating Error" on display
break;
case ERROR_IGBT_CURRENT:
GenerateBeep(500);
// Display "IGBT Current Rating Error" on display
break;
default:
GenerateBeep(100);
// Display "Unknown Error" on display
break;
}
}
void SystemShutdown(void) {
// Safe shutdown procedure
PTCONbits.PTEN = 0; // Disable PWM
LATBbits.LATB7 = 0; // Deactivate bypass contactor
LATB = 0x0000; // All outputs low
systemStatus.softStartState = SOFT_START_FAULT;
systemStatus.protectionTimer = 1; // Start protection timer
// Reset after 1 second
__delay32(FCY); // 1 second delay
asm("reset"); // Soft reset
}
void SoftStartControl(void) {
// Soft start control for heavy loads
switch (systemStatus.softStartState) {
case SOFT_START_IDLE:
// Wait for start command
PDC1 = 0;
PDC2 = 0;
break;
case SOFT_START_RAMP_UP:
// Gradually increase output voltage
if (systemStatus.softStartCounter >= systemStatus.systemConfig.softStart) {
// Ramp up complete
systemStatus.softStartState = SOFT_START_BYPASS;
systemStatus.softStartCycles++;
} else {
// Calculate ramp factor (0-100%)
unsigned int rampFactor = (systemStatus.softStartCounter * 100) / systemStatus.systemConfig.softStart;
// Apply to PWM duty cycle
int32_t pdc_val = (ptper/2) * rampFactor / 100;
// Apply limits
if (pdc_val < 10) pdc_val = 10;
if (pdc_val > (int32_t)ptper/2) pdc_val = (int32_t)ptper/2;
// Update PWM
PDC1 = (uint16_t)pdc_val;
PDC2 = (uint16_t)pdc_val;
}
break;
case SOFT_START_BYPASS:
// Full power with bypass contactor
PDC1 = ptper/2;
PDC2 = ptper/2;
LATBbits.LATB7 = 1; // Activate bypass contactor
break;
case SOFT_START_FAULT:
// Fault state - wait for reset
PDC1 = 0;
PDC2 = 0;
LATBbits.LATB7 = 0;
break;
}
}
void BypassContactorControl(void) {
// Control bypass contactor to reduce heat generation
if (systemStatus.softStartState == SOFT_START_BYPASS) {
LATBbits.LATB7 = 1; // Activate bypass contactor
} else {
LATBbits.LATB7 = 0; // Deactivate bypass contactor
}
}
void ElectronicOverloadProtection(void) {
// Built-in electronic overload protective relay
static unsigned int overloadCounter = 0;
// Get current IGBT model
IGBT_Model model = systemStatus.systemConfig.igbtModel;
// Check for overload condition based on IGBT rating
unsigned int maxCurrent = igbtDatabase[model].ic;
unsigned int threshold = (maxCurrent * 1270) / 100; // 127% of max current
// Convert to ADC value (assuming 1mΩ shunt, 100x amplifier)
unsigned int adcThreshold = (threshold * 950) / maxCurrent;
if (adcValues[3] > adcThreshold) {
overloadCounter++;
if (overloadCounter >= 60000) { // 60 seconds
systemStatus.faultCode = ERROR_ELECTRONIC_OVERLOAD;
SystemShutdown();
}
} else {
overloadCounter = 0;
}
systemStatus.electronicOverloadCounter = overloadCounter;
}
void TorqueControl(void) {
// Control torque for smoother starts and stops
static int32_t targetPDC = 0;
static int32_t currentPDC = 0;
// Calculate target torque based on load
int32_t torqueFactor = (int32_t)adcValues[3] * 100 / 950; // 0-100%
// Limit torque during start-up
if (systemStatus.softStartState == SOFT_START_RAMP_UP) {
torqueFactor = torqueFactor * systemStatus.softStartCounter / systemStatus.systemConfig.softStart;
}
// Calculate target PDC
targetPDC = (ptper/2) * torqueFactor / 100;
// Apply smooth transition
if (currentPDC < targetPDC) {
currentPDC += 10; // Accelerate
} else if (currentPDC > targetPDC) {
currentPDC -= 10; // Decelerate
}
// Apply limits
if (currentPDC < 10) currentPDC = 10;
if (currentPDC > (int32_t)ptper/2) currentPDC = (int32_t)ptper/2;
// Update PWM if not in soft start
if (systemStatus.softStartState != SOFT_START_RAMP_UP) {
PDC1 = (uint16_t)currentPDC;
PDC2 = (uint16_t)currentPDC;
}
}
void VibrationReduction(void) {
// Reduce vibration and mechanical damage
static unsigned int vibrationCounter = 0;
static unsigned int prevCurrent = 0;
unsigned int current = adcValues[3];
unsigned int currentChange = (current > prevCurrent) ? current - prevCurrent : prevCurrent - current;
// Detect rapid current changes (vibration)
if (currentChange > 200) {
vibrationCounter++;
if (vibrationCounter > 10) {
// Apply damping
PDC1 = PDC1 * 90 / 100; // Reduce power by 10%
PDC2 = PDC2 * 90 / 100;
vibrationCounter = 0;
}
} else {
vibrationCounter = 0;
}
prevCurrent = current;
}
void MechanicalStressRelief(void) {
// Relieve shock and drive train stress on startup
if (systemStatus.softStartState == SOFT_START_RAMP_UP) {
// Apply controlled acceleration
unsigned int rampTime = systemStatus.softStartCounter;
unsigned int totalRampTime = systemStatus.systemConfig.softStart;
// Use S-curve acceleration profile
// This reduces mechanical stress at start and end of acceleration
if (rampTime < totalRampTime/2) {
// First half: quadratic acceleration
unsigned int factor = (rampTime * rampTime * 100) / (totalRampTime * totalRampTime/4);
if (factor > 50) factor = 50;
PDC1 = (ptper/2) * factor / 100;
PDC2 = (ptper/2) * factor / 100;
} else {
// Second half: linear deceleration of acceleration
unsigned int factor = 50 + ((rampTime - totalRampTime/2) * 50) / (totalRampTime/2);
PDC1 = (ptper/2) * factor / 100;
PDC2 = (ptper/2) * factor / 100;
}
}
}
void UpdateOperationHours(void) {
// Update operation hours (better than 45,000 hours)
static unsigned int hourCounter = 0;
hourCounter++;
if (hourCounter >= 3600000) { // 1 hour
systemStatus.operationHours++;
hourCounter = 0;
}
}
void DetectShortCircuit(void) {
// Advanced short-circuit detection using both hardware and software methods
// Hardware detection via FLTA pin (dsPIC30F2010 Section 14.10)
// This provides the fastest response (<10µs)
if (PORTBbits.RB12 == 0) { // FLTA pin is active low
systemStatus.faultCode = ERROR_SHORT_CIRCUIT;
systemStatus.faultTimestamp = systemStatus.runtimeHours;
// Log fault
LogFault(ERROR_SHORT_CIRCUIT, systemStatus.runtimeHours);
// Immediate shutdown
SystemShutdown();
return;
}
// Software detection using ADC (secondary method)
// Check if output current exceeds threshold
if (adcValues[3] > 900) {
// Verify with voltage reading (short circuit should have low voltage)
if (adcValues[2] < 200) { // Output voltage below 100V
systemStatus.faultCode = ERROR_SHORT_CIRCUIT;
systemStatus.faultTimestamp = systemStatus.runtimeHours;
// Log fault
LogFault(ERROR_SHORT_CIRCUIT, systemStatus.runtimeHours);
// Shutdown system
SystemShutdown();
}
}
}
void DetectLeakageCurrent(void) {
// Current leakage detection using ADC channel AN5 (RB5)
// Synchronized with PWM cycles for noise immunity
// Check if leakage current exceeds threshold
if (adcValues[5] > 3) {
systemStatus.faultCode = ERROR_CURRENT_LEAKAGE;
systemStatus.faultTimestamp = systemStatus.runtimeHours;
// Log fault
LogFault(ERROR_CURRENT_LEAKAGE, systemStatus.runtimeHours);
// Disable PWM outputs
PTCONbits.PTEN = 0;
// Activate beeper
LATBbits.LATB6 = 1;
// Shutdown system
SystemShutdown();
}
}
void DetectDesaturation(void) {
// IGBT desaturation detection using KGF75N65 and TLP250
// Desaturation occurs when IGBT is commanded to turn on but collector-emitter voltage remains high
// Check desaturation detection pin (RB14)
if (PORTBbits.RB14 == 1) {
// Desaturation detected
systemStatus.igbtDesaturationCounter++;
// Get current IGBT model
IGBT_Model model = systemStatus.systemConfig.igbtModel;
// If desaturation persists for more than short circuit withstand time
if (systemStatus.igbtDesaturationCounter > igbtDatabase[model].shortCircuitWithstand) {
systemStatus.faultCode = ERROR_IGBT_DESATURATION;
systemStatus.faultTimestamp = systemStatus.runtimeHours;
// Log fault
LogFault(ERROR_IGBT_DESATURATION, systemStatus.runtimeHours);
// Immediate shutdown
SystemShutdown();
}
} else {
systemStatus.igbtDesaturationCounter = 0;
}
}
void DetectThermalRunaway(void) {
// Thermal protection based on IGBT temperature
// KGF75N65 has high temperature stable behavior
// Check IGBT temperature
if (systemStatus.igbtTemperature > 850) { // ~85°C
systemStatus.thermalProtectionCounter++;
// If high temperature persists
if (systemStatus.thermalProtectionCounter > 1000) { // 1 second
systemStatus.faultCode = ERROR_THERMAL_RUNAWAY;
systemStatus.faultTimestamp = systemStatus.runtimeHours;
// Log fault
LogFault(ERROR_THERMAL_RUNAWAY, systemStatus.runtimeHours);
// Shutdown system
SystemShutdown();
}
} else {
systemStatus.thermalProtectionCounter = 0;
}
}
void LogFault(uint16_t code, uint32_t timestamp) {
// Log fault in circular buffer
faultHistory[faultIndex].faultCode = code;
faultHistory[faultIndex].timestamp = timestamp;
faultHistory[faultIndex].adcValue = (code == ERROR_SHORT_CIRCUIT) ? adcValues[3] :
(code == ERROR_CURRENT_LEAKAGE) ? adcValues[5] : 0;
// Increment index with wrap-around
faultIndex = (faultIndex + 1) % FAULT_HISTORY_SIZE;
}
void ConfigureSystemPower(unsigned int kwRating) {
// Configure system for specified power rating (1-30KW)
if (kwRating >= 1 && kwRating <= 30) {
systemStatus.systemConfig.powerRating = kwRating;
// Set appropriate parameters based on power rating
if (kwRating <= 5) {
systemStatus.systemConfig.frequency = PWM_FREQ_14K; // Higher frequency for smaller systems
systemStatus.systemConfig.softStart = 3000; // 3 seconds soft start
} else if (kwRating <= 15) {
systemStatus.systemConfig.frequency = PWM_FREQ_14K;
systemStatus.systemConfig.softStart = 5000; // 5 seconds soft start
} else {
systemStatus.systemConfig.frequency = PWM_FREQ_7K; // Lower frequency for larger systems
systemStatus.systemConfig.softStart = 8000; // 8 seconds soft start for larger loads
}
// Update carrier frequency
systemStatus.carrierFreq = systemStatus.systemConfig.frequency;
// Reinitialize PWM with new parameters
InitializePWM();
} else {
systemStatus.faultCode = ERROR_POWER_RATING;
SystemShutdown();
}
}
void HandleParallelOperation(void) {
// Handle parallel operation for higher power systems
if (systemStatus.systemConfig.isParallel) {
// Master-slave synchronization
if (systemStatus.systemConfig.masterSlave == 0) {
// Master unit - generate sync signal
if (systemStatus.parallelSyncCounter >= 1000) { // 1 second
LATBbits.LATB11 = 1; // Send sync pulse
__delay32(FCY/1000); // 1ms pulse
LATBbits.LATB11 = 0;
systemStatus.parallelSyncCounter = 0;
}
} else {
// Slave unit - synchronize to master
if (PORTBbits.RB10 == 1) {
// Sync pulse received - align phase
gridPhase = 0;
}
}
}
}
void UpdateSystemEfficiency(void) {
// Calculate and update system efficiency
static unsigned long prevInputEnergy = 0;
static unsigned long prevOutputEnergy = 0;
static unsigned int efficiencyCounter = 0;
efficiencyCounter++;
if (efficiencyCounter >= 1000) { // 1 second
// Calculate energy in and out
unsigned long inputEnergy = adcValues[0] * adcValues[1]; // PV power
unsigned long outputEnergy = adcValues[2] * adcValues[3]; // Output power
// Calculate efficiency
if (inputEnergy > 0) {
systemStatus.systemEfficiency = (outputEnergy * 100) / inputEnergy;
} else {
systemStatus.systemEfficiency = 0;
}
// Limit to reasonable values
if (systemStatus.systemEfficiency > 100) {
systemStatus.systemEfficiency = 100;
}
prevInputEnergy = inputEnergy;
prevOutputEnergy = outputEnergy;
efficiencyCounter = 0;
}
}
void SelectIGBTModel(IGBT_Model model) {
// Select IGBT model for the system
if (model >= 0 && model < 6) {
systemStatus.systemConfig.igbtModel = model;
// Validate the selection
ValidateIGBTSelection();
}
}
void ValidateIGBTSelection(void) {
// Validate IGBT selection based on system requirements
IGBT_Model model = systemStatus.systemConfig.igbtModel;
// Check if IGBT is suitable for solar applications
if (igbtDatabase[model].recommendedKW == 0) {
systemStatus.faultCode = ERROR_IGBT_SUITABILITY;
return;
}
// Check if IGBT voltage rating is sufficient for system
if (igbtDatabase[model].vces < 600) {
systemStatus.faultCode = ERROR_IGBT_VOLTAGE;
return;
}
// Check if IGBT current rating is sufficient for system power
unsigned int requiredCurrent = (systemStatus.systemConfig.powerRating * 1000) / 230;
if (igbtDatabase[model].ic < requiredCurrent) {
systemStatus.faultCode = ERROR_IGBT_CURRENT;
return;
}
// Check package type
if (strcmp(igbtDatabase[model].package, "Module") == 0) {
// Module packages are preferred for high power applications
systemStatus.igbtHealth = 100;
} else {
// TO-247 or TO-264 packages
systemStatus.igbtHealth = 75;
}
// Test passed
componentTestResults.igbtSelectionTest = 1;
}
void CalculateIGBTLosses(void) {
// Calculate IGBT switching and conduction losses
static unsigned int lossCounter = 0;
lossCounter++;
if (lossCounter >= 1000) { // 1 second
// Get current IGBT model
IGBT_Model model = systemStatus.systemConfig.igbtModel;
// Calculate switching losses
// Esw = switching energy * switching frequency
systemStatus.igbtSwitchingLoss = (igbtDatabase[model].esw * systemStatus.carrierFreq) / 1000000;
// Calculate conduction losses
// Pcond = Vce(sat) * Ic * duty cycle
unsigned int currentADC = adcValues[3];
float current = (currentADC * 75.0) / 950.0; // Convert ADC to amps
systemStatus.igbtConductionLoss = (unsigned int)(igbtDatabase[model].vcesat * current);
lossCounter = 0;
}
}
void DisplayIGBTInfo(void) {
// Display IGBT information via UART
IGBT_Model model = systemStatus.systemConfig.igbtModel;
char buffer[100];
// Send IGBT model information
sprintf(buffer, "IGBT Model: %s\r\n", igbtDatabase[model].model);
// Send via UART
sprintf(buffer, "Vces: %dV\r\n", igbtDatabase[model].vces);
// Send via UART
sprintf(buffer, "Ic: %dA\r\n", igbtDatabase[model].ic);
// Send via UART
sprintf(buffer, "Vce(sat): %.1fV\r\n", igbtDatabase[model].vcesat);
// Send via UART
sprintf(buffer, "Esw: %dµJ\r\n", igbtDatabase[model].esw);
// Send via UART
sprintf(buffer, "Package: %s\r\n", igbtDatabase[model].package);
// Send via UART
sprintf(buffer, "Has Diode: %s\r\n", igbtDatabase[model].hasDiode ? "Yes" : "No");
// Send via UART
sprintf(buffer, "Price: %d PKR\r\n", igbtDatabase[model].pricePKR);
// Send via UART
sprintf(buffer, "Suitability: %s\r\n", igbtDatabase[model].suitability);
// Send via UART
}
void HandleMotorLoad(void) {
// Improved motor load handling
static unsigned int motorLoadCounter = 0;
static unsigned int prevCurrent = 0;
unsigned int current = adcValues[3];
// Detect sudden current increase (motor startup)
if (current > prevCurrent + 200) {
motorLoadCounter = 1000; // 1 second motor load mode
}
if (motorLoadCounter > 0) {
motorLoadCounter--;
// Adjust VMPP during motor load
vmpp += 10;
if (vmpp > 1300) vmpp = 1300;
}
prevCurrent = current;
}
void AdjustDeadTime(void) {
// Adjustable dead time (1088-2000ns as per request)
// dsPIC30F2010 datasheet specifies dead time resolution
unsigned int dtValue = (systemStatus.deadTime - DEADTIME_MIN) / 16;
if (dtValue > 57) dtValue = 57; // Max 2000ns
// Configure dead time for complementary PWM
DTCON1bits.DTAPS = 0; // 1:1 prescaler
DTCON1bits.DTMPS = 0; // Use PWM prescaler
DTCON2 = dtValue; // Dead time value
// Enable dead time
DTCON1bits.DTEN = 1;
}
void HandleMenuSystem(void) {
// Two-button menu access
static unsigned int button1State = 1;
static unsigned int button2State = 1;
static unsigned int button1Pressed = 0;
static unsigned int button2Pressed = 0;
unsigned int currentButton1 = PORTBbits.RB0;
unsigned int currentButton2 = PORTBbits.RB1;
// Detect button presses
if (currentButton1 == 0 && button1State == 1) {
button1Pressed = 1;
systemStatus.lastButtonPress = 1;
}
if (currentButton2 == 0 && button2State == 1) {
button2Pressed = 1;
systemStatus.lastButtonPress = 2;
}
// Enter menu with both buttons
if (button1Pressed && button2Pressed) {
systemStatus.menuActive = !systemStatus.menuActive;
systemStatus.menuTimer = 0;
if (systemStatus.menuActive) {
GenerateBeep(100); // Entry beep
} else {
GenerateBeep(50); // Exit beep
}
button1Pressed = 0;
button2Pressed = 0;
}
// Menu navigation
if (systemStatus.menuActive) {
if (systemStatus.lastButtonPress == 1) {
// Cycle through modulation modes
systemStatus.modMode = (systemStatus.modMode + 1) % 3;
GenerateBeep(50);
__delay32(FCY); // Debounce
}
if (systemStatus.lastButtonPress == 2) {
// Toggle carrier frequency between 14kHz and 7kHz
systemStatus.carrierFreq = (systemStatus.carrierFreq == PWM_FREQ_7K) ?
PWM_FREQ_14K : PWM_FREQ_7K;
GenerateBeep(50);
__delay32(FCY);
}
systemStatus.lastButtonPress = 0;
}
button1State = currentButton1;
button2State = currentButton2;
}
void CalibratePVCurrent(void) {
// PV current calibration
static float calibratedPVCurrent = 0;
static float alpha = 0.95;
float rawCurrent = adcValues[1];
float correctedCurrent = rawCurrent * 1.025; // Calibration factor
// Low-pass filter
calibratedPVCurrent = alpha * calibratedPVCurrent + (1-alpha) * correctedCurrent;
adcValues[1] = (unsigned int)calibratedPVCurrent;
}
void CalibrateOutputCurrent(void) {
// Output current calibration
static float calibratedOutputCurrent = 0;
static float alpha = 0.95;
float rawCurrent = adcValues[3];
float correctedCurrent = rawCurrent * 0.985; // Calibration factor
// Low-pass filter
calibratedOutputCurrent = alpha * calibratedOutputCurrent + (1-alpha) * correctedCurrent;
adcValues[3] = (unsigned int)calibratedOutputCurrent;
}
void SaveConfiguration(void) {
// Save system configuration to EEPROM
unsigned int address = 0x7F0000;
// Erase EEPROM location
NVMCON = 0x4003; // Word erase for data EEPROM
NVMADRU = address >> 16;
NVMADR = address & 0xFFFF;
NVMKEY = 0x55;
NVMKEY = 0xAA;
NVMCONbits.WR = 1;
// Wait for erase to complete
while(NVMCONbits.WR);
// Write configuration data
NVMCON = 0x4001; // Word program for data EEPROM
NVMADRU = address >> 16;
NVMADR = address & 0xFFFF;
// Write system configuration
*((unsigned int*)address) = systemStatus.systemConfig.powerRating;
address += 2;
*((unsigned int*)address) = systemStatus.systemConfig.isParallel;
address += 2;
*((unsigned int*)address) = systemStatus.systemConfig.masterSlave;
address += 2;
*((unsigned int*)address) = systemStatus.systemConfig.frequency;
address += 2;
*((unsigned int*)address) = systemStatus.systemConfig.modulation;
address += 2;
*((unsigned int*)address) = systemStatus.systemConfig.softStart;
address += 2;
*((unsigned int*)address) = systemStatus.systemConfig.igbtModel;
// Program the data
NVMKEY = 0x55;
NVMKEY = 0xAA;
NVMCONbits.WR = 1;
// Wait for write to complete
while(NVMCONbits.WR);
// Generate beep to indicate save complete
GenerateBeep(100);
}
void LoadConfiguration(void) {
// Load system configuration from EEPROM
unsigned int address = 0x7F0000;
// Read configuration data
systemStatus.systemConfig.powerRating = *((unsigned int*)address);
address += 2;
systemStatus.systemConfig.isParallel = *((unsigned int*)address);
address += 2;
systemStatus.systemConfig.masterSlave = *((unsigned int*)address);
address += 2;
systemStatus.systemConfig.frequency = *((unsigned int*)address);
address += 2;
systemStatus.systemConfig.modulation = *((unsigned int*)address);
address += 2;
systemStatus.systemConfig.softStart = *((unsigned int*)address);
address += 2;
systemStatus.systemConfig.igbtModel = *((unsigned int*)address);
// Validate loaded configuration
if (systemStatus.systemConfig.powerRating < 1 || systemStatus.systemConfig.powerRating > 30) {
systemStatus.systemConfig.powerRating = SYSTEM_POWER_RATING;
}
if (systemStatus.systemConfig.igbtModel >= 6) {
systemStatus.systemConfig.igbtModel = IGBT_KGF75N65;
}
}
void UpdateOutputWaveform(void) {
// This function is now controlled by SoftStartControl
// It's kept for backward compatibility
if (systemStatus.softStartState == SOFT_START_IDLE ||
systemStatus.softStartState == SOFT_START_FAULT) {
PDC1 = 0;
PDC2 = 0;
}
// Otherwise, SoftStartControl handles the PWM updates
}