/*
** Copyright 2021 Tjitte van der Ploeg tjitte@tpee.nl
**
** This file is part of the OpenBoost firmware.
** The OpenBoost firmware firmware is free software: you can redistribute
** it and/or modify it under the terms of the GNU General Public License
** as published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version. The VESC firmware is
** distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
** without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
** PARTICULAR PURPOSE. See the GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License along
** with this program. If not, see .
*/
#include
#include "control.h"
#include "testing.h"
#include "crc.h"
#include "string.h"
#define METER_EMA 0.95f
#define EMA(_A_, _B_, _F_) _A_ = (_F_ * _A_) + ((1 - _F_) * _B_)
#define pi 3.14159265359f
ConverterPhase_t phase;
ConverterMueasurements_t meter;
ConverterMueasurements_t meter_slow;
ConverterScope_t scope;
CalibrationData_t cal;
ConverterSettings_t settings;
float Ts; //Sample period, s
float ControllerR;
extern uint32_t adc5data[6];
modTestingSimState_t simstate_c;
void control_init(const ConverterSettings_t* s, const CalibrationData_t * c) {
//Check if settings are valid.
if(control_check_parameters(s,c)){
phase.fault = Converter_ConfigError;
}
//Even though there is a config fault, push on anyway. Do not enable output.
settings=*s;
cal=*c;
phase.HSEpin = PHSEN_Pin;
phase.HSEport = PHSEN_GPIO_Port;
phase.PENpin = PEN_Pin;
phase.PENport = PEN_GPIO_Port;
phase.timerindex = HRTIM_TIMERINDEX_TIMER_B;
phase.LimLEDpin = LED1_Pin;
phase.LimLEDport= LED1_GPIO_Port;
phase.Vsp = 10000;
phase.Vhighlim = settings.HighSideVoltageLimitSoft;
phase.Iindlim = settings.LowSideCurrentMaxLimitSoft;
phase.Ihighlim = settings.HighSideCurrentLimitSoft;
modConverterPWMOutputDisable();
pwm_init(HW_SWITCHINGFREQUENCY, HW_CONTROLLERFREQUENCY, HW_DEADTIMERISING, HW_DEADTIMEFALLING, HW_ADC_DELAY);
analog_init();
Ts = pwm_GetControllerPeriod();
#ifdef SIMULATION
pwm_init(HW_SWITCHINGFREQUENCY*0.5, HW_CONTROLLERFREQUENCY*0.5, HW_DEADTIMERISING, HW_DEADTIMEFALLING, HW_ADC_DELAY);
#endif
ControllerR = sqrtf(HW_L/HW_CLOW)/ HW_Q - HW_RLINT;
HAL_Delay(100);
}
float t;
void control_controlloop(ConverterPhase_t* p){
//LED3_GPIO_Port->BSRR = LED3_Pin;
//LED3_GPIO_Port->BRR = LED3_Pin;
//LED3_GPIO_Port->BSRR = LED3_Pin;
bool TemperatureLimited = false;
bool OutputCurrentLimited = false;
bool OutputVoltageLimited = false;
//Ipv observer
float dvdt = (p->Vlow - p->Vlowm1) / (float)Ts;
float Ilowest = dvdt*HW_CLOW + (p->Iind + p->Iindm1)/2.0f;
p->Vlowm1 = p->Vlow;
p->Iindm1 = p->Iind;
EMA(p->Ilow, Ilowest, CURRENT_PV_FORGETING_FACTOR);
//Time delay compensation
if (p->pwm_enabled){
p->Iind_pred = p->Iind // Zeroth order taylor term
+ HW_delay/HW_L*(p->Vlow - (1.0f-p->dutycycle)*p->Vhigh - HW_RLINT*p->Iind) //1st order taylor term
+ HW_delay*HW_delay/(HW_L*HW_CLOW)*(p->Ilow - p->Iind); //second order (reduced) taylor term.
p->Vhigh_pred = p->Vhigh;// + HW_delay/HW_CHIGH*(p->dutycycle*p->Iind - p->Ihigh);
p->Vlow_pred = p->Vlow;// + HW_delay/HW_CLOW *(p->Ilow - p->Iind);
}else{
p->Iind_pred = p->Iind
+ 0.5f*HW_delay/HW_L*(p->Vlow - (1.0f-p->dutycycle)*p->Vhigh - HW_RLINT*p->Iind); //1st order taylor term
p->Vhigh_pred = p->Vhigh;// + HW_delay/HW_CHIGH*(- p->Ihigh);
p->Vlow_pred = p->Vlow; // + HW_delay/HW_CLOW *(p->Ilow);
}
//These variables need to be set by the controller.
float Vn = 0.0f;
float Ilim = 0.0f;
#ifdef HW_TOPOLOGY_BOOST
float Vnn = p->Vsp - (p->Ilow *(ControllerR+HW_RLINT));
Ilim = p->Iindlim;
//Temperature de-rating
if (p->TemperatureHeatsink > settings.TemperatureLimitStart){
t = (p->TemperatureHeatsink - settings.TemperatureLimitStart)/(settings.TemperatureLimitEnd - settings.TemperatureLimitStart);
Ilim = p->Iindlim * (1 - t);
if (Ilim < 0){
Ilim = 0;
}
TemperatureLimited = true;
}
//Output voltage limit
float Ioutlim = HW_KLIM_VOUT*HW_CHIGH*(p->Vhighlim - p->Vhigh_pred)/(Ts);// + 0.5f*p->Ihigh;
if(Ioutlim > p->Ihighlim){
Ioutlim = p->Ihighlim;
OutputCurrentLimited = true;
}
float Ilimmaxvout = Ioutlim/(1.0f-p->dutycycle);
//Limit the output current loop gain at high duty cycles (low input voltages).
if(p->dutycycle > HW_IOUT_MAXDUTY){
Ilimmaxvout = Ioutlim/(1.0f-HW_IOUT_MAXDUTY);
}
//Limit the input current to higher than 0, to prevent current under-shoot.
//if(Ilimmaxvout < 0.0){
// Ilimmaxvout = 0.0f;
//}
if(Ilim > Ilimmaxvout){
Ilim = Ilimmaxvout;
OutputVoltageLimited = true;
}
p->Ilimvout = Ilim / 1000.0f;
//Current limit
//float Vnlimup = -p->Vlow - (settings.RLint * p->Iind) + ((settings.Klim * settings.L /Ts)*(settings.PhaseCurrentMin - p->Iind) );
//float Vnlimlo = -p->Vlow - (settings.RLint * p->Iind) + ((settings.Klim * settings.L /Ts)*(Ilim - p->Iind) );
float Vnlimup = +p->Vlow_pred - (HW_RLINT * p->Iind_pred) - (HW_KLIM*HW_L*(settings.LowSideCurrentMinLimitSoft - p->Iind_pred)/Ts)
+ Ts/(2*HW_CLOW)*(p->Ilow - p->Iind_pred);
float Vnlimlo = +p->Vlow_pred - (HW_RLINT * p->Iind_pred) - (HW_KLIM*HW_L*(Ilim - p->Iind_pred)/Ts )
+ Ts/(2*HW_CLOW)*(p->Ilow - p->Iind_pred);
//Reset the mode variable.
PhaseMode_t newmode = PhaseMode_CIV;
//Unlimited controller
Vn = Vnn + (p->Iind_pred*ControllerR);
//Limit Vnn to limit phase current
if(Vn > Vnlimup){
Vn = Vnlimup;
newmode = PhaseMode_MinInputCurrent;
}
if(Vn < Vnlimlo) {
Vn = Vnlimlo;
newmode = PhaseMode_CIC;
}
//Select correct operating mode
if(p->mode == PhaseMode_CIC){
if(TemperatureLimited){
newmode = PhaseMode_TD;
}
if(OutputVoltageLimited){
if(OutputCurrentLimited)newmode = PhaseMode_COC;
else newmode = PhaseMode_COV;
}
}
p->mode = newmode;
#elif defined(HW_TOPOLOGY_BUCK)
//p->Vsp = 50000;
PhaseMode_t newmode = PhaseMode_CIV;
//Limit low boost factor.
volatile float vsp = p->Vsp;
if (vsp < (p->Vlow*1.05)){
vsp = (p->Vlow*1.05);
p->mode = PhaseMode_MinInputVoltage;
}
volatile float Ioutsp = HW_KLIM_VOUT*HW_CHIGH*(vsp - p->Vhigh_pred)/(Ts);
volatile float Isp = Ioutsp +p->Ihigh*(vsp/p->Vlow_pred);
p->Ilimvout = (-0.5f*HW_KLIM*HW_CLOW*(settings.LowSideVoltageLimitSoft - p->Vlow)/Ts) +p->Ilow;
Ilim = p->Iindlim;
//Temperature de-rating
if (p->TemperatureHeatsink > settings.TemperatureLimitStart){
t = (p->TemperatureHeatsink - settings.TemperatureLimitStart)/(settings.TemperatureLimitEnd - settings.TemperatureLimitStart);
Ilim = p->Iindlim * (1 - t);
if (Ilim > 0){
Ilim = 0;
}
TemperatureLimited = true;
}
if (Isp > -settings.LowSideCurrentMinLimitSoft){
Isp = -settings.LowSideCurrentMinLimitSoft;
newmode = PhaseMode_MinInputCurrent;
}
if (Isp < -Ilim ){
Isp = -Ilim;
newmode = PhaseMode_COC;
}
if (Isp < p->Ilimvout){
Isp = p->Ilimvout;
newmode = PhaseMode_COV;
}
if(p->mode == PhaseMode_CIC){
if(TemperatureLimited){
newmode = PhaseMode_TD;
}
}
p->mode = newmode;
//Vn = +p->Vlow_pred - (HW_RLINT * p->Iind_pred) - (HW_KLIM*HW_L*(Isp - p->Iind_pred)/Ts )
// + Ts/(2*HW_CLOW)*(p->Ilow - p->Iind_pred);
Vn = +p->Vlow - (HW_KLIM*HW_L/Ts*(Isp - p->Iind));
#endif
float Dn = Vn / p->Vhigh_pred;
if (Dn > 0.999f){
Dn = 0.999f;
}
if (Dn < 0.001f){
Dn = 0.001f;
}
p->dutycycle = 1.0f-Dn;
//If the output is smaller then the input voltage, make sure the duty cycle does not drop to zero.
if((p->Vlow*1.05f) > p->Vhigh){
//if(p->dutycycle < 0.15f)p->dutycycle = 0.15f; TODO TODO
}
//Control PWM enable. Startup disabled to calculate initial pwm, then depending on output current.
//If the upper current limit is lower then the lower current limit, set the duty cycle to 0
//This ensure full shutdown when the power level gets towards zero.
bool disable_voutlim = false;
if(Ilim < 0){
p->HSEport->BRR = p->HSEpin;
p->PENport->BRR = p->PENpin;
disable_voutlim = true;
p->pwm_enabled = false;
}else{
if(Ilim > HW_IOUT_EN_HYST){
if(p->enabled){
p->pwm_enabled = true;
}
}
}
if(p->fault != Converter_OK){
modConverterPWMOutputDisable();
scope_trigger_fault();
}else{
//Set PWM
//Deadtime compensation
float dI = (p->Vlow_pred*p->dutycycle)/ (HW_SWITCHINGFREQUENCY*1e3*HW_L);
float dtcomp = 0;
if (p->Iind_pred + dI/2 > 0.0f){
dtcomp += HW_DEADTIMERISING*1e-6*HW_SWITCHINGFREQUENCY;
}
else{
dtcomp -= HW_DEADTIMERISING*1e-6*HW_SWITCHINGFREQUENCY;
}
if (p->Iind_pred - dI/2 > 0.0f){
dtcomp += HW_DEADTIMEFALLING*1e-6*HW_SWITCHINGFREQUENCY;
}
else{
dtcomp -= HW_DEADTIMEFALLING*1e-6*HW_SWITCHINGFREQUENCY;
}
pwm_setDuty(p->dutycycle + dtcomp);
if(p->pwm_enabled){
#ifndef SIMULATION
p->PENport->BSRR = p->PENpin;
#ifdef HSEN
if(p->dutycycle < 0.01f){
//Do not, ever put on the high side FET continuesly.
//e.g. when the duty cycle is zero.
p->HSEport->BRR = p->HSEpin;
}
#ifdef HW_TOPOLOGY_BOOST
else if(p->Iind > settings.PhaseHighSideEnableCurrent){
if(disable_voutlim == false){
p->HSEport->BSRR = p->HSEpin;
}
}
#elif defined HW_TOPOLOGY_BUCK
else if(disable_voutlim == false){
p->HSEport->BSRR = p->HSEpin;
}
#endif
else{
p->HSEport->BRR = p->HSEpin;
}
#else
p->HSEport->BRR = p->HSEpin;
#endif
#endif
}else{
p->HSEport->BRR = p->HSEpin;
p->PENport->BRR = p->PENpin;
}
}
//LED3_GPIO_Port->BRR = LED3_Pin;
//LED3_GPIO_Port->BRR = LED3_Pin;
//LED3_GPIO_Port->BRR = LED3_Pin;
//LED3_GPIO_Port->BRR = LED3_Pin;
//LED3_GPIO_Port->BSRR = LED3_Pin;
//Do Lower priority duties now.
//Calculate converter input and output currents
//p->Power = (p->Ihigh*p->Vhigh)*1.0e-6f;
p->PowerLow = (p->Ilow*p->Vlow)*1.0e-6f;
p->PowerHigh = (p->Ihigh*p->Vhigh)*1.0e-6f;
if(p->PowerHigh && p->PowerLow){
#ifdef HW_TOPOLOGY_BOOST
p->eff = p->PowerHigh/p->PowerLow;
#elif defined HW_TOPOLOGY_BUCK
p->eff = p->PowerLow/p->PowerHigh;
#endif
}else{
p->eff = 1.0f;
}
EMA(meter.Iind, p->Iind*0.001f,settings.meterfilterCoeficient);
EMA(meter.Ihigh, p->Ihigh*0.001f,settings.meterfilterCoeficient);
EMA(meter.Ilow, p->Ilow*0.001f,settings.meterfilterCoeficient);
EMA(meter.Vlow, p->Vlow*0.001f,settings.meterfilterCoeficient);
EMA(meter.Vhigh, p->Vhigh*0.001f,settings.meterfilterCoeficient);
EMA(meter.Eff, p->eff,settings.meterfilterCoeficient);
EMA(meter.TemperatureAmbient, p->TemperatureAmbient,settings.meterfilterCoeficient);
EMA(meter.TemperatureHeatsink, p->TemperatureHeatsink,settings.meterfilterCoeficient);
EMA(meter.PowerHigh, p->PowerHigh, settings.meterfilterCoeficient);
EMA(meter.PowerLow, p->PowerLow, settings.meterfilterCoeficient);
EMA(meter_slow.Iind, p->Iind*0.001f, SLOW_METER_COEF);
EMA(meter_slow.Ihigh, p->Ihigh*0.001f,SLOW_METER_COEF);
EMA(meter_slow.Ilow, p->Ilow*0.001f,SLOW_METER_COEF);
EMA(meter_slow.Vlow, p->Vlow*0.001f,SLOW_METER_COEF);
EMA(meter_slow.Vhigh, p->Vhigh*0.001f,SLOW_METER_COEF);
EMA(meter_slow.Eff, p->eff,SLOW_METER_COEF);
EMA(meter_slow.TemperatureAmbient, p->TemperatureAmbient,SLOW_METER_COEF);
EMA(meter_slow.TemperatureHeatsink, p->TemperatureHeatsink,SLOW_METER_COEF);
EMA(meter_slow.PowerHigh, p->PowerHigh, SLOW_METER_COEF);
EMA(meter_slow.PowerLow, p->PowerLow, SLOW_METER_COEF);
if(scope.running){
if((scope.dividerindex++ >= scope.divider) || (scope.divider <= 1)){
scope.dividerindex = 0;
for(int ch = 0; ch < CONVERTER_SCOPE_CHANNELS; ch++){
float tempval = 0.0f;
switch (scope.channel[ch].source){
case SourceIndex_Iind:
tempval = p->Iind / 1.0e3f;
break;
case SourceIndex_Ihigh:
tempval = p->Ihigh / 1.0e3f;
break;
case SourceIndex_Vlow:
tempval = p->Vlow / 1.0e3f;
break;
case SourceIndex_Vhigh:
tempval = p->Vhigh / 1.0e3f;
break;
case SourceIndex_Ilow:
tempval = p->Ilow / 1.0e3f;
break;
case SourceIndex_PowerHigh:
tempval = p->PowerHigh;
break;
case SourceIndex_PowerLow:
tempval = p->PowerLow;
break;
case SourceIndex_Eff:
tempval = p->eff;
break;
case SourceIndex_Iind_Filtered:
tempval = meter.Iind;
break;
case SourceIndex_Ihigh_Filtered:
tempval = meter.Ihigh;
break;
case SourceIndex_Vlow_Filtered:
tempval = meter.Vlow;
break;
case SourceIndex_Vhigh_Filtered:
tempval = meter.Vhigh;
break;
case SourceIndex_Ilow_Filtered:
tempval = meter.Ilow;
break;
case SourceIndex_PowerHigh_Filtered:
tempval = meter.PowerHigh;
break;
case SourceIndex_PowerLow_Filtered:
tempval = meter.PowerLow;
break;
case SourceIndex_Eff_Filtered:
tempval = meter.Eff;
break;
}
scope.channel[ch].samples[scope.writeindex] = tempval;
}
scope.writeindex++;
if (scope.writeindex >= scope.samples){
scope.writeindex = 0;
}
if(scope.trigered){
int stopindex = scope.triggerindex - scope.pretrigger;
if (stopindex < 0){
stopindex = scope.samples + stopindex;
}
if(scope.writeindex == stopindex){
scope.running = false;
}
}
}
}
//LED3_GPIO_Port->BRR = LED3_Pin;
//LED3_GPIO_Port->BRR = LED3_Pin;
//LED3_GPIO_Port->BRR = LED3_Pin;
//LED3_GPIO_Port->BRR = LED3_Pin;
//LED3_GPIO_Port->BSRR = LED3_Pin;
#ifdef SIMULATION
simstate_c = modTestingSimstep(Ts, &phase);
#endif
//LED3_GPIO_Port->BRR = LED3_Pin;
//LED3_GPIO_Port->BSRR = LED3_Pin;
}
bool control_check_parameters(ConverterSettings_t* s, CalibrationData_t * c){
bool error = false;
//Check calibration CRC
uint16_t crc = libCRCCalcCRC16((unsigned char *)c, sizeof(CalibrationData_t) - sizeof(uint16_t) - 2);
if (crc != c->calcrc){
error = true;
}
//Check Firmware hwname against stored HW name
#ifndef SIMULATION // In simulation mode, this does not matter.
if (strcmp(HW_NAME, c->HardwareName) != 0){
error = true;
}
#endif
//Check firmware verison with calibration compatibility
//Check UUID with calibraiton id, t check if calibration is done for this hardware
//float fres = sqrtf(1/(2*pi*pi*HW_L*c->Clow))*1.0e-3f;
//if(c->ControllerFrequency > 45.0f)error = true;
//if(c->ControllerFrequency < (8*fres))error = true;
//if(c->SwitchingFrequency < (5*fres))error = true;
//if(c->calibrated == false) error = true;
//if(c->Q > 2.0f)error = true;
//Check deadtime values
//if(c->DeadTimeRising > 188.0)error = true;
//if(c->DeadTimeRising < 5)error = true;
//if(c->DeadtimeFalling > 188.0)error = true;
//if(c->DeadtimeFalling < 5)error = true;
return error;
}
void control_disable(void){
phase.HSEport->BRR = phase.HSEpin;
phase.PENport->BRR = phase.PENpin;
phase.pwm_enabled = false;
phase.dutycycle = 0;
phase.enabled = false;
pwm_disable();
}
inline void modConverterPWMOutputDisable(){
#ifndef SIMULATION
phase.PENport->BRR = phase.PENpin;
phase.HSEport->BRR = phase.HSEpin;
DREN_GPIO_Port->BRR = DREN_Pin;
#endif
phase.enabled = false;
phase.pwm_enabled = false;
}
inline void modConverterPWMOutputEnable() {
//Make sure MPPT is not enabled when a fault is active.
if(phase.fault == Converter_OK){
if(settings.outputEnable){
#ifndef SIMULATION
//phase.PENport->BSRR = phase.PENpin;
DREN_GPIO_Port->BSRR = DREN_Pin;
#endif
phase.enabled = true;
//phase.pwm_enabled = true;
}else{
modConverterPWMOutputDisable();
}
}
}
float convertTemperature(uint32_t data){
float vt = ((float)data) * HW_ADCREF * 0.001f / ((float)(1<<16));
float i = ((3.24f-vt) / cal.Temperature_R);
float r = vt / i;
float inverseKelvin = (1.0f / (cal.Temperature_Ref+273.16f)) + (logf(r / cal.Temperature_R))/cal.Temperature_B;
return (1.0f / inverseKelvin) - 273.16f;
return vt;
}
float noise(float amp){
return (((float)rand()/(float)__RAND_MAX)-0.5f)*amp;
//return 0.0f;
}
void control_convert_vls(uint32_t raw){
float V = 0;
#ifdef SIMULATION
V = 1.0e3f*(simstate_c.Vlow + noise(0.05f));
#else
V = ((((float)raw) * cal.InputVoltageGain * HW_ADCREF) / (float)0x1000) + cal.InputVoltageOffset;
#endif
if(fabsf(V) > HW_LIMIT_LS_VOLTAGE_HARD){
phase.fault = Converter_InputOverVolt;
}
phase.Vlowm1 = phase.Vlow;
EMA(phase.Vlow, V , VOLTAGE_IN_FORGETING_FACTOR);
//modConverterIpvObserver(phase);
}
void control_convert_vhs(uint32_t raw){
float V = 0.0;
#ifdef SIMULATION
V = 1.0e3f*(simstate_c.Vhigh + noise(0.05f));
#else
V = ((((float)raw) * cal.OutputVoltageGain * HW_ADCREF) / (float)0x1000) + cal.OutputVoltageOffset;
#endif
if(fabsf(V) > HW_LIMIT_HS_VOLTAGE_HARD){
phase.fault = Converter_OutputOverVolt;
}
EMA(phase.Vhigh, V , VOLTAGE_OUT_FORGETING_FACTOR);
}
void control_convert_iind(uint32_t raw){
float I = 0.0;
#ifdef SIMULATION
I = 1.0e3f*(simstate_c.Iind + noise(0.05f));
#else
I = ((((float)raw-(float)0x800) * cal.InputCurrentGain *2.0f* HW_ADCREF) / (float)0x1000) + cal.InputCurrentOffset;
#endif
if(I > HW_LIMIT_LS_CURRENT_HARD){
phase.fault = Converter_InputOverCurrent;
}else if(I < -HW_LIMIT_LS_CURRENT_HARD){
phase.fault = Converter_InputUnderCurrent;
}
phase.Iind = I;
//EMA(phase.Iind,I, CURRENT_IN_FORGETING_FACTOR);
}
void control_convert_ihs(uint32_t raw){
float I = 0.0f;
#ifdef SIMULATION
I = 1.0e3f*(simstate_c.Ihigh + noise(0.05f));
#else
I = ( ((float)raw-(float)0x800) * cal.OutputCurrentGain *2.0f* (HW_ADCREF / (float)0x1000)) + cal.OutputCurrentOffset;
#endif
if (settings.DisableHighSideCurrentFault == false){
if(I > HW_LIMIT_HS_CURRENT_HARD){
phase.fault = Converter_OutputOverCurrent;
}
if(I < -HW_LIMIT_HS_CURRENT_HARD){
phase.fault = Converter_OutputOverCurrent;
}
}
EMA(phase.Ihigh,I, CURRENT_IN_FORGETING_FACTOR);
}
void convertAdc5(uint32_t* data){
EMA(phase.TemperatureMCU, __LL_ADC_CALC_TEMPERATURE((uint32_t)HW_ADCREF,data[0],LL_ADC_RESOLUTION_12B), TEMP_FORGETING_FACTOR);
EMA(phase.TemperatureHeatsink, convertTemperature(data[2]), TEMP_FORGETING_FACTOR);
EMA(phase.TemperatureAmbient, convertTemperature(data[1]), TEMP_FORGETING_FACTOR);
}
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc){
if(hadc->Instance == ADC5){
convertAdc5(&adc5data[3]);
}
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc){
if(hadc->Instance == ADC5){
convertAdc5(&adc5data[0]);
}
}
PhaseMode_t modConverterGetMode(void){
return phase.mode;
}
PhaseFault_t modConverterGetFault(void){
return phase.fault;
}
void control_set_setpoint(float v){
if (!isnan(v)){
#if defined HW_TOPOLOGY_BOOST
if(v > settings.LowSideVoltageLimitSoft)v = settings.LowSideVoltageLimitSoft;
#elif defined HW_TOPOLOGY_BUCK
if(v > settings.HighSideVoltageLimitSoft)v = settings.HighSideVoltageLimitSoft;
#endif
if(v < HW_LIMIT_LS_VOLTAGE_SOFT_MIN)v = HW_LIMIT_LS_VOLTAGE_SOFT_MIN;
phase.Vsp = v;
}
}
float control_get_setpoint(){
return phase.Vsp;
}
float control_get_regulated_voltage(){
#if defined(HW_TOPOLOGY_BOOST)
return meter.Vlow;
#elif defined(HW_TOPOLOGY_BUCK)
return meter.Vhigh;
#endif
}
float control_get_regulated_current(){
#if defined(HW_TOPOLOGY_BOOST)
return meter.Ilow;
#elif defined(HW_TOPOLOGY_BUCK)
return -meter.Ihigh;
#endif
}
void control_set_output_current_limit(float c_mA){
if(c_mA > settings.HighSideCurrentLimitSoft)
c_mA = settings.HighSideCurrentLimitSoft;
if(c_mA < HW_LIMIT_HS_CURRENT_SOFT_MIN)
c_mA = HW_LIMIT_HS_CURRENT_SOFT_MIN;
phase.Ihighlim = c_mA;
}
void control_set_output_voltage_limit(float v_mV){
if(v_mV > settings.HighSideVoltageLimitSoft)
v_mV = settings.HighSideCurrentLimitSoft;
if(v_mV < HW_LIMIT_HS_VOLTAGE_SOFT_MIN)
v_mV = HW_LIMIT_HS_VOLTAGE_SOFT_MIN;
phase.Vhighlim = v_mV;
}
/*
void modConverterSetInputVoltage_dep(float v){
}
void modConverterSetOutputCurrent_dep(float c){
if(c > settings.HighSideCurrentLimitSoft)c = settings.HighSideCurrentLimitSoft;
if(c < 1000.0f)c = 1000.0f;
phase.Ihighlim;
}
void modConverterSetInputCurrent_dep(float c){
phase.Iindlim = c;
}
*/
void control_set_vhs_limit(float v){
//TODO make this dependent work for a buck converter
if(v > settings.HighSideVoltageLimitSoft)v = settings.HighSideVoltageLimitSoft;
if(v < 5000.0f)v = 5000.0f;
phase.Vhighlim = v;
}
void scope_trigger_fault(){
if(scope.faulttrigger == true){
if(scope.running && (scope.trigered == false)){
if(scope.writeindex > scope.pretrigger){
scope.trigered = true;
scope.triggerindex = scope.writeindex;
}
}
}
}
void scope_trigger(){
if(scope.faulttrigger == false){
if(scope.running && (scope.trigered == false)){
if(scope.writeindex > scope.pretrigger){
scope.trigered = true;
scope.triggerindex = scope.writeindex;
}
}
}
}
void scope_start(bool OnFault){
scope.faulttrigger = OnFault;
scope.running = false;
int div = 1;
if (scope.divider > 1){
div = scope.divider;
}
scope.samplerate = 1/(Ts*div);
scope.writeindex = 0;
scope.trigered = false;
scope.triggerindex = 0;
scope.running = true;
}