Vspoof Calibration (commit 2 of 2)

This commit is contained in:
doppelhub
2025-07-08 05:13:37 -04:00
parent 9bbf9f308e
commit cd6ca7adc4
13 changed files with 83 additions and 60 deletions

View File

@@ -7,8 +7,8 @@
#define config_h
#include "src/libcm.h"
#define FW_VERSION "0.9.5m"
#define BUILD_DATE "2025JUN25"
#define FW_VERSION "0.9.5n"
#define BUILD_DATE "2025JUL07"
//////////////////////////////////////////////////////////////////
@@ -24,20 +24,20 @@
//there are no default options because this firmware works with all LiBCM variants... you need to specify which hardware you have installed
//choose your battery type:
#define BATTERY_TYPE_5AhG3 //if you're not sure, you probably have this battery
//#define BATTERY_TYPE_5AhG3 //if you're not sure, you probably have this battery
//#define BATTERY_TYPE_47Ah //aka FoMoCo //aka Samsung SDI modules
//choose how many cells are in series:
#define STACK_IS_48S //All 5AhG3 Kits & 47Ah Kits with QTY4 modules
//#define STACK_IS_48S //All 5AhG3 Kits & 47Ah Kits with QTY4 modules
//#define STACK_IS_60S //47Ah Kits with QTY5 modules
//choose which grid charger is installed
#define GRIDCHARGER_IS_NOT_1500W //All 5AhG3 Kits & 'standard' 47Ah Kits
//#define GRIDCHARGER_IS_NOT_1500W //All 5AhG3 Kits & 'standard' 47Ah Kits
//#define GRIDCHARGER_IS_1500W //47Ah Kits with 'fast' 6.5A charger
//choose ONE of the following
//must match actual "current hack" hardware configuration:
#define SET_CURRENT_HACK_40 //actually +45.8% //most LiBCM users installed this hardware option
//#define SET_CURRENT_HACK_40 //actually +45.8% //most LiBCM users installed this hardware option
//#define SET_CURRENT_HACK_20 //actually +25.0%
//#define SET_CURRENT_HACK_00 //OEM configuration (no current hack installed inside MCM)

View File

