This commit is contained in:
Joel Spadin 2024-05-06 11:13:21 -03:00 committed by GitHub
commit 88d359f2b1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 75 additions and 69 deletions

View file

@ -388,11 +388,17 @@ if ZMK_BATTERY_REPORTING
choice ZMK_BATTERY_REPORTING_FETCH_MODE
prompt "Battery Reporting Fetch Mode"
config ZMK_BATTERY_REPORTING_FETCH_MODE_STATE_OF_CHARGE
bool "State of charge"
config ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE
bool "Lithium Voltage"
help
Estimate the battery level by reading the voltage of a Lithium battery.
zmk,battery chosen node should be a sensor driver that implements SENSOR_CHAN_VOLTAGE.
config ZMK_BATTERY_REPORTING_FETCH_MODE_STATE_OF_CHARGE
bool "State of charge"
help
Read the battery level from a fuel gauge sensor.
zmk,battery chosen node should be a sensor driver that implements SENSOR_CHAN_GAUGE_STATE_OF_CHARGE.
endchoice
endif

View file

@ -85,4 +85,8 @@ if BOARD_CORNEISH_ZEN_V1_LEFT || BOARD_CORNEISH_ZEN_V1_RIGHT
config BQ274XX
default y
choice ZMK_BATTERY_REPORTING_FETCH_MODE
default ZMK_BATTERY_REPORTING_FETCH_MODE_STATE_OF_CHARGE
endchoice
endif # BOARD_CORNEISH_ZEN_V1_LEFT || BOARD_CORNEISH_ZEN_V1_RIGHT

View file

@ -12,32 +12,14 @@
int battery_channel_get(const struct battery_value *value, enum sensor_channel chan,
struct sensor_value *val_out) {
switch (chan) {
case SENSOR_CHAN_GAUGE_VOLTAGE:
case SENSOR_CHAN_VOLTAGE:
val_out->val1 = value->millivolts / 1000;
val_out->val2 = (value->millivolts % 1000) * 1000U;
break;
case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE:
val_out->val1 = value->state_of_charge;
val_out->val2 = 0;
break;
default:
return -ENOTSUP;
}
return 0;
}
uint8_t lithium_ion_mv_to_pct(int16_t bat_mv) {
// Simple linear approximation of a battery based off adafruit's discharge graph:
// https://learn.adafruit.com/li-ion-and-lipoly-batteries/voltages
if (bat_mv >= 4200) {
return 100;
} else if (bat_mv <= 3450) {
return 0;
}
return bat_mv * 2 / 15 - 459;
}

View file

@ -12,10 +12,7 @@
struct battery_value {
uint16_t adc_raw;
uint16_t millivolts;
uint8_t state_of_charge;
};
int battery_channel_get(const struct battery_value *value, enum sensor_channel chan,
struct sensor_value *val_out);
uint8_t lithium_ion_mv_to_pct(int16_t bat_mv);

View file

