// Automatically generated C++ file on Mon Dec 11 12:54:23 2023 // // To build with Digital Mars C++ Compiler: // // dmc -mn -WD epwm.cpp kernel32.lib #include #include #include #include #include #define PI(y_prev,x,x_prev,kp,kits) y_prev+kp*(x-x_prev)+kits*x #define TRUNC_METHOD //it doubles the simulation time union uData { bool b; char c; unsigned char uc; short s; unsigned short us; int i; unsigned int ui; float f; double d; long long int i64; unsigned long long int ui64; char *str; unsigned char *bytes; }; // int DllMain() must exist and return 1 for a process to load the .DLL // See https://docs.microsoft.com/en-us/windows/win32/dlls/dllmain for more information. int __stdcall DllMain(void *module, unsigned int reason, void *reserved) { return 1; } void display(const char *fmt, ...) { // for diagnostic print statements msleep(30); fflush(stdout); va_list args = { 0 }; va_start(args, fmt); vprintf(fmt, args); va_end(args); fflush(stdout); msleep(30); } void bzero(void *ptr, unsigned int count) { unsigned char *first = (unsigned char *) ptr; unsigned char *last = first + count; while(first < last) *first++ = '\0'; } // #undef pin names lest they collide with names in any header file(s) you might include. #undef vout #undef isense #undef vout_ref #undef ilim //#undef carrier //was left from level 2 //#undef pwm //was left from level 2 #undef pwmhi #undef pwmlo #undef duty #undef iref #undef out1 #undef out2 struct sEPWM { // declare the structure here long long int xcntr; double maxstep; double t_prev; double trg1; // trigger cmp at rising double trg2; // trigger at half period double trg3; // trigger cmp at falling double trg4; // trigger at full period double xpeak; double xcmp; double trgdelay; double pwm; double pwm_delay; bool pwm_trigger; double verror; double verror_prev; double iref; double ierror; double ierror_prev; double out; }; extern "C" __declspec(dllexport) void epwm(struct sEPWM **opaque, double t, union uData *data) { const double mcu_clk = 100E6; // const double peak = 500;//200 //"peak" is the max ramp value (triangular)-->f=mcu_clk/(2*peak) const double pwm_peak = 500; //const double dtime = 50; const double dtime_s = 500E-9; //==================================== // Control Variable ================== //==================================== //const double vin = 48; //const double vout_ref = 14; const double i_peak = 10; const double KP_v = 3; //1.39213; const double KI_v = 0.5; // 0.1623; const double KP_i = 3; //1.84017; const double KI_i = 0.5; //0.128283; double vout = data[0].d; // input double isense = data[1].d; // input double ilim = data[2].d; // input double vout_ref= data[3].d; // input double &pwmhi = data[4].d; // output double &pwmlo = data[5].d; // output double &duty = data[6].d; // output double &iref = data[7].d; // output double &out1 = data[8].d; // output double &out2 = data[9].d; // output if(!*opaque) { *opaque = (struct sEPWM *) malloc(sizeof(struct sEPWM)); bzero(*opaque, sizeof(struct sEPWM)); struct sEPWM *inst = *opaque; pwmhi = 0; pwmlo = 0; inst->xpeak= pwm_peak; inst->xcmp = 0; inst->trg1 = 2*inst->xpeak/mcu_clk; inst->trg2 = 2*inst->xpeak/mcu_clk; inst->trg3 = 2*inst->xpeak/mcu_clk; inst->trg4 = 2*inst->xpeak/mcu_clk; inst->maxstep = 1e-9; } struct sEPWM *inst = *opaque; // Implement module evaluation code here: inst->pwm_trigger = false; if((inst->t_prev <= inst->trg4)&&(t >= inst->trg4)) { inst->xcntr++; inst->xpeak= pwm_peak; inst->xcmp = round(inst->out); inst->trg1 = inst->trg4 + inst->xcmp/mcu_clk; inst->trg2 = inst->trg4 + inst->xpeak/mcu_clk; inst->trg3 = inst->trg4 + (2*inst->xpeak - inst->xcmp)/mcu_clk; inst->trg4 = inst->trg4 + 2*inst->xpeak/mcu_clk; inst->maxstep = pwm_peak/mcu_clk; //=================================================================== // control algorithm interrupt - START ============================== //=================================================================== if(ilim > i_peak) ilim = i_peak; if(ilim < 0) ilim = 0; //PI of voltage error: define iref inst->verror = vout_ref - vout; inst->iref = PI(inst->iref, inst->verror, inst->verror_prev, KP_v, KI_v); //clamping //if(inst->iref > 20) inst->iref = 20; //if(inst->iref < 0) inst->iref = 0; if(inst->iref > ilim) inst->iref = ilim; if(inst->iref < 0) inst->iref = 0; inst->verror_prev = inst->verror; //PI of current error inst->ierror = inst->iref - isense; inst->out = PI(inst->out, inst->ierror, inst->ierror_prev, KP_i, KI_i); if(inst->out > pwm_peak) inst->out = pwm_peak; if(inst->out < 0) inst->out = 0; inst->ierror_prev = inst->ierror; duty = inst->out; iref = inst->iref; //=================================================================== // control algorithm interrupt - END ============================== //=================================================================== } const double _pwm = inst->pwm; if((inst->t_prev <= inst->trg2)&&(t >= inst->trg2)) { inst->xcntr++; } if(t < inst->trg2) { if((inst->t_prev <= inst->trg1)&&(t >= inst->trg1)) { inst->xcntr++; inst->pwm = 0; inst->pwm_trigger = true; } } else { if((inst->t_prev <= inst->trg3)&&(t >= inst->trg3)) { inst->xcntr++; inst->pwm = 1; inst->pwm_trigger = true; } } if(inst->pwm!=_pwm) { inst->trgdelay = t + dtime_s;//dtime/mcu_clk; } if((inst->t_prev <= inst->trgdelay)&&(t >= inst->trgdelay)) { inst->xcntr++; inst->pwm_delay = inst->pwm; inst->pwm_trigger = true; } pwmhi = inst->pwm*inst->pwm_delay; pwmlo = (1 - inst->pwm)*(1 - inst->pwm_delay); inst->t_prev = t; } extern "C" __declspec(dllexport) double MaxExtStepSize(struct sEPWM *inst) { return inst->maxstep; // implement a good choice of max timestep size that depends on struct sEPWM } //#define TRUNC_METHOD extern "C" __declspec(dllexport) void Trunc(struct sEPWM *inst, double t, union uData *data, double *timestep) { // limit the timestep to a tolerance if the circuit causes a change in struct sEPWM const double ttol = 10e-9; #ifdef TRUNC_METHOD if(*timestep > ttol) { double &pwmhi = data[4].d; // output double &pwmlo = data[5].d; // output double &duty = data[6].d; // output double &iref = data[7].d; // output double &out1 = data[8].d; // output double &out2 = data[9].d; // output // Save output vector const double _pwmhi = pwmhi ; const double _pwmlo = pwmlo ; const double _duty = duty ; const double _iref = iref ; const double _out1 = out1 ; const double _out2 = out2 ; struct sEPWM tmp = *inst; epwm(&(&tmp), t, data); if(tmp.xcntr != inst->xcntr) // implement a meaningful way to detect if the state has changed *timestep = ttol; // Restore output vector pwmhi = _pwmhi ; pwmlo = _pwmlo ; duty = _duty ; iref = _iref ; out1 = _out1 ; out2 = _out2 ; } #else struct sEPWM tmp = *inst; if(t < inst->trg1){if(*timestep > (inst->trg1 - t)){*timestep = (inst->trg1 - t);}} if(t < inst->trg2){if(*timestep > (inst->trg2 - t)){*timestep = (inst->trg2 - t);}} if(t < inst->trg3){if(*timestep > (inst->trg3 - t)){*timestep = (inst->trg3 - t);}} if(t < inst->trg4){if(*timestep > (inst->trg4 - t)){*timestep = (inst->trg4 - t);}} if(t < inst->trgdelay){if(*timestep > (inst->trgdelay - t)){*timestep = (inst->trgdelay - t);}} if(inst->pwm_trigger) { if(*timestep > ttol) *timestep = ttol; } #endif } extern "C" __declspec(dllexport) void Destroy(struct sEPWM *inst) { free(inst); }