FuriHal, Power, UnitTests: fix, rename battery charging voltage limit API (#2228)
* FuriHal, Power, UnitTests: rename battery charge voltage limit API * FuriHal: bump API, power info major versions * Power: fix battery charge voltage limit for > 7.935v Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
parent
1d55aee39c
commit
09edf66a2a
@ -3,56 +3,63 @@
|
||||
#include "../minunit.h"
|
||||
|
||||
static void power_test_deinit(void) {
|
||||
// Try to reset to default charging voltage
|
||||
furi_hal_power_set_battery_charging_voltage(4.208f);
|
||||
// Try to reset to default charge voltage limit
|
||||
furi_hal_power_set_battery_charge_voltage_limit(4.208f);
|
||||
}
|
||||
|
||||
MU_TEST(test_power_charge_voltage_exact) {
|
||||
// Power of 16mV charge voltages get applied exactly
|
||||
MU_TEST(test_power_charge_voltage_limit_exact) {
|
||||
// Power of 16mV charge voltage limits get applied exactly
|
||||
// (bq25896 charge controller works in 16mV increments)
|
||||
//
|
||||
// This test may need adapted if other charge controllers are used in the future.
|
||||
for(uint16_t charge_mv = 3840; charge_mv <= 4208; charge_mv += 16) {
|
||||
float charge_volt = (float)charge_mv / 1000.0f;
|
||||
furi_hal_power_set_battery_charging_voltage(charge_volt);
|
||||
mu_assert_double_eq(charge_volt, furi_hal_power_get_battery_charging_voltage());
|
||||
furi_hal_power_set_battery_charge_voltage_limit(charge_volt);
|
||||
mu_assert_double_eq(charge_volt, furi_hal_power_get_battery_charge_voltage_limit());
|
||||
}
|
||||
}
|
||||
|
||||
MU_TEST(test_power_charge_voltage_floating_imprecision) {
|
||||
MU_TEST(test_power_charge_voltage_limit_floating_imprecision) {
|
||||
// 4.016f should act as 4.016 V, even with floating point imprecision
|
||||
furi_hal_power_set_battery_charging_voltage(4.016f);
|
||||
mu_assert_double_eq(4.016f, furi_hal_power_get_battery_charging_voltage());
|
||||
furi_hal_power_set_battery_charge_voltage_limit(4.016f);
|
||||
mu_assert_double_eq(4.016f, furi_hal_power_get_battery_charge_voltage_limit());
|
||||
}
|
||||
|
||||
MU_TEST(test_power_charge_voltage_inexact) {
|
||||
// Charge voltages that are not power of 16mV get truncated down
|
||||
furi_hal_power_set_battery_charging_voltage(3.841f);
|
||||
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charging_voltage());
|
||||
MU_TEST(test_power_charge_voltage_limit_inexact) {
|
||||
// Charge voltage limits that are not power of 16mV get truncated down
|
||||
furi_hal_power_set_battery_charge_voltage_limit(3.841f);
|
||||
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charge_voltage_limit());
|
||||
|
||||
furi_hal_power_set_battery_charging_voltage(3.900f);
|
||||
mu_assert_double_eq(3.888, furi_hal_power_get_battery_charging_voltage());
|
||||
furi_hal_power_set_battery_charge_voltage_limit(3.900f);
|
||||
mu_assert_double_eq(3.888, furi_hal_power_get_battery_charge_voltage_limit());
|
||||
|
||||
furi_hal_power_set_battery_charging_voltage(4.200f);
|
||||
mu_assert_double_eq(4.192, furi_hal_power_get_battery_charging_voltage());
|
||||
furi_hal_power_set_battery_charge_voltage_limit(4.200f);
|
||||
mu_assert_double_eq(4.192, furi_hal_power_get_battery_charge_voltage_limit());
|
||||
}
|
||||
|
||||
MU_TEST(test_power_charge_voltage_invalid_clamped) {
|
||||
// Out-of-range charge voltages get clamped to 3.840 V and 4.208 V
|
||||
furi_hal_power_set_battery_charging_voltage(3.808f);
|
||||
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charging_voltage());
|
||||
MU_TEST(test_power_charge_voltage_limit_invalid_clamped) {
|
||||
// Out-of-range charge voltage limits get clamped to 3.840 V and 4.208 V
|
||||
furi_hal_power_set_battery_charge_voltage_limit(3.808f);
|
||||
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charge_voltage_limit());
|
||||
furi_hal_power_set_battery_charge_voltage_limit(1.0f);
|
||||
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charge_voltage_limit());
|
||||
|
||||
// NOTE: Intentionally picking a small increment above 4.208 V to reduce the risk of an
|
||||
// unhappy battery if this fails.
|
||||
furi_hal_power_set_battery_charging_voltage(4.240f);
|
||||
mu_assert_double_eq(4.208, furi_hal_power_get_battery_charging_voltage());
|
||||
furi_hal_power_set_battery_charge_voltage_limit(4.240f);
|
||||
mu_assert_double_eq(4.208, furi_hal_power_get_battery_charge_voltage_limit());
|
||||
// Likewise, picking a number that the uint8_t wraparound in the driver would result in a
|
||||
// VREG value under 23 if this test fails.
|
||||
// E.g. (uint8_t)((8105-3840)/16) -> 10
|
||||
furi_hal_power_set_battery_charge_voltage_limit(8.105f);
|
||||
mu_assert_double_eq(4.208, furi_hal_power_get_battery_charge_voltage_limit());
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_power_suite) {
|
||||
MU_RUN_TEST(test_power_charge_voltage_exact);
|
||||
MU_RUN_TEST(test_power_charge_voltage_floating_imprecision);
|
||||
MU_RUN_TEST(test_power_charge_voltage_inexact);
|
||||
MU_RUN_TEST(test_power_charge_voltage_invalid_clamped);
|
||||
MU_RUN_TEST(test_power_charge_voltage_limit_exact);
|
||||
MU_RUN_TEST(test_power_charge_voltage_limit_floating_imprecision);
|
||||
MU_RUN_TEST(test_power_charge_voltage_limit_inexact);
|
||||
MU_RUN_TEST(test_power_charge_voltage_limit_invalid_clamped);
|
||||
power_test_deinit();
|
||||
}
|
||||
|
||||
|
@ -13,8 +13,8 @@ void power_draw_battery_callback(Canvas* canvas, void* context) {
|
||||
|
||||
if(power->info.gauge_is_ok) {
|
||||
canvas_draw_box(canvas, 2, 2, (power->info.charge + 4) / 5, 4);
|
||||
if(power->info.voltage_battery_charging < 4.2) {
|
||||
// Battery charging voltage is modified, indicate with cross pattern
|
||||
if(power->info.voltage_battery_charge_limit < 4.2) {
|
||||
// Battery charge voltage limit is modified, indicate with cross pattern
|
||||
canvas_invert_color(canvas);
|
||||
uint8_t battery_bar_width = (power->info.charge + 4) / 5;
|
||||
bool cross_odd = false;
|
||||
@ -147,7 +147,7 @@ static bool power_update_info(Power* power) {
|
||||
info.capacity_full = furi_hal_power_get_battery_full_capacity();
|
||||
info.current_charger = furi_hal_power_get_battery_current(FuriHalPowerICCharger);
|
||||
info.current_gauge = furi_hal_power_get_battery_current(FuriHalPowerICFuelGauge);
|
||||
info.voltage_battery_charging = furi_hal_power_get_battery_charging_voltage();
|
||||
info.voltage_battery_charge_limit = furi_hal_power_get_battery_charge_voltage_limit();
|
||||
info.voltage_charger = furi_hal_power_get_battery_voltage(FuriHalPowerICCharger);
|
||||
info.voltage_gauge = furi_hal_power_get_battery_voltage(FuriHalPowerICFuelGauge);
|
||||
info.voltage_vbus = furi_hal_power_get_usb_voltage();
|
||||
|
@ -41,7 +41,7 @@ typedef struct {
|
||||
float current_charger;
|
||||
float current_gauge;
|
||||
|
||||
float voltage_battery_charging;
|
||||
float voltage_battery_charge_limit;
|
||||
float voltage_charger;
|
||||
float voltage_gauge;
|
||||
float voltage_vbus;
|
||||
|
@ -7,7 +7,7 @@ static void power_settings_scene_battery_info_update_model(PowerSettingsApp* app
|
||||
.gauge_voltage = app->info.voltage_gauge,
|
||||
.gauge_current = app->info.current_gauge,
|
||||
.gauge_temperature = app->info.temperature_gauge,
|
||||
.charging_voltage = app->info.voltage_battery_charging,
|
||||
.charge_voltage_limit = app->info.voltage_battery_charge_limit,
|
||||
.charge = app->info.charge,
|
||||
.health = app->info.health,
|
||||
};
|
||||
|
@ -69,7 +69,7 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) {
|
||||
drain_current > HIGH_DRAIN_CURRENT_THRESHOLD ? "mA!" : "mA");
|
||||
} else if(drain_current != 0) {
|
||||
snprintf(header, 20, "...");
|
||||
} else if(data->charging_voltage < 4.2) {
|
||||
} else if(data->charge_voltage_limit < 4.2) {
|
||||
// Non-default battery charging limit, mention it
|
||||
snprintf(emote, sizeof(emote), "Charged!");
|
||||
snprintf(header, sizeof(header), "Limited to");
|
||||
@ -77,8 +77,8 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) {
|
||||
value,
|
||||
sizeof(value),
|
||||
"%lu.%luV",
|
||||
(uint32_t)(data->charging_voltage),
|
||||
(uint32_t)(data->charging_voltage * 10) % 10);
|
||||
(uint32_t)(data->charge_voltage_limit),
|
||||
(uint32_t)(data->charge_voltage_limit * 10) % 10);
|
||||
} else {
|
||||
snprintf(header, sizeof(header), "Charged!");
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ typedef struct {
|
||||
float gauge_voltage;
|
||||
float gauge_current;
|
||||
float gauge_temperature;
|
||||
float charging_voltage;
|
||||
float charge_voltage_limit;
|
||||
uint8_t charge;
|
||||
uint8_t health;
|
||||
} BatteryInfoModel;
|
||||
|
@ -1211,7 +1211,7 @@ Function,+,furi_hal_power_enable_external_3_3v,void,
|
||||
Function,+,furi_hal_power_enable_otg,void,
|
||||
Function,+,furi_hal_power_gauge_is_ok,_Bool,
|
||||
Function,+,furi_hal_power_get_bat_health_pct,uint8_t,
|
||||
Function,+,furi_hal_power_get_battery_charging_voltage,float,
|
||||
Function,+,furi_hal_power_get_battery_charge_voltage_limit,float,
|
||||
Function,+,furi_hal_power_get_battery_current,float,FuriHalPowerIC
|
||||
Function,+,furi_hal_power_get_battery_design_capacity,uint32_t,
|
||||
Function,+,furi_hal_power_get_battery_full_capacity,uint32_t,
|
||||
@ -1230,7 +1230,7 @@ Function,+,furi_hal_power_is_charging_done,_Bool,
|
||||
Function,+,furi_hal_power_is_otg_enabled,_Bool,
|
||||
Function,+,furi_hal_power_off,void,
|
||||
Function,+,furi_hal_power_reset,void,
|
||||
Function,+,furi_hal_power_set_battery_charging_voltage,void,float
|
||||
Function,+,furi_hal_power_set_battery_charge_voltage_limit,void,float
|
||||
Function,+,furi_hal_power_shutdown,void,
|
||||
Function,+,furi_hal_power_sleep,void,
|
||||
Function,+,furi_hal_power_sleep_available,_Bool,
|
||||
|
|
@ -341,14 +341,14 @@ bool furi_hal_power_is_otg_enabled() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
float furi_hal_power_get_battery_charging_voltage() {
|
||||
float furi_hal_power_get_battery_charge_voltage_limit() {
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
float ret = (float)bq25896_get_vreg_voltage(&furi_hal_i2c_handle_power) / 1000.0f;
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void furi_hal_power_set_battery_charging_voltage(float voltage) {
|
||||
void furi_hal_power_set_battery_charge_voltage_limit(float voltage) {
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
// Adding 0.0005 is necessary because 4.016f is 4.015999794000, which gets truncated
|
||||
bq25896_set_vreg_voltage(&furi_hal_i2c_handle_power, (uint16_t)(voltage * 1000.0f + 0.0005f));
|
||||
@ -486,7 +486,7 @@ void furi_hal_power_info_get(PropertyValueCallback out, char sep, void* context)
|
||||
property_value_out(&property_context, NULL, 2, "format", "major", "2");
|
||||
property_value_out(&property_context, NULL, 2, "format", "minor", "1");
|
||||
} else {
|
||||
property_value_out(&property_context, NULL, 3, "power", "info", "major", "1");
|
||||
property_value_out(&property_context, NULL, 3, "power", "info", "major", "2");
|
||||
property_value_out(&property_context, NULL, 3, "power", "info", "minor", "1");
|
||||
}
|
||||
|
||||
@ -505,8 +505,10 @@ void furi_hal_power_info_get(PropertyValueCallback out, char sep, void* context)
|
||||
}
|
||||
|
||||
property_value_out(&property_context, NULL, 2, "charge", "state", charge_state);
|
||||
uint16_t charge_voltage = (uint16_t)(furi_hal_power_get_battery_charging_voltage() * 1000.f);
|
||||
property_value_out(&property_context, "%u", 2, "charge", "voltage", charge_voltage);
|
||||
uint16_t charge_voltage_limit =
|
||||
(uint16_t)(furi_hal_power_get_battery_charge_voltage_limit() * 1000.f);
|
||||
property_value_out(
|
||||
&property_context, "%u", 3, "charge", "voltage", "limit", charge_voltage_limit);
|
||||
uint16_t voltage =
|
||||
(uint16_t)(furi_hal_power_get_battery_voltage(FuriHalPowerICFuelGauge) * 1000.f);
|
||||
property_value_out(&property_context, "%u", 2, "battery", "voltage", voltage);
|
||||
|
@ -121,21 +121,21 @@ void furi_hal_power_check_otg_status();
|
||||
*/
|
||||
bool furi_hal_power_is_otg_enabled();
|
||||
|
||||
/** Get battery charging voltage in V
|
||||
/** Get battery charge voltage limit in V
|
||||
*
|
||||
* @return voltage in V
|
||||
*/
|
||||
float furi_hal_power_get_battery_charging_voltage();
|
||||
float furi_hal_power_get_battery_charge_voltage_limit();
|
||||
|
||||
/** Set battery charging voltage in V
|
||||
/** Set battery charge voltage limit in V
|
||||
*
|
||||
* Invalid values will be clamped to the nearest valid value.
|
||||
* Invalid values will be clamped downward to the nearest valid value.
|
||||
*
|
||||
* @param voltage[in] voltage in V
|
||||
*
|
||||
* @return voltage in V
|
||||
*/
|
||||
void furi_hal_power_set_battery_charging_voltage(float voltage);
|
||||
void furi_hal_power_set_battery_charge_voltage_limit(float voltage);
|
||||
|
||||
/** Get remaining battery battery capacity in mAh
|
||||
*
|
||||
|
@ -140,15 +140,18 @@ uint16_t bq25896_get_vreg_voltage(FuriHalI2cBusHandle* handle) {
|
||||
|
||||
void bq25896_set_vreg_voltage(FuriHalI2cBusHandle* handle, uint16_t vreg_voltage) {
|
||||
if(vreg_voltage < 3840) {
|
||||
// Minimum value is 3840 mV
|
||||
bq25896_regs.r06.VREG = 0;
|
||||
} else {
|
||||
// Minimum valid value is 3840 mV
|
||||
vreg_voltage = 3840;
|
||||
} else if(vreg_voltage > 4208) {
|
||||
// Maximum safe value is 4208 mV
|
||||
vreg_voltage = 4208;
|
||||
}
|
||||
|
||||
// Find the nearest voltage value (subtract offset, divide into sections)
|
||||
// Values are truncated downward as needed (e.g. 4200mV -> 4192 mV)
|
||||
bq25896_regs.r06.VREG = (uint8_t)((vreg_voltage - 3840) / 16);
|
||||
}
|
||||
|
||||
// Do not allow values above 23 (0x17, 4208mV)
|
||||
// Double check: do not allow values above 23 (0x17, 4208mV)
|
||||
// Exceeding 4.2v will overcharge the battery!
|
||||
if(bq25896_regs.r06.VREG > 23) {
|
||||
bq25896_regs.r06.VREG = 23;
|
||||
|
@ -36,10 +36,10 @@ void bq25896_disable_otg(FuriHalI2cBusHandle* handle);
|
||||
/** Is otg enabled */
|
||||
bool bq25896_is_otg_enabled(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Get VREG (charging) voltage in mV */
|
||||
/** Get VREG (charging limit) voltage in mV */
|
||||
uint16_t bq25896_get_vreg_voltage(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Set VREG (charging) voltage in mV
|
||||
/** Set VREG (charging limit) voltage in mV
|
||||
*
|
||||
* Valid range: 3840mV - 4208mV, in steps of 16mV
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user