diff options
author | Nick <nick.win999@gmail.com> | 2020-09-19 19:14:59 -0500 |
---|---|---|
committer | Nick <nick.win999@gmail.com> | 2020-09-19 19:14:59 -0500 |
commit | 844f2c76749cbc5ff611d8e69819af82b698089a (patch) | |
tree | 9e235ea8156772c61c0c7438051011e25c1fa3d4 /app/drivers/zephyr | |
parent | ceda57ddfd7b49dd61e8795c37cd678b69a4a76f (diff) |
Voltage divider driver initial implementation
Diffstat (limited to 'app/drivers/zephyr')
-rw-r--r-- | app/drivers/zephyr/CMakeLists.txt | 1 | ||||
-rw-r--r-- | app/drivers/zephyr/battery_voltage_divider.c | 115 | ||||
-rw-r--r-- | app/drivers/zephyr/dts/bindings/zmk,battery-voltage-divider.yaml | 9 |
3 files changed, 125 insertions, 0 deletions
diff --git a/app/drivers/zephyr/CMakeLists.txt b/app/drivers/zephyr/CMakeLists.txt index 8778ded..0b1d18f 100644 --- a/app/drivers/zephyr/CMakeLists.txt +++ b/app/drivers/zephyr/CMakeLists.txt @@ -5,6 +5,7 @@ if(CONFIG_ZMK_KSCAN_GPIO_DRIVER) zephyr_library_sources( kscan_gpio_matrix.c kscan_gpio_direct.c + battery_voltage_divider.c ) zephyr_library_sources_ifdef(CONFIG_EC11 ec11.c) diff --git a/app/drivers/zephyr/battery_voltage_divider.c b/app/drivers/zephyr/battery_voltage_divider.c new file mode 100644 index 0000000..35fc799 --- /dev/null +++ b/app/drivers/zephyr/battery_voltage_divider.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_battery_voltage_divider + +#include <device.h> +#include <drivers/kscan.h> +#include <drivers/gpio.h> +#include <drivers/adc.h> +#include <drivers/sensor.h> +#include <logging/log.h> +#include <math.h> + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +#define VBATT DT_PATH(vbatt) + +struct battery_config { + struct device *adc; + struct adc_channel_cfg acc; + struct adc_sequence as; + int16_t adc_raw; +}; + +static struct battery_config battery_config; + +static int lithium_ion_mv_to_pct(int16_t bat_mv) { + // Magic function that maps mV to this discharge graph from adafruit: https://learn.adafruit.com/li-ion-and-lipoly-batteries/voltages + return round(106.818 + (-0.032685 - 106.818) / pow(1 + pow(bat_mv/3679.35, 58.979), 0.347386)); +} + +static void battery_read(struct k_work *workd) { + struct battery_config *cfg = &battery_config; + struct adc_sequence *as = &cfg->as; + + int rc = adc_read(cfg->adc, as); + as->calibrate = false; + if (rc == 0) { + int32_t val = cfg->adc_raw; + + adc_raw_to_millivolts(adc_ref_internal(cfg->adc), cfg->acc.gain, as->resolution, &val); + + rc = val * (uint64_t)DT_PROP(VBATT, full_ohms) / DT_PROP(VBATT, output_ohms); + LOG_DBG("ADC raw %d ~ %d mV => %d mV\n", cfg->adc_raw, val, rc); + int percent = lithium_ion_mv_to_pct(rc); + LOG_DBG("Percent: %d", percent); + } else { + LOG_DBG("Failed to read ADC: %d", rc); + } +} + +K_WORK_DEFINE(battery_work, battery_read); + +static void battery_handler(struct k_timer *timer) +{ + k_work_submit(&battery_work); +} + +K_TIMER_DEFINE(battery_tick, battery_handler, NULL); + +static int battery_setup(struct device *_arg) { + struct battery_config *cfg = &battery_config; + struct adc_sequence *as = &cfg->as; + struct adc_channel_cfg *acc = &cfg->acc; + + cfg->adc = device_get_binding(DT_IO_CHANNELS_LABEL(VBATT)); + + if (cfg->adc == NULL) { + LOG_ERR("ADC %s failed to retrieve", DT_IO_CHANNELS_LABEL(VBATT)); + return -ENOENT; + } + + *as = (struct adc_sequence){ + .channels = BIT(0), + .buffer = &cfg->adc_raw, + .buffer_size = sizeof(cfg->adc_raw), + .oversampling = 4, + .calibrate = true, + }; + +#ifdef CONFIG_ADC_NRFX_SAADC + *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_PSELP_PSELP_AnalogInput0 + DT_IO_CHANNELS_INPUT(VBATT), + }; + + as->resolution = 12; +#else +#error Unsupported ADC +#endif + + int adc_rc = adc_channel_setup(cfg->adc, acc); + LOG_DBG("AIN%u setup returned %d", DT_IO_CHANNELS_INPUT(VBATT), adc_rc); + + if (adc_rc != 0) { + return adc_rc; + } + + k_timer_start(&battery_tick, K_NO_WAIT, K_SECONDS(5)); + + return 0; +} + +SYS_INIT(battery_setup, + APPLICATION, + CONFIG_APPLICATION_INIT_PRIORITY); + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
\ No newline at end of file diff --git a/app/drivers/zephyr/dts/bindings/zmk,battery-voltage-divider.yaml b/app/drivers/zephyr/dts/bindings/zmk,battery-voltage-divider.yaml new file mode 100644 index 0000000..f6e0642 --- /dev/null +++ b/app/drivers/zephyr/dts/bindings/zmk,battery-voltage-divider.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Battery SoC monitoring using voltage divider + +compatible: "zmk,battery-voltage-divider" + +include: voltage-divider.yaml +
\ No newline at end of file |