-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added a driver which uses the nRF52's ADC channel on the VDDH pin to read the battery voltage when using high voltage mode.
- Loading branch information
1 parent
262e50a
commit 96ec814
Showing
11 changed files
with
236 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
# Copyright (c) 2020 The ZMK Contributors | ||
# Copyright (c) 2020-2021 The ZMK Contributors | ||
# SPDX-License-Identifier: MIT | ||
|
||
add_subdirectory_ifdef(CONFIG_ZMK_BATTERY_VOLTAGE_DIVIDER battery_voltage_divider) | ||
add_subdirectory_ifdef(CONFIG_ZMK_BATTERY battery) | ||
add_subdirectory_ifdef(CONFIG_EC11 ec11) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
# Copyright (c) 2020 The ZMK Contributors | ||
# SPDX-License-Identifier: MIT | ||
|
||
rsource "battery_voltage_divider/Kconfig" | ||
rsource "battery/Kconfig" | ||
rsource "ec11/Kconfig" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Copyright (c) 2020-2021 The ZMK Contributors | ||
# SPDX-License-Identifier: MIT | ||
|
||
zephyr_include_directories(.) | ||
|
||
zephyr_library() | ||
|
||
zephyr_library_sources(battery_common.c) | ||
zephyr_library_sources_ifdef(CONFIG_ZMK_BATTERY_NRF_VDDH battery_nrf_vddh.c) | ||
zephyr_library_sources_ifdef(CONFIG_ZMK_BATTERY_VOLTAGE_DIVIDER battery_voltage_divider.c) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Copyright (c) 2020-2021 The ZMK Contributors | ||
# SPDX-License-Identifier: MIT | ||
|
||
config ZMK_BATTERY | ||
bool "ZMK battery monitoring" | ||
help | ||
Enable battery monitoring | ||
|
||
config ZMK_BATTERY_NRF_VDDH | ||
bool "ZMK nRF VDDH battery monitoring" | ||
select ADC | ||
select ZMK_BATTERY | ||
help | ||
Enable ZMK nRF VDDH voltage driver for battery monitoring. | ||
|
||
config ZMK_BATTERY_VOLTAGE_DIVIDER | ||
bool "ZMK battery voltage divider" | ||
select ADC | ||
select ZMK_BATTERY | ||
help | ||
Enable ZMK battery voltage divider driver for battery monitoring. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/* | ||
* Copyright (c) 2021 The ZMK Contributors | ||
* | ||
* SPDX-License-Identifier: MIT | ||
*/ | ||
|
||
#include <errno.h> | ||
#include <drivers/sensor.h> | ||
|
||
#include "battery_common.h" | ||
|
||
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: | ||
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/* | ||
* Copyright (c) 2021 The ZMK Contributors | ||
* | ||
* SPDX-License-Identifier: MIT | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <drivers/sensor.h> | ||
#include <stdint.h> | ||
|
||
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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
/* | ||
* Copyright (c) 2021 The ZMK Contributors | ||
* | ||
* SPDX-License-Identifier: MIT | ||
* | ||
* This is a simplified version of battery_voltage_divider.c which always reads | ||
* the VDDHDIV5 channel of the &adc node and multiplies it by 5. | ||
*/ | ||
|
||
#define DT_DRV_COMPAT zmk_battery_nrf_vddh | ||
|
||
#include <device.h> | ||
#include <devicetree.h> | ||
#include <drivers/adc.h> | ||
#include <drivers/sensor.h> | ||
#include <logging/log.h> | ||
|
||
#include "battery_common.h" | ||
|
||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); | ||
|
||
#define VDDHDIV (5) | ||
|
||
static const struct device *adc = DEVICE_DT_GET(DT_NODELABEL(adc)); | ||
|
||
struct vddh_data { | ||
struct adc_channel_cfg acc; | ||
struct adc_sequence as; | ||
struct battery_value value; | ||
}; | ||
|
||
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) { | ||
LOG_DBG("Selected channel is not supported: %d.", chan); | ||
return -ENOTSUP; | ||
} | ||
|
||
struct vddh_data *drv_data = dev->data; | ||
struct adc_sequence *as = &drv_data->as; | ||
|
||
int rc = adc_read(adc, as); | ||
as->calibrate = false; | ||
|
||
if (rc != 0) { | ||
LOG_ERR("Failed to read ADC: %d", rc); | ||
return rc; | ||
} | ||
|
||
int32_t val = drv_data->value.adc_raw; | ||
rc = adc_raw_to_millivolts(adc_ref_internal(adc), drv_data->acc.gain, as->resolution, &val); | ||
if (rc != 0) { | ||
LOG_ERR("Failed to convert raw ADC to mV: %d", rc); | ||
return rc; | ||
} | ||
|
||
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); | ||
|
||
return rc; | ||
} | ||
|
||
static int vddh_channel_get(const struct device *dev, enum sensor_channel chan, | ||
struct sensor_value *val) { | ||
struct vddh_data const *drv_data = dev->data; | ||
return battery_channel_get(&drv_data->value, chan, val); | ||
} | ||
|
||
static const struct sensor_driver_api vddh_api = { | ||
.sample_fetch = vddh_sample_fetch, | ||
.channel_get = vddh_channel_get, | ||
}; | ||
|
||
static int vddh_init(const struct device *dev) { | ||
struct vddh_data *drv_data = dev->data; | ||
|
||
if (!device_is_ready(adc)) { | ||
LOG_ERR("ADC device is not ready %s", adc->name); | ||
return -ENODEV; | ||
} | ||
|
||
drv_data->as = (struct adc_sequence){ | ||
.channels = BIT(0), | ||
.buffer = &drv_data->value.adc_raw, | ||
.buffer_size = sizeof(drv_data->value.adc_raw), | ||
.oversampling = 4, | ||
.calibrate = true, | ||
}; | ||
|
||
#ifdef CONFIG_ADC_NRFX_SAADC | ||
drv_data->acc = (struct adc_channel_cfg){ | ||
.gain = ADC_GAIN_1_5, | ||
.reference = ADC_REF_INTERNAL, | ||
.acquisition_time = ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 40), | ||
.input_positive = SAADC_CH_PSELN_PSELN_VDDHDIV5, | ||
}; | ||
|
||
drv_data->as.resolution = 12; | ||
#else | ||
#error Unsupported ADC | ||
#endif | ||
|
||
const int rc = adc_channel_setup(adc, &drv_data->acc); | ||
LOG_DBG("VDDHDIV5 setup returned %d", rc); | ||
|
||
return rc; | ||
} | ||
|
||
static struct vddh_data vddh_data; | ||
|
||
DEVICE_DT_INST_DEFINE(0, &vddh_init, device_pm_control_nop, &vddh_data, NULL, POST_KERNEL, | ||
CONFIG_SENSOR_INIT_PRIORITY, &vddh_api); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
11 changes: 11 additions & 0 deletions
11
app/drivers/zephyr/dts/bindings/sensor/zmk,battery-nrf-vddh.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Copyright (c) 2021 The ZMK Contributors | ||
# SPDX-License-Identifier: MIT | ||
|
||
description: Battery SoC monitoring using nRF VDDH | ||
|
||
compatible: "zmk,battery-nrf-vddh" | ||
|
||
properties: | ||
label: | ||
required: true | ||
type: string |