From 6a7bd1c7fa8f1d7029cb3d2991fb93445452edd6 Mon Sep 17 00:00:00 2001 From: kopecdav Date: Thu, 10 Jul 2025 18:57:19 +0200 Subject: [PATCH] feat(core): introduce simple charging temperature controller. [no changelog] --- .../sys/power_manager/stm32u5/power_manager.c | 1 + .../stm32u5/power_manager_internal.h | 10 +++++ .../power_manager/stm32u5/power_monitoring.c | 43 ++++++++++++++++++- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/core/embed/sys/power_manager/stm32u5/power_manager.c b/core/embed/sys/power_manager/stm32u5/power_manager.c index 42fdc21e92..9781757ec0 100644 --- a/core/embed/sys/power_manager/stm32u5/power_manager.c +++ b/core/embed/sys/power_manager/stm32u5/power_manager.c @@ -159,6 +159,7 @@ pm_status_t pm_init(bool inherit_state) { // Set default SOC target and max charging current limit drv->soc_target = 100; drv->charging_current_max_limit_ma = PM_BATTERY_CHARGING_CURRENT_MAX; + drv->i_chg_temp_limit_ma = PM_BATTERY_CHARGING_CURRENT_MAX; // Fuel gauge SoC available, set fuel_gauge initialized. drv->fuel_gauge_initialized = true; 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 239b54a2d3..2036d0288e 100644 --- a/core/embed/sys/power_manager/stm32u5/power_manager_internal.h +++ b/core/embed/sys/power_manager/stm32u5/power_manager_internal.h @@ -55,6 +55,12 @@ #define PM_SUSPENDED_CHARGING_TIMEOUT_S 60 #define PM_STABILIZATION_TIMEOUT_MS 2000 +// Temperature controller parameters +#define PM_TEMP_CONTROL_IDLE_PERIOD_MS 2 * 60 * 1000 // 2 minutes +#define PM_TEMP_CONTROL_BAND_1_MAX_TEMP 39.0f +#define PM_TEMP_CONTROL_BAND_2_MAX_TEMP 43.0f +#define PM_TEMP_CONTROL_BAND_3_MAX_TEMP 45.0f +#define PM_TEMP_CONTROL_BAND_4_MAX_TEMP 47.0f // Power manager battery sampling data structure typedef struct { @@ -93,6 +99,10 @@ typedef struct { uint16_t charging_current_target_ma; uint16_t charging_current_max_limit_ma; + // Temp controller + uint32_t temp_control_timeout; + uint16_t i_chg_temp_limit_ma; + // Power source hardware state pmic_report_t pmic_data; stwlc38_report_t wireless_data; diff --git a/core/embed/sys/power_manager/stm32u5/power_monitoring.c b/core/embed/sys/power_manager/stm32u5/power_monitoring.c index 37e751c9a4..5927f7103d 100644 --- a/core/embed/sys/power_manager/stm32u5/power_monitoring.c +++ b/core/embed/sys/power_manager/stm32u5/power_monitoring.c @@ -29,9 +29,21 @@ #include "../stwlc38/stwlc38.h" #include "power_manager_internal.h" +static void pm_temperature_controller(pm_driver_t* drv); static void pm_battery_sampling(float vbat, float ibat, float ntc_temp); static void pm_parse_power_source_state(pm_driver_t* drv); +// Temperature controller LUT +static const struct { + float max_temp; + float current_limit_factor; +} temp_bands[] = { + {PM_TEMP_CONTROL_BAND_1_MAX_TEMP, 1.0}, + {PM_TEMP_CONTROL_BAND_2_MAX_TEMP, 0.7}, + {PM_TEMP_CONTROL_BAND_3_MAX_TEMP, 0.5}, + {PM_TEMP_CONTROL_BAND_4_MAX_TEMP, 0.3}, +}; + void pm_monitor_power_sources(void) { // Periodically called timer to request PMIC measurements. PMIC will call // pm_pmic_data_ready() callback when the measurements are ready. @@ -162,6 +174,8 @@ void pm_charging_controller(pm_driver_t* drv) { drv->charging_current_target_ma = drv->charging_current_max_limit_ma; } + pm_temperature_controller(drv); + // Set charging target if (drv->charging_current_target_ma != pmic_get_charging_limit()) { // Set charging current limit @@ -195,7 +209,7 @@ void pm_charging_controller(pm_driver_t* drv) { } if (drv->soc_target_reached) { - drv->charging_current_target_ma = 0; + drv->i_chg_target_ma = 0; } if (drv->charging_current_target_ma == 0) { @@ -205,6 +219,33 @@ void pm_charging_controller(pm_driver_t* drv) { } } +static void pm_temperature_controller(pm_driver_t* drv) { + if (ticks_expired(drv->temp_control_timeout)) { + uint16_t i_chg_temp_limit_ma = 0; + + i_chg_temp_limit_ma = 0; // Default to safety limit + for (size_t i = 0; i < sizeof(temp_bands) / sizeof(temp_bands[0]); ++i) { + if (drv->pmic_data.ntc_temp < temp_bands[i].max_temp) { + i_chg_temp_limit_ma = PM_BATTERY_CHARGING_CURRENT_MAX * + temp_bands[i].current_limit_factor; + break; + } + } + + // If the temperature limit has changed, update the limit and reset the + // debounce timer + if (drv->i_chg_temp_limit_ma != i_chg_temp_limit_ma) { + drv->i_chg_temp_limit_ma = i_chg_temp_limit_ma; + drv->temp_control_timeout = ticks_timeout(PM_TEMP_CONTROL_IDLE_PERIOD_MS); + } + } + + if (drv->charging_current_target_ma > drv->i_chg_temp_limit_ma) { + // Limit the charging current by temperature controller + drv->charging_current_target_ma = drv->i_chg_temp_limit_ma; + } +} + static void pm_battery_sampling(float vbat, float ibat, float ntc_temp) { pm_driver_t* drv = &g_pm;