Merge pull request #77 from doppelhub/JTS_inWork

JTS_IN_WORK to Prerelease:
-VpackSpoof Calibration
-Improved Balancing
This commit is contained in:
doppelhub
2025-07-08 05:48:10 -04:00
committed by GitHub
26 changed files with 827 additions and 566 deletions

View File

@@ -7,8 +7,8 @@
#define config_h
#include "src/libcm.h"
#define FW_VERSION "0.9.5f"
#define BUILD_DATE "2025JUN02"
#define FW_VERSION "0.9.5n"
#define BUILD_DATE "2025JUL07"
//////////////////////////////////////////////////////////////////
@@ -25,15 +25,15 @@
//choose your battery type:
//#define BATTERY_TYPE_5AhG3 //if you're not sure, you probably have this battery
//#define BATTERY_TYPE_47AhFoMoCo
//#define BATTERY_TYPE_47Ah //aka FoMoCo //aka Samsung SDI modules
//choose how many cells are in series:
//#define STACK_IS_48S //All 5AhG3 Kits & FoMoCo Kits with QTY4 modules
//#define STACK_IS_60S //FoMoCo Kits with QTY5 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 FoMoCo Kits
//#define GRIDCHARGER_IS_1500W //'faster' 47Ah FoMoCo Kits only
//#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:
@@ -95,14 +95,11 @@
#define CELL_VMAX_REGEN 43000 //43000 = 4.3000 volts
#define CELL_VMIN_ASSIST 31900
#define CELL_VMAX_GRIDCHARGER 39600 //3.9 volts is 75% SoC //other values: See SoC.cpp //MUST be less than 'CELL_VREST_85_PERCENT_SoC'
#define CELL_VMAX_GRIDCHARGER 39600 //MUST be less than 'CELL_VREST_085_PERCENT_SoC'
#define CELL_VMIN_GRIDCHARGER 30000 //grid charger will not charge severely empty cells
#define CELL_VMIN_KEYOFF CELL_VREST_10_PERCENT_SoC //when car is off, LiBCM turns off below this voltage
#define CELL_VMIN_KEYOFF CELL_VREST_010_PERCENT_SoC //when car is off, LiBCM turns off below this voltage
#define CELL_BALANCE_MIN_SoC 65 //when car is off, cell balancing is disabled when battery is less than this percent charged
#define CELL_BALANCE_TO_WITHIN_COUNTS_LOOSE 32 //'32' = 3.2 mV //CANNOT exceed 255 counts (25.5 mV)
#define CELL_BALANCE_TO_WITHIN_COUNTS_TIGHT 22 //'22' = 2.2 mV //LTC6804 measurement uncertainty is 2.2 mV //MUST be less than CELL_BALANCE_TO_WITHIN_COUNTS_LOOSE
#define CELL_BALANCE_MAX_TEMP_C 40
//#define ONLY_BALANCE_CELLS_WHEN_GRID_CHARGER_PLUGGED_IN //uncomment to disable keyOFF cell balancing (unless the grid charger is plugged in)
//temp setpoints
#define COOL_BATTERY_ABOVE_TEMP_C_KEYOFF 36 //cabin air cooling

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
@@ -130,15 +130,10 @@ void validateAndStoreNextCVR(uint8_t chipAddress, char cellVoltageRegister)
/////////////////////////////////////////////////////////////////////////////////////////
//results stored in LTC68042results.c
void processAllCellVoltages(void)
//For hardware reasons, cell 19's measured voltage is corrected here
uint16_t calculateVoltageCell19(uint16_t cell19Voltage_measured, uint16_t hiCellVoltage, uint16_t loCellVoltage)
{
uint32_t packVoltage_RAW = 0; //Multiply by 0.0001 for volts
uint16_t loCellVoltage = 65535;
uint16_t hiCellVoltage = 0;
#ifdef BATTERY_TYPE_5AhG3
//On LiBCM, QTY3 LTC6804 ICs measure QTY2 18S EHW5 modules:
//On LiBCM, QTY3 LTC6804 ICs measure QTY2 18S EHW5 modules:
// -LTC6804 'A' measures the first QTY12 cells in the 1st 18S module (stack cells 01:12). No problems here.
// -LTC6804 'C' measures the last QTY12 cells in the 2nd 18S module (stack cells 25:36). No problems here.
// -LTC6804 'B' measures the remaining QTY6 cells in both modules (stack cells 13:18 in module 'A', as well as stack cells 19:24 in module 'C').
@@ -157,79 +152,88 @@ void processAllCellVoltages(void)
//The ideal solution would be to use the LTC6813 - which measures QTY18 cells - on both 18S EHW5 modules.
//However, that IC is backordered for years, hence the above hardware decision and this workaround.
//It's not ideal, but it's what we've got. STFP!
const uint8_t VOLTAGECORRECTION_mV_PER_AMP = 1; //1 mV/A error measured on 4 AWG cable between modules
const uint8_t LTC6804_COUNTS_PER_mV = 10; //LSB is 100 uV
const uint8_t LTC6804_COUNT_ADJUSTMENT_PER_AMP = (VOLTAGECORRECTION_mV_PER_AMP * LTC6804_COUNTS_PER_mV);
//cell 19 is the seventh cell on the second IC
#define CELL19_CHIP_NUMBER 1 //array is zero-indexed // '1' is the 2nd IC
#define CELL19_CELL_NUMBER 6 //array is zero-indexed // '6' is seventh cell (i.e. stack cell 19)
uint16_t midpointVoltage = ((hiCellVoltage - loCellVoltage) >> 1) + loCellVoltage;
uint16_t cell19absDelta_measured = 0;
uint16_t cell19absDelta_adjusted = 0;
uint16_t cell19Voltage_adjusted = cell19Voltage_measured + adc_getLatestBatteryCurrent_amps() * LTC6804_COUNT_ADJUSTMENT_PER_AMP;
#define VOLTAGECORRECTION_mV_PER_AMP 1 //1 mV/A error measured on RevC hardware //only corrects cell 19 for this specific issue
#define LTC6804_COUNTS_PER_mV 10 //LSB is 100 uV
#define LTC6804_COUNT_ADJUSTMENT_PER_AMP (VOLTAGECORRECTION_mV_PER_AMP * LTC6804_COUNTS_PER_mV) //preprocessor handles this multiply
//find measured voltage magnitude from midpoint
if (cell19Voltage_measured > midpointVoltage) { cell19absDelta_measured = cell19Voltage_measured - midpointVoltage; }
else { cell19absDelta_measured = midpointVoltage - cell19Voltage_measured; }
uint16_t cell19Voltage_measured = cellVoltages_counts[CELL19_CHIP_NUMBER][CELL19_CELL_NUMBER]; //store cell 19 voltage for later
uint16_t cell19Voltage_adjusted = cell19Voltage_measured + adc_getLatestBatteryCurrent_amps() * LTC6804_COUNT_ADJUSTMENT_PER_AMP;
//find adjusted voltage magnitude from midpoint
if (cell19Voltage_adjusted > midpointVoltage) { cell19absDelta_adjusted = cell19Voltage_adjusted - midpointVoltage; }
else { cell19absDelta_adjusted = midpointVoltage - cell19Voltage_adjusted; }
//temporarily replace cell 19's voltage with cell 18's, to prevent cell 19's (possibly incorrect) voltage from being either the highest or lowest voltage
cellVoltages_counts[CELL19_CHIP_NUMBER][CELL19_CELL_NUMBER] = cellVoltages_counts[CELL19_CHIP_NUMBER][CELL19_CELL_NUMBER - 1];
//we'll restore cell 19's voltage after we determine pack hi/lo (in the for loops below)
uint16_t cell19Voltage_closest = 0;
if (cell19absDelta_measured > cell19absDelta_adjusted) { cell19Voltage_closest = cell19Voltage_adjusted; } //adjusted value is closer to midpoint
else { cell19Voltage_closest = cell19Voltage_measured; } //measured value is closer to midpoint
return cell19Voltage_closest;
}
/////////////////////////////////////////////////////////////////////////////////////////
//results stored in LTC68042results.c
void processAllCellVoltages(void)
{
#ifdef BATTERY_TYPE_5AhG3
//store actual cell 19 voltage measurement for later recall
uint16_t cell19Voltage_measured = cellVoltages_counts[CELL19_CHIP_NUMBER][CELL19_CELL_NUMBER];
//temporarily replace cell 19's voltage with another cell
uint16_t cell19Voltage_spoofed = cellVoltages_counts[CELL19_CHIP_NUMBER][CELL19_CELL_NUMBER - 1];
cellVoltages_counts[CELL19_CHIP_NUMBER][CELL19_CELL_NUMBER] = cell19Voltage_spoofed;
//see calculateVoltageCell19() for explanation
#endif
uint32_t packVoltage_RAW = 0; //Multiply by 0.0001 for volts
uint16_t loCellVoltage = 65535;
uint16_t hiCellVoltage = 0;
uint8_t loCellNumber = 0;
uint8_t hiCellNumber = 0;
//loop through every cell in pack
for (int chip = 0 ; chip < TOTAL_IC; chip++) //actual LTC serial address: 'chip' + FIRST_IC_ADDR )
{
for (int cell=0; cell < CELLS_PER_IC; cell++) //actual LTC cell number: 'cell' + 1 (zero-indexed)
{
for (int cell=0; cell < CELLS_PER_IC; cell++) //physical LTC cell number (1 to 48): 'cell' + 1 (array is zero-indexed)
{
uint16_t cellVoltageUnderTest = cellVoltages_counts[chip][cell];
//accumulate Vpack
packVoltage_RAW += cellVoltageUnderTest;
uint16_t Vcell = cellVoltages_counts[chip][cell];
LTC68042result_specificCellVoltage_set(chip, cell, Vcell);
packVoltage_RAW += Vcell;
//find hi/lo cells
if (cellVoltageUnderTest < loCellVoltage) { loCellVoltage = cellVoltageUnderTest; }
if (cellVoltageUnderTest > hiCellVoltage) { hiCellVoltage = cellVoltageUnderTest; }
//check for new maxEver/minEver cells (if any)
//If BATTERY_TYPE_5AhG3 is defined, cell 19 voltage cannot become maxEver or minEver right now, but we'll check again down below
if (cellVoltageUnderTest > LTC68042result_maxEverCellVoltage_get()) {LTC68042result_maxEverCellVoltage_set(cellVoltageUnderTest); }
if (cellVoltageUnderTest < LTC68042result_minEverCellVoltage_get()) {LTC68042result_minEverCellVoltage_set(cellVoltageUnderTest); }
LTC68042result_specificCellVoltage_set(chip, cell, cellVoltageUnderTest);
if (Vcell < loCellVoltage) { loCellVoltage = Vcell; loCellNumber = chip*CELLS_PER_IC+cell+1; }
if (Vcell > hiCellVoltage) { hiCellVoltage = Vcell; hiCellNumber = chip*CELLS_PER_IC+cell+1; }
}
}
LTC68042result_packVoltage_set( (uint8_t)(packVoltage_RAW * 0.0001) );
#ifdef BATTERY_TYPE_5AhG3
uint16_t cell19Voltage_final = calculateVoltageCell19(cell19Voltage_measured, hiCellVoltage, loCellVoltage);
LTC68042result_specificCellVoltage_set(CELL19_CHIP_NUMBER, CELL19_CELL_NUMBER, cell19Voltage_final);
if (cell19Voltage_final > hiCellVoltage) { hiCellVoltage = cell19Voltage_final; hiCellNumber = 19; }
if (cell19Voltage_final < loCellVoltage) { loCellVoltage = cell19Voltage_final; loCellNumber = 19; }
packVoltage_RAW = packVoltage_RAW - cell19Voltage_spoofed + cell19Voltage_measured;
#endif
LTC68042result_loCellVoltage_set(loCellVoltage);
LTC68042result_hiCellVoltage_set(hiCellVoltage);
LTC68042result_loCellNum_set(loCellNumber);
LTC68042result_hiCellNum_set(hiCellNumber);
LTC68042result_deltaCellVoltage_set(hiCellVoltage - loCellVoltage);
LTC68042result_packVoltage_set( (uint8_t)(packVoltage_RAW * 0.0001) );
#ifdef BATTERY_TYPE_5AhG3
//Now we need to determine which cell 19 voltage is correct (the actual measured value, or the current-adjusted one)
//We do this by determining which voltage has the smallest magnitude from the max/min cell voltages (determined above).
uint16_t midpointVoltage = ((hiCellVoltage - loCellVoltage) >> 1) + loCellVoltage;
uint16_t cell19deltaMagnitude_measured = 0;
uint16_t cell19deltaMagnitude_adjusted = 0;
//find measured voltage magnitude from midpoint
if (cell19Voltage_measured > midpointVoltage) { cell19deltaMagnitude_measured = cell19Voltage_measured - midpointVoltage; }
else { cell19deltaMagnitude_measured = midpointVoltage - cell19Voltage_measured; }
//find adjusted voltage magnitude from midpoint
if (cell19Voltage_adjusted > midpointVoltage) { cell19deltaMagnitude_adjusted = cell19Voltage_adjusted - midpointVoltage; }
else { cell19deltaMagnitude_adjusted = midpointVoltage - cell19Voltage_adjusted; }
uint16_t cell19Voltage_final = 0;
if (cell19deltaMagnitude_measured > cell19deltaMagnitude_adjusted) { cell19Voltage_final = cell19Voltage_adjusted; } //adjusted value is closer to midpoint
else { cell19Voltage_final = cell19Voltage_measured; } //measured value is closer to midpoint
//store whichever cell 19 voltage is closest to the other cells
LTC68042result_specificCellVoltage_set(CELL19_CHIP_NUMBER, CELL19_CELL_NUMBER, cell19Voltage_final);
//finally, we need to check if cell 19 is either the highest or lowest voltage
if (cell19Voltage_final > hiCellVoltage) { LTC68042result_hiCellVoltage_set(cell19Voltage_final); }
if (cell19Voltage_final < loCellVoltage) { LTC68042result_loCellVoltage_set(cell19Voltage_final); }
#endif
if (hiCellVoltage > LTC68042result_maxEverCellVoltage_get()) {LTC68042result_maxEverCellVoltage_set(hiCellVoltage); }
if (loCellVoltage < LTC68042result_minEverCellVoltage_get()) {LTC68042result_minEverCellVoltage_set(loCellVoltage); }
}
/////////////////////////////////////////////////////////////////////////////////////////
@@ -300,6 +304,9 @@ bool LTC68042cell_nextVoltages(void)
while (1) {;} //hang here until watchdog resets.
}
if (cellVoltageDataStatus == CELL_DATA_PROCESSED) { LTC68042result_wasDataProcessedThisLoop_set(YES); }
else { LTC68042result_wasDataProcessedThisLoop_set(NO); }
return cellVoltageDataStatus;
}

View File

