1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-07-30 18:38:27 +00:00

feat(core): rework soc limit to battery model dependant soc target.

[no changelog]
This commit is contained in:
kopecdav 2025-07-15 21:21:02 +02:00 committed by kopecdav
parent 93c3b54e2b
commit 6eed9178fa
4 changed files with 47 additions and 22 deletions

View File

@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -24,6 +24,7 @@
#include <sys/systick.h>
#include <trezor_rtl.h>
#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;
}