1375 lines
70 KiB
C
1375 lines
70 KiB
C
/*
|
|
Copyright 2017 - 2018 Danny Bokma danny@diebie.nl
|
|
Copyright 2019 - 2020 Kevin Dionne kevin.dionne@ennoid.me
|
|
|
|
This file is part of the DieBieMS/ENNOID-BMS firmware.
|
|
|
|
The DieBieMS/ENNOID-BMS 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 DieBieMS/ENNOID-BMS 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "modPowerElectronics.h"
|
|
#include "main.h"
|
|
//#include "modTerminal.h"
|
|
|
|
modPowerElectronicsPackStateTypedef *modPowerElectronicsPackStateHandle;
|
|
modConfigGeneralConfigStructTypedef *modPowerElectronicsGeneralConfigHandle;
|
|
uint32_t modPowerElectronicsMeasureIntervalLastTick;
|
|
|
|
uint32_t modPowerElectronicsChargeRetryLastTick;
|
|
uint32_t modPowerElectronicsDisChargeLCRetryLastTick;
|
|
uint32_t modPowerElectronicsDisChargeHCRetryLastTick;
|
|
uint32_t modPowerElectronicsCellBalanceUpdateLastTick;
|
|
uint32_t modPowerElectronicsTempMeasureDelayLastTick;
|
|
uint32_t modPowerElectronicsChargeCurrentDetectionLastTick;
|
|
uint32_t modPowerElectronicsBalanceModeActiveLastTick;
|
|
|
|
uint32_t modPowerElectronicsBuzzerUpdateIntervalLastTick;
|
|
uint32_t modPowerElectronicsThrottleChargeLastTick;
|
|
uint8_t modPowerElectronicsUnderAndOverVoltageErrorCount;
|
|
uint8_t modPowerElectronicsUnderAndOverTemperatureErrorCount;
|
|
bool modPowerElectronicsAllowForcedOnState;
|
|
uint16_t modPowerElectronicsAuxVoltageArray[3];
|
|
uint16_t tempTemperature;
|
|
uint8_t modPowerElectronicsVinErrorCount;
|
|
configCellMonitorICTypeEnum modPowerElectronicsCellMonitorsTypeActive;
|
|
float modPowerElectronicsChargeDiodeBypassHysteresis;
|
|
bool modPowerElectronicsVoltageSenseError;
|
|
|
|
bool modPowerElectronicsChargeDeratingActive;
|
|
uint32_t modPowerElectronicsChargeIncreaseLastTick;
|
|
uint32_t modPowerElectronicsSOAChargeChangeLastTick;
|
|
uint32_t modPowerElectronicsSOADisChargeChangeLastTick;
|
|
uint32_t chargeIncreaseIntervalTime;
|
|
|
|
uint16_t calculatedChargeThrottle = 0;
|
|
float initCurrentOffset = 0.0f;
|
|
//float initCurrentOffsetTemp = 0.0f;
|
|
uint8_t initCurrentOffsetCounter = 0;
|
|
|
|
//uint32_t hardUnderVoltageFlags, hardOverVoltageFlags;
|
|
|
|
void modPowerElectronicsInit(modPowerElectronicsPackStateTypedef *packState, modConfigGeneralConfigStructTypedef *generalConfigPointer) {
|
|
modPowerElectronicsGeneralConfigHandle = generalConfigPointer;
|
|
modPowerElectronicsPackStateHandle = packState;
|
|
modPowerElectronicsUnderAndOverVoltageErrorCount = 0;
|
|
modPowerElectronicsUnderAndOverTemperatureErrorCount = 0;
|
|
modPowerElectronicsAllowForcedOnState = false;
|
|
modPowerElectronicsVinErrorCount = 0;
|
|
modPowerElectronicsChargeDiodeBypassHysteresis = 0.0f;
|
|
modPowerElectronicsVoltageSenseError = false;
|
|
modPowerElectronicsChargeDeratingActive = false;
|
|
|
|
// Init pack status
|
|
modPowerElectronicsPackStateHandle->throttleDutyGeneralTemperatureBMS = 0;
|
|
modPowerElectronicsPackStateHandle->throttleDutyChargeVoltage = 0;
|
|
modPowerElectronicsPackStateHandle->throttleDutyChargeTemperatureBattery = 0;
|
|
modPowerElectronicsPackStateHandle->throttleDutyCharge = 0;
|
|
modPowerElectronicsPackStateHandle->throttleDutyDischargeVoltage = 0;
|
|
modPowerElectronicsPackStateHandle->throttleDutyDischargeTemperatureBattery = 0;
|
|
modPowerElectronicsPackStateHandle->throttleDutyDischarge = 0;
|
|
modPowerElectronicsPackStateHandle->SoC = 0.0f;
|
|
modPowerElectronicsPackStateHandle->SoCCapacityAh = 0.0f;
|
|
modPowerElectronicsPackStateHandle->operationalState = OP_STATE_INIT;
|
|
modPowerElectronicsPackStateHandle->faultState = FAULT_CODE_NONE;
|
|
modPowerElectronicsPackStateHandle->packVoltage = 0.0f;
|
|
modPowerElectronicsPackStateHandle->packCurrent = 0.0f;
|
|
modPowerElectronicsPackStateHandle->packPower = 0.0f;
|
|
modPowerElectronicsPackStateHandle->loCurrentLoadCurrent = 0.0f;
|
|
modPowerElectronicsPackStateHandle->loCurrentLoadVoltage = 0.0f;
|
|
modPowerElectronicsPackStateHandle->chargerVoltage = 0.0f;
|
|
modPowerElectronicsPackStateHandle->cellVoltageHigh = 0.0f;
|
|
modPowerElectronicsPackStateHandle->cellVoltageLow = 0.0f;
|
|
modPowerElectronicsPackStateHandle->cellVoltageAverage = 0.0;
|
|
modPowerElectronicsPackStateHandle->disChargeDesired = false;
|
|
modPowerElectronicsPackStateHandle->disChargeLCAllowed = true;
|
|
modPowerElectronicsPackStateHandle->preChargeDesired = false;
|
|
modPowerElectronicsPackStateHandle->chargeDesired = false;
|
|
modPowerElectronicsPackStateHandle->chargePFETDesired = false;
|
|
modPowerElectronicsPackStateHandle->chargeAllowed = true;
|
|
modPowerElectronicsPackStateHandle->coolingDesired = false;
|
|
modPowerElectronicsPackStateHandle->coolingAllowed = true;
|
|
modPowerElectronicsPackStateHandle->safetyOverCANHCSafeNSafe = false;
|
|
modPowerElectronicsPackStateHandle->chargeBalanceActive = false;
|
|
modPowerElectronicsPackStateHandle->balanceActive = false;
|
|
modPowerElectronicsPackStateHandle->chargeCurrentDetected = false;
|
|
modPowerElectronicsPackStateHandle->powerButtonActuated = false;
|
|
modPowerElectronicsPackStateHandle->packInSOACharge = true;
|
|
modPowerElectronicsPackStateHandle->packInSOADischarge = true;
|
|
modPowerElectronicsPackStateHandle->watchDogTime = 255;
|
|
modPowerElectronicsPackStateHandle->packOperationalCellState = PACK_STATE_NORMAL;
|
|
// modPowerElectronicsPackStateHandle->temperatures[0] = 0.0f;
|
|
// modPowerElectronicsPackStateHandle->temperatures[1] = 0.0f;
|
|
// modPowerElectronicsPackStateHandle->temperatures[2] = 0.0f;
|
|
// modPowerElectronicsPackStateHandle->temperatures[3] = 0.0f;
|
|
modPowerElectronicsPackStateHandle->tempBatteryHigh = 0.0f;
|
|
modPowerElectronicsPackStateHandle->tempBatteryLow = 0.0f;
|
|
modPowerElectronicsPackStateHandle->tempBatteryAverage = 0.0f;
|
|
modPowerElectronicsPackStateHandle->tempBMSHigh = 0.0f;
|
|
modPowerElectronicsPackStateHandle->tempBMSLow = 0.0f;
|
|
modPowerElectronicsPackStateHandle->tempBMSAverage = 0.0f;
|
|
modPowerElectronicsPackStateHandle->humidity = 0.0f;
|
|
modPowerElectronicsPackStateHandle->buzzerOn = false;
|
|
modPowerElectronicsPackStateHandle->powerDownDesired = false;
|
|
modPowerElectronicsPackStateHandle->powerOnLongButtonPress = false;
|
|
|
|
modPowerElectronicsPackStateHandle->disChargeOverMaxTemperature = false;
|
|
modPowerElectronicsPackStateHandle->disChargeOverMinTemperature = false;
|
|
modPowerElectronicsPackStateHandle->chargeOverMaxTemperature = false;
|
|
modPowerElectronicsPackStateHandle->chargeOverMinTemperature = false;
|
|
|
|
for (uint8_t tempPointer = 0; tempPointer < NoOfTempSensors; ++tempPointer)
|
|
{
|
|
modPowerElectronicsPackStateHandle->temperatures[tempPointer] = 0;
|
|
}
|
|
|
|
// init the cell module variables empty
|
|
for( uint8_t modulePointer = 0; modulePointer < NoOfCellMonitorsPossibleOnBMS; modulePointer++) {
|
|
for(uint8_t cellPointer = 0; cellPointer < modPowerElectronicsGeneralConfigHandle->noOfCellsPerModule; cellPointer++)
|
|
modPowerElectronicsPackStateHandle->cellModuleVoltages[modulePointer][cellPointer] = 0.0f;
|
|
|
|
modPowerElectronicsPackStateHandle->cellModuleBalanceResistorEnableMask[modulePointer] = 0;
|
|
}
|
|
// init the aux module variables empty
|
|
for( uint8_t modulePointer = 0; modulePointer < NoOfCellMonitorsPossibleOnBMS; modulePointer++) {
|
|
for(uint8_t auxPointer = 0; auxPointer < modPowerElectronicsGeneralConfigHandle->noOfTempSensorPerModule; auxPointer++)
|
|
modPowerElectronicsPackStateHandle->auxModuleVoltages[modulePointer][auxPointer] = 0.0f;
|
|
}
|
|
// init the exp module variables empty
|
|
for( uint8_t modulePointer = 0; modulePointer < modPowerElectronicsGeneralConfigHandle->noOfExpansionBoard; modulePointer++) {
|
|
for(uint8_t expPointer = 0; expPointer < modPowerElectronicsGeneralConfigHandle->noOfTempSensorPerExpansionBoard; expPointer++)
|
|
modPowerElectronicsPackStateHandle->expModuleVoltages[modulePointer][expPointer] = 0.0f;
|
|
}
|
|
|
|
//added
|
|
modPowerElectronicsCellMonitorsInit();
|
|
|
|
modPowerElectronicsCellMonitorsStartCellConversion();
|
|
|
|
// Init the external bus monitor
|
|
//modPowerElectronicsInitISL();
|
|
|
|
#if (ENNOID_SS || ENNOID_SS_LITE)
|
|
if(modPowerElectronicsGeneralConfigHandle->humidityICType == si7020)
|
|
driverSWSHT21Init();
|
|
else
|
|
driverSWHTC1080Init();
|
|
#endif
|
|
|
|
// Init internal ADC
|
|
// driverHWADCInit();
|
|
// driverHWSwitchesInit();
|
|
|
|
// Init battery stack monitor
|
|
modPowerElectronicsCellMonitorsInit();
|
|
|
|
modPowerElectronicsChargeCurrentDetectionLastTick = HAL_GetTick();
|
|
modPowerElectronicsBalanceModeActiveLastTick = HAL_GetTick();
|
|
modPowerElectronicsSOAChargeChangeLastTick = HAL_GetTick();
|
|
modPowerElectronicsSOADisChargeChangeLastTick = HAL_GetTick();
|
|
|
|
// Sample the first pack voltage moment
|
|
// driverSWISL28022GetBusVoltage(ISL28022_MASTER_ADDRES,ISL28022_MASTER_BUS,&modPowerElectronicsPackStateHandle->packVoltage,modPowerElectronicsGeneralConfigHandle->voltageLCOffset, modPowerElectronicsGeneralConfigHandle->voltageLCFactor);
|
|
|
|
|
|
// Register terminal commands
|
|
// modTerminalRegisterCommandCallBack("testbms","Test the cell connection between cell monitor and pack and pack vs cell measurement.","[error (V)] [bal drop (mV)]",modPowerElectronicsTerminalCellConnectionTest);
|
|
|
|
};
|
|
|
|
bool modPowerElectronicsTask(void) {
|
|
bool returnValue = false;
|
|
// Static variable for SHT measure timer
|
|
|
|
|
|
if(modDelayTick1ms(&modPowerElectronicsMeasureIntervalLastTick,100)) {
|
|
// reset tick for LTC Temp start conversion delay
|
|
modPowerElectronicsTempMeasureDelayLastTick = HAL_GetTick();
|
|
|
|
// Collect low current current path, pack data and check validity + recover if invalid.
|
|
modPowerElectronicsSamplePackAndLCData();
|
|
|
|
// Check whether packvoltage is whithin theoretical limits
|
|
if(modPowerElectronicsPackStateHandle->packVoltage >= (modPowerElectronicsGeneralConfigHandle->noOfCellsSeries*modPowerElectronicsGeneralConfigHandle->cellHardOverVoltage)) {
|
|
modPowerElectronicsVoltageSenseError = true;
|
|
}
|
|
|
|
// Combine the currents based on config and calculate pack power.
|
|
modPowerElectronicsPackStateHandle->packCurrent = modPowerElectronicsCalcPackCurrent();
|
|
modPowerElectronicsPackStateHandle->packPower = modPowerElectronicsPackStateHandle->packCurrent * modPowerElectronicsPackStateHandle->packVoltage;
|
|
|
|
// Read the battery cell voltages and temperatures with the cell monitor ICs
|
|
modPowerElectronicsCellMonitorsCheckConfigAndReadAnalogData();
|
|
|
|
|
|
|
|
// When temperature and cellvoltages are known calculate charge and discharge throttle.
|
|
modPowerElectronicsCalcThrottle();
|
|
|
|
// Do the balancing task
|
|
modPowerElectronicsSubTaskBalancing();
|
|
|
|
// Measure cell voltages
|
|
modPowerElectronicsCellMonitorsStartCellConversion();
|
|
|
|
//Measure temperature voltages
|
|
modPowerElectronicsCellMonitorsStartTemperatureConversion();
|
|
|
|
// Calculate temperature statisticks
|
|
modPowerElectronicsCalcTempStats();
|
|
|
|
// Check and respond to the measured voltage values
|
|
modPowerElectronicsSubTaskVoltageWatch();
|
|
|
|
// Check and respond to the measured current values
|
|
modPowerElectronicsSubTaskCurrentWatch();
|
|
|
|
|
|
// Check and respond to the measured temperature values
|
|
modPowerElectronicsCheckPackSOA();
|
|
|
|
// modPowerElectronicsPackStateHandle->powerButtonActuated = modPowerStateGetButtonPressedState();
|
|
|
|
returnValue = true;
|
|
}else
|
|
returnValue = false;
|
|
|
|
return returnValue;
|
|
};
|
|
|
|
void modPowerElectronicsAllowForcedOn(bool allowedState){
|
|
modPowerElectronicsAllowForcedOnState = allowedState;
|
|
}
|
|
|
|
void modPowerElectronicsSetPreCharge(bool newState) {
|
|
static bool preChargeLastState = false;
|
|
|
|
if(preChargeLastState != newState) {
|
|
preChargeLastState = newState;
|
|
modPowerElectronicsPackStateHandle->preChargeDesired = newState;
|
|
modPowerElectronicsUpdateSwitches();
|
|
}
|
|
};
|
|
|
|
|
|
bool modPowerElectronicsSetDisCharge(bool newState) {
|
|
static bool dischargeLastState = false;
|
|
|
|
if(dischargeLastState != newState) {
|
|
modPowerElectronicsPackStateHandle->disChargeDesired = newState;
|
|
modPowerElectronicsUpdateSwitches();
|
|
dischargeLastState = newState;
|
|
}
|
|
|
|
if((modPowerElectronicsPackStateHandle->loCurrentLoadVoltage < modPowerElectronicsGeneralConfigHandle->minimalPrechargePercentage*(modPowerElectronicsPackStateHandle->packVoltage)) && modPowerElectronicsGeneralConfigHandle->LCUsePrecharge>=1) // Prevent turn on with to low output voltage
|
|
return false; // Load voltage to low (output not precharged enough) return whether or not precharge is needed.
|
|
else
|
|
return true;
|
|
};
|
|
|
|
void modPowerElectronicsSetCharge(bool newState) {
|
|
static bool chargeLastState = false;
|
|
|
|
if(chargeLastState != newState) {
|
|
chargeLastState = newState;
|
|
modPowerElectronicsPackStateHandle->chargeDesired = newState;
|
|
modPowerElectronicsUpdateSwitches();
|
|
}
|
|
};
|
|
|
|
void modPowerElectronicsSetChargePFET(bool newState) {
|
|
static bool chargePFETLastState = false;
|
|
|
|
if(chargePFETLastState != newState) {
|
|
chargePFETLastState = newState;
|
|
modPowerElectronicsPackStateHandle->chargePFETDesired = newState;
|
|
modPowerElectronicsUpdateSwitches();
|
|
}
|
|
};
|
|
|
|
void modPowerElectronicsSetCooling(bool newState) {
|
|
static bool coolingLastState = false;
|
|
|
|
if(coolingLastState != newState) {
|
|
coolingLastState = newState;
|
|
modPowerElectronicsPackStateHandle->coolingDesired = newState;
|
|
modPowerElectronicsUpdateSwitches();
|
|
}
|
|
};
|
|
|
|
void modPowerElectronicsDisableAll(void) {
|
|
if(modPowerElectronicsPackStateHandle->disChargeDesired | modPowerElectronicsPackStateHandle->preChargeDesired | modPowerElectronicsPackStateHandle->chargeDesired) {
|
|
modPowerElectronicsPackStateHandle->disChargeDesired = false;
|
|
modPowerElectronicsPackStateHandle->preChargeDesired = false;
|
|
modPowerElectronicsPackStateHandle->chargeDesired = false;
|
|
modPowerElectronicsPackStateHandle->chargePFETDesired = false;
|
|
modPowerElectronicsPackStateHandle->coolingDesired = false;
|
|
// driverHWSwitchesDisableAll();
|
|
}
|
|
};
|
|
|
|
void modPowerElectronicsCalculateCellStats(void) {
|
|
float cellVoltagesSummed = 0.0f;
|
|
modPowerElectronicsPackStateHandle->cellVoltageHigh = 0.0f;
|
|
modPowerElectronicsPackStateHandle->cellVoltageLow = 10.0f;
|
|
|
|
for(uint8_t cellPointer = 0; cellPointer < modPowerElectronicsGeneralConfigHandle->noOfCellsSeries*modPowerElectronicsGeneralConfigHandle->noOfParallelModules; cellPointer++) {
|
|
cellVoltagesSummed += modPowerElectronicsPackStateHandle->cellVoltagesIndividual[cellPointer].cellVoltage;
|
|
|
|
if(modPowerElectronicsPackStateHandle->cellVoltagesIndividual[cellPointer].cellVoltage > modPowerElectronicsPackStateHandle->cellVoltageHigh)
|
|
modPowerElectronicsPackStateHandle->cellVoltageHigh = modPowerElectronicsPackStateHandle->cellVoltagesIndividual[cellPointer].cellVoltage;
|
|
|
|
if(modPowerElectronicsPackStateHandle->cellVoltagesIndividual[cellPointer].cellVoltage < modPowerElectronicsPackStateHandle->cellVoltageLow)
|
|
modPowerElectronicsPackStateHandle->cellVoltageLow = modPowerElectronicsPackStateHandle->cellVoltagesIndividual[cellPointer].cellVoltage;
|
|
}
|
|
|
|
modPowerElectronicsPackStateHandle->cellVoltageAverage = cellVoltagesSummed/(modPowerElectronicsGeneralConfigHandle->noOfCellsSeries*modPowerElectronicsGeneralConfigHandle->noOfParallelModules);
|
|
|
|
modPowerElectronicsPackStateHandle->cellVoltageMisMatch = modPowerElectronicsPackStateHandle->cellVoltageHigh - modPowerElectronicsPackStateHandle->cellVoltageLow;
|
|
};
|
|
|
|
void modPowerElectronicsSubTaskBalancing(void) {
|
|
static uint32_t delayTimeHolder = 100;
|
|
static bool delaytoggle = false;
|
|
|
|
|
|
if(modDelayTick1ms(&modPowerElectronicsCellBalanceUpdateLastTick,delayTimeHolder)) {
|
|
delaytoggle ^= true;
|
|
delayTimeHolder = delaytoggle ? modPowerElectronicsGeneralConfigHandle->cellBalanceUpdateInterval : 200;
|
|
//delayTimeHolder = delaytoggle ? 500 : 500;
|
|
|
|
if(delaytoggle) {
|
|
//if((modPowerElectronicsPackStateHandle->chargeDesired && !modPowerElectronicsPackStateHandle->disChargeDesired) || modPowerStateChargerDetected() || modPowerElectronicsGeneralConfigHandle->cellBalanceAllTime) {
|
|
if(charge_switch_state){
|
|
//if(1) {
|
|
for(uint8_t i = 0; i < (modPowerElectronicsGeneralConfigHandle->noOfCellsSeries + 2)*modPowerElectronicsGeneralConfigHandle->noOfParallelModules; i++) {
|
|
if(modPowerElectronicsPackStateHandle->cellVoltagesIndividual[i].cellVoltage >= (modPowerElectronicsPackStateHandle->cellVoltageLow + modPowerElectronicsGeneralConfigHandle->cellBalanceDifferenceThreshold)) {
|
|
//if(modPowerElectronicsPackStateHandle->cellVoltagesIndividual[i].cellVoltage >= (modPowerElectronicsPackStateHandle->cellVoltageLow)) {
|
|
//if(1){
|
|
if(modPowerElectronicsPackStateHandle->cellVoltagesIndividual[i].cellVoltage >= modPowerElectronicsGeneralConfigHandle->cellBalanceStart) {
|
|
//if(1){
|
|
modPowerElectronicsPackStateHandle->cellVoltagesIndividual[i].cellBleedActive = true;
|
|
modPowerElectronicsPackStateHandle->balanceActive = true;
|
|
}else{
|
|
modPowerElectronicsPackStateHandle->cellVoltagesIndividual[i].cellBleedActive = false;
|
|
}
|
|
}else{
|
|
modPowerElectronicsPackStateHandle->cellVoltagesIndividual[i].cellBleedActive = false;
|
|
}
|
|
}
|
|
}
|
|
}else{
|
|
for(uint8_t i = 0; i < (modPowerElectronicsGeneralConfigHandle->noOfCellsSeries + 2)*modPowerElectronicsGeneralConfigHandle->noOfParallelModules; i++) {
|
|
modPowerElectronicsPackStateHandle->cellVoltagesIndividual[i].cellBleedActive = false;
|
|
|
|
}
|
|
modPowerElectronicsPackStateHandle->balanceActive = false;
|
|
}
|
|
|
|
modPowerElectronicsCallMonitorsCalcBalanceResistorArray();
|
|
modPowerElectronicsCellMonitorsEnableBalanceResistorsArray();
|
|
}
|
|
};
|
|
|
|
void modPowerElectronicsCallMonitorsCalcBalanceResistorArray(void) {
|
|
uint8_t modulePointer = 0;
|
|
uint8_t cellInMaskPointer = 0;
|
|
uint8_t seriesCount = 0;
|
|
uint8_t moduleCount = 0;
|
|
|
|
// Clear array
|
|
for(uint8_t moduleClearPointer = 0; moduleClearPointer < NoOfCellMonitorsPossibleOnBMS; moduleClearPointer++)
|
|
modPowerElectronicsPackStateHandle->cellModuleBalanceResistorEnableMask[moduleClearPointer] = 0;
|
|
|
|
for(uint8_t cellPointer = 0; cellPointer < modPowerElectronicsGeneralConfigHandle->noOfCellsSeries*modPowerElectronicsGeneralConfigHandle->noOfParallelModules; cellPointer++) {
|
|
seriesCount = cellPointer/modPowerElectronicsGeneralConfigHandle->noOfCellsSeries;
|
|
moduleCount = seriesCount*(modPowerElectronicsGeneralConfigHandle->cellMonitorICCount/modPowerElectronicsGeneralConfigHandle->noOfParallelModules);
|
|
modulePointer = moduleCount + (cellPointer % modPowerElectronicsGeneralConfigHandle->noOfCellsSeries)/modPowerElectronicsGeneralConfigHandle->noOfCellsPerModule;
|
|
cellInMaskPointer = (cellPointer - (seriesCount*modPowerElectronicsGeneralConfigHandle->noOfCellsSeries)) % modPowerElectronicsGeneralConfigHandle->noOfCellsPerModule;
|
|
|
|
if(modPowerElectronicsPackStateHandle->cellVoltagesIndividual[cellPointer].cellBleedActive)
|
|
modPowerElectronicsPackStateHandle->cellModuleBalanceResistorEnableMask[modulePointer] |= (1 << cellInMaskPointer);
|
|
else
|
|
modPowerElectronicsPackStateHandle->cellModuleBalanceResistorEnableMask[modulePointer] &= ~(1 << cellInMaskPointer);
|
|
}
|
|
}
|
|
|
|
void modPowerElectronicsSubTaskVoltageWatch(void)
|
|
{
|
|
static bool lastdisChargeLCAllowed = false;
|
|
static bool lastChargeAllowed = false;
|
|
|
|
//modPowerElectronicsCellMonitorsReadVoltageFlags(&hardUnderVoltageFlags,&hardOverVoltageFlags);
|
|
modPowerElectronicsCalculateCellStats();
|
|
|
|
if (modPowerElectronicsPackStateHandle->packOperationalCellState != PACK_STATE_ERROR_HARD_CELLVOLTAGE && modPowerElectronicsPackStateHandle->packOperationalCellState != PACK_STATE_ERROR_TEMPERATURE)
|
|
{
|
|
// Handle soft cell voltage limits & temperatures
|
|
//Discharge disable
|
|
if (modPowerElectronicsPackStateHandle->cellVoltageLow <= modPowerElectronicsGeneralConfigHandle->cellLCSoftUnderVoltage)
|
|
{
|
|
modPowerElectronicsPackStateHandle->disChargeLCAllowed = false;
|
|
modPowerElectronicsDisChargeLCRetryLastTick = HAL_GetTick();
|
|
modPowerElectronicsPackStateHandle->faultState = FAULT_CODE_CELL_SOFT_UNDER_VOLTAGE;
|
|
}
|
|
|
|
const float minTempDisChargeThreshold = modPowerElectronicsPackStateHandle->disChargeOverMinTemperature ?
|
|
modPowerElectronicsGeneralConfigHandle->allowedTempBattDischargingMin + 10 :
|
|
modPowerElectronicsGeneralConfigHandle->allowedTempBattDischargingMin;
|
|
|
|
const float maxTempDisChargeThreshold = modPowerElectronicsPackStateHandle->disChargeOverMaxTemperature ?
|
|
modPowerElectronicsGeneralConfigHandle->allowedTempBattDischargingMax - 10 :
|
|
modPowerElectronicsGeneralConfigHandle->allowedTempBattDischargingMax;
|
|
|
|
if (modPowerElectronicsPackStateHandle->tempBatteryHigh >= maxTempDisChargeThreshold)
|
|
{
|
|
modPowerElectronicsPackStateHandle->disChargeLCAllowed = false;
|
|
modPowerElectronicsPackStateHandle->disChargeOverMinTemperature = false;
|
|
modPowerElectronicsPackStateHandle->disChargeOverMaxTemperature = true;
|
|
modPowerElectronicsDisChargeLCRetryLastTick = HAL_GetTick();
|
|
modPowerElectronicsPackStateHandle->faultState = FAULT_CODE_DISCHARGE_OVER_TEMP_CELLS;
|
|
}
|
|
|
|
if (modPowerElectronicsPackStateHandle->tempBatteryLow <= minTempDisChargeThreshold)
|
|
{
|
|
modPowerElectronicsPackStateHandle->disChargeLCAllowed = false;
|
|
modPowerElectronicsPackStateHandle->disChargeOverMinTemperature = true;
|
|
modPowerElectronicsPackStateHandle->disChargeOverMaxTemperature = false;
|
|
modPowerElectronicsDisChargeLCRetryLastTick = HAL_GetTick();
|
|
modPowerElectronicsPackStateHandle->faultState = FAULT_CODE_DISCHARGE_UNDER_TEMP_CELLS;
|
|
}
|
|
|
|
//Charge disable
|
|
if (modPowerElectronicsPackStateHandle->cellVoltageHigh >= modPowerElectronicsGeneralConfigHandle->cellSoftOverVoltage)
|
|
{
|
|
modPowerElectronicsPackStateHandle->chargeAllowed = false;
|
|
modPowerElectronicsChargeRetryLastTick = HAL_GetTick();
|
|
modPowerElectronicsPackStateHandle->faultState = FAULT_CODE_CELL_SOFT_OVER_VOLTAGE;
|
|
}
|
|
|
|
const float minTempChargeThreshold = modPowerElectronicsPackStateHandle->chargeOverMinTemperature ?
|
|
modPowerElectronicsGeneralConfigHandle->allowedTempBattChargingMin + 10 :
|
|
modPowerElectronicsGeneralConfigHandle->allowedTempBattChargingMin;
|
|
|
|
const float maxTempChargeThreshold = modPowerElectronicsPackStateHandle->chargeOverMaxTemperature ?
|
|
modPowerElectronicsGeneralConfigHandle->allowedTempBattChargingMax - 10 :
|
|
modPowerElectronicsGeneralConfigHandle->allowedTempBattChargingMax;
|
|
|
|
if (modPowerElectronicsPackStateHandle->tempBatteryHigh >= maxTempChargeThreshold)
|
|
{
|
|
modPowerElectronicsPackStateHandle->chargeAllowed = false;
|
|
modPowerElectronicsPackStateHandle->chargeOverMinTemperature = false;
|
|
modPowerElectronicsPackStateHandle->chargeOverMaxTemperature = true;
|
|
modPowerElectronicsChargeRetryLastTick = HAL_GetTick();
|
|
modPowerElectronicsPackStateHandle->faultState = FAULT_CODE_CHARGE_OVER_TEMP_CELLS;
|
|
}
|
|
|
|
if (modPowerElectronicsPackStateHandle->tempBatteryLow <= minTempChargeThreshold)
|
|
{
|
|
modPowerElectronicsPackStateHandle->chargeAllowed = false;
|
|
modPowerElectronicsPackStateHandle->chargeOverMinTemperature = true;
|
|
modPowerElectronicsPackStateHandle->chargeOverMaxTemperature = false;
|
|
modPowerElectronicsChargeRetryLastTick = HAL_GetTick();
|
|
modPowerElectronicsPackStateHandle->faultState = FAULT_CODE_CHARGE_UNDER_TEMP_CELLS;
|
|
}
|
|
|
|
//Enable discharge
|
|
if (modPowerElectronicsPackStateHandle->cellVoltageLow >= (modPowerElectronicsGeneralConfigHandle->cellLCSoftUnderVoltage + modPowerElectronicsGeneralConfigHandle->hysteresisDischarge) &&
|
|
modPowerElectronicsPackStateHandle->tempBatteryHigh <= maxTempDisChargeThreshold &&
|
|
modPowerElectronicsPackStateHandle->tempBatteryLow >= minTempDisChargeThreshold)
|
|
{
|
|
if (modDelayTick1ms(&modPowerElectronicsDisChargeLCRetryLastTick, modPowerElectronicsGeneralConfigHandle->timeoutDischargeRetry))
|
|
{
|
|
modPowerElectronicsPackStateHandle->disChargeLCAllowed = true;
|
|
modPowerElectronicsPackStateHandle->disChargeOverMinTemperature = false;
|
|
modPowerElectronicsPackStateHandle->disChargeOverMaxTemperature = false;
|
|
modPowerElectronicsPackStateHandle->faultState = FAULT_CODE_NONE;
|
|
}
|
|
}
|
|
|
|
//Enable charge
|
|
if (modPowerElectronicsPackStateHandle->cellVoltageHigh <= (modPowerElectronicsGeneralConfigHandle->cellSoftOverVoltage - modPowerElectronicsGeneralConfigHandle->hysteresisCharge) &&
|
|
modPowerElectronicsPackStateHandle->tempBatteryHigh <= maxTempChargeThreshold &&
|
|
modPowerElectronicsPackStateHandle->tempBatteryLow >= minTempChargeThreshold)
|
|
{
|
|
if (modDelayTick1ms(&modPowerElectronicsChargeRetryLastTick, modPowerElectronicsGeneralConfigHandle->timeoutChargeRetry))
|
|
{
|
|
modPowerElectronicsPackStateHandle->chargeAllowed = true;
|
|
modPowerElectronicsPackStateHandle->chargeOverMinTemperature = false;
|
|
modPowerElectronicsPackStateHandle->chargeOverMaxTemperature = false;
|
|
modPowerElectronicsPackStateHandle->faultState = FAULT_CODE_NONE;
|
|
}
|
|
}
|
|
|
|
//Handle cooling
|
|
if (modPowerElectronicsPackStateHandle->tempBatteryHigh <= modPowerElectronicsGeneralConfigHandle->allowedTempBattCoolingMax &&
|
|
modPowerElectronicsPackStateHandle->tempBatteryLow >= modPowerElectronicsGeneralConfigHandle->allowedTempBattCoolingMin)
|
|
{
|
|
modPowerElectronicsPackStateHandle->coolingAllowed = false;
|
|
}
|
|
else
|
|
{
|
|
modPowerElectronicsPackStateHandle->coolingAllowed = true;
|
|
};
|
|
}
|
|
|
|
// Handle hard cell voltage limits
|
|
if (modPowerElectronicsVoltageSenseError ||
|
|
modPowerElectronicsPackStateHandle->cellVoltageHigh > modPowerElectronicsGeneralConfigHandle-> cellHardOverVoltage ||
|
|
modPowerElectronicsPackStateHandle->cellVoltageLow < modPowerElectronicsGeneralConfigHandle-> cellHardUnderVoltage ||
|
|
modPowerElectronicsPackStateHandle->packVoltage > modPowerElectronicsGeneralConfigHandle->noOfCellsSeries * modPowerElectronicsGeneralConfigHandle->cellHardOverVoltage)
|
|
{
|
|
if (modPowerElectronicsUnderAndOverVoltageErrorCount++ > modPowerElectronicsGeneralConfigHandle->maxUnderAndOverVoltageErrorCount)
|
|
{
|
|
modPowerElectronicsPackStateHandle->packOperationalCellState = PACK_STATE_ERROR_HARD_CELLVOLTAGE;
|
|
modPowerElectronicsPackStateHandle->faultState = FAULT_CODE_MAX_UVP_OVP_ERRORS;
|
|
}
|
|
modPowerElectronicsPackStateHandle->disChargeLCAllowed = false;
|
|
modPowerElectronicsPackStateHandle->chargeAllowed = false;
|
|
}
|
|
else
|
|
{
|
|
modPowerElectronicsUnderAndOverVoltageErrorCount = 0;
|
|
}
|
|
|
|
// Handle temperature limits
|
|
if (modPowerElectronicsPackStateHandle->tempBatteryHigh > (modPowerElectronicsGeneralConfigHandle->allowedTempBattDischargingMax + 10.0f) ||
|
|
modPowerElectronicsPackStateHandle->tempBatteryLow < (modPowerElectronicsGeneralConfigHandle->allowedTempBattDischargingMin - 10.0f))
|
|
{
|
|
if(modPowerElectronicsUnderAndOverTemperatureErrorCount++ > modPowerElectronicsGeneralConfigHandle->maxUnderAndOverTemperatureErrorCount)
|
|
{
|
|
modPowerElectronicsPackStateHandle->packOperationalCellState = PACK_STATE_ERROR_TEMPERATURE;
|
|
modPowerElectronicsPackStateHandle->faultState = FAULT_CODE_MAX_UVT_OVT_ERRORS;
|
|
}
|
|
modPowerElectronicsPackStateHandle->disChargeLCAllowed = false;
|
|
modPowerElectronicsPackStateHandle->chargeAllowed = false;
|
|
}
|
|
else
|
|
{
|
|
modPowerElectronicsUnderAndOverTemperatureErrorCount = 0;
|
|
}
|
|
|
|
// update outputs directly if needed
|
|
if (lastChargeAllowed != modPowerElectronicsPackStateHandle->chargeAllowed ||
|
|
lastdisChargeLCAllowed != modPowerElectronicsPackStateHandle->disChargeLCAllowed)
|
|
{
|
|
lastChargeAllowed = modPowerElectronicsPackStateHandle->chargeAllowed;
|
|
lastdisChargeLCAllowed = modPowerElectronicsPackStateHandle->disChargeLCAllowed;
|
|
modPowerElectronicsUpdateSwitches();
|
|
}
|
|
};
|
|
|
|
void modPowerElectronicsSubTaskCurrentWatch(void){
|
|
// Handle over current limits
|
|
if(modPowerElectronicsPackStateHandle->packCurrent > modPowerElectronicsGeneralConfigHandle->maxAllowedCurrent){
|
|
modPowerElectronicsPackStateHandle->packOperationalCellState = PACK_STATE_ERROR_OVER_CURRENT;
|
|
modPowerElectronicsPackStateHandle->disChargeLCAllowed = false;
|
|
modPowerElectronicsPackStateHandle->chargeAllowed = false;
|
|
}
|
|
};
|
|
|
|
// Update switch states, should be called after every desired/allowed switch state change
|
|
void modPowerElectronicsUpdateSwitches(void) {
|
|
// Do the actual power switching in here
|
|
|
|
//Handle precharge output
|
|
if(modPowerElectronicsPackStateHandle->preChargeDesired && (modPowerElectronicsPackStateHandle->disChargeLCAllowed || modPowerElectronicsAllowForcedOnState)){
|
|
// driverHWSwitchesSetSwitchState(SWITCH_PRECHARGE,(driverHWSwitchesStateTypedef)SWITCH_SET);
|
|
// driverHWSwitchesSetSwitchState(SWITCH_DISCHARGEHV,(driverHWSwitchesStateTypedef)SWITCH_SET);
|
|
}else{
|
|
// driverHWSwitchesSetSwitchState(SWITCH_PRECHARGE,(driverHWSwitchesStateTypedef)SWITCH_RESET);
|
|
// driverHWSwitchesSetSwitchState(SWITCH_DISCHARGEHV,(driverHWSwitchesStateTypedef)SWITCH_RESET);
|
|
};
|
|
//Handle discharge output
|
|
if(modPowerElectronicsPackStateHandle->disChargeDesired && (modPowerElectronicsPackStateHandle->disChargeLCAllowed || modPowerElectronicsAllowForcedOnState)){
|
|
// driverHWSwitchesSetSwitchState(SWITCH_DISCHARGE,(driverHWSwitchesStateTypedef)SWITCH_SET);
|
|
// driverHWSwitchesSetSwitchState(SWITCH_DISCHARGEHV,(driverHWSwitchesStateTypedef)SWITCH_SET);
|
|
}else{
|
|
// driverHWSwitchesSetSwitchState(SWITCH_DISCHARGE,(driverHWSwitchesStateTypedef)SWITCH_RESET);
|
|
};
|
|
//Handle charge input
|
|
if(modPowerElectronicsPackStateHandle->chargeDesired && modPowerElectronicsPackStateHandle->chargeAllowed){
|
|
// driverHWSwitchesSetSwitchState(SWITCH_CHARGE,(driverHWSwitchesStateTypedef)SWITCH_SET);
|
|
}else{
|
|
// driverHWSwitchesSetSwitchState(SWITCH_CHARGE,(driverHWSwitchesStateTypedef)SWITCH_RESET);
|
|
};
|
|
#if (ENNOID_SS || ENNOID_SS_LITE)
|
|
//Handle chargePFET input
|
|
if(modPowerElectronicsPackStateHandle->chargePFETDesired && modPowerElectronicsPackStateHandle->chargeAllowed){
|
|
driverHWSwitchesSetSwitchState(SWITCH_CHARGE_BYPASS,(driverHWSwitchesStateTypedef)SWITCH_SET);
|
|
}else{
|
|
driverHWSwitchesSetSwitchState(SWITCH_CHARGE_BYPASS,(driverHWSwitchesStateTypedef)SWITCH_RESET);
|
|
};
|
|
//Handle cooling output
|
|
#else
|
|
if(modPowerElectronicsPackStateHandle->coolingDesired && modPowerElectronicsPackStateHandle->coolingAllowed)
|
|
;//driverHWSwitchesSetSwitchState(SWITCH_COOLING,(driverHWSwitchesStateTypedef)SWITCH_SET);
|
|
else
|
|
;//driverHWSwitchesSetSwitchState(SWITCH_COOLING,(driverHWSwitchesStateTypedef)SWITCH_RESET);
|
|
#endif
|
|
};
|
|
|
|
void modPowerElectronicsSortCells(cellMonitorCellsTypeDef *cells, uint8_t cellCount) {
|
|
int i,j;
|
|
cellMonitorCellsTypeDef value;
|
|
|
|
for(i=0 ; i<(cellCount-1) ; i++) {
|
|
for(j=0 ; j<(cellCount-i-1) ; j++) {
|
|
if(cells[j].cellVoltage < cells[j+1].cellVoltage) {
|
|
value = cells[j+1];
|
|
cells[j+1] = cells[j];
|
|
cells[j] = value;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
void modPowerElectronicsCalcTempStats(void) {
|
|
|
|
// Battery
|
|
float tempBatteryMax;
|
|
float tempBatteryMin;
|
|
float tempBatterySum = 0.0f;
|
|
uint8_t tempBatterySumCount = 0;
|
|
|
|
// BMS
|
|
float tempBMSMax;
|
|
float tempBMSMin;
|
|
float tempBMSSum = 0.0f;
|
|
uint8_t tempBMSSumCount = 0;
|
|
|
|
if(modPowerElectronicsGeneralConfigHandle->tempEnableMaskBattery || modPowerElectronicsGeneralConfigHandle->tempEnableMaskExpansion){
|
|
tempBatteryMax = -100.0f;
|
|
tempBatteryMin = 100.0f;
|
|
}else{
|
|
tempBatteryMax = 0.0f;
|
|
tempBatteryMin = 0.0f;
|
|
}
|
|
|
|
if(modPowerElectronicsGeneralConfigHandle->tempEnableMaskBMS){
|
|
tempBMSMax = -100.0f;
|
|
tempBMSMin = 100.0f;
|
|
}else{
|
|
tempBMSMax = 0.0f;
|
|
tempBMSMin = 0.0f;
|
|
}
|
|
|
|
// BMS temperatures
|
|
|
|
for(uint8_t sensorPointer = 0; sensorPointer < 16; sensorPointer++){
|
|
if(modPowerElectronicsGeneralConfigHandle->tempEnableMaskBMS & (1 << sensorPointer)){
|
|
modPowerElectronicsPackStateHandle->temperatures[sensorPointer] = modPowerElectronicsPackStateHandle->auxVoltagesIndividual[sensorPointer-1].auxVoltage;
|
|
}
|
|
}
|
|
|
|
// for(uint8_t sensorPointer = 0; sensorPointer < 16; sensorPointer++){
|
|
|
|
// if(modPowerElectronicsGeneralConfigHandle->tempEnableMaskBMS & (1 << sensorPointer)){
|
|
// if(modPowerElectronicsPackStateHandle->temperatures[sensorPointer] > tempBMSMax)
|
|
// tempBMSMax = modPowerElectronicsPackStateHandle->temperatures[sensorPointer];
|
|
|
|
// if(modPowerElectronicsPackStateHandle->temperatures[sensorPointer] < tempBMSMin)
|
|
// tempBMSMin = modPowerElectronicsPackStateHandle->temperatures[sensorPointer];
|
|
|
|
// tempBMSSum += modPowerElectronicsPackStateHandle->temperatures[sensorPointer];
|
|
// tempBMSSumCount++;
|
|
// }
|
|
// }
|
|
|
|
// Battery temperatures statistics for LTC aux channels without taking into account the first slave board temp measurement
|
|
|
|
for(uint8_t sensorModulePointer = 0; sensorModulePointer < modPowerElectronicsGeneralConfigHandle->cellMonitorICCount; sensorModulePointer++) {
|
|
for(uint8_t sensorPointer = 0; sensorPointer < modPowerElectronicsGeneralConfigHandle->noOfTempSensorPerModule; sensorPointer++) {
|
|
if(modPowerElectronicsGeneralConfigHandle->tempEnableMaskBMS & (1 << sensorPointer)){
|
|
if(modPowerElectronicsPackStateHandle->temperatures[sensorPointer] > tempBMSMax)
|
|
tempBMSMax = modPowerElectronicsPackStateHandle->temperatures[sensorPointer];
|
|
|
|
if(modPowerElectronicsPackStateHandle->temperatures[sensorPointer] < tempBMSMin)
|
|
tempBMSMin = modPowerElectronicsPackStateHandle->temperatures[sensorPointer];
|
|
|
|
tempBMSSum += modPowerElectronicsPackStateHandle->temperatures[sensorPointer];
|
|
tempBMSSumCount++;
|
|
}
|
|
|
|
if(modPowerElectronicsGeneralConfigHandle->tempEnableMaskBattery & (1 << sensorPointer)){
|
|
if(modPowerElectronicsPackStateHandle->auxVoltagesIndividual[sensorPointer].auxVoltage > tempBatteryMax)
|
|
tempBatteryMax = modPowerElectronicsPackStateHandle->auxVoltagesIndividual[sensorPointer].auxVoltage;
|
|
|
|
if(modPowerElectronicsPackStateHandle->auxVoltagesIndividual[sensorPointer].auxVoltage < tempBatteryMin)
|
|
tempBatteryMin = modPowerElectronicsPackStateHandle->auxVoltagesIndividual[sensorPointer].auxVoltage;
|
|
|
|
tempBatterySum += modPowerElectronicsPackStateHandle->auxVoltagesIndividual[sensorPointer].auxVoltage;
|
|
tempBatterySumCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Battery temperatures statistics for expansion board
|
|
for(uint8_t sensorModulePointer = 0; sensorModulePointer < modPowerElectronicsGeneralConfigHandle->noOfExpansionBoard; sensorModulePointer++) {
|
|
for(uint8_t sensorPointer = 0; sensorPointer < modPowerElectronicsGeneralConfigHandle->noOfTempSensorPerExpansionBoard; sensorPointer++) {
|
|
if(modPowerElectronicsGeneralConfigHandle->tempEnableMaskExpansion & (1 << sensorPointer)){
|
|
if(modPowerElectronicsPackStateHandle->expVoltagesIndividual[sensorPointer].expVoltage > tempBatteryMax)
|
|
tempBatteryMax = modPowerElectronicsPackStateHandle->expVoltagesIndividual[sensorPointer].expVoltage;
|
|
|
|
if(modPowerElectronicsPackStateHandle->expVoltagesIndividual[sensorPointer].expVoltage < tempBatteryMin)
|
|
tempBatteryMin = modPowerElectronicsPackStateHandle->expVoltagesIndividual[sensorPointer].expVoltage;
|
|
|
|
tempBatterySum += modPowerElectronicsPackStateHandle->expVoltagesIndividual[sensorPointer].expVoltage;
|
|
tempBatterySumCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Battery temperatures
|
|
modPowerElectronicsPackStateHandle->tempBatteryHigh = tempBatteryMax;
|
|
modPowerElectronicsPackStateHandle->tempBatteryLow = tempBatteryMin;
|
|
if(tempBatterySumCount)
|
|
modPowerElectronicsPackStateHandle->tempBatteryAverage = tempBatterySum/tempBatterySumCount;
|
|
else
|
|
modPowerElectronicsPackStateHandle->tempBatteryAverage = 0.0f;
|
|
|
|
// BMS temperatures
|
|
modPowerElectronicsPackStateHandle->tempBMSHigh = tempBMSMax;
|
|
modPowerElectronicsPackStateHandle->tempBMSLow = tempBMSMin;
|
|
if(tempBMSSumCount)
|
|
modPowerElectronicsPackStateHandle->tempBMSAverage = tempBMSSum/tempBMSSumCount;
|
|
else
|
|
modPowerElectronicsPackStateHandle->tempBMSAverage = 0.0f;
|
|
};
|
|
|
|
void modPowerElectronicsCalcThrottle(void) {
|
|
static uint16_t filteredChargeThrottle = 0;
|
|
static uint16_t filteredDisChargeThrottle = 0;
|
|
|
|
// TODO make config to either do the throttling on the high or low current output
|
|
// TODO Make lower percentages configurable
|
|
|
|
//uint16_t calculatedChargeThrottle = 0;
|
|
uint16_t calculatedDisChargeThrottle = 0;
|
|
uint32_t chargeIncreaseIntervalTime;
|
|
uint16_t chargeIncreaseRate;
|
|
float cellSoftUnderVoltage = modPowerElectronicsGeneralConfigHandle->cellLCSoftUnderVoltage;
|
|
|
|
// Throttle charge
|
|
float inputLowerLimitChargeVoltage = modPowerElectronicsGeneralConfigHandle->cellSoftOverVoltage - modPowerElectronicsGeneralConfigHandle->cellThrottleUpperMargin - modPowerElectronicsGeneralConfigHandle->cellThrottleUpperStart;
|
|
float inputUpperLimitChargeVoltage = modPowerElectronicsGeneralConfigHandle->cellSoftOverVoltage - modPowerElectronicsGeneralConfigHandle->cellThrottleUpperMargin;
|
|
float inputLowerLimitChargeTemperatureBattery = modPowerElectronicsGeneralConfigHandle->allowedTempBattChargingMax - 3.0f;
|
|
float inputUpperLimitChargeTemperatureBattery = modPowerElectronicsGeneralConfigHandle->allowedTempBattChargingMax;
|
|
float outputLowerLimitCharge = 1000.0f;
|
|
float outputUpperLimitCharge = 100.0f;
|
|
|
|
// Throttle discharge
|
|
float inputLowerLimitDisChargeVoltage = cellSoftUnderVoltage + modPowerElectronicsGeneralConfigHandle->cellThrottleLowerMargin;
|
|
float inputUpperLimitDisChargeVoltage = cellSoftUnderVoltage + modPowerElectronicsGeneralConfigHandle->cellThrottleLowerMargin + modPowerElectronicsGeneralConfigHandle->cellThrottleLowerStart;
|
|
float inputLowerLimitDisChargeTemperatureBattery = modPowerElectronicsGeneralConfigHandle->allowedTempBattDischargingMax - 3.0f;
|
|
float inputUpperLimitDisChargeTemperatureBattery = modPowerElectronicsGeneralConfigHandle->allowedTempBattDischargingMax;
|
|
float outputLowerLimitDisCharge = 50.0f;
|
|
float outputUpperLimitDisCharge = 1000.0f;
|
|
|
|
// Throttle general
|
|
float inputLowerLimitTemperatureBMS = modPowerElectronicsGeneralConfigHandle->allowedTempBMSMax - 4.0f;
|
|
float inputUpperLimitTemperatureBMS = modPowerElectronicsGeneralConfigHandle->allowedTempBMSMax;
|
|
|
|
modPowerElectronicsPackStateHandle->throttleDutyGeneralTemperatureBMS = (uint16_t)modPowerElectronicsMapVariableFloat(modPowerElectronicsPackStateHandle->tempBMSHigh,inputLowerLimitTemperatureBMS,inputUpperLimitTemperatureBMS,outputUpperLimitDisCharge,outputLowerLimitDisCharge);
|
|
modPowerElectronicsPackStateHandle->throttleDutyChargeVoltage = (uint16_t)modPowerElectronicsMapVariableFloat(modPowerElectronicsPackStateHandle->cellVoltageHigh,inputLowerLimitChargeVoltage,inputUpperLimitChargeVoltage,outputLowerLimitCharge,outputUpperLimitCharge);
|
|
modPowerElectronicsPackStateHandle->throttleDutyChargeTemperatureBattery = (uint16_t)modPowerElectronicsMapVariableFloat(modPowerElectronicsPackStateHandle->tempBatteryHigh,inputLowerLimitChargeTemperatureBattery,inputUpperLimitChargeTemperatureBattery,outputLowerLimitCharge,outputUpperLimitCharge);
|
|
modPowerElectronicsPackStateHandle->throttleDutyDischargeVoltage = (uint16_t)modPowerElectronicsMapVariableFloat(modPowerElectronicsPackStateHandle->cellVoltageLow,inputLowerLimitDisChargeVoltage,inputUpperLimitDisChargeVoltage,outputLowerLimitDisCharge,outputUpperLimitDisCharge);
|
|
modPowerElectronicsPackStateHandle->throttleDutyDischargeTemperatureBattery = (uint16_t)modPowerElectronicsMapVariableFloat(modPowerElectronicsPackStateHandle->tempBatteryHigh,inputLowerLimitDisChargeTemperatureBattery,inputUpperLimitDisChargeTemperatureBattery,outputUpperLimitDisCharge,outputLowerLimitDisCharge);
|
|
|
|
// Calculate (dis)charge throttle and pass it if in SOA
|
|
if(modPowerElectronicsPackStateHandle->packInSOACharge){
|
|
//modPowerElectronicsPackStateHandle->throttleDutyGeneralTemperatureBMS
|
|
//modPowerElectronicsPackStateHandle->throttleDutyChargeVoltage
|
|
//modPowerElectronicsPackStateHandle->throttleDutyChargeTemperatureBattery
|
|
calculatedChargeThrottle = modPowerElectronicsLowestInThree(modPowerElectronicsPackStateHandle->throttleDutyGeneralTemperatureBMS,modPowerElectronicsPackStateHandle->throttleDutyChargeVoltage,modPowerElectronicsPackStateHandle->throttleDutyChargeTemperatureBattery);
|
|
}else{
|
|
calculatedChargeThrottle = 0;
|
|
}
|
|
|
|
if(modPowerElectronicsPackStateHandle->packInSOADischarge){
|
|
//modPowerElectronicsPackStateHandle->throttleDutyGeneralTemperatureBMS
|
|
//modPowerElectronicsPackStateHandle->throttleDutyDischargeVoltage
|
|
//modPowerElectronicsPackStateHandle->throttleDutyDischargeTemperatureBattery
|
|
|
|
calculatedDisChargeThrottle = modPowerElectronicsLowestInThree(modPowerElectronicsPackStateHandle->throttleDutyGeneralTemperatureBMS,modPowerElectronicsPackStateHandle->throttleDutyDischargeVoltage,modPowerElectronicsPackStateHandle->throttleDutyDischargeTemperatureBattery);
|
|
}else{
|
|
calculatedDisChargeThrottle = 0;
|
|
}
|
|
|
|
// Filter the calculated throttle charging
|
|
if(calculatedChargeThrottle >= filteredChargeThrottle) {
|
|
if(modPowerElectronicsChargeDeratingActive) {
|
|
chargeIncreaseIntervalTime = 5000;
|
|
chargeIncreaseRate = 1;
|
|
}else{
|
|
chargeIncreaseIntervalTime = 100;
|
|
chargeIncreaseRate = modPowerElectronicsGeneralConfigHandle->throttleChargeIncreaseRate;
|
|
}
|
|
|
|
if(modDelayTick1ms(&modPowerElectronicsChargeIncreaseLastTick,chargeIncreaseIntervalTime)){
|
|
if(abs(calculatedChargeThrottle-filteredChargeThrottle) > chargeIncreaseRate) {
|
|
filteredChargeThrottle += chargeIncreaseRate;
|
|
}else{
|
|
filteredChargeThrottle = calculatedChargeThrottle;
|
|
}
|
|
}
|
|
}else{
|
|
modPowerElectronicsChargeDeratingActive = true;
|
|
filteredChargeThrottle = calculatedChargeThrottle;
|
|
}
|
|
|
|
// Filter the calculated throttle discharging
|
|
if(calculatedDisChargeThrottle >= filteredDisChargeThrottle){
|
|
if((calculatedDisChargeThrottle-filteredDisChargeThrottle) > modPowerElectronicsGeneralConfigHandle->throttleDisChargeIncreaseRate) {
|
|
filteredDisChargeThrottle += modPowerElectronicsGeneralConfigHandle->throttleDisChargeIncreaseRate;
|
|
}else{
|
|
filteredDisChargeThrottle = calculatedDisChargeThrottle;
|
|
}
|
|
}else{
|
|
filteredDisChargeThrottle = calculatedDisChargeThrottle;
|
|
}
|
|
|
|
// Output the filtered output
|
|
if(modPowerElectronicsPackStateHandle->chargeAllowed)
|
|
modPowerElectronicsPackStateHandle->throttleDutyCharge = filteredChargeThrottle;
|
|
else
|
|
modPowerElectronicsPackStateHandle->throttleDutyCharge = 0;
|
|
|
|
// TODO have it configurable to either HC or LC
|
|
if(modPowerElectronicsPackStateHandle->disChargeLCAllowed)
|
|
modPowerElectronicsPackStateHandle->throttleDutyDischarge = filteredDisChargeThrottle;
|
|
else
|
|
modPowerElectronicsPackStateHandle->throttleDutyDischarge = 0;
|
|
}
|
|
|
|
int32_t modPowerElectronicsMapVariableInt(int32_t inputVariable, int32_t inputLowerLimit, int32_t inputUpperLimit, int32_t outputLowerLimit, int32_t outputUpperLimit) {
|
|
inputVariable = inputVariable < inputLowerLimit ? inputLowerLimit : inputVariable;
|
|
inputVariable = inputVariable > inputUpperLimit ? inputUpperLimit : inputVariable;
|
|
|
|
return (inputVariable - inputLowerLimit) * (outputUpperLimit - outputLowerLimit) / (inputUpperLimit - inputLowerLimit) + outputLowerLimit;
|
|
}
|
|
|
|
float modPowerElectronicsMapVariableFloat(float inputVariable, float inputLowerLimit, float inputUpperLimit, float outputLowerLimit, float outputUpperLimit) {
|
|
inputVariable = inputVariable < inputLowerLimit ? inputLowerLimit : inputVariable;
|
|
inputVariable = inputVariable > inputUpperLimit ? inputUpperLimit : inputVariable;
|
|
|
|
return (inputVariable - inputLowerLimit) * (outputUpperLimit - outputLowerLimit) / (inputUpperLimit - inputLowerLimit) + outputLowerLimit;
|
|
}
|
|
|
|
void modPowerElectronicsInitISL(void) {
|
|
// Init BUS monitor
|
|
// driverSWISL28022InitStruct ISLInitStruct;
|
|
// ISLInitStruct.ADCSetting = ADC_128_64010US;
|
|
// ISLInitStruct.busVoltageRange = BRNG_60V_1;
|
|
// ISLInitStruct.currentShuntGain = PGA_4_160MV;
|
|
// ISLInitStruct.Mode = MODE_SHUNTANDBUS_CONTINIOUS;
|
|
// driverSWISL28022Init(ISL28022_MASTER_ADDRES,ISL28022_MASTER_BUS,ISLInitStruct);
|
|
}
|
|
|
|
void modPowerElectronicsCheckPackSOA(void) {
|
|
static float hysteresysBMS = -2.0f;
|
|
static float hysteresysDischarge = -2.0f;
|
|
static float hysteresysCharge = -2.0f;
|
|
|
|
static bool lastPackInSOACharge = true;
|
|
static bool lastPackInSOADisCharge = true;
|
|
|
|
bool outsideLimitsBMS = false;
|
|
bool outsideLimitsDischarge = false;
|
|
bool outsideLimitsCharge = false;
|
|
|
|
outsideLimitsBMS |= (modPowerElectronicsVinErrorCount >= VinErrorThreshold) ? true : false;
|
|
|
|
// Check BMS Limits
|
|
if(modPowerElectronicsGeneralConfigHandle->tempEnableMaskBMS) {
|
|
outsideLimitsBMS |= (modPowerElectronicsPackStateHandle->tempBMSHigh > (modPowerElectronicsGeneralConfigHandle->allowedTempBMSMax + hysteresysBMS) ) ? true : false;
|
|
outsideLimitsBMS |= (modPowerElectronicsPackStateHandle->tempBMSLow < (modPowerElectronicsGeneralConfigHandle->allowedTempBMSMin - hysteresysBMS) ) ? true : false;
|
|
|
|
if(outsideLimitsBMS)
|
|
hysteresysBMS = -2.0f;
|
|
else
|
|
hysteresysBMS = 2.0f;
|
|
}
|
|
|
|
// Check Battery Limits discharge
|
|
if(modPowerElectronicsGeneralConfigHandle->tempEnableMaskBattery || modPowerElectronicsGeneralConfigHandle->tempEnableMaskExpansion) {
|
|
outsideLimitsDischarge |= (modPowerElectronicsPackStateHandle->tempBatteryHigh > (modPowerElectronicsGeneralConfigHandle->allowedTempBattDischargingMax + hysteresysDischarge) ) ? true : false;
|
|
outsideLimitsDischarge |= (modPowerElectronicsPackStateHandle->tempBatteryLow < (modPowerElectronicsGeneralConfigHandle->allowedTempBattDischargingMin - hysteresysDischarge) ) ? true : false;
|
|
|
|
if(outsideLimitsDischarge)
|
|
hysteresysDischarge = -2.0f;
|
|
else
|
|
hysteresysDischarge = 2.0f;
|
|
}
|
|
|
|
// Check Battery Limits charge
|
|
if(modPowerElectronicsGeneralConfigHandle->tempEnableMaskExpansion) {
|
|
outsideLimitsCharge |= (modPowerElectronicsPackStateHandle->tempBatteryHigh > (modPowerElectronicsGeneralConfigHandle->allowedTempBattChargingMax + hysteresysCharge) ) ? true : false;
|
|
outsideLimitsCharge |= (modPowerElectronicsPackStateHandle->tempBatteryLow < (modPowerElectronicsGeneralConfigHandle->allowedTempBattChargingMin - hysteresysCharge) ) ? true : false;
|
|
|
|
if(outsideLimitsCharge)
|
|
hysteresysCharge = -2.0f;
|
|
else
|
|
hysteresysCharge = 2.0f;
|
|
}
|
|
|
|
// DisCharge delayed response
|
|
if(lastPackInSOADisCharge != !(outsideLimitsBMS || outsideLimitsDischarge)){
|
|
if(modDelayTick1ms(&modPowerElectronicsSOADisChargeChangeLastTick,1000)) {
|
|
// lastPackInSOADisCharge = modPowerElectronicsPackStateHandle->packInSOADischarge = !(outsideLimitsBMS || outsideLimitsDischarge);
|
|
}
|
|
}else{
|
|
modPowerElectronicsSOADisChargeChangeLastTick = HAL_GetTick();
|
|
}
|
|
|
|
// Charge delayed response
|
|
if(lastPackInSOACharge != !(outsideLimitsBMS || outsideLimitsCharge)){
|
|
if(modDelayTick1ms(&modPowerElectronicsSOAChargeChangeLastTick,1000)) {
|
|
// lastPackInSOACharge = modPowerElectronicsPackStateHandle->packInSOACharge = !(outsideLimitsBMS || outsideLimitsCharge);
|
|
}
|
|
}else{
|
|
modPowerElectronicsSOAChargeChangeLastTick = HAL_GetTick();
|
|
}
|
|
}
|
|
|
|
bool modPowerElectronicsHCSafetyCANAndPowerButtonCheck(void) {
|
|
if(modPowerElectronicsGeneralConfigHandle->useCANSafetyInput)
|
|
return (modPowerElectronicsPackStateHandle->safetyOverCANHCSafeNSafe && (modPowerElectronicsPackStateHandle->powerButtonActuated | modPowerElectronicsGeneralConfigHandle->pulseToggleButton));
|
|
else
|
|
return true;
|
|
}
|
|
|
|
void modPowerElectronicsResetBalanceModeActiveTimeout(void) {
|
|
modPowerElectronicsBalanceModeActiveLastTick = HAL_GetTick();
|
|
}
|
|
|
|
void modPowerElectronicsCellMonitorsInit(void){
|
|
|
|
driverLTC6804ConfigStructTypedef configStruct;
|
|
configStruct.GPIO1 = true; // Do not pull down this pin (false = pull down)
|
|
configStruct.GPIO2 = true; //
|
|
configStruct.GPIO3 = true; //
|
|
configStruct.GPIO4 = true; //
|
|
configStruct.GPIO5 = true; //
|
|
configStruct.GPIO6 = true; //
|
|
configStruct.GPIO7 = true; //
|
|
configStruct.GPIO8 = true; //
|
|
configStruct.GPIO9 = true; //
|
|
configStruct.ReferenceON = true; // Reference ON
|
|
configStruct.ADCOption = true; // ADC Option register for configuration of over sampling ratio
|
|
configStruct.noOfCells = modPowerElectronicsGeneralConfigHandle->noOfCellsPerModule; // Number of cells to monitor (that can cause interrupt)
|
|
configStruct.DisChargeEnableMask = 0x00000000; // Set enable state of discharge, 1=EnableDischarge, 0=DisableDischarge
|
|
configStruct.DischargeTimout = 0; // Discharge timout value / limit
|
|
configStruct.CellUnderVoltageLimit = modPowerElectronicsGeneralConfigHandle->cellHardUnderVoltage; // Undervoltage level, cell voltages under this limit will cause interrupt
|
|
configStruct.CellOverVoltageLimit = modPowerElectronicsGeneralConfigHandle->cellHardOverVoltage; // Over voltage limit, cell voltages over this limit will cause interrupt
|
|
|
|
|
|
// test 01.11.2021 //
|
|
// modPowerElectronicsGeneralConfigHandle->cellMonitorICCount = 3;
|
|
// test 01.11.2021 //
|
|
|
|
driverSWLTC6804Init(configStruct, modPowerElectronicsGeneralConfigHandle->cellMonitorICCount, 12, 4, modPowerElectronicsGeneralConfigHandle->cellMonitorType);
|
|
|
|
// Safety signal is managed by the controller, it is configured as open drain and will be kept low by. watchdog will make the output to be released.
|
|
// driverHWSwitchesSetSwitchState(SWITCH_SAFETY_OUTPUT,SWITCH_RESET);
|
|
|
|
|
|
modPowerElectronicsCellMonitorsTypeActive = (configCellMonitorICTypeEnum)modPowerElectronicsGeneralConfigHandle->cellMonitorType;
|
|
}
|
|
|
|
void modPowerElectronicsCellMonitorsCheckConfigAndReadAnalogData(void){
|
|
modPowerElectronicsCellMonitorsCheckAndSolveInitState();
|
|
|
|
// Check config valid and reinit
|
|
// TODO: Implement
|
|
|
|
// Read cell voltages
|
|
driverSWLTC6804ReadCellVoltagesArray(modPowerElectronicsPackStateHandle->cellModuleVoltages);
|
|
|
|
modPowerElectronicsCellMonitorsArrayTranslate();
|
|
|
|
|
|
// Convert modules to full array
|
|
|
|
// Read aux voltages
|
|
driverSWLTC6804ReadAuxVoltagesArray(modPowerElectronicsPackStateHandle->auxModuleVoltages,modPowerElectronicsGeneralConfigHandle->NTC25DegResistance[modConfigNTCGroupLTCExt],modPowerElectronicsGeneralConfigHandle->NTCTopResistor[modConfigNTCGroupLTCExt],modPowerElectronicsGeneralConfigHandle->NTCBetaFactor[modConfigNTCGroupLTCExt],25.0f);
|
|
modPowerElectronicsAuxMonitorsArrayTranslate();
|
|
|
|
// driverSWLTC6804ReadAuxSensors(modPowerElectronicsAuxVoltageArray);
|
|
// modPowerElectronicsPackStateHandle->temperatures[0] = modPowerElectronicsPackStateHandle->temperatures[1] = driverSWLTC6804ConvertTemperatureExt(modPowerElectronicsAuxVoltageArray[1],modPowerElectronicsGeneralConfigHandle->NTC25DegResistance[modConfigNTCGroupLTCExt],modPowerElectronicsGeneralConfigHandle->NTCTopResistor[modConfigNTCGroupLTCExt],modPowerElectronicsGeneralConfigHandle->NTCBetaFactor[modConfigNTCGroupLTCExt],25.0f);
|
|
|
|
//Read exp voltages
|
|
// driverSWADC128D818ReadExpVoltagesArray(modPowerElectronicsPackStateHandle->expModuleVoltages,modPowerElectronicsGeneralConfigHandle->NTC25DegResistance[modConfigNTCGroupExp],modPowerElectronicsGeneralConfigHandle->NTCTopResistor[modConfigNTCGroupExp],modPowerElectronicsGeneralConfigHandle->NTCBetaFactor[modConfigNTCGroupExp],25.0f);
|
|
modPowerElectronicsExpMonitorsArrayTranslate();
|
|
}
|
|
|
|
void modPowerElectronicsCellMonitorsArrayTranslate(void) {
|
|
uint8_t individualCellPointer = 0;
|
|
|
|
for(uint8_t modulePointer = 0; modulePointer < modPowerElectronicsGeneralConfigHandle->cellMonitorICCount; modulePointer++) {
|
|
if((modulePointer+1) % (modPowerElectronicsGeneralConfigHandle->cellMonitorICCount/modPowerElectronicsGeneralConfigHandle->noOfParallelModules)==0 && modulePointer != 0){ // If end of serie string, use lastICNoOfCells instead of noOfCellsPerModule
|
|
for(uint8_t modulePointerCell = 0; modulePointerCell < modPowerElectronicsGeneralConfigHandle->lastICNoOfCells; modulePointerCell++) {
|
|
modPowerElectronicsPackStateHandle->cellVoltagesIndividual[individualCellPointer].cellVoltage = modPowerElectronicsPackStateHandle->cellModuleVoltages[modulePointer][modulePointerCell];
|
|
modPowerElectronicsPackStateHandle->cellVoltagesIndividual[individualCellPointer].cellNumber = individualCellPointer++;
|
|
}
|
|
}else{ // use noOfCellsPerModule as usually
|
|
for(uint8_t modulePointerCell = 0; modulePointerCell < modPowerElectronicsGeneralConfigHandle->noOfCellsPerModule; modulePointerCell++) {
|
|
// if( (modulePointerCell >= 4) && (modulePointerCell <= 7) ) {
|
|
// modPowerElectronicsPackStateHandle->cellVoltagesIndividual[individualCellPointer].cellVoltage = modPowerElectronicsPackStateHandle->cellModuleVoltages[modulePointer][modulePointerCell+2];
|
|
// modPowerElectronicsPackStateHandle->cellVoltagesIndividual[individualCellPointer].cellNumber = individualCellPointer++;
|
|
// } else {
|
|
// if( (modulePointerCell > 7) ) {
|
|
// modPowerElectronicsPackStateHandle->cellVoltagesIndividual[individualCellPointer].cellVoltage = modPowerElectronicsPackStateHandle->cellModuleVoltages[modulePointer][modulePointerCell-1];
|
|
// modPowerElectronicsPackStateHandle->cellVoltagesIndividual[individualCellPointer].cellNumber = individualCellPointer++;
|
|
// } else {
|
|
modPowerElectronicsPackStateHandle->cellVoltagesIndividual[individualCellPointer].cellVoltage = modPowerElectronicsPackStateHandle->cellModuleVoltages[modulePointer][modulePointerCell];
|
|
modPowerElectronicsPackStateHandle->cellVoltagesIndividual[individualCellPointer].cellNumber = individualCellPointer++;
|
|
// }
|
|
// }
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
void modPowerElectronicsAuxMonitorsArrayTranslate(void) {
|
|
uint8_t individualAuxPointer = 0;
|
|
|
|
for(uint8_t modulePointer = 0; modulePointer < modPowerElectronicsGeneralConfigHandle->cellMonitorICCount; modulePointer++) {
|
|
for(uint8_t modulePointerAux = 0; modulePointerAux < modPowerElectronicsGeneralConfigHandle->noOfTempSensorPerModule; modulePointerAux++) {
|
|
if(modulePointerAux < 5){
|
|
modPowerElectronicsPackStateHandle->auxVoltagesIndividual[individualAuxPointer].auxVoltage = modPowerElectronicsPackStateHandle->auxModuleVoltages[modulePointer][modulePointerAux];
|
|
modPowerElectronicsPackStateHandle->auxVoltagesIndividual[individualAuxPointer].auxNumber = individualAuxPointer++;
|
|
}else{ // when above 5, remove reference voltage measurement from Aux register group B : AVBR4 & AVBR5 for LTC6812 & LTC6813
|
|
modPowerElectronicsPackStateHandle->auxVoltagesIndividual[individualAuxPointer].auxVoltage = modPowerElectronicsPackStateHandle->auxModuleVoltages[modulePointer][modulePointerAux+1];
|
|
modPowerElectronicsPackStateHandle->auxVoltagesIndividual[individualAuxPointer].auxNumber = individualAuxPointer++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void modPowerElectronicsExpMonitorsArrayTranslate(void) {
|
|
uint8_t individualExpPointer = 0;
|
|
|
|
for(uint8_t modulePointer = 0; modulePointer < modPowerElectronicsGeneralConfigHandle->noOfExpansionBoard; modulePointer++) {
|
|
for(uint8_t modulePointerExp = 0; modulePointerExp < modPowerElectronicsGeneralConfigHandle->noOfTempSensorPerExpansionBoard; modulePointerExp++) {
|
|
modPowerElectronicsPackStateHandle->expVoltagesIndividual[individualExpPointer].expVoltage = modPowerElectronicsPackStateHandle->expModuleVoltages[modulePointer][modulePointerExp];
|
|
modPowerElectronicsPackStateHandle->expVoltagesIndividual[individualExpPointer].expNumber = individualExpPointer++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void modPowerElectronicsCellMonitorsStartCellConversion(void) {
|
|
modPowerElectronicsCellMonitorsCheckAndSolveInitState();
|
|
driverSWLTC6804ResetCellVoltageRegisters();
|
|
driverSWLTC6804StartCellVoltageConversion(MD_FILTERED,DCP_DISABLED,CELL_CH_ALL);
|
|
}
|
|
|
|
void modPowerElectronicsCellMonitorsStartLoadedCellConversion(bool PUP) {
|
|
modPowerElectronicsCellMonitorsCheckAndSolveInitState();
|
|
driverSWLTC6804ResetCellVoltageRegisters();
|
|
driverSWLTC6804StartLoadedCellVoltageConversion(MD_FILTERED,DCP_ENABLED,CELL_CH_ALL,PUP);
|
|
}
|
|
|
|
void modPowerElectronicsCellMonitorsStartTemperatureConversion(void) {
|
|
modPowerElectronicsCellMonitorsCheckAndSolveInitState();
|
|
|
|
// For other GPIOs voltages conversions, the below functions are used.
|
|
driverSWLTC6804ResetAuxRegisters();
|
|
driverSWLTC6804StartAuxVoltageConversion(MD_FILTERED, AUX_CH_ALL);
|
|
|
|
}
|
|
|
|
void modPowerElectronicsCellMonitorsEnableBalanceResistors(uint32_t balanceEnableMask){
|
|
modPowerElectronicsCellMonitorsCheckAndSolveInitState();
|
|
driverSWLTC6804EnableBalanceResistors(balanceEnableMask, modPowerElectronicsGeneralConfigHandle->cellMonitorType);
|
|
}
|
|
|
|
void modPowerElectronicsCellMonitorsEnableBalanceResistorsArray(){
|
|
modPowerElectronicsCellMonitorsCheckAndSolveInitState();
|
|
driverSWLTC6804EnableBalanceResistorsArray(modPowerElectronicsPackStateHandle->cellModuleBalanceResistorEnableMask, modPowerElectronicsGeneralConfigHandle->cellMonitorType);
|
|
}
|
|
|
|
void modPowerElectronicsCellMonitorsReadVoltageFlags(uint32_t *underVoltageFlags, uint32_t *overVoltageFlags){
|
|
modPowerElectronicsCellMonitorsCheckAndSolveInitState();
|
|
driverSWLTC6804ReadVoltageFlags(underVoltageFlags,overVoltageFlags, modPowerElectronicsGeneralConfigHandle->lastICMask, modPowerElectronicsGeneralConfigHandle->noOfParallelModules, modPowerElectronicsPackStateHandle->dieTemperature);
|
|
}
|
|
|
|
void modPowerElectronicsCellMonitorsCheckAndSolveInitState(void){
|
|
if(modPowerElectronicsCellMonitorsTypeActive != modPowerElectronicsGeneralConfigHandle->cellMonitorType){
|
|
modPowerElectronicsCellMonitorsInit();
|
|
}
|
|
}
|
|
|
|
void modPowerElectronicsTerminalCellConnectionTest(int argc, const char **argv) {
|
|
// (void)argc;
|
|
// (void)argv;
|
|
// uint32_t delayLastTick = HAL_GetTick();
|
|
// float conversionResults[5][modPowerElectronicsGeneralConfigHandle->noOfCellsSeries]; // unloaded, 100uAloaded, balance resistor load even and uneven.
|
|
// float difference;
|
|
// uint8_t cellIDPointer;
|
|
// bool passFail = true;
|
|
// bool overAllPassFail = true;
|
|
//
|
|
// float argErrorVoltage = 1.0f;
|
|
// int32_t argBalanceDropMiliVoltage = 2;
|
|
//
|
|
// // Handle argument inputs
|
|
// modCommandsPrintf("--------- Test inputs: ---------");
|
|
// if(argc == 3){
|
|
// // Two arguments given, taking this as balance and error threshold.
|
|
////ni sscanf(argv[1], "%f", &argErrorVoltage);
|
|
// sscanf(argv[2], "%d", &argBalanceDropMiliVoltage);
|
|
// }else{
|
|
// modCommandsPrintf("No valid test arguments given. Using defaults:");
|
|
// }
|
|
//
|
|
// modCommandsPrintf("Error threshold: %.1fV",argErrorVoltage);
|
|
// modCommandsPrintf("Balance threshold: %dmV",argBalanceDropMiliVoltage);
|
|
// // end of argument inputs
|
|
//
|
|
//
|
|
// // Start of general voltage test
|
|
// modCommandsPrintf("--- Starting voltage measure test ---");
|
|
// modCommandsPrintf("Pack voltage Direct : %.2fV",modPowerElectronicsPackStateHandle->packVoltage);
|
|
// modCommandsPrintf("Pack voltage CVAverage: %.2fV",modPowerElectronicsPackStateHandle->cellVoltageAverage*modPowerElectronicsGeneralConfigHandle->noOfCellsSeries);
|
|
// modCommandsPrintf("Measure error : %.2fV",fabs(modPowerElectronicsPackStateHandle->cellVoltageAverage*modPowerElectronicsGeneralConfigHandle->noOfCellsSeries-modPowerElectronicsPackStateHandle->packVoltage));
|
|
//
|
|
// if(fabs(modPowerElectronicsPackStateHandle->cellVoltageAverage*modPowerElectronicsGeneralConfigHandle->noOfCellsSeries-modPowerElectronicsPackStateHandle->packVoltage) > argErrorVoltage){
|
|
// passFail = overAllPassFail = false;
|
|
// }else{
|
|
// passFail = true;
|
|
// }
|
|
// modCommandsPrintf("Result : %s",passFail ? "Pass" : "Fail");// Tell whether test passed / failed
|
|
//
|
|
//
|
|
// // Start of connection test
|
|
// while(!modDelayTick100ms(&delayLastTick,2)){}; // Wait
|
|
// modPowerElectronicsCellMonitorsCheckConfigAndReadAnalogData(); // Read cell voltages from monitor
|
|
// modPowerElectronicsCellMonitorsStartCellConversion(); // Start ADC conversion
|
|
// while(!modDelayTick100ms(&delayLastTick,2)){}; // Wait
|
|
// modPowerElectronicsCellMonitorsCheckConfigAndReadAnalogData(); // Read cell voltages from monitor
|
|
// for(cellIDPointer = 0; cellIDPointer < modPowerElectronicsGeneralConfigHandle->noOfCellsSeries ; cellIDPointer++){
|
|
// conversionResults[4][cellIDPointer] = modPowerElectronicsPackStateHandle->cellVoltagesIndividual[cellIDPointer].cellVoltage;
|
|
// }
|
|
//
|
|
//
|
|
// modCommandsPrintf("------ Starting connectionTest ------");
|
|
// while(!modDelayTick100ms(&delayLastTick,3)){}; // Wait
|
|
// modPowerElectronicsCellMonitorsCheckConfigAndReadAnalogData(); // Read cell voltages from monitor
|
|
// modPowerElectronicsCellMonitorsStartLoadedCellConversion(false); // Start ADC conversion
|
|
//
|
|
// while(!modDelayTick100ms(&delayLastTick,3)){}; // Wait
|
|
// modPowerElectronicsCellMonitorsCheckConfigAndReadAnalogData(); // Read cell voltages from monitor
|
|
// modPowerElectronicsCellMonitorsStartLoadedCellConversion(false); // Start ADC conversion
|
|
//
|
|
// while(!modDelayTick100ms(&delayLastTick,3)){}; // Wait
|
|
// modPowerElectronicsCellMonitorsCheckConfigAndReadAnalogData(); // Read cell voltages from monitor
|
|
// for(cellIDPointer = 0; cellIDPointer < modPowerElectronicsGeneralConfigHandle->noOfCellsSeries ; cellIDPointer++){
|
|
// conversionResults[0][cellIDPointer] = modPowerElectronicsPackStateHandle->cellVoltagesIndividual[cellIDPointer].cellVoltage;
|
|
// }
|
|
//
|
|
//
|
|
// while(!modDelayTick100ms(&delayLastTick,3)){}; // Wait
|
|
// modPowerElectronicsCellMonitorsCheckConfigAndReadAnalogData(); // Read cell voltages from monitor
|
|
// modPowerElectronicsCellMonitorsStartLoadedCellConversion(true); // Start ADC conversion
|
|
//
|
|
// while(!modDelayTick100ms(&delayLastTick,3)){}; // Wait
|
|
// modPowerElectronicsCellMonitorsCheckConfigAndReadAnalogData(); // Read cell voltages from monitor
|
|
// modPowerElectronicsCellMonitorsStartLoadedCellConversion(true); // Start ADC conversion
|
|
//
|
|
// while(!modDelayTick100ms(&delayLastTick,3)){}; // Wait
|
|
// modPowerElectronicsCellMonitorsCheckConfigAndReadAnalogData(); // Read cell voltages from monitor
|
|
// modPowerElectronicsCellMonitorsStartLoadedCellConversion(true); // Start ADC conversion
|
|
//
|
|
// for(cellIDPointer = 0; cellIDPointer < modPowerElectronicsGeneralConfigHandle->noOfCellsSeries ; cellIDPointer++){
|
|
// conversionResults[1][cellIDPointer] = modPowerElectronicsPackStateHandle->cellVoltagesIndividual[cellIDPointer].cellVoltage;
|
|
// }
|
|
//
|
|
// for(cellIDPointer = 0; cellIDPointer < modPowerElectronicsGeneralConfigHandle->noOfCellsSeries ; cellIDPointer++){
|
|
// difference = conversionResults[0][cellIDPointer] - conversionResults[1][cellIDPointer]; // Calculate difference
|
|
//
|
|
// if((conversionResults[0][cellIDPointer] >= modPowerElectronicsGeneralConfigHandle->cellHardOverVoltage) || (conversionResults[0][cellIDPointer] <= modPowerElectronicsGeneralConfigHandle->cellHardUnderVoltage)) {
|
|
// overAllPassFail = passFail = false;
|
|
// }else{
|
|
// if((cellIDPointer != 0) && (cellIDPointer != (modPowerElectronicsGeneralConfigHandle->noOfCellsSeries-1)) && (fabs(difference) >= 0.05f))
|
|
// overAllPassFail = passFail = false;
|
|
// else
|
|
// passFail = true;
|
|
// }
|
|
//
|
|
// modCommandsPrintf("[%2d] %.3fV - %.3fV = % .3fV -> %s",cellIDPointer+1,conversionResults[0][cellIDPointer],conversionResults[1][cellIDPointer],difference,passFail ? "Pass" : "Fail"); // Print the results
|
|
// }
|
|
// modCommandsPrintf("------ End connectionTest ------");
|
|
// modCommandsPrintf("------ Start balance test ------");
|
|
//
|
|
// uint32_t cellBalanceMaskEnableRegister = 0;
|
|
// for(int outputPointer = 0 ; outputPointer < modPowerElectronicsGeneralConfigHandle->noOfCellsSeries; outputPointer++) {
|
|
// cellBalanceMaskEnableRegister |= (1 << outputPointer);
|
|
// }
|
|
//
|
|
// // Even cells
|
|
// modPowerElectronicsCellMonitorsCheckConfigAndReadAnalogData();
|
|
// modPowerElectronicsCellMonitorsEnableBalanceResistors(cellBalanceMaskEnableRegister & 0x0002AAAA);
|
|
//
|
|
// for(int delay = 0; delay < 5; delay++){
|
|
// while(!modDelayTick100ms(&delayLastTick,3)){}; // Wait
|
|
// modPowerElectronicsCellMonitorsCheckConfigAndReadAnalogData(); // Read cell voltages from monitor
|
|
// modPowerElectronicsCellMonitorsStartLoadedCellConversion(false); // Start ADC conversion
|
|
// }
|
|
//
|
|
// while(!modDelayTick100ms(&delayLastTick,3)){}; // Wait
|
|
// modPowerElectronicsCellMonitorsCheckConfigAndReadAnalogData(); // Read cell voltages from monitor
|
|
//
|
|
// for(cellIDPointer = 0; cellIDPointer < modPowerElectronicsGeneralConfigHandle->noOfCellsSeries ; cellIDPointer++){
|
|
// conversionResults[2][cellIDPointer] = modPowerElectronicsPackStateHandle->cellVoltagesIndividual[cellIDPointer].cellVoltage;
|
|
// }
|
|
//
|
|
// // Uneven cells
|
|
// modPowerElectronicsCellMonitorsCheckConfigAndReadAnalogData();
|
|
// modPowerElectronicsCellMonitorsEnableBalanceResistors(cellBalanceMaskEnableRegister & 0x00015555);
|
|
//
|
|
//
|
|
// for(int delay = 0; delay < 5; delay++){
|
|
// while(!modDelayTick100ms(&delayLastTick,3)){}; // Wait
|
|
// modPowerElectronicsCellMonitorsCheckConfigAndReadAnalogData(); // Read cell voltages from monitor
|
|
// modPowerElectronicsCellMonitorsStartLoadedCellConversion(false); // Start ADC conversion
|
|
// }
|
|
//
|
|
// while(!modDelayTick100ms(&delayLastTick,3)){}; // Wait
|
|
// modPowerElectronicsCellMonitorsCheckConfigAndReadAnalogData(); // Read cell voltages from monitor
|
|
//
|
|
// for(cellIDPointer = 0; cellIDPointer < modPowerElectronicsGeneralConfigHandle->noOfCellsSeries ; cellIDPointer++){
|
|
// conversionResults[3][cellIDPointer] = modPowerElectronicsPackStateHandle->cellVoltagesIndividual[cellIDPointer].cellVoltage;
|
|
// }
|
|
//
|
|
// modPowerElectronicsCellMonitorsEnableBalanceResistors(0);
|
|
//
|
|
// for(cellIDPointer = 0; cellIDPointer < modPowerElectronicsGeneralConfigHandle->noOfCellsSeries ; cellIDPointer++){
|
|
// float difference = fabs(conversionResults[4][cellIDPointer] - conversionResults[2][cellIDPointer]) + fabs(conversionResults[4][cellIDPointer] - conversionResults[3][cellIDPointer]); // Calculate difference
|
|
//
|
|
// if(difference >= (0.001f*argBalanceDropMiliVoltage))
|
|
// passFail = true;
|
|
// else
|
|
// overAllPassFail = passFail = false;
|
|
//
|
|
// modCommandsPrintf("[%2d] %.3fV - %.3fV = % .3fV -> %s",cellIDPointer+1,conversionResults[2][cellIDPointer],conversionResults[3][cellIDPointer],difference,passFail ? "Pass" : "Fail"); // Print the results
|
|
// }
|
|
//
|
|
// modCommandsPrintf("------ End balance test ------");
|
|
// modCommandsPrintf("------ Overall: %s ------",overAllPassFail ? "Pass" : "Fail");// Tell whether test passed / failed
|
|
}
|
|
|
|
void modPowerElectronicsSamplePackAndLCData(void) {
|
|
float tempPackVoltage;
|
|
|
|
modPowerElectronicsSamplePackVoltage(&tempPackVoltage);
|
|
modPowerElectronicsPackStateHandle->packVoltage = tempPackVoltage;
|
|
modPowerElectronicsLCSenseSample();
|
|
|
|
if(fabs(tempPackVoltage - modPowerElectronicsGeneralConfigHandle->noOfCellsSeries*modPowerElectronicsPackStateHandle->cellVoltageAverage) < 0.2f*(modPowerElectronicsGeneralConfigHandle->noOfCellsSeries*modPowerElectronicsPackStateHandle->cellVoltageAverage)) { // If the error is different than 20% continue normal operation.
|
|
modPowerElectronicsVinErrorCount = 0; // Reset error count.
|
|
}else{ // Error in voltage measurement.
|
|
if(modPowerElectronicsVinErrorCount++ >= VinErrorThreshold){ // Increase error count
|
|
modPowerElectronicsVinErrorCount = VinErrorThreshold;
|
|
// Make BMS signal error state and power down.
|
|
modPowerElectronicsVoltageSenseError = true;
|
|
}else{
|
|
modPowerElectronicsLCSenseInit(); // Reinit I2C and ISL
|
|
}
|
|
}
|
|
}
|
|
|
|
void modPowerElectronicsSamplePackVoltage(float *voltagePointer) {
|
|
switch(modPowerElectronicsGeneralConfigHandle->packVoltageDataSource) {
|
|
case sourcePackVoltageNone:
|
|
break;
|
|
case sourcePackVoltageISL28022_2_BatteryIn:
|
|
// driverSWISL28022GetBusVoltage(ISL28022_MASTER_ADDRES,ISL28022_MASTER_BUS,voltagePointer,modPowerElectronicsGeneralConfigHandle->voltageLCOffset, modPowerElectronicsGeneralConfigHandle->voltageLCFactor);
|
|
break;
|
|
case sourcePackVoltageSumOfIndividualCellVoltages:
|
|
*voltagePointer = modPowerElectronicsGeneralConfigHandle->noOfCellsSeries*modPowerElectronicsPackStateHandle->cellVoltageAverage;
|
|
break;
|
|
case sourcePackVoltageCANDieBieShunt:
|
|
*voltagePointer = 0.0f;
|
|
break;
|
|
case sourcePackVoltageCANIsabellenhutte:
|
|
*voltagePointer = 0.0f;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
float modPowerElectronicsCalcPackCurrent(void){
|
|
float returnCurrent = 0.0f;
|
|
|
|
switch(modPowerElectronicsGeneralConfigHandle->packCurrentDataSource){
|
|
case sourcePackCurrentLowCurrentShunt:
|
|
returnCurrent = modPowerElectronicsPackStateHandle->loCurrentLoadCurrent;
|
|
break;
|
|
case sourcePackCurrentNone:
|
|
case sourcePackCurrentCANDieBieShunt:
|
|
case sourcePackCurrentCANIsaBellenHuette:
|
|
returnCurrent = 0.0f;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
returnCurrent = float_current;
|
|
|
|
return returnCurrent;
|
|
}
|
|
|
|
void modPowerElectronicsLCSenseSample(void) {
|
|
// driverSWISL28022GetBusCurrent(ISL28022_MASTER_ADDRES,ISL28022_MASTER_BUS,&modPowerElectronicsPackStateHandle->loCurrentLoadCurrent,initCurrentOffset, modPowerElectronicsGeneralConfigHandle->shuntLCFactor);
|
|
// driverHWADCGetLoadVoltage(&modPowerElectronicsPackStateHandle->loCurrentLoadVoltage, modPowerElectronicsGeneralConfigHandle->loadVoltageOffset, modPowerElectronicsGeneralConfigHandle->loadVoltageFactor);
|
|
#if (ENNOID_SS_LITE)
|
|
modPowerElectronicsPackStateHandle->loCurrentLoadVoltage = 0;
|
|
#endif
|
|
|
|
#if (ENNOID_SS || ENNOID_SS_LITE)
|
|
driverHWADCGetChargerVoltage(&modPowerElectronicsPackStateHandle->chargerVoltage, modPowerElectronicsGeneralConfigHandle->chargerVoltageOffset, modPowerElectronicsGeneralConfigHandle->chargerVoltageFactor);
|
|
#endif
|
|
|
|
//Calculate the zero current offset
|
|
if(initCurrentOffsetCounter < 2){
|
|
//initCurrentOffsetTemp += modPowerElectronicsPackStateHandle->loCurrentLoadCurrent;
|
|
initCurrentOffsetCounter++;
|
|
if(initCurrentOffsetCounter == 2){
|
|
initCurrentOffset = modPowerElectronicsPackStateHandle->loCurrentLoadCurrent;
|
|
}
|
|
}
|
|
}
|
|
|
|
void modPowerElectronicsLCSenseInit(void) {
|
|
modPowerElectronicsInitISL();
|
|
}
|
|
|
|
uint16_t modPowerElectronicsLowestInThree(uint16_t num1,uint16_t num2,uint16_t num3) {
|
|
if(num1 < num2 && num1 < num3) {
|
|
return num1;
|
|
} else if(num2 < num3) {
|
|
return num2;
|
|
} else{
|
|
return num3;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|