diff options
| -rw-r--r-- | builddefs/common_features.mk | 22 | ||||
| -rw-r--r-- | docs/_sidebar.json | 1 | ||||
| -rw-r--r-- | docs/drivers/battery.md | 51 | ||||
| -rw-r--r-- | drivers/battery/battery.c | 31 | ||||
| -rw-r--r-- | drivers/battery/battery.h | 34 | ||||
| -rw-r--r-- | drivers/battery/battery_adc.c | 55 | ||||
| -rw-r--r-- | drivers/battery/battery_driver.h | 29 | ||||
| -rw-r--r-- | keyboards/handwired/onekey/keymaps/battery/config.h | 6 | ||||
| -rw-r--r-- | keyboards/handwired/onekey/keymaps/battery/keymap.c | 28 | ||||
| -rw-r--r-- | keyboards/handwired/onekey/keymaps/battery/keymap.json | 7 | ||||
| -rw-r--r-- | keyboards/handwired/onekey/keymaps/battery/rules.mk | 1 | ||||
| -rw-r--r-- | quantum/keyboard.c | 10 |
12 files changed, 275 insertions, 0 deletions
diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk index c88ce36011..cbfbbcced5 100644 --- a/builddefs/common_features.mk +++ b/builddefs/common_features.mk | |||
| @@ -934,6 +934,28 @@ ifeq ($(strip $(DIP_SWITCH_ENABLE)), yes) | |||
| 934 | endif | 934 | endif |
| 935 | endif | 935 | endif |
| 936 | 936 | ||
| 937 | VALID_BATTERY_DRIVER_TYPES := adc custom vendor | ||
| 938 | |||
| 939 | BATTERY_DRIVER ?= adc | ||
| 940 | ifeq ($(strip $(BATTERY_DRIVER_REQUIRED)), yes) | ||
| 941 | ifeq ($(filter $(BATTERY_DRIVER),$(VALID_BATTERY_DRIVER_TYPES)),) | ||
| 942 | $(call CATASTROPHIC_ERROR,Invalid BATTERY_DRIVER,BATTERY_DRIVER="$(BATTERY_DRIVER)" is not a valid battery driver) | ||
| 943 | endif | ||
| 944 | |||
| 945 | OPT_DEFS += -DBATTERY_DRIVER | ||
| 946 | OPT_DEFS += -DBATTERY_$(strip $(shell echo $(BATTERY_DRIVER) | tr '[:lower:]' '[:upper:]')) | ||
| 947 | |||
| 948 | COMMON_VPATH += $(DRIVER_PATH)/battery | ||
| 949 | |||
| 950 | SRC += battery.c | ||
| 951 | SRC += battery_$(strip $(BATTERY_DRIVER)).c | ||
| 952 | |||
| 953 | # add extra deps | ||
| 954 | ifeq ($(strip $(BATTERY_DRIVER)), adc) | ||
| 955 | ANALOG_DRIVER_REQUIRED = yes | ||
| 956 | endif | ||
| 957 | endif | ||
| 958 | |||
| 937 | VALID_WS2812_DRIVER_TYPES := bitbang custom i2c pwm spi vendor | 959 | VALID_WS2812_DRIVER_TYPES := bitbang custom i2c pwm spi vendor |
| 938 | 960 | ||
| 939 | WS2812_DRIVER ?= bitbang | 961 | WS2812_DRIVER ?= bitbang |
diff --git a/docs/_sidebar.json b/docs/_sidebar.json index ae4d8fe4a9..f504f6f900 100644 --- a/docs/_sidebar.json +++ b/docs/_sidebar.json | |||
| @@ -227,6 +227,7 @@ | |||
| 227 | { "text": "ADC Driver", "link": "/drivers/adc" }, | 227 | { "text": "ADC Driver", "link": "/drivers/adc" }, |
| 228 | { "text": "APA102 Driver", "link": "/drivers/apa102" }, | 228 | { "text": "APA102 Driver", "link": "/drivers/apa102" }, |
| 229 | { "text": "Audio Driver", "link": "/drivers/audio" }, | 229 | { "text": "Audio Driver", "link": "/drivers/audio" }, |
| 230 | { "text": "Battery Driver", "link": "/drivers/battery" }, | ||
| 230 | { "text": "EEPROM Driver", "link": "/drivers/eeprom" }, | 231 | { "text": "EEPROM Driver", "link": "/drivers/eeprom" }, |
| 231 | { "text": "Flash Driver", "link": "/drivers/flash" }, | 232 | { "text": "Flash Driver", "link": "/drivers/flash" }, |
| 232 | { "text": "I2C Driver", "link": "/drivers/i2c" }, | 233 | { "text": "I2C Driver", "link": "/drivers/i2c" }, |
diff --git a/docs/drivers/battery.md b/docs/drivers/battery.md new file mode 100644 index 0000000000..b1f75c1156 --- /dev/null +++ b/docs/drivers/battery.md | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | # Battery Driver | ||
| 2 | |||
| 3 | This driver provides support for sampling battery level. | ||
| 4 | |||
| 5 | ## Usage | ||
| 6 | |||
| 7 | To use this driver, add the following to your `rules.mk`: | ||
| 8 | |||
| 9 | ```make | ||
| 10 | BATTERY_DRIVER_REQUIRED = yes | ||
| 11 | ``` | ||
| 12 | |||
| 13 | ## Basic Configuration {#basic-configuration} | ||
| 14 | |||
| 15 | Add the following to your `config.h`: | ||
| 16 | |||
| 17 | |Define |Default |Description | | ||
| 18 | |--------------------------|--------|--------------------------------------------------| | ||
| 19 | |`BATTERY_SAMPLE_INTERVAL` |`30000` |The time between battery samples in milliseconds. | | ||
| 20 | |||
| 21 | ## Driver Configuration {#driver-configuration} | ||
| 22 | |||
| 23 | Driver selection can be configured in `rules.mk` as `BATTERY_DRIVER`. Valid values are `adc` (default), `vendor`, or `custom`. See below for information on individual drivers. | ||
| 24 | |||
| 25 | ### ADC Driver {#adc-driver} | ||
| 26 | |||
| 27 | This is the default battery driver. The default configuration assumes the battery is connected to a ADC capable pin through a voltage divider. | ||
| 28 | |||
| 29 | ```make | ||
| 30 | BATTERY_DRIVER = adc | ||
| 31 | ``` | ||
| 32 | |||
| 33 | The following `#define`s apply only to the `adc` driver: | ||
| 34 | |||
| 35 | |Define |Default |Description | | ||
| 36 | |-----------------------------|--------------|--------------------------------------------------------------| | ||
| 37 | |`BATTERY_PIN` |*Not defined* |The GPIO pin connected to the voltage divider. | | ||
| 38 | |`BATTERY_REF_VOLTAGE_MV` |`3300` |The ADC reverence voltage, in millivolts. | | ||
| 39 | |`BATTERY_VOLTAGE_DIVIDER_R1` |`100000` |The voltage divider resistance, in kOhm. Set to 0 to disable. | | ||
| 40 | |`BATTERY_VOLTAGE_DIVIDER_R1` |`100000` |The voltage divider resistance, in kOhm. Set to 0 to disable. | | ||
| 41 | |`BATTERY_ADC_RESOLUTION` |`10` |The ADC resolution configured for the ADC Driver. | | ||
| 42 | |||
| 43 | ## Functions | ||
| 44 | |||
| 45 | ### `uint8_t battery_get_percent(void)` {#api-battery-get-percent} | ||
| 46 | |||
| 47 | Sample battery level. | ||
| 48 | |||
| 49 | #### Return Value {#api-battery-get-percent-return} | ||
| 50 | |||
| 51 | The battery percentage, in the range 0-100. | ||
diff --git a/drivers/battery/battery.c b/drivers/battery/battery.c new file mode 100644 index 0000000000..65497399e8 --- /dev/null +++ b/drivers/battery/battery.c | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | // Copyright 2025 QMK | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "battery_driver.h" | ||
| 5 | #include "battery.h" | ||
| 6 | #include "timer.h" | ||
| 7 | |||
| 8 | #ifndef BATTERY_SAMPLE_INTERVAL | ||
| 9 | # define BATTERY_SAMPLE_INTERVAL 30000 | ||
| 10 | #endif | ||
| 11 | |||
| 12 | static uint8_t last_bat_level = 100; | ||
| 13 | |||
| 14 | void battery_init(void) { | ||
| 15 | battery_driver_init(); | ||
| 16 | |||
| 17 | last_bat_level = battery_driver_sample_percent(); | ||
| 18 | } | ||
| 19 | |||
| 20 | void battery_task(void) { | ||
| 21 | static uint32_t bat_timer = 0; | ||
| 22 | if (timer_elapsed32(bat_timer) > BATTERY_SAMPLE_INTERVAL) { | ||
| 23 | last_bat_level = battery_driver_sample_percent(); | ||
| 24 | |||
| 25 | bat_timer = timer_read32(); | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | uint8_t battery_get_percent(void) { | ||
| 30 | return last_bat_level; | ||
| 31 | } | ||
diff --git a/drivers/battery/battery.h b/drivers/battery/battery.h new file mode 100644 index 0000000000..831b1f07e5 --- /dev/null +++ b/drivers/battery/battery.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | // Copyright 2025 QMK | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <stdint.h> | ||
| 7 | |||
| 8 | /** | ||
| 9 | * \file | ||
| 10 | * | ||
| 11 | * \defgroup battery Battery API | ||
| 12 | * | ||
| 13 | * \brief API to query battery status. | ||
| 14 | * \{ | ||
| 15 | */ | ||
| 16 | |||
| 17 | /** | ||
| 18 | * \brief Initialize the battery driver. | ||
| 19 | */ | ||
| 20 | void battery_init(void); | ||
| 21 | |||
| 22 | /** | ||
| 23 | * \brief Perform housekeeping tasks. | ||
| 24 | */ | ||
| 25 | void battery_task(void); | ||
| 26 | |||
| 27 | /** | ||
| 28 | * \brief Sample battery level. | ||
| 29 | * | ||
| 30 | * \return The battery percentage, in the range 0-100. | ||
| 31 | */ | ||
| 32 | uint8_t battery_get_percent(void); | ||
| 33 | |||
| 34 | /** \} */ | ||
diff --git a/drivers/battery/battery_adc.c b/drivers/battery/battery_adc.c new file mode 100644 index 0000000000..cf0e69cb48 --- /dev/null +++ b/drivers/battery/battery_adc.c | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | // Copyright 2025 QMK | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "analog.h" | ||
| 5 | #include "gpio.h" | ||
| 6 | |||
| 7 | #ifndef BATTERY_PIN | ||
| 8 | # error("BATTERY_PIN not configured!") | ||
| 9 | #endif | ||
| 10 | |||
| 11 | #ifndef BATTERY_REF_VOLTAGE_MV | ||
| 12 | # define BATTERY_REF_VOLTAGE_MV 3300 | ||
| 13 | #endif | ||
| 14 | |||
| 15 | #ifndef BATTERY_VOLTAGE_DIVIDER_R1 | ||
| 16 | # define BATTERY_VOLTAGE_DIVIDER_R1 100 | ||
| 17 | #endif | ||
| 18 | |||
| 19 | #ifndef BATTERY_VOLTAGE_DIVIDER_R2 | ||
| 20 | # define BATTERY_VOLTAGE_DIVIDER_R2 100 | ||
| 21 | #endif | ||
| 22 | |||
| 23 | // TODO: infer from adc config? | ||
| 24 | #ifndef BATTERY_ADC_RESOLUTION | ||
| 25 | # define BATTERY_ADC_RESOLUTION 10 | ||
| 26 | #endif | ||
| 27 | |||
| 28 | void battery_driver_init(void) { | ||
| 29 | gpio_set_pin_input(BATTERY_PIN); | ||
| 30 | } | ||
| 31 | |||
| 32 | uint16_t battery_driver_get_mv(void) { | ||
| 33 | uint32_t raw = analogReadPin(BATTERY_PIN); | ||
| 34 | |||
| 35 | uint32_t bat_mv = raw * BATTERY_REF_VOLTAGE_MV / (1 << BATTERY_ADC_RESOLUTION); | ||
| 36 | |||
| 37 | #if BATTERY_VOLTAGE_DIVIDER_R1 > 0 && BATTERY_VOLTAGE_DIVIDER_R2 > 0 | ||
| 38 | bat_mv = bat_mv * (BATTERY_VOLTAGE_DIVIDER_R1 + BATTERY_VOLTAGE_DIVIDER_R2) / BATTERY_VOLTAGE_DIVIDER_R2; | ||
| 39 | #endif | ||
| 40 | |||
| 41 | return bat_mv; | ||
| 42 | } | ||
| 43 | |||
| 44 | uint8_t battery_driver_sample_percent(void) { | ||
| 45 | uint16_t bat_mv = battery_driver_get_mv(); | ||
| 46 | |||
| 47 | // https://github.com/zmkfirmware/zmk/blob/3f7c9d7cc4f46617faad288421025ea2a6b0bd28/app/module/drivers/sensor/battery/battery_common.c#L33 | ||
| 48 | if (bat_mv >= 4200) { | ||
| 49 | return 100; | ||
| 50 | } else if (bat_mv <= 3450) { | ||
| 51 | return 0; | ||
| 52 | } | ||
| 53 | |||
| 54 | return bat_mv * 2 / 15 - 459; | ||
| 55 | } | ||
diff --git a/drivers/battery/battery_driver.h b/drivers/battery/battery_driver.h new file mode 100644 index 0000000000..c2ee75e966 --- /dev/null +++ b/drivers/battery/battery_driver.h | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | // Copyright 2025 QMK | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <stdint.h> | ||
| 7 | |||
| 8 | /** | ||
| 9 | * \file | ||
| 10 | * | ||
| 11 | * \defgroup battery Battery Driver API | ||
| 12 | * | ||
| 13 | * \brief API to query battery status. | ||
| 14 | * \{ | ||
| 15 | */ | ||
| 16 | |||
| 17 | /** | ||
| 18 | * \brief Initialize the battery driver. This function must be called only once, before any of the below functions can be called. | ||
| 19 | */ | ||
| 20 | void battery_driver_init(void); | ||
| 21 | |||
| 22 | /** | ||
| 23 | * \brief Sample battery level. | ||
| 24 | * | ||
| 25 | * \return The battery percentage, in the range 0-100. | ||
| 26 | */ | ||
| 27 | uint8_t battery_driver_sample_percent(void); | ||
| 28 | |||
| 29 | /** \} */ | ||
diff --git a/keyboards/handwired/onekey/keymaps/battery/config.h b/keyboards/handwired/onekey/keymaps/battery/config.h new file mode 100644 index 0000000000..8a1c05d436 --- /dev/null +++ b/keyboards/handwired/onekey/keymaps/battery/config.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | // Copyright 2024 QMK | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #define BATTERY_PIN ADC_PIN | ||
diff --git a/keyboards/handwired/onekey/keymaps/battery/keymap.c b/keyboards/handwired/onekey/keymaps/battery/keymap.c new file mode 100644 index 0000000000..74191e83fc --- /dev/null +++ b/keyboards/handwired/onekey/keymaps/battery/keymap.c | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | // Copyright 2024 QMK | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include QMK_KEYBOARD_H | ||
| 5 | #include "battery.h" | ||
| 6 | |||
| 7 | const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | ||
| 8 | LAYOUT_ortho_1x1(KC_A) | ||
| 9 | }; | ||
| 10 | |||
| 11 | void keyboard_post_init_user(void) { | ||
| 12 | // Customise these values to desired behaviour | ||
| 13 | debug_enable=true; | ||
| 14 | // debug_matrix=false; | ||
| 15 | // debug_keyboard=true; | ||
| 16 | // debug_mouse=false; | ||
| 17 | |||
| 18 | battery_init(); | ||
| 19 | } | ||
| 20 | |||
| 21 | void housekeeping_task_user(void) { | ||
| 22 | static uint32_t last = 0; | ||
| 23 | if (timer_elapsed32(last) > 2000) { | ||
| 24 | uprintf("Bat: %d!\n", battery_get_percent()); | ||
| 25 | |||
| 26 | last = timer_read32(); | ||
| 27 | } | ||
| 28 | } | ||
diff --git a/keyboards/handwired/onekey/keymaps/battery/keymap.json b/keyboards/handwired/onekey/keymaps/battery/keymap.json new file mode 100644 index 0000000000..c641dfe773 --- /dev/null +++ b/keyboards/handwired/onekey/keymaps/battery/keymap.json | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | { | ||
| 2 | "config": { | ||
| 3 | "features": { | ||
| 4 | "console": true | ||
| 5 | } | ||
| 6 | } | ||
| 7 | } | ||
diff --git a/keyboards/handwired/onekey/keymaps/battery/rules.mk b/keyboards/handwired/onekey/keymaps/battery/rules.mk new file mode 100644 index 0000000000..06908179ae --- /dev/null +++ b/keyboards/handwired/onekey/keymaps/battery/rules.mk | |||
| @@ -0,0 +1 @@ | |||
| BATTERY_DRIVER_REQUIRED = yes | |||
diff --git a/quantum/keyboard.c b/quantum/keyboard.c index ad740de4b3..fccdaf2990 100644 --- a/quantum/keyboard.c +++ b/quantum/keyboard.c | |||
| @@ -122,6 +122,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 122 | #ifdef SPLIT_KEYBOARD | 122 | #ifdef SPLIT_KEYBOARD |
| 123 | # include "split_util.h" | 123 | # include "split_util.h" |
| 124 | #endif | 124 | #endif |
| 125 | #ifdef BATTERY_DRIVER | ||
| 126 | # include "battery.h" | ||
| 127 | #endif | ||
| 125 | #ifdef BLUETOOTH_ENABLE | 128 | #ifdef BLUETOOTH_ENABLE |
| 126 | # include "bluetooth.h" | 129 | # include "bluetooth.h" |
| 127 | #endif | 130 | #endif |
| @@ -522,6 +525,9 @@ void keyboard_init(void) { | |||
| 522 | // init after split init | 525 | // init after split init |
| 523 | pointing_device_init(); | 526 | pointing_device_init(); |
| 524 | #endif | 527 | #endif |
| 528 | #ifdef BATTERY_DRIVER | ||
| 529 | battery_init(); | ||
| 530 | #endif | ||
| 525 | #ifdef BLUETOOTH_ENABLE | 531 | #ifdef BLUETOOTH_ENABLE |
| 526 | bluetooth_init(); | 532 | bluetooth_init(); |
| 527 | #endif | 533 | #endif |
| @@ -782,6 +788,10 @@ void keyboard_task(void) { | |||
| 782 | joystick_task(); | 788 | joystick_task(); |
| 783 | #endif | 789 | #endif |
| 784 | 790 | ||
| 791 | #ifdef BATTERY_DRIVER | ||
| 792 | battery_task(); | ||
| 793 | #endif | ||
| 794 | |||
| 785 | #ifdef BLUETOOTH_ENABLE | 795 | #ifdef BLUETOOTH_ENABLE |
| 786 | bluetooth_task(); | 796 | bluetooth_task(); |
| 787 | #endif | 797 | #endif |