@@ -13,6 +13,10 @@
#define LTC6804_MAX_CONVERSION_TIME_ms 5 //4.43 ms in '2kHz' sampling mode
//cell 19 is the seventh cell on the second IC
#define CELL19_CHIP_NUMBER 1 //array is zero-indexed // '1' is the 2nd IC
#define CELL19_CELL_NUMBER 6 //array is zero-indexed // '6' is seventh cell (i.e. stack cell 19)
bool LTC68042cell_nextVoltages(void);
void LTC68042cell_acquireAllCellVoltages(void);

View File

@@ -1,10 +1,14 @@
//Copyright 2021-2024(c) John Sullivan
//github.com/doppelhub/Honda_Insight_LiBCM
//The latest results gathered from LTC6804 are stored here.
//latest LTC6804 results are stored here
#include "libcm.h"
bool wasProcessed = NO;
bool LTC68042result_wasDataProcessedThisLoop_get(void ) { return wasProcessed; }
void LTC68042result_wasDataProcessedThisLoop_set(bool newStatus) { wasProcessed = newStatus; }
uint8_t isoSPI_errorCount = 0;
uint8_t LTC68042result_errorCount_get (void ) { return isoSPI_errorCount; }
void LTC68042result_errorCount_set (uint8_t newErrorCount) { isoSPI_errorCount = newErrorCount; }
@@ -12,7 +16,15 @@ void LTC68042result_errorCount_increment (void ) { isoSPI_err
uint8_t packVoltage_actual = 170;
void LTC68042result_packVoltage_set (uint8_t voltage) { packVoltage_actual = voltage; }
uint8_t LTC68042result_packVoltage_get (void ) { return packVoltage_actual; }
uint8_t LTC68042result_packVoltage_get (void ) { return packVoltage_actual; }
uint8_t loCellNumber = 0;
void LTC68042result_loCellNum_set(uint8_t cellNumber) { loCellNumber = cellNumber; }
uint8_t LTC68042result_loCellNum_get(void) { return loCellNumber; }
uint8_t hiCellNumber = 0;
void LTC68042result_hiCellNum_set(uint8_t cellNumber) { hiCellNumber = cellNumber; }
uint8_t LTC68042result_hiCellNum_get(void) { return hiCellNumber; }
uint16_t minEverCellVoltage_counts = 65535; //since last key event
void LTC68042result_minEverCellVoltage_set(uint16_t newMin_counts) { minEverCellVoltage_counts = newMin_counts; }
@@ -30,6 +42,10 @@ uint16_t hiCellVoltage_counts = 34567;
void LTC68042result_hiCellVoltage_set(uint16_t newHi_counts) { hiCellVoltage_counts = newHi_counts; }
uint16_t LTC68042result_hiCellVoltage_get(void ) { return hiCellVoltage_counts; }
uint16_t deltaCellVoltage_counts = 0;
void LTC68042result_deltaCellVoltage_set(uint16_t newDelta_counts) { deltaCellVoltage_counts = newDelta_counts; }
uint16_t LTC68042result_deltaCellVoltage_get(void ) { return deltaCellVoltage_counts; }
/////////////////////////////////////////////////////////////////////////////////////////
//All cell voltages in this array are guaranteed to be acquired at the same time

View File

@@ -4,12 +4,21 @@
#ifndef LTC68042result_h
#define LTC68042result_h
uint8_t LTC68042result_errorCount_get (void );
void LTC68042result_errorCount_set (uint8_t newErrorCount);
void LTC68042result_errorCount_increment (void );
bool LTC68042result_wasDataProcessedThisLoop_get(void );
void LTC68042result_wasDataProcessedThisLoop_set(bool newStatus);
void LTC68042result_packVoltage_set (uint8_t voltage);
uint8_t LTC68042result_packVoltage_get (void );
uint8_t LTC68042result_errorCount_get (void );
void LTC68042result_errorCount_set (uint8_t newErrorCount);
void LTC68042result_errorCount_increment(void );
void LTC68042result_packVoltage_set(uint8_t voltage);
uint8_t LTC68042result_packVoltage_get(void );
void LTC68042result_loCellNum_set(uint8_t cellNumber);
uint8_t LTC68042result_loCellNum_get(void); //first cell is '1'
void LTC68042result_hiCellNum_set(uint8_t cellNumber);
uint8_t LTC68042result_hiCellNum_get(void); //first cell is '1'
void LTC68042result_minEverCellVoltage_set(uint16_t newMin_counts);
uint16_t LTC68042result_minEverCellVoltage_get(void );
@@ -23,9 +32,9 @@
void LTC68042result_hiCellVoltage_set(uint16_t newHi_counts);
uint16_t LTC68042result_hiCellVoltage_get(void );
void LTC68042result_deltaCellVoltage_set(uint16_t newDelta_counts);
uint16_t LTC68042result_deltaCellVoltage_get(void );
void LTC68042result_specificCellVoltage_set(uint8_t icNumber, uint8_t cellNumber, uint16_t cellVoltage);
uint16_t LTC68042result_specificCellVoltage_get (uint8_t icNumber, uint8_t cellNumber);
uint16_t LTC68042result_specificCellVoltage_get(uint8_t icNumber, uint8_t cellNumber);
#endif
// void printCellVoltage_all(); //JTS2doLater: Add back

View File

@@ -97,7 +97,7 @@ void LiDisplay_begin(void)
{
#ifdef LIDISPLAY_CONNECTED
#ifdef BATTERY_TYPE_47AhFoMoCo
#ifdef BATTERY_TYPE_47Ah
#undef LIDISPLAY_GRIDCHARGE_PAGE_ID
#define LIDISPLAY_GRIDCHARGE_PAGE_ID 5
#endif
@@ -300,7 +300,7 @@ LiDisplay_updateNextCellValue() {
static uint8_t cellToUpdate = 0;
static uint8_t ic_index = 0;
static uint8_t ic_cell_num = 0;
static uint16_t cell_avg_voltage = 0;
static uint16_t cell_avg_voltage = 0; //TODO_NATALYA - JTS: this doesn't need to be static
static String cell_color_number = "2016";
static int cell_voltage_diff_from_avg = 0;
static int temp_cell_voltage = 0;
@@ -318,10 +318,11 @@ LiDisplay_updateNextCellValue() {
else if (cellToUpdate <= 59) { ic_index = 4; ic_cell_num = (cellToUpdate - 48); }
// 09 Feb 2023 -- cell_avg_voltage is a crude approximation of the centre of the voltage range. Ideally this would be replaced with the median cell voltage.
LiDisplayAverageCellVoltage = ((LTC68042result_hiCellVoltage_get() - LTC68042result_loCellVoltage_get()) * 0.5);
LiDisplayAverageCellVoltage = ((LTC68042result_hiCellVoltage_get() - LTC68042result_loCellVoltage_get()) * 0.5); //TODO_NATALYA - JTS: replace this line with next line
//LiDisplayAverageCellVoltage = (LTC68042result_deltaCellVoltage_get() >> 1 ) + LTC68042result_loCellVoltage_get();
cell_avg_voltage = (LiDisplayAverageCellVoltage + LTC68042result_loCellVoltage_get());
LiDisplayAverageCellVoltage = (cell_avg_voltage); // TODO_NATALYA - get rid of cell_avg_voltage
cell_avg_voltage = (LiDisplayAverageCellVoltage + LTC68042result_loCellVoltage_get()); //TODO_NATALYA - JTS: remove entire line and entire variable
LiDisplayAverageCellVoltage = (cell_avg_voltage); // TODO_NATALYA - get rid of cell_avg_voltage //TODO_NATALYA - JTS: remove entire line
temp_cell_voltage = LTC68042result_specificCellVoltage_get(ic_index, ic_cell_num);
cell_voltage_diff_from_avg = cell_avg_voltage - temp_cell_voltage;
@@ -856,7 +857,7 @@ void LiDisplay_updateElement() {
LiDisplay_calculateFanSpeedStr();
if (!gc_sixty_s_fomoco_e_block_enabled && (MAX_CELL_INDEX == 59))
{
LiDisplay_updateNumericVal(LIDISPLAY_GRIDCHARGE_PAGE_ID, "t16", 3, "65516"); // E block label will be missing on a 60S FoMoCo pack display if we don't run this once.
LiDisplay_updateNumericVal(LIDISPLAY_GRIDCHARGE_PAGE_ID, "t16", 3, "65516"); // E block label will be missing on a 60S 47Ah pack display if we don't run this once.
gc_sixty_s_fomoco_e_block_enabled = true;
}
else if (LiDisplayFanSpeed_onScreen != currentFanSpeed)

View File

@@ -104,224 +104,224 @@ void SoC_updateUsingLatestOpenCircuitVoltage(void)
uint16_t restingCellVoltage = LTC68042result_loCellVoltage_get(); //JTS2doLater: need an algorithm to look at hi cell, too.
uint8_t estimatedSoC = 0;
if (restingCellVoltage >= 42000) { estimatedSoC = 100; }
else if (restingCellVoltage >= 41820) { estimatedSoC = 99; }
else if (restingCellVoltage >= 41640) { estimatedSoC = 98; }
else if (restingCellVoltage >= 41460) { estimatedSoC = 97; }
else if (restingCellVoltage >= 41280) { estimatedSoC = 96; }
else if (restingCellVoltage >= 41100) { estimatedSoC = 95; }
else if (restingCellVoltage >= 40980) { estimatedSoC = 94; }
else if (restingCellVoltage >= 40860) { estimatedSoC = 93; }
else if (restingCellVoltage >= 40740) { estimatedSoC = 92; }
else if (restingCellVoltage >= 40620) { estimatedSoC = 91; }
else if (restingCellVoltage >= 40500) { estimatedSoC = 90; }
else if (restingCellVoltage >= 40400) { estimatedSoC = 89; }
else if (restingCellVoltage >= 40300) { estimatedSoC = 88; }
else if (restingCellVoltage >= 40200) { estimatedSoC = 87; }
else if (restingCellVoltage >= 40100) { estimatedSoC = 86; }
else if (restingCellVoltage >= CELL_VREST_85_PERCENT_SoC) { estimatedSoC = 85; } //max cell voltage for long lifetime
else if (restingCellVoltage >= 39880) { estimatedSoC = 84; }
else if (restingCellVoltage >= 39760) { estimatedSoC = 83; }
else if (restingCellVoltage >= 39640) { estimatedSoC = 82; }
else if (restingCellVoltage >= 39520) { estimatedSoC = 81; }
else if (restingCellVoltage >= 39400) { estimatedSoC = 80; }
else if (restingCellVoltage >= 39260) { estimatedSoC = 79; }
else if (restingCellVoltage >= 39120) { estimatedSoC = 78; }
else if (restingCellVoltage >= 38980) { estimatedSoC = 77; }
else if (restingCellVoltage >= 38840) { estimatedSoC = 76; }
else if (restingCellVoltage >= 38700) { estimatedSoC = 75; }
else if (restingCellVoltage >= 38620) { estimatedSoC = 74; }
else if (restingCellVoltage >= 38540) { estimatedSoC = 73; }
else if (restingCellVoltage >= 38460) { estimatedSoC = 72; }
else if (restingCellVoltage >= 38380) { estimatedSoC = 71; }
else if (restingCellVoltage >= 38300) { estimatedSoC = 70; }
else if (restingCellVoltage >= 38230) { estimatedSoC = 69; }
else if (restingCellVoltage >= 38160) { estimatedSoC = 68; }
else if (restingCellVoltage >= 38090) { estimatedSoC = 67; }
else if (restingCellVoltage >= 38020) { estimatedSoC = 66; }
else if (restingCellVoltage >= 37950) { estimatedSoC = 65; }
else if (restingCellVoltage >= 37890) { estimatedSoC = 64; }
else if (restingCellVoltage >= 37830) { estimatedSoC = 63; }
else if (restingCellVoltage >= 37770) { estimatedSoC = 62; }
else if (restingCellVoltage >= 37710) { estimatedSoC = 61; }
else if (restingCellVoltage >= 37650) { estimatedSoC = 60; }
else if (restingCellVoltage >= 37580) { estimatedSoC = 59; }
else if (restingCellVoltage >= 37510) { estimatedSoC = 58; }
else if (restingCellVoltage >= 37440) { estimatedSoC = 57; }
else if (restingCellVoltage >= 37370) { estimatedSoC = 56; }
else if (restingCellVoltage >= 37300) { estimatedSoC = 55; }
else if (restingCellVoltage >= 37250) { estimatedSoC = 54; }
else if (restingCellVoltage >= 37200) { estimatedSoC = 53; }
else if (restingCellVoltage >= 37150) { estimatedSoC = 52; }
else if (restingCellVoltage >= 37100) { estimatedSoC = 51; }
else if (restingCellVoltage >= 37050) { estimatedSoC = 50; }
else if (restingCellVoltage >= 37000) { estimatedSoC = 49; }
else if (restingCellVoltage >= 36950) { estimatedSoC = 48; }
else if (restingCellVoltage >= 36900) { estimatedSoC = 47; }
else if (restingCellVoltage >= 36850) { estimatedSoC = 46; }
else if (restingCellVoltage >= 36800) { estimatedSoC = 45; }
else if (restingCellVoltage >= 36750) { estimatedSoC = 44; }
else if (restingCellVoltage >= 36700) { estimatedSoC = 43; }
else if (restingCellVoltage >= 36650) { estimatedSoC = 42; }
else if (restingCellVoltage >= 36600) { estimatedSoC = 41; }
else if (restingCellVoltage >= 36550) { estimatedSoC = 40; }
else if (restingCellVoltage >= 36480) { estimatedSoC = 39; }
else if (restingCellVoltage >= 36410) { estimatedSoC = 38; }
else if (restingCellVoltage >= 36340) { estimatedSoC = 37; }
else if (restingCellVoltage >= 36270) { estimatedSoC = 36; }
else if (restingCellVoltage >= 36200) { estimatedSoC = 35; }
else if (restingCellVoltage >= 36140) { estimatedSoC = 34; }
else if (restingCellVoltage >= 36080) { estimatedSoC = 33; }
else if (restingCellVoltage >= 36020) { estimatedSoC = 32; }
else if (restingCellVoltage >= 35960) { estimatedSoC = 31; }
else if (restingCellVoltage >= 35900) { estimatedSoC = 30; }
else if (restingCellVoltage >= 35800) { estimatedSoC = 29; }
else if (restingCellVoltage >= 35700) { estimatedSoC = 28; }
else if (restingCellVoltage >= 35600) { estimatedSoC = 27; }
else if (restingCellVoltage >= 35500) { estimatedSoC = 26; }
else if (restingCellVoltage >= 35400) { estimatedSoC = 25; }
else if (restingCellVoltage >= 35360) { estimatedSoC = 24; }
else if (restingCellVoltage >= 35320) { estimatedSoC = 23; }
else if (restingCellVoltage >= 35280) { estimatedSoC = 22; }
else if (restingCellVoltage >= 35240) { estimatedSoC = 21; }
else if (restingCellVoltage >= 35200) { estimatedSoC = 20; }
else if (restingCellVoltage >= 35160) { estimatedSoC = 19; }
else if (restingCellVoltage >= 35120) { estimatedSoC = 18; }
else if (restingCellVoltage >= 35080) { estimatedSoC = 17; }
else if (restingCellVoltage >= 35040) { estimatedSoC = 16; }
else if (restingCellVoltage >= 35000) { estimatedSoC = 15; }
else if (restingCellVoltage >= 34900) { estimatedSoC = 14; }
else if (restingCellVoltage >= 34800) { estimatedSoC = 13; }
else if (restingCellVoltage >= 34700) { estimatedSoC = 12; }
else if (restingCellVoltage >= 34540) { estimatedSoC = 11; }
else if (restingCellVoltage >= CELL_VREST_10_PERCENT_SoC) { estimatedSoC = 10; } //min cell voltage for long lifetime
else if (restingCellVoltage >= 33900) { estimatedSoC = 9; }
else if (restingCellVoltage >= 33600) { estimatedSoC = 8; }
else if (restingCellVoltage >= 33200) { estimatedSoC = 7; }
else if (restingCellVoltage >= 32800) { estimatedSoC = 6; }
else if (restingCellVoltage >= 32200) { estimatedSoC = 5; }
else if (restingCellVoltage >= 31700) { estimatedSoC = 4; }
else if (restingCellVoltage >= 31000) { estimatedSoC = 3; }
else if (restingCellVoltage >= 30500) { estimatedSoC = 2; }
else if (restingCellVoltage >= 29500) { estimatedSoC = 1; }
else { estimatedSoC = 0; }
if (restingCellVoltage >= CELL_VREST_100_PERCENT_SoC) { estimatedSoC = 100; }
else if (restingCellVoltage >= 41820) { estimatedSoC = 99; }
else if (restingCellVoltage >= 41640) { estimatedSoC = 98; }
else if (restingCellVoltage >= 41460) { estimatedSoC = 97; }
else if (restingCellVoltage >= 41280) { estimatedSoC = 96; }
else if (restingCellVoltage >= 41100) { estimatedSoC = 95; }
else if (restingCellVoltage >= 40980) { estimatedSoC = 94; }
else if (restingCellVoltage >= 40860) { estimatedSoC = 93; }
else if (restingCellVoltage >= 40740) { estimatedSoC = 92; }
else if (restingCellVoltage >= 40620) { estimatedSoC = 91; }
else if (restingCellVoltage >= 40500) { estimatedSoC = 90; }
else if (restingCellVoltage >= 40400) { estimatedSoC = 89; }
else if (restingCellVoltage >= 40300) { estimatedSoC = 88; }
else if (restingCellVoltage >= 40200) { estimatedSoC = 87; }
else if (restingCellVoltage >= 40100) { estimatedSoC = 86; }
else if (restingCellVoltage >= CELL_VREST_085_PERCENT_SoC) { estimatedSoC = 85; } //Vmax for long lifetime
else if (restingCellVoltage >= 39880) { estimatedSoC = 84; }
else if (restingCellVoltage >= 39760) { estimatedSoC = 83; }
else if (restingCellVoltage >= 39640) { estimatedSoC = 82; }
else if (restingCellVoltage >= 39520) { estimatedSoC = 81; }
else if (restingCellVoltage >= 39400) { estimatedSoC = 80; }
else if (restingCellVoltage >= 39260) { estimatedSoC = 79; }
else if (restingCellVoltage >= 39120) { estimatedSoC = 78; }
else if (restingCellVoltage >= 38980) { estimatedSoC = 77; }
else if (restingCellVoltage >= 38840) { estimatedSoC = 76; }
else if (restingCellVoltage >= 38700) { estimatedSoC = 75; }
else if (restingCellVoltage >= 38620) { estimatedSoC = 74; }
else if (restingCellVoltage >= 38540) { estimatedSoC = 73; }
else if (restingCellVoltage >= 38460) { estimatedSoC = 72; }
else if (restingCellVoltage >= 38380) { estimatedSoC = 71; }
else if (restingCellVoltage >= 38300) { estimatedSoC = 70; }
else if (restingCellVoltage >= 38230) { estimatedSoC = 69; }
else if (restingCellVoltage >= 38160) { estimatedSoC = 68; }
else if (restingCellVoltage >= 38090) { estimatedSoC = 67; }
else if (restingCellVoltage >= 38020) { estimatedSoC = 66; }
else if (restingCellVoltage >= 37950) { estimatedSoC = 65; }
else if (restingCellVoltage >= 37890) { estimatedSoC = 64; }
else if (restingCellVoltage >= 37830) { estimatedSoC = 63; }
else if (restingCellVoltage >= 37770) { estimatedSoC = 62; }
else if (restingCellVoltage >= 37710) { estimatedSoC = 61; }
else if (restingCellVoltage >= 37650) { estimatedSoC = 60; }
else if (restingCellVoltage >= 37580) { estimatedSoC = 59; }
else if (restingCellVoltage >= 37510) { estimatedSoC = 58; }
else if (restingCellVoltage >= 37440) { estimatedSoC = 57; }
else if (restingCellVoltage >= 37370) { estimatedSoC = 56; }
else if (restingCellVoltage >= 37300) { estimatedSoC = 55; }
else if (restingCellVoltage >= 37250) { estimatedSoC = 54; }
else if (restingCellVoltage >= 37200) { estimatedSoC = 53; }
else if (restingCellVoltage >= 37150) { estimatedSoC = 52; }
else if (restingCellVoltage >= 37100) { estimatedSoC = 51; }
else if (restingCellVoltage >= 37050) { estimatedSoC = 50; }
else if (restingCellVoltage >= 37000) { estimatedSoC = 49; }
else if (restingCellVoltage >= 36950) { estimatedSoC = 48; }
else if (restingCellVoltage >= 36900) { estimatedSoC = 47; }
else if (restingCellVoltage >= 36850) { estimatedSoC = 46; }
else if (restingCellVoltage >= 36800) { estimatedSoC = 45; }
else if (restingCellVoltage >= 36750) { estimatedSoC = 44; }
else if (restingCellVoltage >= 36700) { estimatedSoC = 43; }
else if (restingCellVoltage >= 36650) { estimatedSoC = 42; }
else if (restingCellVoltage >= 36600) { estimatedSoC = 41; }
else if (restingCellVoltage >= 36550) { estimatedSoC = 40; }
else if (restingCellVoltage >= 36480) { estimatedSoC = 39; }
else if (restingCellVoltage >= 36410) { estimatedSoC = 38; }
else if (restingCellVoltage >= 36340) { estimatedSoC = 37; }
else if (restingCellVoltage >= 36270) { estimatedSoC = 36; }
else if (restingCellVoltage >= 36200) { estimatedSoC = 35; }
else if (restingCellVoltage >= 36140) { estimatedSoC = 34; }
else if (restingCellVoltage >= 36080) { estimatedSoC = 33; }
else if (restingCellVoltage >= 36020) { estimatedSoC = 32; }
else if (restingCellVoltage >= 35960) { estimatedSoC = 31; }
else if (restingCellVoltage >= 35900) { estimatedSoC = 30; }
else if (restingCellVoltage >= 35800) { estimatedSoC = 29; }
else if (restingCellVoltage >= 35700) { estimatedSoC = 28; }
else if (restingCellVoltage >= 35600) { estimatedSoC = 27; }
else if (restingCellVoltage >= 35500) { estimatedSoC = 26; }
else if (restingCellVoltage >= 35400) { estimatedSoC = 25; }
else if (restingCellVoltage >= 35360) { estimatedSoC = 24; }
else if (restingCellVoltage >= 35320) { estimatedSoC = 23; }
else if (restingCellVoltage >= 35280) { estimatedSoC = 22; }
else if (restingCellVoltage >= 35240) { estimatedSoC = 21; }
else if (restingCellVoltage >= 35200) { estimatedSoC = 20; }
else if (restingCellVoltage >= 35160) { estimatedSoC = 19; }
else if (restingCellVoltage >= 35120) { estimatedSoC = 18; }
else if (restingCellVoltage >= 35080) { estimatedSoC = 17; }
else if (restingCellVoltage >= 35040) { estimatedSoC = 16; }
else if (restingCellVoltage >= 35000) { estimatedSoC = 15; }
else if (restingCellVoltage >= 34900) { estimatedSoC = 14; }
else if (restingCellVoltage >= 34800) { estimatedSoC = 13; }
else if (restingCellVoltage >= 34700) { estimatedSoC = 12; }
else if (restingCellVoltage >= 34540) { estimatedSoC = 11; }
else if (restingCellVoltage >= CELL_VREST_010_PERCENT_SoC) { estimatedSoC = 10; } //Vmin for long lifetime
else if (restingCellVoltage >= 33900) { estimatedSoC = 9; }
else if (restingCellVoltage >= 33600) { estimatedSoC = 8; }
else if (restingCellVoltage >= 33200) { estimatedSoC = 7; }
else if (restingCellVoltage >= 32800) { estimatedSoC = 6; }
else if (restingCellVoltage >= 32200) { estimatedSoC = 5; }
else if (restingCellVoltage >= 31700) { estimatedSoC = 4; }
else if (restingCellVoltage >= 31000) { estimatedSoC = 3; }
else if (restingCellVoltage >= 30500) { estimatedSoC = 2; }
else if (restingCellVoltage >= 29500) { estimatedSoC = 1; }
else { estimatedSoC = 0; }
return estimatedSoC;
}
#elif defined BATTERY_TYPE_47AhFoMoCo
#elif defined BATTERY_TYPE_47Ah
uint8_t SoC_estimateFromRestingCellVoltage_percent(void)
{
uint16_t restingCellVoltage = LTC68042result_loCellVoltage_get();
uint8_t estimatedSoC = 0;
{
uint16_t restingCellVoltage = LTC68042result_loCellVoltage_get();
uint8_t estimatedSoC = 0;
//~/Honda_Insight_LiBCM/Electronics/Lithium Batteries/47 Ah FoMoCo Modules/Resting SoC Discharge Curve
if (restingCellVoltage >= 42000) { estimatedSoC = 100; }
else if (restingCellVoltage >= 41800) { estimatedSoC = 99; }
else if (restingCellVoltage >= 41600) { estimatedSoC = 98; }
else if (restingCellVoltage >= 41400) { estimatedSoC = 97; }
else if (restingCellVoltage >= 41200) { estimatedSoC = 96; }
else if (restingCellVoltage >= 41000) { estimatedSoC = 95; }
else if (restingCellVoltage >= 40880) { estimatedSoC = 94; }
else if (restingCellVoltage >= 40760) { estimatedSoC = 93; }
else if (restingCellVoltage >= 40640) { estimatedSoC = 92; }
else if (restingCellVoltage >= 40520) { estimatedSoC = 91; }
else if (restingCellVoltage >= 40400) { estimatedSoC = 90; }
else if (restingCellVoltage >= 40260) { estimatedSoC = 89; }
else if (restingCellVoltage >= 40120) { estimatedSoC = 88; }
else if (restingCellVoltage >= 39980) { estimatedSoC = 87; }
else if (restingCellVoltage >= 39840) { estimatedSoC = 86; }
else if (restingCellVoltage >= CELL_VREST_85_PERCENT_SoC) { estimatedSoC = 85; } //max cell voltage for long lifetime
else if (restingCellVoltage >= 39600) { estimatedSoC = 84; }
else if (restingCellVoltage >= 39500) { estimatedSoC = 83; }
else if (restingCellVoltage >= 39400) { estimatedSoC = 82; }
else if (restingCellVoltage >= 39300) { estimatedSoC = 81; }
else if (restingCellVoltage >= 39200) { estimatedSoC = 80; }
else if (restingCellVoltage >= 39100) { estimatedSoC = 79; }
else if (restingCellVoltage >= 39000) { estimatedSoC = 78; }
else if (restingCellVoltage >= 38900) { estimatedSoC = 77; }
else if (restingCellVoltage >= 38800) { estimatedSoC = 76; }
else if (restingCellVoltage >= 38700) { estimatedSoC = 75; }
else if (restingCellVoltage >= 38600) { estimatedSoC = 74; }
else if (restingCellVoltage >= 38500) { estimatedSoC = 73; }
else if (restingCellVoltage >= 38400) { estimatedSoC = 72; }
else if (restingCellVoltage >= 38300) { estimatedSoC = 71; }
else if (restingCellVoltage >= 38200) { estimatedSoC = 70; }
else if (restingCellVoltage >= 38100) { estimatedSoC = 69; }
else if (restingCellVoltage >= 38000) { estimatedSoC = 68; }
else if (restingCellVoltage >= 37900) { estimatedSoC = 67; }
else if (restingCellVoltage >= 37800) { estimatedSoC = 66; }
else if (restingCellVoltage >= 37700) { estimatedSoC = 65; }
else if (restingCellVoltage >= 37580) { estimatedSoC = 64; }
else if (restingCellVoltage >= 37460) { estimatedSoC = 63; }
else if (restingCellVoltage >= 37340) { estimatedSoC = 62; }
else if (restingCellVoltage >= 37220) { estimatedSoC = 61; }
else if (restingCellVoltage >= 37100) { estimatedSoC = 60; }
else if (restingCellVoltage >= 37020) { estimatedSoC = 59; }
else if (restingCellVoltage >= 36940) { estimatedSoC = 58; }
else if (restingCellVoltage >= 36860) { estimatedSoC = 57; }
else if (restingCellVoltage >= 36780) { estimatedSoC = 56; }
else if (restingCellVoltage >= 36770) { estimatedSoC = 55; }
else if (restingCellVoltage >= 36640) { estimatedSoC = 54; }
else if (restingCellVoltage >= 36580) { estimatedSoC = 53; }
else if (restingCellVoltage >= 36520) { estimatedSoC = 52; }
else if (restingCellVoltage >= 36460) { estimatedSoC = 51; }
else if (restingCellVoltage >= 36400) { estimatedSoC = 50; }
else if (restingCellVoltage >= 36360) { estimatedSoC = 49; }
else if (restingCellVoltage >= 36320) { estimatedSoC = 48; }
else if (restingCellVoltage >= 36280) { estimatedSoC = 47; }
else if (restingCellVoltage >= 36240) { estimatedSoC = 46; }
else if (restingCellVoltage >= 36200) { estimatedSoC = 45; }
else if (restingCellVoltage >= 36160) { estimatedSoC = 44; }
else if (restingCellVoltage >= 36120) { estimatedSoC = 43; }
else if (restingCellVoltage >= 36080) { estimatedSoC = 42; }
else if (restingCellVoltage >= 36040) { estimatedSoC = 41; }
else if (restingCellVoltage >= 36000) { estimatedSoC = 40; }
else if (restingCellVoltage >= 35960) { estimatedSoC = 39; }
else if (restingCellVoltage >= 35920) { estimatedSoC = 38; }
else if (restingCellVoltage >= 35880) { estimatedSoC = 37; }
else if (restingCellVoltage >= 35840) { estimatedSoC = 36; }
else if (restingCellVoltage >= 35800) { estimatedSoC = 35; }
else if (restingCellVoltage >= 35760) { estimatedSoC = 34; }
else if (restingCellVoltage >= 35720) { estimatedSoC = 33; }
else if (restingCellVoltage >= 35680) { estimatedSoC = 32; }
else if (restingCellVoltage >= 35640) { estimatedSoC = 31; }
else if (restingCellVoltage >= 35600) { estimatedSoC = 30; }
else if (restingCellVoltage >= 35540) { estimatedSoC = 29; }
else if (restingCellVoltage >= 35480) { estimatedSoC = 28; }
else if (restingCellVoltage >= 35420) { estimatedSoC = 27; }
else if (restingCellVoltage >= 35360) { estimatedSoC = 26; }
else if (restingCellVoltage >= 35300) { estimatedSoC = 25; }
else if (restingCellVoltage >= 35240) { estimatedSoC = 24; }
else if (restingCellVoltage >= 35180) { estimatedSoC = 23; }
else if (restingCellVoltage >= 35120) { estimatedSoC = 22; }
else if (restingCellVoltage >= 35060) { estimatedSoC = 21; }
else if (restingCellVoltage >= 35000) { estimatedSoC = 20; }
else if (restingCellVoltage >= 34880) { estimatedSoC = 19; }
else if (restingCellVoltage >= 34760) { estimatedSoC = 18; }
else if (restingCellVoltage >= 34640) { estimatedSoC = 17; }
else if (restingCellVoltage >= 34520) { estimatedSoC = 16; }
else if (restingCellVoltage >= 34400) { estimatedSoC = 15; }
else if (restingCellVoltage >= 34320) { estimatedSoC = 14; }
else if (restingCellVoltage >= 34240) { estimatedSoC = 13; }
else if (restingCellVoltage >= 34160) { estimatedSoC = 12; }
else if (restingCellVoltage >= 34080) { estimatedSoC = 11; }
else if (restingCellVoltage >= CELL_VREST_10_PERCENT_SoC) { estimatedSoC = 10; } //min cell voltage for long lifetime
else if (restingCellVoltage >= 33900) { estimatedSoC = 9; }
else if (restingCellVoltage >= 33800) { estimatedSoC = 8; }
else if (restingCellVoltage >= 33700) { estimatedSoC = 7; }
else if (restingCellVoltage >= 33600) { estimatedSoC = 6; }
else if (restingCellVoltage >= 33200) { estimatedSoC = 5; }
else if (restingCellVoltage >= 32600) { estimatedSoC = 4; }
else if (restingCellVoltage >= 32000) { estimatedSoC = 3; }
else if (restingCellVoltage >= 31000) { estimatedSoC = 2; }
else if (restingCellVoltage >= 30000) { estimatedSoC = 1; }
else { estimatedSoC = 0; }
//~/Honda_Insight_LiBCM/Electronics/Lithium Batteries/47 Ah FoMoCo Modules/Resting SoC Discharge Curve
if (restingCellVoltage >= CELL_VREST_100_PERCENT_SoC) { estimatedSoC = 100; }
else if (restingCellVoltage >= 41800) { estimatedSoC = 99; }
else if (restingCellVoltage >= 41600) { estimatedSoC = 98; }
else if (restingCellVoltage >= 41400) { estimatedSoC = 97; }
else if (restingCellVoltage >= 41200) { estimatedSoC = 96; }
else if (restingCellVoltage >= 41000) { estimatedSoC = 95; }
else if (restingCellVoltage >= 40880) { estimatedSoC = 94; }
else if (restingCellVoltage >= 40760) { estimatedSoC = 93; }
else if (restingCellVoltage >= 40640) { estimatedSoC = 92; }
else if (restingCellVoltage >= 40520) { estimatedSoC = 91; }
else if (restingCellVoltage >= 40400) { estimatedSoC = 90; }
else if (restingCellVoltage >= 40260) { estimatedSoC = 89; }
else if (restingCellVoltage >= 40120) { estimatedSoC = 88; }
else if (restingCellVoltage >= 39980) { estimatedSoC = 87; }
else if (restingCellVoltage >= 39840) { estimatedSoC = 86; }
else if (restingCellVoltage >= CELL_VREST_085_PERCENT_SoC) { estimatedSoC = 85; } //Vmax for long lifetime
else if (restingCellVoltage >= 39600) { estimatedSoC = 84; }
else if (restingCellVoltage >= 39500) { estimatedSoC = 83; }
else if (restingCellVoltage >= 39400) { estimatedSoC = 82; }
else if (restingCellVoltage >= 39300) { estimatedSoC = 81; }
else if (restingCellVoltage >= 39200) { estimatedSoC = 80; }
else if (restingCellVoltage >= 39100) { estimatedSoC = 79; }
else if (restingCellVoltage >= 39000) { estimatedSoC = 78; }
else if (restingCellVoltage >= 38900) { estimatedSoC = 77; }
else if (restingCellVoltage >= 38800) { estimatedSoC = 76; }
else if (restingCellVoltage >= 38700) { estimatedSoC = 75; }
else if (restingCellVoltage >= 38600) { estimatedSoC = 74; }
else if (restingCellVoltage >= 38500) { estimatedSoC = 73; }
else if (restingCellVoltage >= 38400) { estimatedSoC = 72; }
else if (restingCellVoltage >= 38300) { estimatedSoC = 71; }
else if (restingCellVoltage >= 38200) { estimatedSoC = 70; }
else if (restingCellVoltage >= 38100) { estimatedSoC = 69; }
else if (restingCellVoltage >= 38000) { estimatedSoC = 68; }
else if (restingCellVoltage >= 37900) { estimatedSoC = 67; }
else if (restingCellVoltage >= 37800) { estimatedSoC = 66; }
else if (restingCellVoltage >= 37700) { estimatedSoC = 65; }
else if (restingCellVoltage >= 37580) { estimatedSoC = 64; }
else if (restingCellVoltage >= 37460) { estimatedSoC = 63; }
else if (restingCellVoltage >= 37340) { estimatedSoC = 62; }
else if (restingCellVoltage >= 37220) { estimatedSoC = 61; }
else if (restingCellVoltage >= 37100) { estimatedSoC = 60; }
else if (restingCellVoltage >= 37020) { estimatedSoC = 59; }
else if (restingCellVoltage >= 36940) { estimatedSoC = 58; }
else if (restingCellVoltage >= 36860) { estimatedSoC = 57; }
else if (restingCellVoltage >= 36780) { estimatedSoC = 56; }
else if (restingCellVoltage >= 36770) { estimatedSoC = 55; }
else if (restingCellVoltage >= 36640) { estimatedSoC = 54; }
else if (restingCellVoltage >= 36580) { estimatedSoC = 53; }
else if (restingCellVoltage >= 36520) { estimatedSoC = 52; }
else if (restingCellVoltage >= 36460) { estimatedSoC = 51; }
else if (restingCellVoltage >= 36400) { estimatedSoC = 50; }
else if (restingCellVoltage >= 36360) { estimatedSoC = 49; }
else if (restingCellVoltage >= 36320) { estimatedSoC = 48; }
else if (restingCellVoltage >= 36280) { estimatedSoC = 47; }
else if (restingCellVoltage >= 36240) { estimatedSoC = 46; }
else if (restingCellVoltage >= 36200) { estimatedSoC = 45; }
else if (restingCellVoltage >= 36160) { estimatedSoC = 44; }
else if (restingCellVoltage >= 36120) { estimatedSoC = 43; }
else if (restingCellVoltage >= 36080) { estimatedSoC = 42; }
else if (restingCellVoltage >= 36040) { estimatedSoC = 41; }
else if (restingCellVoltage >= 36000) { estimatedSoC = 40; }
else if (restingCellVoltage >= 35960) { estimatedSoC = 39; }
else if (restingCellVoltage >= 35920) { estimatedSoC = 38; }
else if (restingCellVoltage >= 35880) { estimatedSoC = 37; }
else if (restingCellVoltage >= 35840) { estimatedSoC = 36; }
else if (restingCellVoltage >= 35800) { estimatedSoC = 35; }
else if (restingCellVoltage >= 35760) { estimatedSoC = 34; }
else if (restingCellVoltage >= 35720) { estimatedSoC = 33; }
else if (restingCellVoltage >= 35680) { estimatedSoC = 32; }
else if (restingCellVoltage >= 35640) { estimatedSoC = 31; }
else if (restingCellVoltage >= 35600) { estimatedSoC = 30; }
else if (restingCellVoltage >= 35540) { estimatedSoC = 29; }
else if (restingCellVoltage >= 35480) { estimatedSoC = 28; }
else if (restingCellVoltage >= 35420) { estimatedSoC = 27; }
else if (restingCellVoltage >= 35360) { estimatedSoC = 26; }
else if (restingCellVoltage >= 35300) { estimatedSoC = 25; }
else if (restingCellVoltage >= 35240) { estimatedSoC = 24; }
else if (restingCellVoltage >= 35180) { estimatedSoC = 23; }
else if (restingCellVoltage >= 35120) { estimatedSoC = 22; }
else if (restingCellVoltage >= 35060) { estimatedSoC = 21; }
else if (restingCellVoltage >= 35000) { estimatedSoC = 20; }
else if (restingCellVoltage >= 34880) { estimatedSoC = 19; }
else if (restingCellVoltage >= 34760) { estimatedSoC = 18; }
else if (restingCellVoltage >= 34640) { estimatedSoC = 17; }
else if (restingCellVoltage >= 34520) { estimatedSoC = 16; }
else if (restingCellVoltage >= 34400) { estimatedSoC = 15; }
else if (restingCellVoltage >= 34320) { estimatedSoC = 14; }
else if (restingCellVoltage >= 34240) { estimatedSoC = 13; }
else if (restingCellVoltage >= 34160) { estimatedSoC = 12; }
else if (restingCellVoltage >= 34080) { estimatedSoC = 11; }
else if (restingCellVoltage >= CELL_VREST_010_PERCENT_SoC) { estimatedSoC = 10; } //Vmin for long lifetime
else if (restingCellVoltage >= 33900) { estimatedSoC = 9; }
else if (restingCellVoltage >= 33800) { estimatedSoC = 8; }
else if (restingCellVoltage >= 33700) { estimatedSoC = 7; }
else if (restingCellVoltage >= 33600) { estimatedSoC = 6; }
else if (restingCellVoltage >= 33200) { estimatedSoC = 5; }
else if (restingCellVoltage >= 32600) { estimatedSoC = 4; }
else if (restingCellVoltage >= 32000) { estimatedSoC = 3; }
else if (restingCellVoltage >= 31000) { estimatedSoC = 2; }
else if (restingCellVoltage >= 30000) { estimatedSoC = 1; }
else { estimatedSoC = 0; }
return estimatedSoC;
}
#endif
return estimatedSoC;
}
#endif
/////////////////////////////////////////////////////////////////////////////////////////

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);
@@ -19,13 +19,18 @@
void SoC_handler(void);
#define VCELL_CRITICALLY_OVERCHARGED 43000 //'43000' = 4.3 V
#define VCELL_CRITICALLY_DISCHARGED 28000 //'28000' = 2.8 V
#ifdef BATTERY_TYPE_5AhG3
#define CELL_VREST_85_PERCENT_SoC 40000 //for maximum life, resting cell voltage should remain below 85% SoC
#define CELL_VREST_10_PERCENT_SoC 34200 //for maximum life, resting cell voltage should remain above 10% SoC
#define CELL_VREST_100_PERCENT_SoC 42000
#define CELL_VREST_085_PERCENT_SoC 40000 //for maximum life, resting cell voltage should remain below 85% SoC
#define CELL_VREST_010_PERCENT_SoC 34200 //for maximum life, resting cell voltage should remain above 10% SoC
#define STACK_mAh_NOM 5000 //5 Ah nominal //nominal pack size (0:100% SoC)
#elif defined BATTERY_TYPE_47AhFoMoCo
#define CELL_VREST_85_PERCENT_SoC 39700
#define CELL_VREST_10_PERCENT_SoC 34000
#elif defined BATTERY_TYPE_47Ah
#define CELL_VREST_100_PERCENT_SoC 42000
#define CELL_VREST_085_PERCENT_SoC 39700
#define CELL_VREST_010_PERCENT_SoC 34000
#define STACK_mAh_NOM 47000
#else
#error (Battery type not specified in config.h)

View File

@@ -53,6 +53,9 @@ void printDebug(void)
Serial.print(F("\n -Has LiBCM limited regen since last cleared?: "));
(eeprom_hasLibcmDisabledRegen_get() == EEPROM_LIBCM_DISABLED_REGEN) ? Serial.print(F("YES")) : Serial.print(F("NO"));
Serial.print(F("\n -Maximum resting cell delta (min is '1000' = 100.0 mV): "));
Serial.print(eeprom_maxCellVoltageDelta_get(), DEC);
}
/////////////////////////////////////////////////////////////////////////////////////////
@@ -115,7 +118,6 @@ void USB_userInterface_runTestCode(uint8_t testToRun)
else if (testToRun == 'T') { temperature_measureAndPrintAll(); }
else if (testToRun == 'R') { LTC6804gpio_areAllVoltageReferencesPassing(); }
else if (testToRun == 'W') { batteryHistory_printAll(); }
else if (testToRun == 'E') { eeprom_resetAll_userConfirm(); }
else if (testToRun == 'C')
{
LTC68042cell_acquireAllCellVoltages();
@@ -150,41 +152,38 @@ void(* rebootLiBCM) (void) = 0;//declare reset function at address 0
void printHelp(void)
{
Serial.print(F("\n\nLiBCM commands:"
"\n -'$BOOT': restart LiBCM"
"\n -'$OFF': turn LiBCM off (for testing purposes)"
"\n -'$BOOT' : restart LiBCM"
"\n -'$OFF' : turn LiBCM off (for testing purposes)"
"\n -'$TESTR': run LTC6804 VREF test"
"\n -'$TESTW': battery temp & SoC history"
"\n -'$TESTH': blink heater LED"
"\n -'$TESTC': print cell voltages"
"\n -'$TESTT': print temperatures"
"\n -'$TESTE': EEPROM factory reset"
"\n -'$TEST1'/2/3/4: run temporary debug test code. See 'USB_userInterface_runTestCode()')"
"\n -'$DEBUG': info stored in EEPROM. 'DEBUG=CLR' to restore defaults"
"\n -'$KEYms': delay after keyON before LiBCM starts. 'KEYms=___' to set (0 to 254 ms)"
"\n -'$SoC': battery charge in percent. 'SoC=___' to set (0 to 100%)"
"\n -'$DISP=PWR'/SCI/CELL/TEMP/DBG/OFF: data to stream (power/BAT&METSCI/Vcell/temperature/none)"
"\n -'$RATE=___': USB updates per second (1 to 255 Hz)"
"\n -'$LOOP: LiBCM loop period. '$LOOP=___' to set (1 to 255 ms)"
"\n -'$SCIms': period between BATTSCI frames. '$SCIms=___' to set (0 to 255 ms)"
"\n -'$TRIP': print energy consumption and distance records ('TRIP=CLR' to zero all)"
"\n -'$EPROM': dump EEPROM. '$EPROM=RST' to factory reset"
"\n -'$TEST_': 1/2/3/4: run temporary debug test code. See 'USB_userInterface_runTestCode()')"
"\n -'$DEBUG': info stored in EEPROM. '$DEBUG=CLR' to restore defaults"
"\n -'$KEYms': delay after keyON before LiBCM starts. 'KEYms=_' to set (0 to 254 ms)"
"\n -'$SoC' : battery charge in percent. '$SoC=_' to set (0 to 100%)"
"\n -'$DISP=_: PWR/SCI/CELL/TEMP/DBG/OFF: data to stream"
"\n -'$RATE=_: USB updates per second (1 to 255 Hz)"
"\n -'$LOOP : LiBCM loop period. '$LOOP=_' to set (1 to 255 ms)"
"\n -'$SCIms': period between BATTSCI frames. '$SCIms=_' to set (0 to 255 ms)"
"\n -'$TRIP' : print energy consumption and distance records ('TRIP=CLR' to zero all)"
"\n -'$SPOOF': print voltage spoofing calibration commands and instructions"
"\n"
"\nDebug characters:"
"\n -'@': isoSPI error occurred"
"\n -'*': loop period exceeded"
"\n"
"\nTip: Hit up arrow to recall previous commands"
"\n"
/*
"\nFuture LiBCM commands (not presently supported"
"\n -'$DEFAULT' restore all EEPROM values to default"
"\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 -'BATTmAh' display battery capacity in mAh. 'BATTmAh=____' to set."
"\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:
@@ -195,6 +194,32 @@ void printHelp(void)
/////////////////////////////////////////////////////////////////////////////////////////
void printVspoofInstructions(void)
{
Serial.print(F("\n\nVoltage Spoofing Commands:"
"\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"
"\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)"
));
}
/////////////////////////////////////////////////////////////////////////////////////////
void printText_invalidEntry (void) { Serial.print(F("\nInvalid Entry")); }
/////////////////////////////////////////////////////////////////////////////////////////
//LiBCM's atoi() implementation for uint8_t
uint8_t get_uint8_FromInput(uint8_t digit1, uint8_t digit2, uint8_t digit3)
{
@@ -222,13 +247,13 @@ uint8_t get_uint8_FromInput(uint8_t digit1, uint8_t digit2, uint8_t digit3)
//determine which command to run
void USB_userInterface_executeUserInput(void)
{
if (line[0] == '$') //valid commands start with '$'
if (line[0]=='$') //valid commands start with '$'
{
//$HELP
if ((line[1] == 'H') && (line[2] == 'E') && (line[3] == 'L') && (line[4] == 'P')) { printHelp(); }
if ((line[1]=='H') && (line[2]=='E') && (line[3]=='L') && (line[4]=='P')) { printHelp(); }
//$BOOT
else if ((line[1] == 'B') && (line[2] == 'O') && (line[3] == 'O') && (line[4] == 'T'))
else if ((line[1]=='B') && (line[2]=='O') && (line[3]=='O') && (line[4]=='T'))
{
Serial.print(F("\nRebooting LiBCM"));
delay(50); //give serial buffer time to send
@@ -236,7 +261,7 @@ void USB_userInterface_executeUserInput(void)
}
//$OFF
else if ((line[1] == 'O') && (line[2] == 'F') && (line[3] == 'F'))
else if ((line[1]=='O') && (line[2]=='F') && (line[3]=='F'))
{
Serial.print(F("\nUnplug USB cable before the counter gets to zero:"));
Serial.print(F("\nLiBCM turning off in "));
@@ -258,125 +283,173 @@ void USB_userInterface_executeUserInput(void)
}
//$TEST
else if ((line[1] == 'T') && (line[2] == 'E') && (line[3] == 'S') && (line[4] == 'T')) { USB_userInterface_runTestCode(line[5]); }
else if ((line[1]=='T') && (line[2]=='E') && (line[3]=='S') && (line[4]=='T')) { USB_userInterface_runTestCode(line[5]); }
//$DEBUG
else if ((line[1] == 'D') && (line[2] == 'E') && (line[3] == 'B') && (line[4] == 'U') && (line[5] == 'G'))
else if ((line[1]=='D') && (line[2]=='E') && (line[3]=='B') && (line[4]=='U') && (line[5]=='G'))
{
if ((line[6] == '=') && (line[7] == 'C') && (line[8] == 'L') && (line[9] == 'R'))
if ((line[6]=='=') && (line[7]=='C') && (line[8]=='L') && (line[9]=='R'))
{
Serial.print(F("\nRestoring default DEBUG values"));
eeprom_resetDebugValues();
}
else if (line[6] == STRING_TERMINATION_CHARACTER) { printDebug(); }
else if (line[6]==STRING_TERMINATION_CHARACTER) { printDebug(); }
else { printText_invalidEntry(); }
}
/*
//$LIDISP //TOTO_Natalya: Move to '$TEST' //JTS2doLater: Delete if no longer used
else if ((line[1] == 'L') && (line[2] == 'I') && (line[3] == 'D') && (line[4] == 'I') && (line[5] == 'S') && (line[6] == 'P'))
{
LiDisplay_setDebugMode(line[7]);
} */
//KEYms
else if ((line[1] == 'K') && (line[2] == 'E') && (line[3] == 'Y') && (line[4] == 'M') && (line[5] == 'S'))
//$KEYms
else if ((line[1]=='K') && (line[2]=='E') && (line[3]=='Y') && (line[4]=='M') && (line[5]=='S'))
{
if (line[6] == '=')
if (line[6]=='=')
{
uint8_t newKeyOnDelay_ms = get_uint8_FromInput(line[7],line[8],line[9]);
Serial.print(F("\nnewKeyOnDelay_ms is "));
Serial.print(newKeyOnDelay_ms, DEC);
eeprom_delayKeyON_ms_set(newKeyOnDelay_ms);
}
else if (line[6] == STRING_TERMINATION_CHARACTER)
else if (line[6]==STRING_TERMINATION_CHARACTER)
{
Serial.print(F("\n Additional delay before LiBCM responds to keyON event (ms): "));
Serial.print( eeprom_delayKeyON_ms_get(), DEC);
}
else { printText_invalidEntry(); }
}
//SoC
else if ((line[1] == 'S') && (line[2] == 'O') && (line[3] == 'C'))
//$SoC
else if ((line[1]=='S') && (line[2]=='O') && (line[3]=='C'))
{
if (line[4] == '=')
if (line[4]=='=')
{
uint8_t newSoC_percent = get_uint8_FromInput(line[5],line[6],line[7]);
Serial.print(F("\nnewSoC is "));
Serial.print(newSoC_percent, DEC);
SoC_setBatteryStateNow_percent(newSoC_percent);
}
else if (line[4] == STRING_TERMINATION_CHARACTER)
else if (line[4]==STRING_TERMINATION_CHARACTER)
{
Serial.print(F("\nBattery SoC is (%): "));
Serial.print(SoC_getBatteryStateNow_percent(),DEC);
}
else { printText_invalidEntry(); }
}
//DISP
//$DISP
//JTS2doLater: Make this function work while grid charging, too
else if ((line[1] == 'D') && (line[2] == 'I') && (line[3] == 'S') && (line[4] == 'P') && (line[5] == '='))
else if ((line[1]=='D') && (line[2]=='I') && (line[3]=='S') && (line[4]=='P') && (line[5]=='='))
{
if ((line[6] == 'P') && (line[7] == 'W') && (line[8] == 'R')) { debugUSB_dataTypeToStream_set(DEBUGUSB_STREAM_POWER); }
else if ((line[6] == 'S') && (line[7] == 'C') && (line[8] == 'I')) { debugUSB_dataTypeToStream_set(DEBUGUSB_STREAM_BATTMETSCI); }
else if ((line[6] == 'C') && (line[7] == 'E') && (line[8] == 'L')) { debugUSB_dataTypeToStream_set(DEBUGUSB_STREAM_CELL); }
else if ((line[6] == 'O') && (line[7] == 'F') && (line[8] == 'F')) { debugUSB_dataTypeToStream_set(DEBUGUSB_STREAM_NONE); }
else if ((line[6] == 'T') && (line[7] == 'E') && (line[8] == 'M')) { debugUSB_dataTypeToStream_set(DEBUGUSB_STREAM_TEMP); }
else if ((line[6] == 'D') && (line[7] == 'B') && (line[8] == 'G')) { debugUSB_dataTypeToStream_set(DEBUGUSB_STREAM_DEBUG); }
if ((line[6]=='P') && (line[7]=='W') && (line[8]=='R')) { debugUSB_dataTypeToStream_set(DEBUGUSB_STREAM_POWER); }
else if ((line[6]=='S') && (line[7]=='C') && (line[8]=='I')) { debugUSB_dataTypeToStream_set(DEBUGUSB_STREAM_BATTMETSCI); }
else if ((line[6]=='C') && (line[7]=='E') && (line[8]=='L')) { debugUSB_dataTypeToStream_set(DEBUGUSB_STREAM_CELL); }
else if ((line[6]=='O') && (line[7]=='F') && (line[8]=='F')) { debugUSB_dataTypeToStream_set(DEBUGUSB_STREAM_NONE); }
else if ((line[6]=='T') && (line[7]=='E') && (line[8]=='M')) { debugUSB_dataTypeToStream_set(DEBUGUSB_STREAM_TEMP); }
else if ((line[6]=='D') && (line[7]=='B') && (line[8]=='G')) { debugUSB_dataTypeToStream_set(DEBUGUSB_STREAM_DEBUG); }
else { printText_invalidEntry(); }
}
//RATE
else if ((line[1] == 'R') && (line[2] == 'A') && (line[3] == 'T') && (line[4] == 'E') && (line[5] == '='))
//$RATE
else if ((line[1]=='R') && (line[2]=='A') && (line[3]=='T') && (line[4]=='E') && (line[5]=='='))
{
uint8_t newUpdatesPerSecond = get_uint8_FromInput(line[6],line[7],line[8]);
debugUSB_dataUpdatePeriod_ms_set( time_hertz_to_milliseconds(newUpdatesPerSecond) );
}
//LOOP
else if ((line[1] == 'L') && (line[2] == 'O') && (line[3] == 'O') && (line[4] == 'P'))
//$LOOP
else if ((line[1]=='L') && (line[2]=='O') && (line[3]=='O') && (line[4]=='P'))
{
if (line[5] == '=')
if (line[5]=='=')
{
uint8_t newLooprate_ms = get_uint8_FromInput(line[6],line[7],line[8]);
time_loopPeriod_ms_set(newLooprate_ms);
}
else if (line[5] == STRING_TERMINATION_CHARACTER)
else if (line[5]==STRING_TERMINATION_CHARACTER)
{
Serial.print(F("\nLoop period is (ms): "));
Serial.print(time_loopPeriod_ms_get(),DEC);
}
else { printText_invalidEntry(); }
}
//SCIms
else if ((line[1] == 'S') && (line[2] == 'C') && (line[3] == 'I') && (line[4] == 'M') && (line[5] == 'S'))
//$SCIms
else if ((line[1]=='S') && (line[2]=='C') && (line[3]=='I') && (line[4]=='M') && (line[5]=='S'))
{
if (line[6] == '=')
if (line[6]=='=')
{
uint8_t newPeriod_ms = get_uint8_FromInput(line[7],line[8],line[9]);
BATTSCI_framePeriod_ms_set(newPeriod_ms);
}
else if (line[6] == STRING_TERMINATION_CHARACTER)
else if (line[6]==STRING_TERMINATION_CHARACTER)
{
Serial.print(F("\nBATTSCI period is (ms): "));
Serial.print(BATTSCI_framePeriod_ms_get(),DEC);
}
else { printText_invalidEntry(); }
}
//TRIP
else if ((line[1] == 'T') && (line[2] == 'R') && (line[3] == 'I') && (line[4] == 'P'))
//$TRIP
else if ((line[1]=='T') && (line[2]=='R') && (line[3]=='I') && (line[4]=='P'))
{
if ((line[5] == '=') && (line[6] == 'C') && (line[7] == 'L') && (line[8] == 'R'))
if ((line[5]=='=') && (line[6]=='C') && (line[7]=='L') && (line[8]=='R'))
{
eeprom_wattHourHistory_reset();
}
else if (line[5] == STRING_TERMINATION_CHARACTER)
{
eeprom_wattHourHistory_printTripHistory();
}
else if (line[5]==STRING_TERMINATION_CHARACTER) { eeprom_wattHourHistory_printTripHistory(); }
else { printText_invalidEntry(); }
}
//$DEFAULT
else { Serial.print(F("\nInvalid Entry")); }
//$EPROM
else if ((line[1]=='E') && (line[2]=='P') && (line[3]=='R') && (line[4]=='O') && (line[5]=='M'))
{
if ((line[6]=='=') && (line[7]=='R') && (line[8]=='S') && (line[9]=='T')) { eeprom_resetAll_userConfirm(); }
else if (line[6]==STRING_TERMINATION_CHARACTER) { eeprom_printAll(); }
else { printText_invalidEntry(); }
}
//$BVO
else if ((line[1]=='B') && (line[2]=='V') && (line[3]=='O'))
{
//BVO affects MCMe output
Serial.print(' ');
if ( (line[4]=='=') &&
((line[5]=='+') || (line[5]=='-') || (line[5]=='0')) &&
(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(); }
}
//$MDV
else if ((line[1]=='M') && (line[2]=='D') && (line[3]=='V'))
{
//MDV affects VPIN output
Serial.print(' ');
if ( (line[4]=='=') &&
((line[5]=='+') || (line[5]=='-') || (line[5]=='0')) &&
(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(); }
}
//$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
else if ((line[1]=='S') && (line[2]=='P') && (line[3]=='O') && (line[4]=='O') && (line[5]=='F'))
{
printVspoofInstructions();
}
//DEFAULT
else { printText_invalidEntry(); }
}
else { Serial.print(F("\nInvalid Entry")); }
else { printText_invalidEntry(); }
}
/////////////////////////////////////////////////////////////////////////////////////////

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

@@ -39,12 +39,10 @@ bool cellBalance_areCellsBalancing(void) { return cellsAreBalancing; }
/////////////////////////////////////////////////////////////////////////////////////////
//JTS2doLater: Always allow discharge balancing when a cell is overcharged (for safety)
//JTS2doLater: Write keyOff test that measures each cell voltage twice: once with discharge resistor off, and again with resistor on.
// Then verify voltage drop, which means the discharge resistor is turning off and on. If there isn't enough resolution,
// another method would be to wait a few hours for pack voltages to settle, then log all cell voltages an hour apart.
//JTS2doLater: Add per-cell SoC, to allow balancing at any SoC (see icn.net:post#1502833,comment#579)
//balance cells (if needed)
void configureDischargeResistors(void)
{
static uint8_t balanceHysteresis = CELL_BALANCE_TO_WITHIN_COUNTS_TIGHT;
@@ -53,7 +51,7 @@ void configureDischargeResistors(void)
cellsAreBalancing = NO;
if (LTC68042result_hiCellVoltage_get() > CELL_VREST_85_PERCENT_SoC) { cellDischargeVoltageThreshold = CELL_VREST_85_PERCENT_SoC; }
if (LTC68042result_hiCellVoltage_get() > CELL_VREST_085_PERCENT_SoC) { cellDischargeVoltageThreshold = CELL_VREST_085_PERCENT_SoC; }
else { cellDischargeVoltageThreshold = LTC68042result_loCellVoltage_get() + balanceHysteresis; }
//determine which cells to balance
@@ -94,42 +92,81 @@ void disableDischargeResistors(void)
/////////////////////////////////////////////////////////////////////////////////////////
//JTS2doNext: Add "balance really unbalanced pack" code outlined in ic.net post #3876
uint8_t isBalancingAllowed(void)
//balancing criteria for a healthy pack
uint8_t isBalancingPossible(void)
{
//order is important
//external checks
if (key_getSampledState() == KEYSTATE_ON ) { return NO__KEY_IS_ON; }
#ifdef ONLY_BALANCE_CELLS_WHEN_GRID_CHARGER_PLUGGED_IN
if (gpio_isGridChargerPluggedInNow() == NO ) { return NO__CHARGER_UNPLUGGED; }
#else
if ((gpio_isGridChargerPluggedInNow() == NO ) &&
(SoC_getBatteryStateNow_percent() < CELL_BALANCE_MIN_SoC) ) { return NO__SoC_TOO_LOW; }
#endif
//cell voltage checks
if (LTC68042result_hiCellVoltage_get() > CELL_VMAX_REGEN ) { return NO__ATLEASTONECELL_TOO_HIGH; }
if (LTC68042result_loCellVoltage_get() < CELL_VMIN_GRIDCHARGER ) { return NO__ATLEASTONECELL_TOO_LOW; }
//thermal checks
if (temperature_battery_getLatest() > CELL_BALANCE_MAX_TEMP_C) { return NO__BATTERY_IS_HOT; }
//time checks
if (time_isItTimeToPerformKeyOffTasks() == NO ) { return DELAY_DO_NOTHING; }
return YES__BALANCING_ALLOWED;
}
/////////////////////////////////////////////////////////////////////////////////////////
//JTS2doLater: balance majorly imbalanced cells even when grid charger is unplugged
void cellBalance_handler(void)
//balancing criteria for a majorly unbalanced pack
uint8_t isBalancingMandatory(void)
{
static uint8_t isBalancingAllowed_previous = NO__UNINITIALIZED;
uint8_t isBalancingAllowed_now = isBalancingAllowed();
uint16_t cellDeltaV = LTC68042result_deltaCellVoltage_get();
if (isBalancingAllowed_now == YES__BALANCING_ALLOWED)
{
if (time_isItTimeToPerformKeyOffTasks() == YES) { configureDischargeResistors(); }
}
else if (isBalancingAllowed_previous == YES__BALANCING_ALLOWED) { disableDischargeResistors(); }
if (cellDeltaV < CELL_MAJOR_IMBALANCE_DELTA) { return NO__BALANCING_NOT_REQUESTED; }
isBalancingAllowed_previous = isBalancingAllowed_now;
//if we get here, pack is majorly unbalanced
//keyState doesn't matter
//grid charger state doesn't matter
//pack temperature doesn't matter
if (LTC68042result_loCellVoltage_get() < CELL_VMIN_GRIDCHARGER ) { return NO__ATLEASTONECELL_TOO_LOW; }
if (adc_getLatestSpoofedCurrent_deciAmps() > CELL_IMAX_MAJOR_IMBALANCE_DECIAMPS) { return NO__PACK_CURRENT_TOO_HIGH; }
if (adc_getLatestSpoofedCurrent_deciAmps() < -CELL_IMAX_MAJOR_IMBALANCE_DECIAMPS) { return NO__PACK_CURRENT_TOO_HIGH; }
if (cellDeltaV > eeprom_maxCellVoltageDelta_get()) { eeprom_maxCellVoltageDelta_set(cellDeltaV); }
return YES__BALANCING_ALLOWED;
}
/////////////////////////////////////////////////////////////////////////////////////////
uint8_t isEntirePackOvercharged(void)
{
if ((LTC68042result_hiCellVoltage_get() > CELL_VREST_100_PERCENT_SoC ) &&
(LTC68042result_loCellVoltage_get() > CELL_VMAX_GRIDCHARGER ) ) { return YES__BALANCING_ALLOWED; }
return NO__BALANCING_NOT_REQUESTED;
}
/////////////////////////////////////////////////////////////////////////////////////////
uint8_t getBalanceRequest(void)
{
if (isBalancingMandatory() == YES__BALANCING_ALLOWED) { return YES__BALANCING_ALLOWED; }
if (isEntirePackOvercharged() == YES__BALANCING_ALLOWED) { return YES__BALANCING_ALLOWED; }
return isBalancingPossible();
}
/////////////////////////////////////////////////////////////////////////////////////////
void cellBalance_handler(void)
{
if (LTC68042result_wasDataProcessedThisLoop_get() == NO) { return; } //wait for new Vcell data
static uint8_t isBalancingAllowed_previous = NO__UNINITIALIZED;
uint8_t isBalancingAllowed_now = getBalanceRequest();
if (isBalancingAllowed_now == DELAY_DO_NOTHING ) { return; }
else if (isBalancingAllowed_now == YES__BALANCING_ALLOWED) { configureDischargeResistors(); }
else if (isBalancingAllowed_previous == YES__BALANCING_ALLOWED) { disableDischargeResistors(); }
isBalancingAllowed_previous = isBalancingAllowed_now; //not updated if 'DELAY_DO_NOTHING'
}
/////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -7,7 +7,14 @@
#define BALANCING_DISABLED 0
#define BALANCING_ALLOWED 1
#define YES__BALANCING_ALLOWED YES__CHARGING_ALLOWED //balancing code reusing grid charging constants
#define CELL_MAJOR_IMBALANCE_DELTA 1000 // '1000' = 100 mV
#define CELL_IMAX_MAJOR_IMBALANCE_DECIAMPS 90 // '90' = 9.0 A
#define CELL_BALANCE_TO_WITHIN_COUNTS_LOOSE 32 // '32' = 3.2 mV //CANNOT exceed 255 counts (25.5 mV)
#define CELL_BALANCE_TO_WITHIN_COUNTS_TIGHT 22 // '22' = 2.2 mV //ADC uncertainty: 2.2 mV //MUST be less than CELL_BALANCE_TO_WITHIN_COUNTS_LOOSE
//balancing constants reuse grid charging constants
#define YES__BALANCING_ALLOWED YES__CHARGING_ALLOWED
#define NO__BALANCING_NOT_REQUESTED NO__CHARGING_NOT_REQUESTED
bool cellBalance_areCellsBalancing(void);

View File

@@ -14,8 +14,8 @@
#define PIN_BATTCURRENT A0
#define PIN_USER_SW A1
#define PIN_VPIN_IN A2
#define PIN_TEMP_YEL A3 // 5AhG3: Exhaust, FoMoCo Top middle battery module
#define PIN_TEMP_GRN A4 // 5AhG3: Intake, FoMoCo Top rear battery module
#define PIN_TEMP_YEL A3 // 5AhG3: Exhaust //47Ah: Top middle battery
#define PIN_TEMP_GRN A4 // 5AhG3: Intake //47Ah: Top rear battery
#define PIN_TEMP_WHT A5
#define PIN_TEMP_BLU A6
#define PIN_FANOEM_LOW A7
@@ -48,7 +48,7 @@
#define PIN_BATTSCI_DE 41
#define PIN_COVER_SWITCH 42
#define PIN_GPIO0_CS_MIMA 43
#define PIN_GPIO3 44 //with daughterboard: 1500W charger current (if installed) //without daughterboard: heater (if installed)
#define PIN_GPIO3 44 //with daughterboard: 1500W charger current //without DB: heater (if installed)
#define PIN_BUZZER_PWM 45
#define PIN_LED3 46
#define PIN_SPI_EXT_CS 47

View File

@@ -193,7 +193,7 @@ void debugUSB_printData_temperatures(void)
Serial.print(F(", T_in:"));
Serial.print(String(temperature_intake_getLatest()));
Serial.print(F(", T_out:"));
#ifndef BATTERY_TYPE_47AhFoMoCo
#ifndef BATTERY_TYPE_47Ah
Serial.print(String(temperature_exhaust_getLatest()));
#else
Serial.print(F("none"));
@@ -201,7 +201,7 @@ void debugUSB_printData_temperatures(void)
Serial.print(F(", T_charger:"));
Serial.print(String(temperature_gridCharger_getLatest()));
Serial.print(F(", T_bay:"));
#ifndef BATTERY_TYPE_47AhFoMoCo
#ifndef BATTERY_TYPE_47Ah
Serial.print(String(temperature_ambient_getLatest()));
#else
Serial.print(F("none"));
@@ -277,8 +277,8 @@ void debugUSB_printConfigParameters(void)
#ifdef BATTERY_TYPE_5AhG3
Serial.print(F("/5AhG3"));
#elif defined BATTERY_TYPE_47AhFoMoCo
Serial.print(F("/FoMoCo"));
#elif defined BATTERY_TYPE_47Ah
Serial.print(F("/47Ah"));
#endif
#ifdef STACK_IS_48S

View File

@@ -25,6 +25,10 @@ const uint16_t EEPROM_ADDRESS_BATTSCI_ASSIST = 0x010; //EEPROM range is 0x0
const uint16_t EEPROM_ADDRESS_KEYON_DELAY = 0x011; //EEPROM range is 0x011 ( 1B)
const uint16_t EEPROM_ADDRESS_NEXT_Wh_RECORD = 0x012; //EEPROM range is 0x012 ( 1B)
const uint16_t EEPROM_ADDRESS_COMPILE_TIME = 0x013; //EEPROM range is 0x013:0x01B ( 9B)
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)
@@ -145,9 +149,6 @@ uint16_t hoursSincePreviousKeyOff(void)
remainder_ms = delta_ms;
Serial.print(F("\nRemainder_ms: "));
Serial.print(remainder_ms);
return delta_hours;
}
@@ -189,41 +190,86 @@ void eeprom_keyOffCheckForExpiredFirmware(void)
/////////////////////////////////////////////////////////////////////////////////////////
uint8_t eeprom_hasLibcmDisabledAssist_get(void) { return EEPROM.read(EEPROM_ADDRESS_BATTSCI_ASSIST); }
uint8_t eeprom_hasLibcmDisabledAssist_get(void) { return EEPROM.read (EEPROM_ADDRESS_BATTSCI_ASSIST); }
void eeprom_hasLibcmDisabledAssist_set(uint8_t wasAssistLimited) { EEPROM.update(EEPROM_ADDRESS_BATTSCI_ASSIST, wasAssistLimited); }
uint8_t eeprom_hasLibcmDisabledRegen_get(void) { return EEPROM.read(EEPROM_ADDRESS_BATTSCI_REGEN); }
void eeprom_hasLibcmDisabledRegen_set(uint8_t wasRegenLimited) { EEPROM.update(EEPROM_ADDRESS_BATTSCI_REGEN, wasRegenLimited); }
uint8_t eeprom_hasLibcmDisabledRegen_get(void) { return EEPROM.read (EEPROM_ADDRESS_BATTSCI_REGEN); }
void eeprom_hasLibcmDisabledRegen_set(uint8_t wasRegenLimited) { EEPROM.update(EEPROM_ADDRESS_BATTSCI_REGEN, wasRegenLimited); }
uint16_t eeprom_maxCellVoltageDelta_get(void) { return readFromEEPROM_uint16(EEPROM_ADDRESS_MAX_VCELL_DELTA); }
void eeprom_maxCellVoltageDelta_set(uint16_t newMax) { writeToEEPROM_uint16(EEPROM_ADDRESS_MAX_VCELL_DELTA, newMax); }
uint8_t eeprom_delayKeyON_ms_get(void) { return EEPROM.read (EEPROM_ADDRESS_KEYON_DELAY); }
void eeprom_delayKeyON_ms_set(uint8_t delay_ms) { EEPROM.update(EEPROM_ADDRESS_KEYON_DELAY, delay_ms); }
/////////////////////////////////////////////////////////////////////////////////////////
uint8_t eeprom_delayKeyON_ms_get(void) { return EEPROM.read(EEPROM_ADDRESS_KEYON_DELAY); }
void eeprom_delayKeyON_ms_set(uint8_t delay_ms) { EEPROM.update(EEPROM_ADDRESS_KEYON_DELAY, delay_ms); }
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); }
/////////////////////////////////////////////////////////////////////////////////////////
void printMessage_RestoringEEPROM(void) { Serial.print(F("\nRestoring EEPROM value: ")); }
/////////////////////////////////////////////////////////////////////////////////////////
void eeprom_verifyDataValid(void)
{
//verify all runtime-configurable data stored in EEPROM is valid. If not, load default value(s)
if ( !( (eeprom_hasLibcmDisabledRegen_get() == EEPROM_LIBCM_DISABLED_REGEN) || (eeprom_hasLibcmDisabledRegen_get() == EEPROM_REGEN_NEVER_LIMITED) ) )
if ( !((eeprom_hasLibcmDisabledRegen_get() == EEPROM_LIBCM_DISABLED_REGEN) ||
(eeprom_hasLibcmDisabledRegen_get() == EEPROM_REGEN_NEVER_LIMITED ) ) )
{
//invalid data in EEPROM
Serial.print(F("\nRestoring EEPROM value: EEPROM_LIBCM_DISABLED_REGEN"));
printMessage_RestoringEEPROM(); Serial.print(F("LIBCM_DISABLED_REGEN"));
eeprom_hasLibcmDisabledRegen_set(EEPROM_REGEN_NEVER_LIMITED);
}
if ( !( (eeprom_hasLibcmDisabledAssist_get() == EEPROM_LIBCM_DISABLED_ASSIST) || (eeprom_hasLibcmDisabledAssist_get() == EEPROM_ASSIST_NEVER_LIMITED) ) )
if ( !((eeprom_hasLibcmDisabledAssist_get() == EEPROM_LIBCM_DISABLED_ASSIST) ||
(eeprom_hasLibcmDisabledAssist_get() == EEPROM_ASSIST_NEVER_LIMITED ) ) )
{
//invalid data in EEPROM
Serial.print(F("\nRestoring EEPROM value: EEPROM_LIBCM_DISABLED_ASSIST"));
printMessage_RestoringEEPROM(); Serial.print(F("LIBCM_DISABLED_ASSIST"));
eeprom_hasLibcmDisabledAssist_set(EEPROM_ASSIST_NEVER_LIMITED);
}
if (eeprom_delayKeyON_ms_get() == EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE)
if (eeprom_delayKeyON_ms_get() == EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE_8b)
{
Serial.print(F("\nRestoring EEPROM value: EEPROM_ADDRESS_KEYON_DELAY"));
printMessage_RestoringEEPROM(); Serial.print(F("KEYON_DELAY"));
eeprom_delayKeyON_ms_set(0);
}
if (eeprom_maxCellVoltageDelta_get() == EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE_16b)
{
printMessage_RestoringEEPROM(); Serial.print(F("IMBALANCE_DELTA"));
eeprom_maxCellVoltageDelta_set(CELL_MAJOR_IMBALANCE_DELTA);
}
if (EEPROM.read(EEPROM_ADDRESS_BATT_HISTORY_UNINIT) == EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE_8b)
{
eeprom_batteryHistory_reset();
EEPROM.update(EEPROM_ADDRESS_BATT_HISTORY_UNINIT, EEPROM_ADDRESS_FORMATTED_VALUE);
}
if (EEPROM.read(EEPROM_ADDRESS_Wh_RECORDS_UNINIT) == EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE_8b)
{
eeprom_wattHourHistory_reset();
EEPROM.update(EEPROM_ADDRESS_Wh_RECORDS_UNINIT, EEPROM_ADDRESS_FORMATTED_VALUE);
EEPROM.update(EEPROM_ADDRESS_NEXT_Wh_RECORD, EEPROM_ADDRESS_FORMATTED_VALUE);
}
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) )
{
//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);
EEPROM.update(EEPROM_ADDRESS_MDV_OFFSET, EEPROM_ADDRESS_FORMATTED_VALUE);
EEPROM.update(EEPROM_ADDRESS_SPF_OFFSET, EEPROM_ADDRESS_FORMATTED_VALUE);
}
}
/////////////////////////////////////////////////////////////////////////////////////////
@@ -232,6 +278,7 @@ void eeprom_resetDebugValues(void)
{
eeprom_hasLibcmDisabledRegen_set(EEPROM_REGEN_NEVER_LIMITED);
eeprom_hasLibcmDisabledAssist_set(EEPROM_ASSIST_NEVER_LIMITED);
eeprom_maxCellVoltageDelta_set(CELL_MAJOR_IMBALANCE_DELTA);
}
/////////////////////////////////////////////////////////////////////////////////////////
@@ -266,20 +313,18 @@ void eeprom_batteryHistory_incrementValue(uint8_t indexTemperature, uint8_t inde
/////////////////////////////////////////////////////////////////////////////////////////
void eeprom_eraseRange(uint16_t minAddress, uint16_t maxAddress, uint8_t valueToWrite)
{
Serial.print('\n');
{
for (uint16_t address = minAddress; address <= maxAddress; address++)
{
EEPROM.update(address, valueToWrite);
Serial.print('.');
if ((address & 0b01111111) == 0) //if divisible by 128
{
wdt_reset();
Serial.print('\n');
}
EEPROM.update(address, valueToWrite);
Serial.print('.');
}
}
@@ -388,7 +433,7 @@ void eeprom_resetAll(void)
Serial.print(F("\nEEPROM factory reset"));
eeprom_eraseRange(minAddress, maxAddress, EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE);
eeprom_eraseRange(minAddress, maxAddress, EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE_8b);
Serial.print(F("\nDone. Rebooting."));
@@ -412,23 +457,36 @@ void eeprom_resetAll_userConfirm(void)
/////////////////////////////////////////////////////////////////////////////////////////
void eeprom_begin(void)
void eeprom_printAll(void)
{
eeprom_verifyDataValid();
Serial.print(F("\n\nDumping EEPROM"));
if (EEPROM.read(EEPROM_ADDRESS_BATT_HISTORY_UNINIT) == EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE)
for(uint16_t address = 0; address <= EEPROM_LAST_USABLE_ADDRESS; address++)
{
eeprom_batteryHistory_reset();
EEPROM.update(EEPROM_ADDRESS_BATT_HISTORY_UNINIT, EEPROM_ADDRESS_FORMATTED_VALUE);
}
if ((address & 0b00001111) == 0) //if divisible by 16
{
wdt_reset();
Serial.print('\n');
Serial.print(F("0x"));
if (address <= 0xF ) { Serial.print('0'); }
if (address <= 0xFF) { Serial.print('0'); }
Serial.print(address, HEX);
Serial.print(F(": "));
}
if (EEPROM.read(EEPROM_ADDRESS_Wh_RECORDS_UNINIT) == EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE)
{
eeprom_wattHourHistory_reset();
EEPROM.update(EEPROM_ADDRESS_Wh_RECORDS_UNINIT, EEPROM_ADDRESS_FORMATTED_VALUE);
EEPROM.update(EEPROM_ADDRESS_NEXT_Wh_RECORD, EEPROM_ADDRESS_FORMATTED_VALUE);
}
uint8_t data = EEPROM.read(address);
if (data <= 0xF) { Serial.print('0'); }
Serial.print(data, HEX);
Serial.print(',');
}
}
/////////////////////////////////////////////////////////////////////////////////////////
void eeprom_begin(void)
{
eeprom_verifyDataValid();
}
/////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -9,11 +9,12 @@
#define EEPROM_LIBCM_DISABLED_ASSIST 0xCC
#define EEPROM_ASSIST_NEVER_LIMITED 0x33
#define EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE 0xFF
#define EEPROM_ADDRESS_FORMATTED_VALUE 0x00
#define EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE_16b 0xFFFF
#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)
@@ -39,9 +40,20 @@
uint8_t eeprom_hasLibcmDisabledRegen_get(void);
void eeprom_hasLibcmDisabledRegen_set(uint8_t);
uint16_t eeprom_maxCellVoltageDelta_get(void);
void eeprom_maxCellVoltageDelta_set(uint16_t);
uint8_t eeprom_delayKeyON_ms_get(void);
void eeprom_delayKeyON_ms_set(uint8_t);
int8_t eeprom_getVspoofOffset_BVO(void);
int8_t eeprom_getVspoofOffset_MDV(void);
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);
void eeprom_verifyDataValid(void);
@@ -63,4 +75,6 @@
void writeToEEPROM_uint16(uint16_t startAddress, uint16_t value);
void eeprom_printAll(void);
#endif

View File

@@ -246,8 +246,8 @@ void fan_handler(void)
#ifdef BATTERY_TYPE_5AhG3
gpio_setFanSpeed_OEM(fanSpeed_now);
#elif defined BATTERY_TYPE_47AhFoMoCo
//OEM battery fan is removed in FoMoCo systems. The battery fan circuitry is repurposed to allow LiBCM to control the PDU fan
#elif defined BATTERY_TYPE_47Ah
//OEM battery fan is removed in 47Ah Kits. The battery fan circuitry is repurposed to allow LiBCM to control the PDU fan
//Note that the MCM retains its OEM behavior (i.e. it can still control the PDU fan, too).
//JTS2doLater: Add new fan handler specifically for OEM fan... the direct gpio functions used below will only work properly if no other subsystem calls them
//JTS2doLater: Enable high speed if more than 500 kJ have flowed through the IGBT stage over the previous 60 seconds.

View File

@@ -90,7 +90,7 @@ void gpio_setFanSpeed_OEM(char speed)
//case FAN_MED: digitalWrite(PIN_FANOEM_LOW, HIGH); digitalWrite(PIN_FANOEM_HI, LOW); break; //same as FAN_LOW... OEM fan only supports OFF/LOW/HIGH
#ifdef BATTERY_TYPE_5AhG3
case FAN_HIGH: digitalWrite(PIN_FANOEM_LOW, LOW); digitalWrite(PIN_FANOEM_HI, HIGH); break; //OEM fan schematic requires one relay for high speed
#elif defined BATTERY_TYPE_47AhFoMoCo
#elif defined BATTERY_TYPE_47Ah
case FAN_HIGH: digitalWrite(PIN_FANOEM_LOW, HIGH); digitalWrite(PIN_FANOEM_HI, HIGH); break; //PDU fan schematic requires both relays for high speed
#endif
}

