Skip to content

Commit

Permalink
fuel_gauge: composite: cached voltage for SoC
Browse files Browse the repository at this point in the history
Cache the voltage queried from `FUEL_GAUGE_VOLTAGE` for immediate use
in `FUEL_GAUGE_ABSOLUTE_STATE_OF_CHARGE` if the second call occurs
within a short delay of the first call.

This eliminates small mismatches between voltage and SoC values when
queried back to back due to noise on the voltage measurement.

Signed-off-by: Jordan Yates <jordan@embeint.com>
  • Loading branch information
JordanYates committed Jan 12, 2025
1 parent 99a63a7 commit 2dcae04
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 2 deletions.
14 changes: 14 additions & 0 deletions drivers/fuel_gauge/composite/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,17 @@ config FUEL_GAUGE_COMPOSITE
depends on DT_HAS_ZEPHYR_FUEL_GAUGE_COMPOSITE_ENABLED
help
Enable driver for the Zephyr composite fuel gauge device.

config FUEL_GAUGE_COMPOSITE_VOLTAGE_REUSE_TIMEOUT_MS
int "Maximum age of a cached voltage reading to use in SoC conversion"
depends on FUEL_GAUGE_COMPOSITE
default 100
help
Since the fuel gauge API reads values one call at a time, reading the battery
voltage and charge percentage are by necessity the product of two calls.
Unfortunately voltage measurements can be noisy, so two calls back to back may
return slightly different values. This can result in the voltage and charge
percentage not exactly matching each other when querying both back to back.
To mitigate this, if a charge percentage call is made within N milliseconds of
a previous `FUEL_GAUGE_VOLTAGE` call, the voltage from the previous call is
used directly in the percentage calulation.
32 changes: 30 additions & 2 deletions drivers/fuel_gauge/composite/fuel_gauge_composite.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ struct composite_config {
enum battery_chemistry chemistry;
};

struct composite_data {
int voltage_val;
k_ticks_t voltage_time;
};

static int composite_read_micro(const struct device *dev, enum sensor_channel chan, int *val)
{
struct sensor_value sensor_val;
Expand Down Expand Up @@ -51,6 +56,7 @@ static int composite_get_prop(const struct device *dev, fuel_gauge_prop_t prop,
{
const struct composite_config *config = dev->config;
int voltage, rc = 0;
int voltage_age_ms;

switch (prop) {
case FUEL_GAUGE_FULL_CHARGE_CAPACITY:
Expand All @@ -68,13 +74,33 @@ static int composite_get_prop(const struct device *dev, fuel_gauge_prop_t prop,
case FUEL_GAUGE_VOLTAGE:
rc = composite_read_micro(config->battery_voltage, SENSOR_CHAN_VOLTAGE,
&val->voltage);
if (rc == 0) {
data->voltage_val = voltage;
data->voltage_time = k_uptime_ticks();
}
break;
case FUEL_GAUGE_ABSOLUTE_STATE_OF_CHARGE:
case FUEL_GAUGE_RELATIVE_STATE_OF_CHARGE:
if (config->ocv_lookup_table[0] == -1) {
return -ENOTSUP;
}
rc = composite_read_micro(config->battery_voltage, SENSOR_CHAN_VOLTAGE, &voltage);
/* Age of the previous voltage measurement */
voltage_age_ms = k_ticks_to_ms_near32(k_uptime_ticks() - data->voltage_time);
if (data->voltage_time &&
(voltage_age_ms < CONFIG_FUEL_GAUGE_COMPOSITE_VOLTAGE_REUSE_TIMEOUT_MS)) {
/* Re-use the latest voltage measurement rather than sampling again */
voltage = data->voltage_val;
rc = 0;
} else {
/* Measure voltage in this call */
rc = composite_read_micro(config->battery_voltage, SENSOR_CHAN_VOLTAGE,
&voltage);
if (rc == 0) {
data->voltage_val = voltage;
data->voltage_time = k_uptime_ticks();
}
}
/* Convert voltage to state of charge */
val->relative_state_of_charge =
battery_soc_lookup(config->ocv_lookup_table, voltage) / 1000;
break;
Expand Down Expand Up @@ -106,7 +132,9 @@ static DEVICE_API(fuel_gauge, composite_api) = {
DT_INST_PROP_OR(inst, charge_full_design_microamp_hours, 0), \
.chemistry = BATTERY_CHEMISTRY_DT_GET(inst), \
}; \
DEVICE_DT_INST_DEFINE(inst, NULL, NULL, NULL, &composite_##inst##_config, POST_KERNEL, \
static struct composite_data composite_##inst##_data; \
DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &composite_##inst##_data, \
&composite_##inst##_config, POST_KERNEL, \
CONFIG_SENSOR_INIT_PRIORITY, &composite_api);

DT_INST_FOREACH_STATUS_OKAY(COMPOSITE_INIT)

0 comments on commit 2dcae04

Please sign in to comment.