@@ -113,7 +113,7 @@ void validateAndStoreNextCVR(uint8_t chipAddress, char cellVoltageRegister)
uint8_t cellX=0; //1st cell in returnedData (LTC cell 1, 4, 7, or 10)
uint8_t cellY=0; //2nd cell in returnedData (LTC cell 2, 5, 8, or 11)
uint8_t cellZ=0; //3rd cell in returnedData (LTC cell 3, 6, 9, or 12)
switch (cellVoltageRegister) //LUT to prevent QTY3 multiplies & QTY12 adds per call
switch (cellVoltageRegister) //LUT prevents QTY3 multiplies & QTY12 adds per call
{
case 'A': cellX=0; cellY=1; cellZ=2 ; break; //LTC cells 1/ 2/ 3 (LTC 1-indexed, array 0-indexed)
case 'B': cellX=3; cellY=4; cellZ=5 ; break; //LTC cells 4/ 5/ 6

View File

@@ -11,7 +11,7 @@
void SoC_setBatteryStateNow_percent(uint8_t newSoC);
uint8_t SoC_getBatteryStateNow_percent(void);
uint16_t SoC_getBatteryStateNow_deciPercent(void); //JTS2doNow: Use this in Battsci, etc.
uint16_t SoC_getBatteryStateNow_deciPercent(void); //JTS2doLater: Use this in Battsci, etc.
uint8_t SoC_estimateFromRestingCellVoltage_percent(void);

View File

@@ -182,12 +182,8 @@ void printHelp(void)
"\n -'$FAN' display fan status. '$FAN=OFF'/LOW/HI to set."
"\n -'$IHACK' display current hack setting. '$IHACK=00'/20/40/60 to set."
"\n -'$VHACK' display voltage hack setting. '$VHACK=OEM'/ASSISTONLY_VAR/ASSISTONLY_BIN/ALWAYS."
"\n -'$ASSIST_OFF' disable assist until LiBCM resets."
"\n -'$ASSIST_ON' enable assist until LiBCM resets."
"\n -'$REGEN_OFF' disable regen until LiBCM resets."
"\n -'$REGEN_ON' enable regen until LiBCM resets."
"\n -'SoC_MAX' display max allowed SoC. 'SoC_MAX=__' to set."
"\n -'SoC_MIN' display min allowed SoC. 'SoC_MIN=__' to set."
"\n -'$AST=ON/OFF'"
"\n -'$RGN=ON/OFF'"
*/
));
//When adding new commands, make sure to add cases to the following functions:
@@ -198,28 +194,24 @@ void printHelp(void)
/////////////////////////////////////////////////////////////////////////////////////////
//JTS2doNow: Add '$SPOOF' code
//JTS2doNow: Finish this function
void printVspoofInstructions(void)
{
Serial.print(F("\n\nVoltage Spoofing Commands:"
"\n -'$BVO=_ : +/-/0: increase/decrease/reset OBDIIC&C parameter 0x0A"
"\n -'$MDV=_ : +/-/0: increase/decrease/reset OBDIIC&C parameter 0x05"
"\n -'$BVO=_ : +/-/0: adjust OBDIIC&C parameter 0x0A"
"\n -'$MDV=_ : +/-/0: adjust OBDIIC&C parameter 0x05"
"\n -'$SPF=_ : +/-/0: adjust max allowed spoofed pack voltage"
"\n"
"\nInstructions:"
"\n 1: KeyON, engine not running, no IMA CELs"
"\n 2: Display above parameters on OBDIIC&C"
"\n 3: Compare LiBCM's spoofed pack voltage to the above parameters."
"\n 4: Adjust above parameters as needed to make all voltages equal."
"\n For example, if OBDII BVO is 169 volts & Vspoof is 175 volts,"
"\n type $BVO=+ to increase BVO. Repeat as needed."
"\n Goal: All three parameters within 5 volts."
"\nCalibration instructions:"
"\n 0: KeyON, engine off, IMA light must remain off throughout test"
"\n 1: Configure OBDIIC&C to display BVO parameter 0x0A"
"\n 2: Configure OBDIIC&C to display MDV parameter 0x05"
"\n 4: Adjust BVO (on OBDIIC&C) until equal to SPF (on LiBCM LCD)"
"\n Example: BVO is 169 volts & SPF is 175 volts. Type '$BVO=+' repeatedly until BVO=SPF"
"\n Note: If '$BVO=+' doesn't increase BVO, type '$SPF=-' to reduce SPF"
"\n 5: Adjust MDV until equal to SPF"
"\n Example: MDV is 171 volts & SPF is 168 volts. Type '$MDV=-' repeatedly until MDV=SPF"
"\n 6: Verify SPF & BVO & MDV are within 5 volts (ideally 0 volts)"
));
//When adding new commands, make sure to add cases to the following functions:
//USB_userInterface_executeUserInput()
//eeprom_resetDebugValues() //if debug data is stored in EEPROM
//eeprom_verifyDataValid() //if data is stored in EEPROM
}
/////////////////////////////////////////////////////////////////////////////////////////
@@ -419,9 +411,9 @@ void USB_userInterface_executeUserInput(void)
Serial.print(' ');
if ( (line[4]=='=') &&
((line[5]=='+') || (line[5]=='-') || (line[5]=='0')) &&
(line[6]==STRING_TERMINATION_CHARACTER) ) { vPackSpoof_offsetBVO_adjust(line[5]); }
(line[6]==STRING_TERMINATION_CHARACTER) ) { vPackSpoof_offsetBVO_adjust(line[5]); }
else if (line[4]==STRING_TERMINATION_CHARACTER) { Serial.print(vPackSpoof_offsetBVO_get()); }
else { printText_invalidEntry(); }
else { printText_invalidEntry(); }
}
//$MDV
@@ -431,9 +423,21 @@ void USB_userInterface_executeUserInput(void)
Serial.print(' ');
if ( (line[4]=='=') &&
((line[5]=='+') || (line[5]=='-') || (line[5]=='0')) &&
(line[6]==STRING_TERMINATION_CHARACTER) ) { vPackSpoof_offsetMDV_adjust(line[5]); }
(line[6]==STRING_TERMINATION_CHARACTER) ) { vPackSpoof_offsetMDV_adjust(line[5]); }
else if (line[4]==STRING_TERMINATION_CHARACTER) { Serial.print(vPackSpoof_offsetMDV_get()); }
else { printText_invalidEntry(); }
else { printText_invalidEntry(); }
}
//$SPF
else if ((line[1]=='S') && (line[2]=='P') && (line[3]=='F'))
{
//MDV affects VPIN output
Serial.print(' ');
if ( (line[4]=='=') &&
((line[5]=='+') || (line[5]=='-') || (line[5]=='0')) &&
(line[6]==STRING_TERMINATION_CHARACTER) ) { vPackSpoof_offsetSPF_adjust(line[5]); }
else if (line[4]==STRING_TERMINATION_CHARACTER) { Serial.print(vPackSpoof_offsetSPF_get()); }
else { printText_invalidEntry(); }
}
//$SPOOF