View File

@@ -24,12 +24,12 @@ void runFansIfNeeded(void)
else if (fan_getSpeed_now() == FAN_OFF ) { hysteresis_C = FAN_SPEED_HYSTERESIS_OFF_degC; }
if ( (temperature_intake_getLatest() < (GRID_CHARGING_FANS_OFF_BELOW_TEMP_C - hysteresis_C)) &&
#ifndef BATTERY_TYPE_47AhFoMoCo
#ifndef BATTERY_TYPE_47Ah
(temperature_ambient_getLatest() < (GRID_CHARGING_FANS_OFF_BELOW_TEMP_C - hysteresis_C)) &&
#endif
(temperature_battery_getLatest() < (GRID_CHARGING_FANS_OFF_BELOW_TEMP_C - hysteresis_C)) ) { fan_requestSpeed(FAN_REQUESTOR_GRIDCHARGER, FAN_OFF); }
else if ( (temperature_intake_getLatest() < (GRID_CHARGING_FANS_LOW_BELOW_TEMP_C - hysteresis_C)) &&
#ifndef BATTERY_TYPE_47AhFoMoCo
#ifndef BATTERY_TYPE_47Ah
(temperature_ambient_getLatest() < (GRID_CHARGING_FANS_LOW_BELOW_TEMP_C - hysteresis_C)) &&
#endif
(temperature_battery_getLatest() < (GRID_CHARGING_FANS_LOW_BELOW_TEMP_C - hysteresis_C)) ) { fan_requestSpeed(FAN_REQUESTOR_GRIDCHARGER, FAN_LOW); }
@@ -54,7 +54,7 @@ uint8_t gridCharger_isAllowedNow(void)
if (gpio_isGridChargerPluggedInNow() == NO ) { return NO__CHARGER_UNPLUGGED; }
if (key_getSampledState() == KEYSTATE_ON ) { return NO__KEY_IS_ON; }
//cell voltage checks
if (LTC68042result_hiCellVoltage_get() > CELL_VREST_85_PERCENT_SoC ) { return NO__ATLEASTONECELL_TOO_HIGH; }
if (LTC68042result_hiCellVoltage_get() > CELL_VREST_085_PERCENT_SoC ) { return NO__ATLEASTONECELL_TOO_HIGH; }
if (LTC68042result_loCellVoltage_get() < CELL_VMIN_GRIDCHARGER ) { return NO__ATLEASTONECELL_TOO_LOW; }
if (LTC68042result_hiCellVoltage_get() > CELL_VMAX_GRIDCHARGER ) { return NO__ATLEASTONECELL_FULL; }
if (LTC68042result_hiCellVoltage_get() > determineMaxAllowedCellVoltage() ) { return NO__CELL_VOLTAGE_HYSTERESIS; }
@@ -65,7 +65,7 @@ uint8_t gridCharger_isAllowedNow(void)
if (temperature_battery_getLatest() > DISABLE_GRIDCHARGING_ABOVE_BATTERY_TEMP_C) { return NO__BATTERY_IS_HOT; }
if (temperature_intake_getLatest() > DISABLE_GRIDCHARGING_ABOVE_INTAKE_TEMP_C ) { return NO__AIRINTAKE_IS_HOT; }
if (temperature_intake_getLatest() == TEMPERATURE_SENSOR_FAULT_LO ) { return NO__TEMP_UNPLUGGED_INTAKE; }
#ifndef BATTERY_TYPE_47AhFoMoCo
#ifndef BATTERY_TYPE_47Ah
if (temperature_exhaust_getLatest() > DISABLE_GRIDCHARGING_ABOVE_EXHAUST_TEMP_C) { return NO__TEMP_EXHAUST_IS_HOT; }
#endif
//time checks
@@ -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

