Merge d3434bbf2b
into 4dfc45d4ab
This commit is contained in:
commit
88d359f2b1
8 changed files with 75 additions and 69 deletions
12
app/Kconfig
12
app/Kconfig
|
@ -388,11 +388,17 @@ if ZMK_BATTERY_REPORTING
|
||||||
choice ZMK_BATTERY_REPORTING_FETCH_MODE
|
choice ZMK_BATTERY_REPORTING_FETCH_MODE
|
||||||
prompt "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
|
config ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE
|
||||||
bool "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
|
endchoice
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -85,4 +85,8 @@ if BOARD_CORNEISH_ZEN_V1_LEFT || BOARD_CORNEISH_ZEN_V1_RIGHT
|
||||||
config BQ274XX
|
config BQ274XX
|
||||||
default y
|
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
|
endif # BOARD_CORNEISH_ZEN_V1_LEFT || BOARD_CORNEISH_ZEN_V1_RIGHT
|
||||||
|
|
|
@ -12,32 +12,14 @@
|
||||||
int battery_channel_get(const struct battery_value *value, enum sensor_channel chan,
|
int battery_channel_get(const struct battery_value *value, enum sensor_channel chan,
|
||||||
struct sensor_value *val_out) {
|
struct sensor_value *val_out) {
|
||||||
switch (chan) {
|
switch (chan) {
|
||||||
case SENSOR_CHAN_GAUGE_VOLTAGE:
|
case SENSOR_CHAN_VOLTAGE:
|
||||||
val_out->val1 = value->millivolts / 1000;
|
val_out->val1 = value->millivolts / 1000;
|
||||||
val_out->val2 = (value->millivolts % 1000) * 1000U;
|
val_out->val2 = (value->millivolts % 1000) * 1000U;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE:
|
|
||||||
val_out->val1 = value->state_of_charge;
|
|
||||||
val_out->val2 = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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;
|
|
||||||
}
|
|
|
@ -12,10 +12,7 @@
|
||||||
struct battery_value {
|
struct battery_value {
|
||||||
uint16_t adc_raw;
|
uint16_t adc_raw;
|
||||||
uint16_t millivolts;
|
uint16_t millivolts;
|
||||||
uint8_t state_of_charge;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int battery_channel_get(const struct battery_value *value, enum sensor_channel chan,
|
int battery_channel_get(const struct battery_value *value, enum sensor_channel chan,
|
||||||
struct sensor_value *val_out);
|
struct sensor_value *val_out);
|
||||||
|
|
||||||
uint8_t lithium_ion_mv_to_pct(int16_t bat_mv);
|
|
||||||
|
|
|
@ -31,8 +31,7 @@ struct vddh_data {
|
||||||
|
|
||||||
static int vddh_sample_fetch(const struct device *dev, enum sensor_channel chan) {
|
static int vddh_sample_fetch(const struct device *dev, enum sensor_channel chan) {
|
||||||
// Make sure selected channel is supported
|
// Make sure selected channel is supported
|
||||||
if (chan != SENSOR_CHAN_GAUGE_VOLTAGE && chan != SENSOR_CHAN_GAUGE_STATE_OF_CHARGE &&
|
if (chan != SENSOR_CHAN_VOLTAGE && chan != SENSOR_CHAN_ALL) {
|
||||||
chan != SENSOR_CHAN_ALL) {
|
|
||||||
LOG_DBG("Selected channel is not supported: %d.", chan);
|
LOG_DBG("Selected channel is not supported: %d.", chan);
|
||||||
return -ENOTSUP;
|
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.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,
|
LOG_DBG("ADC raw %u ~ %u mV", drv_data->value.adc_raw, drv_data->value.millivolts);
|
||||||
drv_data->value.state_of_charge);
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,8 +41,7 @@ static int bvd_sample_fetch(const struct device *dev, enum sensor_channel chan)
|
||||||
struct adc_sequence *as = &drv_data->as;
|
struct adc_sequence *as = &drv_data->as;
|
||||||
|
|
||||||
// Make sure selected channel is supported
|
// Make sure selected channel is supported
|
||||||
if (chan != SENSOR_CHAN_GAUGE_VOLTAGE && chan != SENSOR_CHAN_GAUGE_STATE_OF_CHARGE &&
|
if (chan != SENSOR_CHAN_VOLTAGE && chan != SENSOR_CHAN_ALL) {
|
||||||
chan != SENSOR_CHAN_ALL) {
|
|
||||||
LOG_DBG("Selected channel is not supported: %d.", chan);
|
LOG_DBG("Selected channel is not supported: %d.", chan);
|
||||||
return -ENOTSUP;
|
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;
|
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);
|
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.millivolts = millivolts;
|
||||||
drv_data->value.state_of_charge = percent;
|
|
||||||
} else {
|
} else {
|
||||||
LOG_DBG("Failed to read ADC: %d", rc);
|
LOG_DBG("Failed to read ADC: %d", rc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ static const struct device *battery;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE)
|
#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:
|
// Simple linear approximation of a battery based off adafruit's discharge graph:
|
||||||
// https://learn.adafruit.com/li-ion-and-lipoly-batteries/voltages
|
// 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;
|
return bat_mv * 2 / 15 - 459;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE)
|
static int get_state_of_charge(uint8_t *result) {
|
||||||
|
int rc = sensor_sample_fetch_chan(battery, SENSOR_CHAN_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);
|
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
LOG_DBG("Failed to fetch battery values: %d", rc);
|
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;
|
|
||||||
}
|
|
||||||
#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);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sensor_value voltage;
|
struct sensor_value voltage;
|
||||||
rc = sensor_channel_get(battery, SENSOR_CHAN_VOLTAGE, &voltage);
|
rc = sensor_channel_get(battery, SENSOR_CHAN_VOLTAGE, &voltage);
|
||||||
|
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
LOG_DBG("Failed to get battery voltage: %d", rc);
|
LOG_DBG("Failed to get battery voltage: %d", rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t mv = voltage.val1 * 1000 + (voltage.val2 / 1000);
|
int millivolts = voltage.val1 * 1000 + (voltage.val2 / 1000);
|
||||||
state_of_charge.val1 = lithium_ion_mv_to_pct(mv);
|
*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
|
#else
|
||||||
#error "Not a supported reporting fetch mode"
|
#error "Unsupported reporting fetch mode"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (last_state_of_charge != state_of_charge.val1) {
|
static int zmk_battery_update(const struct device *battery) {
|
||||||
last_state_of_charge = state_of_charge.val1;
|
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)
|
#if IS_ENABLED(CONFIG_BT_BAS)
|
||||||
LOG_DBG("Setting BAS GATT battery level to %d.", last_state_of_charge);
|
LOG_DBG("Setting BAS GATT battery level to %d.", last_state_of_charge);
|
||||||
|
|
||||||
|
|
|
@ -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_REPORTING` | bool | Enables/disables all battery level detection/reporting | n |
|
||||||
| `CONFIG_ZMK_BATTERY_REPORT_INTERVAL` | int | Battery level report interval in seconds | 60 |
|
| `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]
|
:::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 |
|
| `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.
|
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
|
### 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).
|
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
|
## nRF VDDH Battery Sensor
|
||||||
|
|
||||||
Driver for reading the voltage of a battery using a Nordic nRF52's VDDH pin.
|
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
|
### Devicetree
|
||||||
|
|
||||||
Applies to: `compatible = "zmk,battery-nrf-vddh"`
|
Applies to: `compatible = "zmk,battery-nrf-vddh"`
|
||||||
|
|
Loading…
Add table
Reference in a new issue