View File

@@ -192,7 +192,7 @@ uint8_t BATTSCI_calculateRegenAssistFlags(void)
if ((BATTSCI_isPackFull() == YES) || //pack is full
((temperature_battery_getLatest() < TEMP_FREEZING_DEGC + 2) && (BATTSCI_isPackEmpty() == NO)) ) //pack too cold to charge; DCDC still powered
//JTS2doLater: Allow minimal regen when pack below freezing (e.g. using LiControl to limit max regen)
//JTS2doNow: Disable assist and regen if pack too hot
//JTS2doLater: Disable assist and regen if pack too hot
#endif
{
flags |= BATTSCI_DISABLE_REGEN_FLAG; //when this flag is set, MCM draws zero power from IMA motor
@@ -219,7 +219,7 @@ uint8_t BATTSCI_calculateRegenAssistFlags(void)
// 0x32 = 50d = 0b0011 0010: pack empty
// 0x52 = 82d = 0b0101 0010: pack full (usually... see "Day1-1" for case where pack is empty)
//JTS2doNow: Allow regen at lower temperatures (see calculations in LiBCM Support Thread post#3637)
//JTS2doLater: Allow regen at lower temperatures (see calculations in LiBCM Support Thread post#3637)
//kindly request regen and/or no regen from MCM
uint8_t BATTSCI_calculateChargeRequestByte(void)
{

View File

@@ -28,6 +28,7 @@ const uint16_t EEPROM_ADDRESS_COMPILE_TIME = 0x013; //EEPROM range is 0x0
const uint16_t EEPROM_ADDRESS_MAX_VCELL_DELTA = 0x01C; //EEPROM range is 0x01C:0x01D ( 2B)
const uint16_t EEPROM_ADDRESS_BVO_OFFSET = 0x01E; //EEPROM range is 0x01E ( 1B)
const uint16_t EEPROM_ADDRESS_MDV_OFFSET = 0x01F; //EEPROM range is 0x01F ( 1B)
const uint16_t EEPROM_ADDRESS_SPF_OFFSET = 0x020; //EEPROM range is 0x020 ( 1B)
//this EEPROM space still available
//The following addresses start from end of EEPROM space and work backwards to beginning
const uint16_t EEPROM_ADDRESS_BATT_HISTORY = EEPROM_LAST_USABLE_ADDRESS - NUM_BYTES_BATTERY_HISTORY; //0xA57:0xF9F (1536B)
@@ -203,10 +204,13 @@ void eeprom_delayKeyON_ms_set(uint8_t delay_ms) { EEPROM.upd
/////////////////////////////////////////////////////////////////////////////////////////
int8_t eeprom_getVspoofOffset_BVO(void) { return EEPROM.read (EEPROM_ADDRESS_BVO_OFFSET); }
void eeprom_setVspoofOffset_BVO(int8_t newOffset_counts) { EEPROM.update(EEPROM_ADDRESS_BVO_OFFSET, newOffset_counts); }
int8_t eeprom_getVspoofOffset_MDV(void) { return EEPROM.read (EEPROM_ADDRESS_MDV_OFFSET); }
void eeprom_setVspoofOffset_MDV(int8_t newOffset_counts) { EEPROM.update(EEPROM_ADDRESS_MDV_OFFSET, newOffset_counts); }
int8_t eeprom_getVspoofOffset_BVO(void) { return EEPROM.read (EEPROM_ADDRESS_BVO_OFFSET); }
int8_t eeprom_getVspoofOffset_MDV(void) { return EEPROM.read (EEPROM_ADDRESS_MDV_OFFSET); }
int8_t eeprom_getVspoofOffset_SPF(void) { return EEPROM.read (EEPROM_ADDRESS_SPF_OFFSET); }
void eeprom_setVspoofOffset_BVO(int8_t newOffset_counts) { EEPROM.update(EEPROM_ADDRESS_BVO_OFFSET, newOffset_counts); }
void eeprom_setVspoofOffset_MDV(int8_t newOffset_counts) { EEPROM.update(EEPROM_ADDRESS_MDV_OFFSET, newOffset_counts); }
void eeprom_setVspoofOffset_SPF(int8_t newOffset_counts) { EEPROM.update(EEPROM_ADDRESS_SPF_OFFSET, newOffset_counts); }
/////////////////////////////////////////////////////////////////////////////////////////
@@ -256,16 +260,15 @@ void eeprom_verifyDataValid(void)
EEPROM.update(EEPROM_ADDRESS_NEXT_Wh_RECORD, EEPROM_ADDRESS_FORMATTED_VALUE);
}
if (EEPROM.read(EEPROM_ADDRESS_BVO_OFFSET) == EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE_8b)
if ((EEPROM.read(EEPROM_ADDRESS_BVO_OFFSET) == EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE_8b) &&
(EEPROM.read(EEPROM_ADDRESS_MDV_OFFSET) == EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE_8b) &&
(EEPROM.read(EEPROM_ADDRESS_SPF_OFFSET) == EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE_8b) )
{
printMessage_RestoringEEPROM(); Serial.print(F("BVO_OFFSET"));
//JTS2doLater: fix int8_t issue where EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE_8b = 0xFF = -1
printMessage_RestoringEEPROM(); Serial.print(F("VPACKSPOOF_OFFSETS"));
EEPROM.update(EEPROM_ADDRESS_BVO_OFFSET, EEPROM_ADDRESS_FORMATTED_VALUE);
}
if (EEPROM.read(EEPROM_ADDRESS_MDV_OFFSET) == EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE_8b)
{
printMessage_RestoringEEPROM(); Serial.print(F("MDV_OFFSET"));
EEPROM.update(EEPROM_ADDRESS_MDV_OFFSET, EEPROM_ADDRESS_FORMATTED_VALUE);
EEPROM.update(EEPROM_ADDRESS_SPF_OFFSET, EEPROM_ADDRESS_FORMATTED_VALUE);
}
}

View File

@@ -13,8 +13,8 @@
#define EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE_8b 0xFF
#define EEPROM_ADDRESS_FORMATTED_VALUE 0x00
#define BYTES_IN_DATE 12 //JTS2doLater: Is date 11 bytes or 12?
#define BYTES_IN_TIME 9 //JTS2doLater: Is time 9 bytes or 8?
#define BYTES_IN_DATE 12
#define BYTES_IN_TIME 9
#define REQUIRED_FIRMWARE_UPDATE_PERIOD_DAYS 120
#define REQUIRED_FIRMWARE_UPDATE_PERIOD_HOURS (REQUIRED_FIRMWARE_UPDATE_PERIOD_DAYS * 24)
@@ -47,9 +47,12 @@
void eeprom_delayKeyON_ms_set(uint8_t);
int8_t eeprom_getVspoofOffset_BVO(void);
void eeprom_setVspoofOffset_BVO(int8_t);
int8_t eeprom_getVspoofOffset_MDV(void);
void eeprom_setVspoofOffset_MDV(int8_t);
int8_t eeprom_getVspoofOffset_SPF(void);
void eeprom_setVspoofOffset_BVO(int8_t);
void eeprom_setVspoofOffset_MDV(int8_t);
void eeprom_setVspoofOffset_SPF(int8_t);
void eeprom_resetDebugValues(void);

View File

@@ -117,6 +117,7 @@ void processChargerDisableReason(uint8_t canWeCharge)
/////////////////////////////////////////////////////////////////////////////////////////
//JTS2doLater: add current feedback to 1500 charger, so LiBCM can cycle charger if no output current detected
//JTS2doLater: add timer/current logic to detect if grid charger isn't working
void chargerControlSignals_handler(void)
{

View File

@@ -22,7 +22,7 @@ void key_handleKeyEvent_off(void)
METSCI_disable();
LTC68042cell_acquireAllCellVoltages();
SoC_updateUsingLatestOpenCircuitVoltage(); //JTS2doLater: Add ten minute delay before VoC->SoC LUT
adc_calibrateBatteryCurrentSensorOffset(DEBUG_TEXT_ENABLED);
adc_calibrateBatteryCurrentSensorOffset(DEBUG_TEXT_ENABLED); //JTS2doNext: move to keyON
gpio_turnPowerSensors_off();
LTC68042configure_handleKeyStateChange();
vPackSpoof_handleKeyOFF();
@@ -127,7 +127,7 @@ void keyOn_coldBootTasks(void)
vPackSpoof_setVoltage();
SoC_setBatteryStateNow_percent(SoC_estimateFromRestingCellVoltage_percent());
BATTSCI_enable(); //must occur after we have valid Vcell data
adc_calibrateBatteryCurrentSensorOffset(DEBUG_TEXT_DISABLED); //current sensor settles almost immediately
adc_calibrateBatteryCurrentSensorOffset(DEBUG_TEXT_DISABLED); //current sensor settles almost immediately //JTS2doLater: Can we detect true keyON from USB reset?
}
/////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -98,7 +98,7 @@ bool lcd_flashBacklight(void)
/////////////////////////////////////////////////////////////////////////////////////////
//JTS2doNow: Build string in RAM, then send all at once to display (much faster).
//JTS2doLater: Build string in RAM, then send all at once to display (much faster).
//alternates between:
//time since last keyON, and; //"tuuuuu" in seconds

View File

@@ -242,7 +242,7 @@ void temperature_handler(void)
uint8_t keyState_Now = key_getSampledState(); //prevent mid-loop key state change
keyState_Now = turnSensorsOff_whenKeyStateChanges(keyState_Now); //JTS2doNow: function returns value meant for tempSensorState //writing to wrong variable?
keyState_Now = turnSensorsOff_whenKeyStateChanges(keyState_Now); //JTS2doNext: function returns value meant for tempSensorState //writing to wrong variable?
static uint32_t latestTempMeasurement_ms = 0;
static uint32_t latestSensorTurnon_ms = 0;

View File

@@ -38,6 +38,7 @@ void vPackSpoof_handleKeyOFF(void)
int8_t vPackSpoof_offsetBVO_get(void) { return eeprom_getVspoofOffset_BVO(); }
int8_t vPackSpoof_offsetMDV_get(void) { return eeprom_getVspoofOffset_MDV(); }
int8_t vPackSpoof_offsetSPF_get(void) { return eeprom_getVspoofOffset_SPF(); }
void vPackSpoof_offsetBVO_adjust(uint8_t action)
{
@@ -53,6 +54,14 @@ void vPackSpoof_offsetMDV_adjust(uint8_t action)
else if (action == '0') { eeprom_setVspoofOffset_MDV(0); }
}
void vPackSpoof_offsetSPF_adjust(uint8_t action)
{
if (action == '+') { eeprom_setVspoofOffset_SPF(eeprom_getVspoofOffset_SPF() + 1); }
else if (action == '-') { eeprom_setVspoofOffset_SPF(eeprom_getVspoofOffset_SPF() - 1); }
else if (action == '0') { eeprom_setVspoofOffset_SPF(0); }
}
/////////////////////////////////////////////////////////////////////////////////////////
void spoofVoltageMCMe(void)
@@ -106,8 +115,6 @@ uint8_t calculate_Vspoof_maxPossible(void)
//The max allowed voltage is a function of the actual pack voltage
//Derivation: ~/Electronics/PCB (KiCAD)/RevD/V&V/VPIN-MCMe Calibration.ods
//JTS2doNow: Decide if adding more headroom here is easier than changing existing calibration method
uint8_t actualPackVoltage = LTC68042result_packVoltage_get();
uint8_t maxAllowedVspoof = 0;
@@ -128,6 +135,8 @@ uint8_t calculate_Vspoof_maxPossible(void)
else if (actualPackVoltage < 245) { maxAllowedVspoof = actualPackVoltage - 20; }
else { maxAllowedVspoof = actualPackVoltage - 21; }
maxAllowedVspoof += eeprom_getVspoofOffset_SPF();
return maxAllowedVspoof;
}

View File

@@ -23,9 +23,12 @@
void vPackSpoof_handleKeyON(void);
int8_t vPackSpoof_offsetBVO_get(void);
void vPackSpoof_offsetBVO_adjust(uint8_t action);
int8_t vPackSpoof_offsetMDV_get(void);
void vPackSpoof_offsetMDV_adjust(uint8_t action);
int8_t vPackSpoof_offsetSPF_get(void);
void vPackSpoof_offsetBVO_adjust(uint8_t action);
void vPackSpoof_offsetMDV_adjust(uint8_t action);
void vPackSpoof_offsetSPF_adjust(uint8_t action);
uint8_t vPackSpoof_getSpoofedPackVoltage(void);