@@ -6,8 +6,9 @@
#define VCELL_HYSTERESIS 150 // '150' = 15 mV //prevents rapid grid charger on/off toggling when first cell is full
#define YES__CHARGING_ALLOWED 0b01111111 //if charging allowed, first three bits are '011'
#define NO__UNINITIALIZED 0b10000000 //if charging disabled, first three bits are '100' //safety feature in case a single bit flips
#define YES__CHARGING_ALLOWED 0b01111111 //first three bits are '011' for 'YES__'
#define DELAY_DO_NOTHING 0b00111110 //first three bits are '001' for 'DELAY'
#define NO__UNINITIALIZED 0b10000000 //first three bits are '100' for 'NO__' //safety feature in case a single bit flips
#define NO__CHARGER_IS_HOT 0b10000001
#define NO__BATTERY_IS_COLD 0b10000010
#define NO__BATTERY_IS_HOT 0b10000011
@@ -15,7 +16,7 @@
#define NO__TEMP_UNPLUGGED_GRID 0b10000101
#define NO__TEMP_UNPLUGGED_INTAKE 0b10000110
#define NO__TEMP_EXHAUST_IS_HOT 0b10000111
#define NO__ATLEASTONECELL_TOO_HIGH 0b10001000 //JTS2doLater: Allow charging if highest cell below 4.3000 when charger plugged in
#define NO__ATLEASTONECELL_TOO_HIGH 0b10001000
#define NO__ATLEASTONECELL_FULL 0b10001001
#define NO__ATLEASTONECELL_TOO_LOW 0b10001010
#define NO__JUST_PLUGGED_IN 0b10001011
@@ -25,10 +26,13 @@
#define NO__CELL_VOLTAGE_HYSTERESIS 0b10001111
#define NO__CHARGER_UNPLUGGED 0b10010000
#define NO__SoC_TOO_LOW 0b10010001
#define NO__PACK_CURRENT_TOO_HIGH 0b10010010
//place other NO__ conditions here
#define NO__CHARGING_NOT_REQUESTED 0b10011111
#define DISABLE_GRIDCHARGING_ABOVE_CHARGER_TEMP_C 60
#define DISABLE_GRIDCHARGING_BELOW_BATTERY_TEMP_C -25
#define DISABLE_GRIDCHARGING_ABOVE_BATTERY_TEMP_C 40
#define DISABLE_GRIDCHARGING_ABOVE_BATTERY_TEMP_C 43
#define DISABLE_GRIDCHARGING_ABOVE_INTAKE_TEMP_C 45
#define DISABLE_GRIDCHARGING_ABOVE_EXHAUST_TEMP_C 50

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
@@ -398,7 +398,7 @@ bool lcd_printCellVoltage_delta(void)
static uint16_t deltaVoltage_onScreen = 0;
uint16_t deltaVoltage_LTC6804 = LTC68042result_hiCellVoltage_get() - LTC68042result_loCellVoltage_get();
uint16_t deltaVoltage_LTC6804 = LTC68042result_deltaCellVoltage_get();
if (deltaVoltage_onScreen != deltaVoltage_LTC6804)
{

View File

@@ -11,19 +11,19 @@
int8_t tempBattery = ROOM_TEMP_DEGC;
int8_t tempIntake = ROOM_TEMP_DEGC;
int8_t tempCharger = ROOM_TEMP_DEGC;
#ifndef BATTERY_TYPE_47AhFoMoCo // No explicit exhaust nor ambient temp sensors in FoMoCo case
int8_t tempExhaust = ROOM_TEMP_DEGC;
int8_t tempAmbient = ROOM_TEMP_DEGC;
#ifndef BATTERY_TYPE_47Ah //47Ah Kits don't have exhaust or ambient sensors
int8_t tempExhaust = ROOM_TEMP_DEGC;
int8_t tempAmbient = ROOM_TEMP_DEGC;
#endif
/////////////////////////////////////////////////////////////////////////////////////////
int8_t temperature_battery_getLatest(void) { return tempBattery; }
int8_t temperature_intake_getLatest(void) { return tempIntake; } //GRN (5AhG3 case) or WHT (FoMoCo case) OEM temp sensor
int8_t temperature_gridCharger_getLatest(void){ return tempCharger; } //BLU OEM temp sensor
#ifndef BATTERY_TYPE_47AhFoMoCo // No explicit exhaust nor ambient temp sensors in FoMoCo case
int8_t temperature_exhaust_getLatest(void) { return tempExhaust; } //YEL OEM temp sensor
int8_t temperature_ambient_getLatest(void) { return tempAmbient; } //WHT OEM temp sensor
int8_t temperature_battery_getLatest(void) { return tempBattery; }
int8_t temperature_intake_getLatest(void) { return tempIntake; } //OEM temp sensor: 5AhG3=GRN 47Ah=WHT
int8_t temperature_gridCharger_getLatest(void) { return tempCharger; } //BLU OEM temp sensor
#ifndef BATTERY_TYPE_47Ah //47Ah Kits don't have exhaust or ambient sensors
int8_t temperature_exhaust_getLatest(void) { return tempExhaust; } //YEL OEM temp sensor
int8_t temperature_ambient_getLatest(void) { return tempAmbient; } //WHT OEM temp sensor
#endif
/////////////////////////////////////////////////////////////////////////////////////////
@@ -36,7 +36,7 @@ void temperature_measureOEM(void)
tempExhaust = temperature_measureOneSensor_degC(PIN_TEMP_YEL);
tempCharger = temperature_measureOneSensor_degC(PIN_TEMP_BLU);
tempAmbient = temperature_measureOneSensor_degC(PIN_TEMP_WHT);
#elif defined BATTERY_TYPE_47AhFoMoCo
#elif defined BATTERY_TYPE_47Ah
tempIntake = temperature_measureOneSensor_degC(PIN_TEMP_WHT);
tempCharger = temperature_measureOneSensor_degC(PIN_TEMP_BLU);
#endif
@@ -54,10 +54,10 @@ void temperature_measureBattery(void)
batteryTemps[1] = temperature_measureOneSensor_degC(PIN_TEMP_BAY1);
batteryTemps[2] = temperature_measureOneSensor_degC(PIN_TEMP_BAY2);
batteryTemps[3] = temperature_measureOneSensor_degC(PIN_TEMP_BAY3);
#ifdef BATTERY_TYPE_47AhFoMoCo
batteryTemps[4] = temperature_measureOneSensor_degC(PIN_TEMP_GRN); //Top rear battery module
batteryTemps[5] = temperature_measureOneSensor_degC(PIN_TEMP_YEL); //Top middle battery module
#endif
#ifdef BATTERY_TYPE_47Ah
batteryTemps[4] = temperature_measureOneSensor_degC(PIN_TEMP_GRN); //Top rear battery module
batteryTemps[5] = temperature_measureOneSensor_degC(PIN_TEMP_YEL); //Top middle battery module
#endif
//stores hottest and coldest temp sensor value
@@ -69,29 +69,21 @@ void temperature_measureBattery(void)
if ((batteryTemps[ii] == TEMPERATURE_SENSOR_FAULT_HI) ||
(batteryTemps[ii] == TEMPERATURE_SENSOR_FAULT_LO) )
{
#ifdef BATTERY_TYPE_5AhG3
Serial.print(F("\nCheck Batt Temp Sensor! Bay: "));
Serial.print(String(ii,DEC));
#elif defined BATTERY_TYPE_47AhFoMoCo
Serial.print(F("\nCheck Batt Temp Sensor!"));
switch (ii) {
case 1:
Serial.print(F(" Middle tray rail, driver side")); //BAY1
break;
case 2:
Serial.print(F(" Bottom tray, middle")); //BAY2
break;
case 3:
Serial.print(F(" Middle tray rail, passenger side")); //BAY3
break;
case 4:
Serial.print(F(" Top rear battery module"));
break;
case 5:
Serial.print(F(" Top middle battery module"));
break;
}
#endif
Serial.print(F("\nCheck Batt Temp Sensor: "));
#ifdef BATTERY_TYPE_5AhG3
Serial.print(F("Bay "));
Serial.print(String(ii,DEC));
#elif defined BATTERY_TYPE_47Ah
switch (ii)
{
case 1: Serial.print(F(" Middle tray, driver" )); break; //5AhG3 BAY1
case 2: Serial.print(F(" Bottom tray, center" )); break; //5AhG3 BAY2
case 3: Serial.print(F(" Middle tray, passenger")); break; //5AhG3 BAY3
case 4: Serial.print(F(" Top rear battery" )); break;
case 5: Serial.print(F(" Top middle battery" )); break;
}
#endif
}
else
{
@@ -126,19 +118,18 @@ void temperature_printAll_latest(void)
Serial.print(temperature_gridCharger_getLatest());
Serial.print(F("\nIn: "));
Serial.print(temperature_intake_getLatest());
#ifndef BATTERY_TYPE_47AhFoMoCo
Serial.print(F("\nAmb: "));
Serial.print(temperature_ambient_getLatest());
Serial.print(F("\nOut: "));
Serial.print(temperature_exhaust_getLatest());
#endif
#ifndef BATTERY_TYPE_47Ah
Serial.print(F("\nAmb: "));
Serial.print(temperature_ambient_getLatest());
Serial.print(F("\nOut: "));
Serial.print(temperature_exhaust_getLatest());
#endif
Serial.print(F("\nBatt: "));
Serial.print(temperature_battery_getLatest());
}
/////////////////////////////////////////////////////////////////////////////////////////
//JTS2doNext: add separate case for FoMoCo
void temperature_measureAndPrintAll(void)
{
if (gpio_getPinState(PIN_TEMP_EN) == PIN_OUTPUT_HIGH)
@@ -146,33 +137,34 @@ void temperature_measureAndPrintAll(void)
Serial.print(F("\nTemperatures(C):"));
Serial.print(F("\nBLU (Charger): "));
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_BLU));
#ifdef BATTERY_TYPE_5AhG3
Serial.print(F("\nGRN (Intake): "));
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_GRN));
Serial.print(F("\nWHT (Ambient): "));
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_WHT));
Serial.print(F("\nYEL (Exhaust): "));
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_YEL));
Serial.print(F("\nBAY1: "));
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_BAY1));
Serial.print(F("\nBAY2: "));
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_BAY2));
Serial.print(F("\nBAY3: "));
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_BAY3));
#elif defined BATTERY_TYPE_47AhFoMoCo
Serial.print(F("\nGRN (Top rear battery module): "));
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_GRN));
Serial.print(F("\nWHT (Intake): "));
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_WHT));
Serial.print(F("\nYEL (Top middle battery module): "));
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_YEL));
Serial.print(F("\nMiddle tray rail, driver side: ")); //BAY1
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_BAY1));
Serial.print(F("\nBottom tray, middle: ")); //BAY2
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_BAY2));
Serial.print(F("\nMiddle tray rail, passenger side: ")); //BAY3
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_BAY3));
#endif
#ifdef BATTERY_TYPE_5AhG3
Serial.print(F("\nGRN (intake): "));
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_GRN));
Serial.print(F("\nWHT (ambient): "));
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_WHT));
Serial.print(F("\nYEL (exhaust): "));
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_YEL));
Serial.print(F("\nBAY1: "));
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_BAY1));
Serial.print(F("\nBAY2: "));
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_BAY2));
Serial.print(F("\nBAY3: "));
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_BAY3));
#elif defined BATTERY_TYPE_47Ah
Serial.print(F("\nGRN (top rear battery): "));
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_GRN));
Serial.print(F("\nWHT (air intake): "));
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_WHT));
Serial.print(F("\nYEL (top middle battery): "));
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_YEL));
Serial.print(F("\nMiddle tray, driver: ")); //BAY1
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_BAY1));
Serial.print(F("\nBottom tray, middle: ")); //BAY2
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_BAY2));
Serial.print(F("\nMiddle tray, passenger: ")); //BAY3
Serial.print(temperature_measureOneSensor_degC(PIN_TEMP_BAY3));
#endif
}
else
{
@@ -250,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

@@ -7,7 +7,7 @@
int8_t temperature_battery_getLatest(void);
int8_t temperature_intake_getLatest(void);
int8_t temperature_gridCharger_getLatest(void);
#ifndef BATTERY_TYPE_47AhFoMoCo
#ifndef BATTERY_TYPE_47Ah
int8_t temperature_exhaust_getLatest(void);
int8_t temperature_ambient_getLatest(void); //IMA bay temperature
#endif
@@ -38,7 +38,7 @@
#ifdef BATTERY_TYPE_5AhG3
#define NUM_BATTERY_TEMP_SENSORS 3
#elif defined BATTERY_TYPE_47AhFoMoCo
#elif defined BATTERY_TYPE_47Ah
// what were 2 OEM temp sensors (PIN_TEMP_GRN, PIN_TEMP_YEL) are now on battery modules
#define NUM_BATTERY_TEMP_SENSORS 5
#endif

View File

@@ -36,21 +36,47 @@ void vPackSpoof_handleKeyOFF(void)
/////////////////////////////////////////////////////////////////////////////////////////
void spoofVoltageMCMe(void)
{
int16_t pwmCounts_MCMe = 0;
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(); }
uint8_t spoofedPackVoltage_MCMe = spoofedPackVoltage + ADDITIONAL_MCMe_OFFSET_VOLTS;
void vPackSpoof_offsetBVO_adjust(uint8_t action)
{
if (action == '+') { eeprom_setVspoofOffset_BVO(eeprom_getVspoofOffset_BVO() - 1); }
else if (action == '-') { eeprom_setVspoofOffset_BVO(eeprom_getVspoofOffset_BVO() + 1); }
else if (action == '0') { eeprom_setVspoofOffset_BVO(0); }
}
void vPackSpoof_offsetMDV_adjust(uint8_t action)
{
if (action == '+') { eeprom_setVspoofOffset_MDV(eeprom_getVspoofOffset_MDV() + 1); }
else if (action == '-') { eeprom_setVspoofOffset_MDV(eeprom_getVspoofOffset_MDV() - 1); }
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)
{
//Derivation, empirically determined (see: ~/Electronics/PCB (KiCAD)/RevB/V&V/voltage spoofing results.ods)
//pwmCounts_MCMe = ( actualPackVoltage * 512) / spoofedPackVoltage_MCMe - 551
//pwmCounts_MCMe = ( actualPackVoltage * 256) / spoofedPackVoltage_MCMe * 2 - 551 //prevent 16b overflow
//pwmCounts_MCMe = (( ( ((uint16_t)actualPackVoltage ) * 256) / spoofedPackVoltage_MCMe) * 2 ) - 551
pwmCounts_MCMe = (( ( ((uint16_t)LTC68042result_packVoltage_get()) << 8 ) / spoofedPackVoltage_MCMe) << 1 ) - 551;
// pwmCounts_MCMe = ( actualPackVoltage * 512) / spoofedPackVoltage - 551
// pwmCounts_MCMe = ( actualPackVoltage * 256) / spoofedPackVoltage * 2 - 551 //prevent 16b overflow
// pwmCounts_MCMe = (( ( ((uint16_t)actualPackVoltage ) * 256) / spoofedPackVoltage) * 2 ) - 551
int16_t pwmCounts_MCMe = (( ( ((uint16_t)LTC68042result_packVoltage_get()) << 8 ) / spoofedPackVoltage) << 1 ) - 551;
pwmCounts_MCMe += eeprom_getVspoofOffset_BVO();
//bounds checking
if (pwmCounts_MCMe > 255) {pwmCounts_MCMe = 255;}
else if (pwmCounts_MCMe < 0) {pwmCounts_MCMe = 0;}
if (pwmCounts_MCMe > 255) { pwmCounts_MCMe = 255; }
else if (pwmCounts_MCMe < 0) { pwmCounts_MCMe = 0; }
analogWrite(PIN_MCME_PWM, (uint8_t)pwmCounts_MCMe);
}
@@ -59,18 +85,20 @@ void spoofVoltageMCMe(void)
void spoofVoltage_VPINout(void)
{
int16_t pwmCounts_VPIN_out = 0;
// V_DIV_CORRECTION = RESISTANCE_MCM / RESISTANCE_R34
// V_DIV_CORRECTION = 100k / 10k
#define V_DIV_CORRECTION 1.1
uint8_t spoofedPackVoltage_VPIN = spoofedPackVoltage + ADDITIONAL_VPIN_OFFSET_VOLTS;
//remap measured Vpin_in value ratiometrically to desired spoofed voltage
//It's important to look at VPIN_in, since V_PDU is different from the Vpack during keyON capacitor charging event
uint16_t intermediateMath = (uint16_t)(adc_packVoltage_VpinIn() * spoofedPackVoltage_VPIN) * V_DIV_CORRECTION;
pwmCounts_VPIN_out = (int16_t)( (uint16_t)intermediateMath / LTC68042result_packVoltage_get() );
// mathematically: VpinOut = VpinIn * spoofedPackVoltage * 1.1 / actualPackvoltage
//must use VPIN_in ratiometrically for two reasons:
// 1) VPIN_in measures voltage inside the PDU, which ramps up during keyON capacitor charging event
// 2) Safety. If we only used LTC6804 Vpack result, we'd lose redundancy required by ASIL-C
uint16_t intermediateMath = (uint16_t)adc_packVoltage_VpinIn() * spoofedPackVoltage;
intermediateMath = (intermediateMath >> 7) * 141; //multiply by 1.1 to correct for LiBCM's hardware voltage divider:
// V_DIV_CORRECTION = RESISTANCE_MCM / RESISTANCE_R34
// V_DIV_CORRECTION = 100k / 10k
// V_DIV_CORRECTION = 1.1
// V_DIV_CORRECTION = (x * 141) >> 7
int16_t pwmCounts_VPIN_out = (int16_t)(intermediateMath / LTC68042result_packVoltage_get());
pwmCounts_VPIN_out += eeprom_getVspoofOffset_MDV();
//bounds checking
if (pwmCounts_VPIN_out > 255) {pwmCounts_VPIN_out = 255;}
@@ -107,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

@@ -16,15 +16,21 @@
#define MAXIMIZE_POWER_ABOVE_CURRENT_AMPS (BEGIN_SPOOFING_VOLTAGE_ABOVE_AMPS + ADDITIONAL_AMPS_UNTIL_MAX_VSPOOF)
#define VSPOOF_TO_MAXIMIZE_POWER 125 //Maximum assist occurs when MCM thinks pack is at 120 volts
#define ADDITIONAL_VPIN_OFFSET_VOLTS 0 //this many volts are added to VPIN output //use with OBDIIC&C to make BATTSCI voltage equal to VPIN voltage
#define ADDITIONAL_MCMe_OFFSET_VOLTS 0 //this many volts are added to MCMe output //use with OBDIIC&C to make BATTSCI voltage equal to MCMe voltage
void vPackSpoof_setVoltage(void);
void vPackSpoof_handleKeyOFF(void);
void vPackSpoof_handleKeyON(void);
int8_t vPackSpoof_offsetBVO_get(void);
int8_t vPackSpoof_offsetMDV_get(void);
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);
#endif