From 6eed9178fa6f3e825f8b456447b92eec5625c11a Mon Sep 17 00:00:00 2001 From: kopecdav Date: Tue, 15 Jul 2025 21:21:02 +0200 Subject: [PATCH] feat(core): rework soc limit to battery model dependant soc target. [no changelog] --- .../sys/power_manager/inc/sys/power_manager.h | 16 +++++++-- .../sys/power_manager/stm32u5/power_manager.c | 14 +++----- .../stm32u5/power_manager_internal.h | 6 ++-- .../power_manager/stm32u5/power_monitoring.c | 33 +++++++++++++++---- 4 files changed, 47 insertions(+), 22 deletions(-) diff --git a/core/embed/sys/power_manager/inc/sys/power_manager.h b/core/embed/sys/power_manager/inc/sys/power_manager.h index 098f7ba565..25af1ccc3c 100644 --- a/core/embed/sys/power_manager/inc/sys/power_manager.h +++ b/core/embed/sys/power_manager/inc/sys/power_manager.h @@ -193,11 +193,21 @@ pm_status_t pm_charging_disable(void); pm_status_t pm_charging_set_max_current(uint16_t current_ma); /** - * @brief Set the battery State of Charge limit for operations - * @param limit SoC limit percentage (0-100%) + * @brief Set the battery State of Charge precharge target. + * + * Charging controller will continously compare taget SoC charging voltage from + * battery model (temperature dependant) with the actual battery voltage and if + * the battery voltage is above the target, charging is stopped. If the battery + * voltage also cross the charging voltage target, Fuel gauge SoC estimate is + * enforced with the target value. + * + * Setting value to `100` disables the precharge target and charging cycle will + * be driven with PMIC driver. + * + * @param target SoC target percentage (0-100%) * @return pm_status_t Status code indicating success or failure */ -pm_status_t pm_set_soc_limit(uint8_t limit); +pm_status_t pm_set_soc_target(uint8_t target); /** * @brief Suspends driver activity so the CPU can enter low-power mode. diff --git a/core/embed/sys/power_manager/stm32u5/power_manager.c b/core/embed/sys/power_manager/stm32u5/power_manager.c index 9f2fbd6011..42fdc21e92 100644 --- a/core/embed/sys/power_manager/stm32u5/power_manager.c +++ b/core/embed/sys/power_manager/stm32u5/power_manager.c @@ -156,8 +156,8 @@ pm_status_t pm_init(bool inherit_state) { // Enable charging by default to max current drv->charging_enabled = true; - // Set default SOC limit and max charging current limit - drv->soc_limit = 100; + // Set default SOC target and max charging current limit + drv->soc_target = 100; drv->charging_current_max_limit_ma = PM_BATTERY_CHARGING_CURRENT_MAX; // Fuel gauge SoC available, set fuel_gauge initialized. @@ -527,23 +527,19 @@ static bool pm_load_recovery_data(pm_recovery_data_t* recovery) { return true; } -pm_status_t pm_set_soc_limit(uint8_t limit) { +pm_status_t pm_set_soc_target(uint8_t target) { pm_driver_t* drv = &g_pm; if (!drv->initialized) { return PM_NOT_INITIALIZED; } - if (limit > 100) { - return PM_ERROR; - } - - if (limit <= PM_SOC_LIMIT_HYSTERESIS) { + if (target > 100) { return PM_ERROR; } irq_key_t irq_key = irq_lock(); - drv->soc_limit = limit; + drv->soc_target = target; irq_unlock(irq_key); return PM_OK; diff --git a/core/embed/sys/power_manager/stm32u5/power_manager_internal.h b/core/embed/sys/power_manager/stm32u5/power_manager_internal.h index 37930704fe..239b54a2d3 100644 --- a/core/embed/sys/power_manager/stm32u5/power_manager_internal.h +++ b/core/embed/sys/power_manager/stm32u5/power_manager_internal.h @@ -35,7 +35,6 @@ #define PM_BATTERY_UNDERVOLT_RECOVERY_THR_V 3.1f #define PM_BATTERY_UNDERVOLT_RECOVERY_WPC_THR_V 3.2f #define PM_BATTERY_LOW_THRESHOLD_SOC 15 -#define PM_SOC_LIMIT_HYSTERESIS 5 #define PM_BATTERY_CHARGING_CURRENT_MAX PMIC_CHARGING_LIMIT_MAX #define PM_BATTERY_CHARGING_CURRENT_MIN PMIC_CHARGING_LIMIT_MIN #define PM_BATTERY_SAMPLING_BUF_SIZE 10 @@ -85,8 +84,9 @@ typedef struct { uint8_t bat_sampling_buf_tail_idx; uint8_t bat_sampling_buf_head_idx; uint8_t soc_ceiled; - uint8_t soc_limit; - bool soc_limit_reached; + + uint8_t soc_target; + bool soc_target_reached; // Battery charging state bool charging_enabled; diff --git a/core/embed/sys/power_manager/stm32u5/power_monitoring.c b/core/embed/sys/power_manager/stm32u5/power_monitoring.c index f019dfd5b6..37e751c9a4 100644 --- a/core/embed/sys/power_manager/stm32u5/power_monitoring.c +++ b/core/embed/sys/power_manager/stm32u5/power_monitoring.c @@ -24,6 +24,7 @@ #include #include +#include "../fuel_gauge/battery_model.h" #include "../fuel_gauge/fuel_gauge.h" #include "../stwlc38/stwlc38.h" #include "power_manager_internal.h" @@ -167,15 +168,33 @@ void pm_charging_controller(pm_driver_t* drv) { pmic_set_charging_limit(drv->charging_current_target_ma); } - if ((drv->soc_ceiled >= drv->soc_limit) && (drv->soc_limit != 100)) { - drv->soc_limit_reached = true; - } else if ((drv->soc_limit == 100) || - (drv->soc_ceiled < (drv->soc_limit - PM_SOC_LIMIT_HYSTERESIS))) { - drv->soc_limit_reached = false; + if (drv->soc_target == 100) { + drv->soc_target_reached = false; + } else { + // Translate SoC target to charging voltage via battery model + float target_ocv_voltage_v = + battery_ocv(drv->soc_target / 100.0f, drv->pmic_data.ntc_temp, false); + + float battery_ocv_v = battery_meas_to_ocv( + drv->pmic_data.vbat, drv->pmic_data.ibat, drv->pmic_data.ntc_temp); + + if (battery_ocv_v > target_ocv_voltage_v) { + // current voltage is within tight bounds of target voltage, + // we may also force SoC estimate to target value. + if (battery_ocv_v < target_ocv_voltage_v + 0.15) { + fuel_gauge_set_soc(&drv->fuel_gauge, + (drv->soc_target / 100.0f) - 0.0001f, + drv->fuel_gauge.P); + } + + drv->soc_target_reached = true; + + } else if (drv->soc_ceiled < drv->soc_target) { + drv->soc_target_reached = false; + } } - if (drv->soc_limit_reached) { - // Set charging current limit to 0 + if (drv->soc_target_reached) { drv->charging_current_target_ma = 0; }