From 57357096ea283042bfde8c6b2e381367f8d5d057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=A4ger?= Date: Mon, 22 Jul 2024 17:12:37 +0200 Subject: [PATCH 1/5] BMS common: Add typical LTO OCV curve --- app/src/bms_common.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/src/bms_common.c b/app/src/bms_common.c index f2d20fb0..28ad172f 100644 --- a/app/src/bms_common.c +++ b/app/src/bms_common.c @@ -21,6 +21,11 @@ static float ocv_nmc[OCV_POINTS] = { 4.198F, 4.135F, 4.089F, 4.056F, 4.026F, 3.9 3.924F, 3.883F, 3.858F, 3.838F, 3.819F, 3.803F, 3.787F, 3.764F, 3.745F, 3.726F, 3.702F, 3.684F, 3.588F, 2.800F }; +// Source: DOI:10.3390/batteries5010031 (https://www.mdpi.com/2313-0105/5/1/31) +static float ocv_lto[OCV_POINTS] = { 2.800F, 2.513F, 2.458F, 2.415F, 2.376F, 2.340F, 2.309F, + 2.282F, 2.259F, 2.240F, 2.224F, 2.210F, 2.198F, 2.187F, + 2.177F, 2.166F, 2.154F, 2.141F, 2.125F, 2.105F, 2.000F }; + float ocv_custom[OCV_POINTS] = { 0 }; static float soc_pct[OCV_POINTS] = { 100.0F, 95.0F, 90.0F, 85.0F, 80.0F, 85.0F, 70.0F, @@ -96,9 +101,8 @@ void bms_init_config(struct bms_context *bms, enum bms_cell_type type, float nom bms->ic_conf.cell_uv_reset = 2.10F; bms->ic_conf.cell_dis_voltage_limit = 2.00F; bms->ic_conf.cell_uv_limit = 1.90F; - // ToDo: Use typical OCV curve for LTO cells - bms->ocv_points = NULL; - bms->soc_points = NULL; + bms->ocv_points = ocv_lto; + bms->soc_points = soc_pct; break; case CELL_TYPE_CUSTOM: bms->ocv_points = ocv_custom; From 2c9d661f0ead6c090fdfed33f7e118af9a2b0258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=A4ger?= Date: Mon, 22 Jul 2024 17:22:30 +0200 Subject: [PATCH 2/5] BMS common: Use common OCV/SOC array and memcpy defaults at boot This avoids having OCV and SOC arrays with all zeros exposed to the user via ThingSet. The curves can be initialized with default values for a certain cell and afterwards be customized. --- app/src/bms_common.c | 50 +++++++++++++++++++++++------------------- app/src/bms_soc.c | 6 ++--- app/src/data_objects.c | 8 +++---- include/bms/bms.h | 2 +- 4 files changed, 35 insertions(+), 31 deletions(-) diff --git a/app/src/bms_common.c b/app/src/bms_common.c index 28ad172f..41f95f2f 100644 --- a/app/src/bms_common.c +++ b/app/src/bms_common.c @@ -13,26 +13,30 @@ LOG_MODULE_REGISTER(bms, CONFIG_LOG_DEFAULT_LEVEL); -static float ocv_lfp[OCV_POINTS] = { 3.392F, 3.314F, 3.309F, 3.308F, 3.304F, 3.296F, 3.283F, - 3.275F, 3.271F, 3.268F, 3.265F, 3.264F, 3.262F, 3.252F, - 3.240F, 3.226F, 3.213F, 3.190F, 3.177F, 3.132F, 2.833F }; +static const float ocv_lfp[NUM_OCV_POINTS] = { + 3.392F, 3.314F, 3.309F, 3.308F, 3.304F, 3.296F, 3.283F, 3.275F, 3.271F, 3.268F, 3.265F, + 3.264F, 3.262F, 3.252F, 3.240F, 3.226F, 3.213F, 3.190F, 3.177F, 3.132F, 2.833F, +}; -static float ocv_nmc[OCV_POINTS] = { 4.198F, 4.135F, 4.089F, 4.056F, 4.026F, 3.993F, 3.962F, - 3.924F, 3.883F, 3.858F, 3.838F, 3.819F, 3.803F, 3.787F, - 3.764F, 3.745F, 3.726F, 3.702F, 3.684F, 3.588F, 2.800F }; +static const float ocv_nmc[NUM_OCV_POINTS] = { + 4.198F, 4.135F, 4.089F, 4.056F, 4.026F, 3.993F, 3.962F, 3.924F, 3.883F, 3.858F, 3.838F, + 3.819F, 3.803F, 3.787F, 3.764F, 3.745F, 3.726F, 3.702F, 3.684F, 3.588F, 2.800F, +}; // Source: DOI:10.3390/batteries5010031 (https://www.mdpi.com/2313-0105/5/1/31) -static float ocv_lto[OCV_POINTS] = { 2.800F, 2.513F, 2.458F, 2.415F, 2.376F, 2.340F, 2.309F, - 2.282F, 2.259F, 2.240F, 2.224F, 2.210F, 2.198F, 2.187F, - 2.177F, 2.166F, 2.154F, 2.141F, 2.125F, 2.105F, 2.000F }; +static const float ocv_lto[NUM_OCV_POINTS] = { + 2.800F, 2.513F, 2.458F, 2.415F, 2.376F, 2.340F, 2.309F, 2.282F, 2.259F, 2.240F, 2.224F, + 2.210F, 2.198F, 2.187F, 2.177F, 2.166F, 2.154F, 2.141F, 2.125F, 2.105F, 2.000F, +}; -float ocv_custom[OCV_POINTS] = { 0 }; +static const float soc_default[NUM_OCV_POINTS] = { + 100.0F, 95.0F, 90.0F, 85.0F, 80.0F, 85.0F, 70.0F, 65.0F, 60.0F, 55.0F, 50.0F, + 45.0F, 40.0F, 35.0F, 30.0F, 25.0F, 20.0F, 15.0F, 10.0F, 5.0F, 0.0F, +}; -static float soc_pct[OCV_POINTS] = { 100.0F, 95.0F, 90.0F, 85.0F, 80.0F, 85.0F, 70.0F, - 65.0F, 60.0F, 55.0F, 50.0F, 45.0F, 40.0F, 35.0F, - 30.0F, 25.0F, 20.0F, 15.0F, 10.0F, 5.0F, 0.0F }; - -float soc_custom[OCV_POINTS] = { 0 }; +// actually used OCV vs. SOC curve +float ocv_points[NUM_OCV_POINTS] = { 0 }; +float soc_points[NUM_OCV_POINTS] = { 0 }; void bms_init_config(struct bms_context *bms, enum bms_cell_type type, float nominal_capacity_Ah) { @@ -66,6 +70,11 @@ void bms_init_config(struct bms_context *bms, enum bms_cell_type type, float nom bms->ic_conf.cell_ov_delay_ms = 2000; bms->ic_conf.cell_uv_delay_ms = 2000; + bms->ocv_points = ocv_points; + bms->soc_points = soc_points; + + memcpy(soc_points, soc_default, sizeof(soc_points)); + switch (type) { case CELL_TYPE_LFP: bms->ic_conf.cell_ov_limit = 3.80F; @@ -79,8 +88,7 @@ void bms_init_config(struct bms_context *bms, enum bms_cell_type type, float nom * self-discharge */ bms->ic_conf.cell_uv_limit = 2.50F; - bms->ocv_points = ocv_lfp; - bms->soc_points = soc_pct; + memcpy(ocv_points, ocv_lfp, sizeof(ocv_points)); break; case CELL_TYPE_NMC: bms->ic_conf.cell_ov_limit = 4.25F; @@ -90,8 +98,7 @@ void bms_init_config(struct bms_context *bms, enum bms_cell_type type, float nom bms->ic_conf.cell_uv_reset = 3.50F; bms->ic_conf.cell_dis_voltage_limit = 3.20F; bms->ic_conf.cell_uv_limit = 3.00F; - bms->ocv_points = ocv_nmc; - bms->soc_points = soc_pct; + memcpy(ocv_points, ocv_nmc, sizeof(ocv_points)); break; case CELL_TYPE_LTO: bms->ic_conf.cell_ov_limit = 2.85F; @@ -101,12 +108,9 @@ void bms_init_config(struct bms_context *bms, enum bms_cell_type type, float nom bms->ic_conf.cell_uv_reset = 2.10F; bms->ic_conf.cell_dis_voltage_limit = 2.00F; bms->ic_conf.cell_uv_limit = 1.90F; - bms->ocv_points = ocv_lto; - bms->soc_points = soc_pct; + memcpy(ocv_points, ocv_lto, sizeof(ocv_points)); break; case CELL_TYPE_CUSTOM: - bms->ocv_points = ocv_custom; - bms->soc_points = soc_custom; break; } diff --git a/app/src/bms_soc.c b/app/src/bms_soc.c index 6ad40a41..44398eb8 100644 --- a/app/src/bms_soc.c +++ b/app/src/bms_soc.c @@ -14,11 +14,11 @@ void bms_soc_reset(struct bms_context *bms, int percent) bms->soc = percent; } else if (bms->ocv_points != NULL && bms->soc_points != NULL - && !is_empty((uint8_t *)bms->ocv_points, OCV_POINTS) - && !is_empty((uint8_t *)bms->soc_points, OCV_POINTS)) + && !is_empty((uint8_t *)bms->ocv_points, NUM_OCV_POINTS) + && !is_empty((uint8_t *)bms->soc_points, NUM_OCV_POINTS)) { // Executes if both OCV and SOC points are valid pointers and arrays contain non-zero data. - bms->soc = interpolate(bms->ocv_points, bms->soc_points, OCV_POINTS, + bms->soc = interpolate(bms->ocv_points, bms->soc_points, NUM_OCV_POINTS, bms->ic_data.cell_voltage_avg); } else { diff --git a/app/src/data_objects.c b/app/src/data_objects.c index 6e282724..91a41ed2 100644 --- a/app/src/data_objects.c +++ b/app/src/data_objects.c @@ -20,8 +20,8 @@ #include extern struct bms_context bms; -extern float ocv_custom[OCV_POINTS]; -extern float soc_custom[OCV_POINTS]; +extern float ocv_points[NUM_OCV_POINTS]; +extern float soc_points[NUM_OCV_POINTS]; static char manufacturer[] = "Libre Solar"; static char device_type[] = DT_PROP(DT_PATH(pcb), type); @@ -35,9 +35,9 @@ static THINGSET_DEFINE_FLOAT_ARRAY(cell_voltages_arr, 3, bms.ic_data.cell_voltag static THINGSET_DEFINE_FLOAT_ARRAY(cell_temps_arr, 1, bms.ic_data.cell_temps, ARRAY_SIZE(bms.ic_data.cell_temps)); -static THINGSET_DEFINE_FLOAT_ARRAY(ocv_points_arr, 3, ocv_custom, ARRAY_SIZE(ocv_custom)); +static THINGSET_DEFINE_FLOAT_ARRAY(ocv_points_arr, 3, ocv_points, ARRAY_SIZE(ocv_points)); -static THINGSET_DEFINE_FLOAT_ARRAY(soc_points_arr, 1, soc_custom, ARRAY_SIZE(soc_custom)); +static THINGSET_DEFINE_FLOAT_ARRAY(soc_points_arr, 1, soc_points, ARRAY_SIZE(soc_points)); // used for xInitConf functions static float new_capacity = 0; diff --git a/include/bms/bms.h b/include/bms/bms.h index c85e30eb..d444019f 100644 --- a/include/bms/bms.h +++ b/include/bms/bms.h @@ -24,7 +24,7 @@ extern "C" { #include /* fixed number of OCV vs. SOC points */ -#define OCV_POINTS 21 +#define NUM_OCV_POINTS 21 /** * Possible BMS states From 22f1e954ca843bd6942a017e3e01f5784b007be4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=A4ger?= Date: Mon, 22 Jul 2024 17:28:26 +0200 Subject: [PATCH 3/5] BMS common: Remove custom cell type Instead, the pre-populated typical values for certain chemistries should be adjusted to avoid having totally invalid configurations (e.g. SOC lookup tables with 0 V) --- app/Kconfig | 17 ++++++----------- app/prj.conf | 2 +- app/src/bms_common.c | 2 -- docs/src/features.rst | 2 +- include/bms/bms.h | 7 +++---- 5 files changed, 11 insertions(+), 19 deletions(-) diff --git a/app/Kconfig b/app/Kconfig index a7bdfbe2..315eef96 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -13,37 +13,32 @@ config BAT_CAPACITY_AH Nominal battery capacity or sum of parallel cells capacity choice - prompt "Cell type" + prompt "Default cell type" default CELL_TYPE_LFP help Select the type of the single cells inside the battery to determine voltage set points. Total voltage set points are multiplied with the selected number of cells. + The default values based on this configuration can be overriden via ThingSet. + config CELL_TYPE_LFP bool "LiFePO4, 3.3V nominal" config CELL_TYPE_NMC bool "NMC/Graphite, 3.7V nominal, 4.2V max" - config CELL_TYPE_NMC_HV - bool "NMC/Graphite High Voltage, 3.7V nominal, 4.35 max" - config CELL_TYPE_LTO bool "NMC/Titanate, 2.4 V nominal" - config CELL_TYPE_CUSTOM - bool "Enable manual configuration for all customizable parameters" endchoice # values must match enum CellType in bms.h config CELL_TYPE int - default 0 if CELL_TYPE_CUSTOM - default 1 if CELL_TYPE_LFP - default 2 if CELL_TYPE_NMC - default 3 if CELL_TYPE_NMC_HV - default 4 if CELL_TYPE_LTO + default 0 if CELL_TYPE_LFP + default 1 if CELL_TYPE_NMC + default 2 if CELL_TYPE_LTO endmenu diff --git a/app/prj.conf b/app/prj.conf index d33914b8..8db09296 100644 --- a/app/prj.conf +++ b/app/prj.conf @@ -29,5 +29,5 @@ CONFIG_THINGSET_NODE_NAME="Libre Solar BMS" # Change default battery nominal capacity (in Ah) #CONFIG_BAT_CAPACITY_AH=? -# Select cell type for initial configuration: LFP (default), NMC, NMC_HV, LTO or CUSTOM +# Select cell type for initial configuration: LFP (default), NMC or LTO #CONFIG_CELL_TYPE_???=y diff --git a/app/src/bms_common.c b/app/src/bms_common.c index 41f95f2f..009a80c7 100644 --- a/app/src/bms_common.c +++ b/app/src/bms_common.c @@ -110,8 +110,6 @@ void bms_init_config(struct bms_context *bms, enum bms_cell_type type, float nom bms->ic_conf.cell_uv_limit = 1.90F; memcpy(ocv_points, ocv_lto, sizeof(ocv_points)); break; - case CELL_TYPE_CUSTOM: - break; } /* trigger alert for all possible errors by default */ diff --git a/docs/src/features.rst b/docs/src/features.rst index 038fa058..ac8c0632 100644 --- a/docs/src/features.rst +++ b/docs/src/features.rst @@ -22,7 +22,7 @@ Amongst all features inherited from underlying Zephyr, the BMS has the following - Pack layout - - Cell chemistry (LiFePO4, NMC, NCA) + - Cell chemistry (e.g. LiFePO4, NMC, NCA, LTO) - Nominal capacity - Number of cells - Thermistor type diff --git a/include/bms/bms.h b/include/bms/bms.h index d444019f..bebb9ca1 100644 --- a/include/bms/bms.h +++ b/include/bms/bms.h @@ -43,10 +43,9 @@ enum bms_state */ enum bms_cell_type { - CELL_TYPE_CUSTOM = 0, ///< Custom settings - CELL_TYPE_LFP, ///< LiFePO4 Li-ion cells (3.3 V nominal) - CELL_TYPE_NMC, ///< NMC/Graphite Li-ion cells (3.7 V nominal) - CELL_TYPE_LTO ///< NMC/Titanate (2.4 V nominal) + CELL_TYPE_LFP, ///< LiFePO4 Li-ion cells (3.3 V nominal) + CELL_TYPE_NMC, ///< NMC/Graphite Li-ion cells (3.7 V nominal) + CELL_TYPE_LTO, ///< NMC/Titanate (2.4 V nominal) }; /** From 754d407a3ffc18c8b2c95fe3647d2f49ed41442a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=A4ger?= Date: Mon, 22 Jul 2024 17:37:36 +0200 Subject: [PATCH 4/5] ThingSet: Add xPresetLTO function and always return 1 on success --- app/src/data_objects.c | 14 +++++++++++++- app/src/data_objects.h | 7 +++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/app/src/data_objects.c b/app/src/data_objects.c index 91a41ed2..4d0f5f2c 100644 --- a/app/src/data_objects.c +++ b/app/src/data_objects.c @@ -188,6 +188,11 @@ THINGSET_ADD_FN_INT32(APP_ID_CONF, APP_ID_CONF_PRESET_LFP, "xPresetLFP", &bat_pr THINGSET_ADD_ITEM_FLOAT(APP_ID_CONF_PRESET_LFP, APP_ID_CONF_PRESET_LFP_CAPACITY, "fCapacity_Ah", &new_capacity, 1, THINGSET_ANY_RW, 0); +THINGSET_ADD_FN_INT32(APP_ID_CONF, APP_ID_CONF_PRESET_LTO, "xPresetLTO", &bat_preset_lto, + THINGSET_ANY_RW); +THINGSET_ADD_ITEM_FLOAT(APP_ID_CONF_PRESET_LTO, APP_ID_CONF_PRESET_LTO_CAPACITY, "fCapacity_Ah", + &new_capacity, 1, THINGSET_ANY_RW, 0); + // MEAS DATA //////////////////////////////////////////////////////////// THINGSET_ADD_GROUP(TS_ID_ROOT, APP_ID_MEAS, "Meas", THINGSET_NO_CALLBACK); @@ -280,7 +285,9 @@ int32_t bat_preset(enum bms_cell_type type) } #endif - return ret; + // Always return 1 in case of success, as the flags returned by bms_ic_configure can be + // confusing for end users in the App. Actually applied config can be retrieved via ThingSet. + return ret > 0 ? 1 : ret; } int32_t bat_preset_nmc() @@ -293,6 +300,11 @@ int32_t bat_preset_lfp() return bat_preset(CELL_TYPE_LFP); } +int32_t bat_preset_lto() +{ + return bat_preset(CELL_TYPE_LTO); +} + void print_registers() { bms_ic_debug_print_mem(bms.ic_dev); diff --git a/app/src/data_objects.h b/app/src/data_objects.h index cc3d6f81..8a8e8cbe 100644 --- a/app/src/data_objects.h +++ b/app/src/data_objects.h @@ -62,6 +62,8 @@ #define APP_ID_CONF_PRESET_NMC_CAPACITY 0xA1 #define APP_ID_CONF_PRESET_LFP 0xA2 #define APP_ID_CONF_PRESET_LFP_CAPACITY 0xA3 +#define APP_ID_CONF_PRESET_LTO 0xA4 +#define APP_ID_CONF_PRESET_LTO_CAPACITY 0xA5 #define APP_ID_CONF_OCV_POINTS 0xB0 #define APP_ID_CONF_SOC_POINTS 0xB1 @@ -103,6 +105,11 @@ int32_t bat_preset_nmc(); */ int32_t bat_preset_lfp(); +/** + * Callback function to apply preset parameters for LTO type via ThingSet + */ +int32_t bat_preset_lto(); + /** * Callback to read and print common BMS registers via ThingSet */ From 0b436bc762fc96ee1a8fe2f2154295231f8dab7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=A4ger?= Date: Mon, 29 Jul 2024 08:40:57 +0200 Subject: [PATCH 5/5] ThingSet: Increase shell cmd buffer size for OCV/SOC configuration --- app/boards/bms_16s100_sc_esp32c3.conf | 1 + app/boards/bms_c1.conf | 1 + app/boards/native_sim.conf | 1 + 3 files changed, 3 insertions(+) diff --git a/app/boards/bms_16s100_sc_esp32c3.conf b/app/boards/bms_16s100_sc_esp32c3.conf index 0413a421..9da84e84 100644 --- a/app/boards/bms_16s100_sc_esp32c3.conf +++ b/app/boards/bms_16s100_sc_esp32c3.conf @@ -28,3 +28,4 @@ CONFIG_SHELL_CMDS_SELECT=y CONFIG_THINGSET_SHELL=y CONFIG_THINGSET_SHELL_REPORTING=n +CONFIG_THINGSET_SHELL_CMD_BUF_SIZE=256 diff --git a/app/boards/bms_c1.conf b/app/boards/bms_c1.conf index 8b5bfce9..c7d95cb8 100644 --- a/app/boards/bms_c1.conf +++ b/app/boards/bms_c1.conf @@ -38,6 +38,7 @@ CONFIG_SHELL_CMDS_SELECT=y CONFIG_THINGSET_SHELL=y CONFIG_THINGSET_SHELL_REPORTING=n +CONFIG_THINGSET_SHELL_CMD_BUF_SIZE=256 # DFU over CAN CONFIG_THINGSET_DFU=y diff --git a/app/boards/native_sim.conf b/app/boards/native_sim.conf index 17d7c26e..72a2d38b 100644 --- a/app/boards/native_sim.conf +++ b/app/boards/native_sim.conf @@ -28,6 +28,7 @@ CONFIG_SHELL_CMDS_SELECT=y CONFIG_THINGSET_SHELL=y CONFIG_THINGSET_SHELL_REPORTING=n +CONFIG_THINGSET_SHELL_CMD_BUF_SIZE=256 CONFIG_EMUL=y CONFIG_EEPROM=y