mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-24 15:38:22 +00:00
feat(core): fuel gauge compensation in hibernation mode.
[no changelog]
This commit is contained in:
parent
513fbcb039
commit
c9acae7b97
@ -125,6 +125,10 @@ static secbool boot_sequence(secbool manufacturing_mode) {
|
||||
haptic_init();
|
||||
#endif
|
||||
|
||||
#ifdef USE_RTC
|
||||
rtc_init();
|
||||
#endif
|
||||
|
||||
#ifdef USE_POWER_MANAGER
|
||||
pm_init(false);
|
||||
|
||||
@ -245,10 +249,6 @@ static void drivers_init(secbool manufacturing_mode,
|
||||
tamper_init();
|
||||
#endif
|
||||
|
||||
#ifdef USE_RTC
|
||||
rtc_init();
|
||||
#endif
|
||||
|
||||
#ifndef LAZY_DISPLAY_INIT
|
||||
display_touch_init(manufacturing_mode, touch_initialized);
|
||||
#endif
|
||||
|
@ -107,6 +107,27 @@ pm_status_t pm_init(bool inherit_state) {
|
||||
irq_key_t irq_key = irq_lock();
|
||||
|
||||
if (recovery_ok) {
|
||||
#ifdef USE_RTC
|
||||
|
||||
// RTC compensation should happen only during initialization in bootloader
|
||||
if (!inherit_state) {
|
||||
// Get RTC timestamp and compare it with the timestamp from recovery data
|
||||
// to estimate time off and compensate self-discharge of the battery.
|
||||
uint32_t rtc_timestamp;
|
||||
if (recovery.last_capture_timestamp != 0 &&
|
||||
rtc_get_timestamp(&rtc_timestamp)) {
|
||||
// If the RTC timestamp is older than the last captured timestamp,
|
||||
// we will not use it.
|
||||
if (rtc_timestamp >= recovery.last_capture_timestamp) {
|
||||
pm_compensate_fuel_gauge(
|
||||
&recovery.soc, rtc_timestamp - recovery.last_capture_timestamp,
|
||||
PM_SELF_DISG_RATE_HIBERNATION_MA, 25.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
fuel_gauge_set_soc(&drv->fuel_gauge, recovery.soc, recovery.P);
|
||||
} else {
|
||||
pm_battery_initial_soc_guess();
|
||||
@ -256,6 +277,13 @@ pm_status_t pm_suspend(wakeup_flags_t* wakeup_reason) {
|
||||
|
||||
wakeup_flags_t wakeup_flags = system_suspend();
|
||||
|
||||
// Wait for pmic measurements to stabilize the fuel gauge estimation.
|
||||
pm_status_t status = pm_wait_to_stabilize(drv, PM_STABILIZATION_TIMEOUT_MS);
|
||||
if (status != PM_OK) {
|
||||
// timeout during state machine stabilization
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Handle wake-up flags
|
||||
// UNUSED(wakeup_flags);
|
||||
|
||||
@ -443,6 +471,13 @@ pm_status_t pm_store_data_to_backup_ram() {
|
||||
recovery.bat_critical = drv->battery_critical;
|
||||
recovery.bootloader_exit_state = drv->state;
|
||||
|
||||
#ifdef USE_RTC
|
||||
if (!rtc_get_timestamp(&recovery.last_capture_timestamp)) {
|
||||
// If RTC timestamp cannot be obtained, set it to 0
|
||||
recovery.last_capture_timestamp = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
irq_unlock(irq_key);
|
||||
|
||||
bool write_ok =
|
||||
@ -532,6 +567,33 @@ bool pm_driver_suspend(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
irq_key_t irq_key = irq_lock();
|
||||
|
||||
if (drv->woke_up_from_suspend) {
|
||||
// Driver just woke up from suspend and have no data available yet.
|
||||
// Request the suspend but wait for the next pmic_meausrement
|
||||
drv->suspending = true;
|
||||
|
||||
} else {
|
||||
pm_schedule_rtc_wakeup();
|
||||
drv->suspended = true;
|
||||
}
|
||||
|
||||
// Delete the monitoring timer to stop the periodic sampling
|
||||
systimer_delete(drv->monitoring_timer);
|
||||
|
||||
irq_unlock(irq_key);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pm_schedule_rtc_wakeup(void) {
|
||||
pm_driver_t* drv = &g_pm;
|
||||
|
||||
if (!drv->initialized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef USE_RTC
|
||||
|
||||
// Capture the timestamp when device was active for the last time.
|
||||
@ -570,6 +632,7 @@ bool pm_driver_suspend(void) {
|
||||
systimer_delete(drv->monitoring_timer);
|
||||
irq_unlock(irq_key);
|
||||
|
||||
drv->suspended = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -580,6 +643,12 @@ bool pm_driver_resume(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!drv->suspended) {
|
||||
// Already resumed, nothing to do
|
||||
return true;
|
||||
}
|
||||
|
||||
drv->suspended = false;
|
||||
drv->woke_up_from_suspend = true;
|
||||
|
||||
#ifdef USE_RTC
|
||||
@ -603,18 +672,18 @@ bool pm_driver_resume(void) {
|
||||
// Set the periodic sampling period
|
||||
systimer_set_periodic(drv->monitoring_timer, PM_BATTERY_SAMPLING_PERIOD_MS);
|
||||
|
||||
// Wait for pmic measurements to stabilize the fuel gauge estimation.
|
||||
pm_status_t status = pm_wait_to_stabilize(drv, PM_STABILIZATION_TIMEOUT_MS);
|
||||
if (status != PM_OK) {
|
||||
// timeout during state machine stabilization
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pm_driver_is_suspended(void) {
|
||||
// No specific pending tasks, just return true
|
||||
return true;
|
||||
pm_driver_t* drv = &g_pm;
|
||||
|
||||
bool suspended;
|
||||
irq_key_t irq_key = irq_lock();
|
||||
suspended = drv->suspended;
|
||||
irq_unlock(irq_key);
|
||||
|
||||
return suspended;
|
||||
}
|
||||
|
||||
void pm_compensate_fuel_gauge(float* soc, uint32_t elapsed_s,
|
||||
@ -623,7 +692,6 @@ void pm_compensate_fuel_gauge(float* soc, uint32_t elapsed_s,
|
||||
bool discharging_mode = battery_current_ma >= 0.0f;
|
||||
*soc -=
|
||||
(compensation_mah / battery_total_capacity(bat_temp_c, discharging_mode));
|
||||
return;
|
||||
}
|
||||
|
||||
static pm_status_t pm_wait_to_stabilize(pm_driver_t* drv, uint32_t timeout_ms) {
|
||||
|
@ -40,8 +40,8 @@
|
||||
#define PM_BATTERY_CHARGING_CURRENT_MIN PMIC_CHARGING_LIMIT_MIN
|
||||
#define PM_BATTERY_SAMPLING_BUF_SIZE 10
|
||||
|
||||
#define PM_SELF_DISG_RATE_HIBERATION_MAH 0.004f
|
||||
#define PM_SELF_DISG_RATE_SUSPEND_MAH 0.032f
|
||||
#define PM_SELF_DISG_RATE_HIBERNATION_MA 0.004f
|
||||
#define PM_SELF_DISG_RATE_SUSPEND_MA 0.032f
|
||||
|
||||
// Fuel gauge extended kalman filter parameters
|
||||
#define PM_FUEL_GAUGE_R 2000.0f
|
||||
@ -70,6 +70,14 @@ typedef struct {
|
||||
bool state_machine_stabilized;
|
||||
pm_power_status_t state;
|
||||
|
||||
// Set if the driver was requested to suspend background operations.
|
||||
// IF so, the driver waits until the last operation is finished,
|
||||
// then enters suspended mode.
|
||||
bool suspending;
|
||||
|
||||
// Set if the driver's background operations are suspended.
|
||||
bool suspended;
|
||||
|
||||
// Fuel gauge
|
||||
fuel_gauge_state_t fuel_gauge;
|
||||
bool fuel_gauge_initialized;
|
||||
@ -156,3 +164,8 @@ pm_status_t pm_store_data_to_backup_ram(void);
|
||||
// suspend or hibernation.
|
||||
void pm_compensate_fuel_gauge(float* soc, uint32_t elapsed_s,
|
||||
float battery_current_mah, float bat_temp_c);
|
||||
|
||||
// Schedule the RTC wakeup when going into suspend mode.
|
||||
// Return false if the driver was not initialized or the RTC timestamp is
|
||||
// not available.
|
||||
bool pm_schedule_rtc_wakeup(void);
|
||||
|
@ -78,10 +78,17 @@ void pm_pmic_data_ready(void* context, pmic_report_t* report) {
|
||||
} else {
|
||||
// Use known battery self-discharge rate to compensate the fuel gauge
|
||||
// estimation during the suspend period. Since this period may be very
|
||||
// long and the batery temperature may vary, use the average ambient
|
||||
// long and the battery temperature may vary, use the average ambient
|
||||
// temperature.
|
||||
pm_compensate_fuel_gauge(&drv->fuel_gauge.soc, drv->time_in_suspend_s,
|
||||
PM_SELF_DISG_RATE_SUSPEND_MAH, 25.0f);
|
||||
PM_SELF_DISG_RATE_SUSPEND_MA, 25.0f);
|
||||
|
||||
// TODO: Currently in suspend mode we use single self-discharge rate
|
||||
// but in practive the discharge rate may change in case the BLE chip
|
||||
// remains active. Since the device is very likely to stay in suspend
|
||||
// mode for limited time, for now we decided to neglect this. but in
|
||||
// the future we may want to distinguish between suspend mode
|
||||
// with/without BLE and use different self-discharge rates.
|
||||
}
|
||||
|
||||
fuel_gauge_set_soc(&drv->fuel_gauge, drv->fuel_gauge.soc,
|
||||
@ -117,6 +124,13 @@ void pm_pmic_data_ready(void* context, pmic_report_t* report) {
|
||||
pm_process_state_machine();
|
||||
|
||||
pm_store_data_to_backup_ram();
|
||||
|
||||
if (drv->suspending) {
|
||||
pm_schedule_rtc_wakeup();
|
||||
drv->suspending = false;
|
||||
drv->suspended = true;
|
||||
}
|
||||
|
||||
drv->state_machine_stabilized = true;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user