@ -31,8 +31,7 @@ struct vddh_data {
static int vddh_sample_fetch(const struct device *dev, enum sensor_channel chan) {
// Make sure selected channel is supported
if (chan != SENSOR_CHAN_GAUGE_VOLTAGE && chan != SENSOR_CHAN_GAUGE_STATE_OF_CHARGE &&
chan != SENSOR_CHAN_ALL) {
if (chan != SENSOR_CHAN_VOLTAGE && chan != SENSOR_CHAN_ALL) {
LOG_DBG("Selected channel is not supported: %d.", chan);
return -ENOTSUP;
}
@ -56,10 +55,8 @@ static int vddh_sample_fetch(const struct device *dev, enum sensor_channel chan)
}
drv_data->value.millivolts = val * VDDHDIV;
drv_data->value.state_of_charge = lithium_ion_mv_to_pct(drv_data->value.millivolts);
LOG_DBG("ADC raw %d ~ %d mV => %d%%", drv_data->value.adc_raw, drv_data->value.millivolts,
drv_data->value.state_of_charge);
LOG_DBG("ADC raw %u ~ %u mV", drv_data->value.adc_raw, drv_data->value.millivolts);
return rc;
}

View file

@ -41,8 +41,7 @@ static int bvd_sample_fetch(const struct device *dev, enum sensor_channel chan)
struct adc_sequence *as = &drv_data->as;
// Make sure selected channel is supported
if (chan != SENSOR_CHAN_GAUGE_VOLTAGE && chan != SENSOR_CHAN_GAUGE_STATE_OF_CHARGE &&
chan != SENSOR_CHAN_ALL) {
if (chan != SENSOR_CHAN_VOLTAGE && chan != SENSOR_CHAN_ALL) {
LOG_DBG("Selected channel is not supported: %d.", chan);
return -ENOTSUP;
}
@ -74,11 +73,8 @@ static int bvd_sample_fetch(const struct device *dev, enum sensor_channel chan)
uint16_t millivolts = val * (uint64_t)drv_cfg->full_ohm / drv_cfg->output_ohm;
LOG_DBG("ADC raw %d ~ %d mV => %d mV", drv_data->value.adc_raw, val, millivolts);
uint8_t percent = lithium_ion_mv_to_pct(millivolts);
LOG_DBG("Percent: %d", percent);
drv_data->value.millivolts = millivolts;
drv_data->value.state_of_charge = percent;
} else {
LOG_DBG("Failed to read ADC: %d", rc);
}

View file

@ -35,7 +35,7 @@ static const struct device *battery;
#endif
#if IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE)
static uint8_t lithium_ion_mv_to_pct(int16_t bat_mv) {
static uint8_t lithium_ion_mv_to_pct(int bat_mv) {
// Simple linear approximation of a battery based off adafruit's discharge graph:
// https://learn.adafruit.com/li-ion-and-lipoly-batteries/voltages
@ -48,51 +48,60 @@ static uint8_t lithium_ion_mv_to_pct(int16_t bat_mv) {
return bat_mv * 2 / 15 - 459;
}
#endif // IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE)
static int zmk_battery_update(const struct device *battery) {
struct sensor_value state_of_charge;
int rc;
#if IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_STATE_OF_CHARGE)
rc = sensor_sample_fetch_chan(battery, SENSOR_CHAN_GAUGE_STATE_OF_CHARGE);
static int get_state_of_charge(uint8_t *result) {
int rc = sensor_sample_fetch_chan(battery, SENSOR_CHAN_VOLTAGE);
if (rc != 0) {
LOG_DBG("Failed to fetch battery values: %d", rc);
return rc;
}
rc = sensor_channel_get(battery, SENSOR_CHAN_GAUGE_STATE_OF_CHARGE, &state_of_charge);
if (rc != 0) {
LOG_DBG("Failed to get battery state of charge: %d", rc);
return rc;
}
#elif IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE)
rc = sensor_sample_fetch_chan(battery, SENSOR_CHAN_VOLTAGE);
if (rc != 0) {
LOG_DBG("Failed to fetch battery values: %d", rc);
LOG_DBG("Failed to fetch sensor value: %d", rc);
return rc;
}
struct sensor_value voltage;
rc = sensor_channel_get(battery, SENSOR_CHAN_VOLTAGE, &voltage);
if (rc != 0) {
LOG_DBG("Failed to get battery voltage: %d", rc);
return rc;
}
uint16_t mv = voltage.val1 * 1000 + (voltage.val2 / 1000);
state_of_charge.val1 = lithium_ion_mv_to_pct(mv);
int millivolts = voltage.val1 * 1000 + (voltage.val2 / 1000);
*result = lithium_ion_mv_to_pct(millivolts);
LOG_DBG("Battery voltage = %d mv -> %u%%", millivolts, *result);
return 0;
}
#elif IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_STATE_OF_CHARGE)
static int get_state_of_charge(uint8_t *result) {
struct sensor_value state_of_charge;
int rc = sensor_sample_fetch_chan(battery, SENSOR_CHAN_GAUGE_STATE_OF_CHARGE);
if (rc != 0) {
LOG_DBG("Failed to fetch sensor value: %d", rc);
return rc;
}
rc = sensor_channel_get(battery, SENSOR_CHAN_GAUGE_STATE_OF_CHARGE, &state_of_charge);
if (rc != 0) {
LOG_DBG("Failed to get battery state of charge: %d", rc);
return rc;
}
*result = state_of_charge.val1;
return 0;
}
LOG_DBG("State of change %d from %d mv", state_of_charge.val1, mv);
#else
#error "Not a supported reporting fetch mode"
#error "Unsupported reporting fetch mode"
#endif
if (last_state_of_charge != state_of_charge.val1) {
last_state_of_charge = state_of_charge.val1;
static int zmk_battery_update(const struct device *battery) {
uint8_t new_state_of_charge = 0;
int rc = get_state_of_charge(&new_state_of_charge);
if (rc != 0) {
return rc;
}
if (new_state_of_charge != last_state_of_charge) {
last_state_of_charge = new_state_of_charge;
#if IS_ENABLED(CONFIG_BT_BAS)
LOG_DBG("Setting BAS GATT battery level to %d.", last_state_of_charge);

View file

@ -16,9 +16,18 @@ Definition file: [zmk/app/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/
| `CONFIG_ZMK_BATTERY_REPORTING` | bool | Enables/disables all battery level detection/reporting | n |
| `CONFIG_ZMK_BATTERY_REPORT_INTERVAL` | int | Battery level report interval in seconds | 60 |
If `CONFIG_ZMK_BATTERY_REPORTING` is enabled, exactly zero or one of the following options may be set to `y`. The first is used if none are set. This should be set to match the type of sensor that is selected for the `zmk,battery` chosen node.
| Config | Description |
| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| `CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE` | Read a sensor that supports `SENSOR_CHAN_VOLTAGE` and estimate state of charge for a Li-Ion or LiPo battery. |
| `CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_STATE_OF_CHARGE` | Read a sensor that supports `SENSOR_CHAN_GAUGE_STATE_OF_CHARGE`. |
ZMK does not yet support Zephyr's recently added fuel gauge API.
:::note[Default setting]
While `CONFIG_ZMK_BATTERY_REPORTING` is disabled by default it is implied by `CONFIG_ZMK_BLE`, thus any board with BLE enabled will have this automatically enabled unless explicitly overriden.
While `CONFIG_ZMK_BATTERY_REPORTING` is disabled by default, it is implied by `CONFIG_ZMK_BLE`, thus any board with BLE enabled will have this automatically enabled unless explicitly overriden.
:::
@ -47,20 +56,26 @@ Applies to: [`/chosen` node](https://docs.zephyrproject.org/3.5.0/build/dts/intr
| ------------- | ---- | --------------------------------------------- |
| `zmk,battery` | path | The node for the battery sensor driver to use |
## Battery Voltage Divider Sensor
## Voltage Divider Sensor
Driver for reading the voltage of a battery using an ADC connected to a voltage divider.
Set `CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE=y` when using this driver.
### Devicetree
Applies to: `compatible = "zmk,battery-voltage-divider"`
Applies to: `compatible = "voltage-divider"`
See [Zephyr's voltage divider documentation](https://docs.zephyrproject.org/3.5.0/build/dts/api/bindings/iio/afe/voltage-divider.html).
ZMK also provides a `compatible = "zmk,battery-voltage-divider"` driver, which is deprecated. Use the improved driver from Zephyr instead.
## nRF VDDH Battery Sensor
Driver for reading the voltage of a battery using a Nordic nRF52's VDDH pin.
Set `CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE=y` when using this driver.
### Devicetree
Applies to: `compatible = "zmk,battery-nrf-vddh"`