From 97d70b5d4ab2541abcc953b71064ba0c5724840a Mon Sep 17 00:00:00 2001 From: Deadline039 <1315374252@qq.com> Date: Sun, 8 Jun 2025 00:37:54 +0800 Subject: [PATCH 1/4] feat(keyboard): Add ble battery level report --- .../esp32_s3_kbd_kit/include/bsp/keyboard.h | 3 +- examples/keyboard/main/CMakeLists.txt | 4 +- examples/keyboard/main/battery_adc.c | 111 ++++++++++++++++++ examples/keyboard/main/battery_adc.h | 26 ++++ examples/keyboard/main/ble_hid.c | 12 +- examples/keyboard/main/ble_hid.h | 10 +- examples/keyboard/main/main.c | 2 + 7 files changed, 163 insertions(+), 5 deletions(-) create mode 100644 examples/keyboard/main/battery_adc.c create mode 100644 examples/keyboard/main/battery_adc.h diff --git a/examples/keyboard/components/esp32_s3_kbd_kit/include/bsp/keyboard.h b/examples/keyboard/components/esp32_s3_kbd_kit/include/bsp/keyboard.h index bea6ded4e..5cbb546e7 100644 --- a/examples/keyboard/components/esp32_s3_kbd_kit/include/bsp/keyboard.h +++ b/examples/keyboard/components/esp32_s3_kbd_kit/include/bsp/keyboard.h @@ -49,7 +49,8 @@ extern "C" { #define KBD_WS2812_POWER_IO 1 /*!< Battery monitor GPIO */ -#define KBD_BATTERY_MONITOR_IO 2 +#define KBD_BATTERY_MONITOR_IO 2 +#define KBD_BATTERY_MONITOR_CHANNEL ADC_CHANNEL_1 #ifdef __cplusplus } diff --git a/examples/keyboard/main/CMakeLists.txt b/examples/keyboard/main/CMakeLists.txt index 575d35576..86a911d47 100644 --- a/examples/keyboard/main/CMakeLists.txt +++ b/examples/keyboard/main/CMakeLists.txt @@ -1,5 +1,5 @@ -idf_component_register(SRCS "main.c" "../hid_device/usb_descriptors.c" "tinyusb_hid.c" "ble_hid.c" "esp_hid_gap.c" "btn_progress.c" "settings.c" - INCLUDE_DIRS "../hid_device") +idf_component_register(SRCS "main.c" "../hid_device/usb_descriptors.c" "tinyusb_hid.c" "ble_hid.c" "esp_hid_gap.c" "btn_progress.c" "settings.c" "battery_adc.c" + INCLUDE_DIRS "../hid_device") idf_component_get_property(tusb_lib espressif__tinyusb COMPONENT_LIB) diff --git a/examples/keyboard/main/battery_adc.c b/examples/keyboard/main/battery_adc.c new file mode 100644 index 000000000..10d84fb15 --- /dev/null +++ b/examples/keyboard/main/battery_adc.c @@ -0,0 +1,111 @@ +/* + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "battery_adc.h" + +#include "ble_hid.h" +#include +#include + +#include "bsp/esp-bsp.h" + +int g_battery_percent; + +static const char *TAG = "BATTERY-ADC"; + +static adc_oneshot_unit_handle_t adc1_handle; +static TaskHandle_t battery_task_handle = NULL; + +static void battery_monitor_task(void *pvParameters); + +/* Pull up resistor value. Unit: KOhm */ +#define PULL_UP_RESISTOR (51) +/* Pull down resistor value. Unit: KOhm */ +#define PULL_DOWN_RESISTOR (100) +/* Max voltage value. Unit: mV */ +#define MAX_REF_VOLTAGE (3469) + +esp_err_t battery_adc_init(void) +{ + if (battery_task_handle != NULL) { + ESP_LOGW(TAG, "Battery ADC already initialized"); + return ESP_OK; + } + + /* ADC1 Init */ + adc_oneshot_unit_init_cfg_t unit_init_cfg = { + .unit_id = ADC_UNIT_1, + .clk_src = ADC_RTC_CLK_SRC_DEFAULT, + .ulp_mode = ADC_ULP_MODE_DISABLE + }; + ESP_ERROR_CHECK(adc_oneshot_new_unit(&unit_init_cfg, &adc1_handle)); + + /* ADC1 Config */ + adc_oneshot_chan_cfg_t channel_config = { + /* Theoretical battery voltage measurement range is about 2.45 to 2.78V. + * So set the input attenuation to 12 dB (about 4x) */ + .atten = ADC_ATTEN_DB_12, + .bitwidth = ADC_BITWIDTH_12 + }; + ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, KBD_BATTERY_MONITOR_CHANNEL, &channel_config)); + + ESP_LOGI(TAG, "Free memory size: %"PRIu32, esp_get_free_heap_size()); + if (xTaskCreate(battery_monitor_task, "battery_monitor", 4096, NULL, 2, &battery_task_handle) != pdPASS) { + return ESP_ERR_NO_MEM; + } + ESP_LOGI(TAG, "Free memory size: %"PRIu32, esp_get_free_heap_size()); + + return ESP_OK; +} + +static void battery_monitor_task(void *pvParameters) +{ + ESP_UNUSED(pvParameters); + /* The table of voltage convert percent. */ + const static int ocv_capacity_table[] = { + 3680, 3700, 3740, 3770, 3790, 3820, 3870, 3920, 3980, 4060, 4200 + }; + + int adc_raw_value; + int adc_voltage; + int battery_voltage; + + int battery_level; + + while (1) { + adc_oneshot_read(adc1_handle, KBD_BATTERY_MONITOR_CHANNEL, &adc_raw_value); + + /* Get the battery voltage. */ + adc_voltage = MAX_REF_VOLTAGE * adc_raw_value / 4095; + battery_voltage = adc_voltage * (PULL_UP_RESISTOR + PULL_DOWN_RESISTOR) / PULL_DOWN_RESISTOR; + + /* Get the percent. */ + for (battery_level = 0; battery_level < 11; ++battery_level) { + if (battery_voltage <= ocv_capacity_table[battery_level]) { + break; + } + } + + if (battery_level == 0) { + /* Low battery. */ + g_battery_percent = 0; + } else if (battery_level >= 11) { + /* Over voltage. */ + g_battery_percent = 100; + } else { + g_battery_percent = (battery_level - 1) * 10; + g_battery_percent += ((battery_voltage - ocv_capacity_table[battery_level]) * 10 / ( + ocv_capacity_table[battery_level] - ocv_capacity_table[battery_level - 1])); + } + + ble_hid_battery_report(g_battery_percent); + + /* Sample period. */ + vTaskDelay(pdMS_TO_TICKS(10000)); + } +} diff --git a/examples/keyboard/main/battery_adc.h b/examples/keyboard/main/battery_adc.h new file mode 100644 index 000000000..103b33e66 --- /dev/null +++ b/examples/keyboard/main/battery_adc.h @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp_err.h" + +/** + * @brief Initialize battery ADC. + * + * @return + * - ESP_OK: Success + * - ESP_ERR_NO_MEM: Out of memory. + */ +esp_err_t battery_adc_init(void); + +#ifdef __cpluscpls +} +#endif diff --git a/examples/keyboard/main/ble_hid.c b/examples/keyboard/main/ble_hid.c index 9a8a8f487..c874a939a 100644 --- a/examples/keyboard/main/ble_hid.c +++ b/examples/keyboard/main/ble_hid.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -161,3 +161,13 @@ void ble_hid_keyboard_report(hid_report_t report) break; } } + +void ble_hid_battery_report(int battery_level) +{ + if (s_ble_hid_param.is_connected == false) { + return; + } + + ESP_LOGI(TAG, "Report level: %d", battery_level); + esp_hidd_dev_battery_set(s_ble_hid_param.hid_dev, (uint8_t)battery_level); +} diff --git a/examples/keyboard/main/ble_hid.h b/examples/keyboard/main/ble_hid.h index efaf17ef2..8d1c1f080 100644 --- a/examples/keyboard/main/ble_hid.h +++ b/examples/keyboard/main/ble_hid.h @@ -1,4 +1,5 @@ -/* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD +/* + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -36,6 +37,13 @@ esp_err_t ble_hid_deinit(void); */ void ble_hid_keyboard_report(hid_report_t report); +/** + * @brief Send ble hid battery level + * + * @param battery_level + */ +void ble_hid_battery_report(int battery_level); + #ifdef __cplusplus } #endif diff --git a/examples/keyboard/main/main.c b/examples/keyboard/main/main.c index 27bf8c53a..de6b00ed9 100644 --- a/examples/keyboard/main/main.c +++ b/examples/keyboard/main/main.c @@ -10,6 +10,7 @@ #include "bsp/esp-bsp.h" #include "bsp/keycodes.h" #include "btn_progress.h" +#include "battery_adc.h" #include "esp_log.h" #include "esp_pm.h" #include "keyboard_button.h" @@ -115,4 +116,5 @@ void app_main(void) keyboard_button_register_cb(kbd_handle, cb_cfg, NULL); xTaskCreate(light_progress_task, "light_progress_task", 4096, NULL, 5, &light_progress_task_handle); + battery_adc_init(); } From b3afa8278f4ec6b9049e8bdae0bba94182a731ee Mon Sep 17 00:00:00 2001 From: Deadline039 <1315374252@qq.com> Date: Sun, 8 Jun 2025 10:57:17 +0800 Subject: [PATCH 2/4] remove(keyboard): remove debugging logs from battery_adc.c --- examples/keyboard/main/battery_adc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/keyboard/main/battery_adc.c b/examples/keyboard/main/battery_adc.c index 10d84fb15..2f692c779 100644 --- a/examples/keyboard/main/battery_adc.c +++ b/examples/keyboard/main/battery_adc.c @@ -54,11 +54,9 @@ esp_err_t battery_adc_init(void) }; ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, KBD_BATTERY_MONITOR_CHANNEL, &channel_config)); - ESP_LOGI(TAG, "Free memory size: %"PRIu32, esp_get_free_heap_size()); if (xTaskCreate(battery_monitor_task, "battery_monitor", 4096, NULL, 2, &battery_task_handle) != pdPASS) { return ESP_ERR_NO_MEM; } - ESP_LOGI(TAG, "Free memory size: %"PRIu32, esp_get_free_heap_size()); return ESP_OK; } From 10d9c52a9e0260241bcc58480cc7e399d5f12f82 Mon Sep 17 00:00:00 2001 From: Deadline039 <1315374252@qq.com> Date: Mon, 9 Jun 2025 20:34:14 +0800 Subject: [PATCH 3/4] refactor(keyboard): use adc battery estimation --- .../esp32_s3_kbd_kit/include/bsp/keyboard.h | 7 +- examples/keyboard/main/battery_adc.c | 82 ++++++------------- examples/keyboard/main/idf_component.yml | 5 +- 3 files changed, 32 insertions(+), 62 deletions(-) diff --git a/examples/keyboard/components/esp32_s3_kbd_kit/include/bsp/keyboard.h b/examples/keyboard/components/esp32_s3_kbd_kit/include/bsp/keyboard.h index 5cbb546e7..1d373af6d 100644 --- a/examples/keyboard/components/esp32_s3_kbd_kit/include/bsp/keyboard.h +++ b/examples/keyboard/components/esp32_s3_kbd_kit/include/bsp/keyboard.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -49,8 +49,9 @@ extern "C" { #define KBD_WS2812_POWER_IO 1 /*!< Battery monitor GPIO */ -#define KBD_BATTERY_MONITOR_IO 2 -#define KBD_BATTERY_MONITOR_CHANNEL ADC_CHANNEL_1 +#define KBD_BATTERY_MONITOR_ADC_UNIT ADC_UNIT_1 +#define KBD_BATTERY_MONITOR_IO 2 +#define KBD_BATTERY_MONITOR_CHANNEL ADC_CHANNEL_1 #ifdef __cplusplus } diff --git a/examples/keyboard/main/battery_adc.c b/examples/keyboard/main/battery_adc.c index 2f692c779..5f075407a 100644 --- a/examples/keyboard/main/battery_adc.c +++ b/examples/keyboard/main/battery_adc.c @@ -13,13 +13,13 @@ #include #include "bsp/esp-bsp.h" +#include "adc_battery_estimation.h" int g_battery_percent; static const char *TAG = "BATTERY-ADC"; -static adc_oneshot_unit_handle_t adc1_handle; -static TaskHandle_t battery_task_handle = NULL; +static TaskHandle_t battery_monitor_task_handle; static void battery_monitor_task(void *pvParameters); @@ -27,34 +27,15 @@ static void battery_monitor_task(void *pvParameters); #define PULL_UP_RESISTOR (51) /* Pull down resistor value. Unit: KOhm */ #define PULL_DOWN_RESISTOR (100) -/* Max voltage value. Unit: mV */ -#define MAX_REF_VOLTAGE (3469) esp_err_t battery_adc_init(void) { - if (battery_task_handle != NULL) { - ESP_LOGW(TAG, "Battery ADC already initialized"); + if (battery_monitor_task_handle != NULL) { + ESP_LOGW(TAG, "Battery monitor task already created! "); return ESP_OK; } - /* ADC1 Init */ - adc_oneshot_unit_init_cfg_t unit_init_cfg = { - .unit_id = ADC_UNIT_1, - .clk_src = ADC_RTC_CLK_SRC_DEFAULT, - .ulp_mode = ADC_ULP_MODE_DISABLE - }; - ESP_ERROR_CHECK(adc_oneshot_new_unit(&unit_init_cfg, &adc1_handle)); - - /* ADC1 Config */ - adc_oneshot_chan_cfg_t channel_config = { - /* Theoretical battery voltage measurement range is about 2.45 to 2.78V. - * So set the input attenuation to 12 dB (about 4x) */ - .atten = ADC_ATTEN_DB_12, - .bitwidth = ADC_BITWIDTH_12 - }; - ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, KBD_BATTERY_MONITOR_CHANNEL, &channel_config)); - - if (xTaskCreate(battery_monitor_task, "battery_monitor", 4096, NULL, 2, &battery_task_handle) != pdPASS) { + if (xTaskCreate(battery_monitor_task, "battery_monitor", 4096, NULL, 2, &battery_monitor_task_handle) != pdPASS) { return ESP_ERR_NO_MEM; } @@ -64,44 +45,31 @@ esp_err_t battery_adc_init(void) static void battery_monitor_task(void *pvParameters) { ESP_UNUSED(pvParameters); - /* The table of voltage convert percent. */ - const static int ocv_capacity_table[] = { - 3680, 3700, 3740, 3770, 3790, 3820, 3870, 3920, 3980, 4060, 4200 + adc_battery_estimation_t config = { + .internal = { + .adc_unit = KBD_BATTERY_MONITOR_ADC_UNIT, + .adc_bitwidth = ADC_BITWIDTH_DEFAULT, + /* Theoretical battery voltage measurement range is about 2.45 to 2.78V. + * So set the input attenuation to 12 dB (about 4x) */ + .adc_atten = ADC_ATTEN_DB_12 + }, + .adc_channel = KBD_BATTERY_MONITOR_CHANNEL, + .lower_resistor = PULL_DOWN_RESISTOR, + .upper_resistor = PULL_UP_RESISTOR, }; - int adc_raw_value; - int adc_voltage; - int battery_voltage; + adc_battery_estimation_handle_t adc_battery_estimation_handle = adc_battery_estimation_create(&config); + if (adc_battery_estimation_handle == NULL) { + ESP_LOGE(TAG, "Initialize adc battery estimation failed! "); + vTaskDelete(battery_monitor_task_handle); + vTaskDelay(portMAX_DELAY); + } - int battery_level; + float capacity = 0.0f; while (1) { - adc_oneshot_read(adc1_handle, KBD_BATTERY_MONITOR_CHANNEL, &adc_raw_value); - - /* Get the battery voltage. */ - adc_voltage = MAX_REF_VOLTAGE * adc_raw_value / 4095; - battery_voltage = adc_voltage * (PULL_UP_RESISTOR + PULL_DOWN_RESISTOR) / PULL_DOWN_RESISTOR; - - /* Get the percent. */ - for (battery_level = 0; battery_level < 11; ++battery_level) { - if (battery_voltage <= ocv_capacity_table[battery_level]) { - break; - } - } - - if (battery_level == 0) { - /* Low battery. */ - g_battery_percent = 0; - } else if (battery_level >= 11) { - /* Over voltage. */ - g_battery_percent = 100; - } else { - g_battery_percent = (battery_level - 1) * 10; - g_battery_percent += ((battery_voltage - ocv_capacity_table[battery_level]) * 10 / ( - ocv_capacity_table[battery_level] - ocv_capacity_table[battery_level - 1])); - } - - ble_hid_battery_report(g_battery_percent); + adc_battery_estimation_get_capacity(adc_battery_estimation_handle, &capacity); + ble_hid_battery_report((int) capacity); /* Sample period. */ vTaskDelay(pdMS_TO_TICKS(10000)); diff --git a/examples/keyboard/main/idf_component.yml b/examples/keyboard/main/idf_component.yml index 9c53e2a33..7fe261ed9 100644 --- a/examples/keyboard/main/idf_component.yml +++ b/examples/keyboard/main/idf_component.yml @@ -1,5 +1,6 @@ version: 0.2.2 dependencies: - idf: ">=5.2" + idf: '>=5.2' espressif/tinyusb: - version: ">=0.15.0~2" + version: '>=0.15.0~2' + espressif/adc_battery_estimation: =* From 66a300c11435744e3b08e26805d71f7ab62aa430 Mon Sep 17 00:00:00 2001 From: Deadline039 <1315374252@qq.com> Date: Mon, 9 Jun 2025 20:45:10 +0800 Subject: [PATCH 4/4] remove(keyboard): remove unused variable --- examples/keyboard/main/battery_adc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/keyboard/main/battery_adc.c b/examples/keyboard/main/battery_adc.c index 5f075407a..4776a3d05 100644 --- a/examples/keyboard/main/battery_adc.c +++ b/examples/keyboard/main/battery_adc.c @@ -15,12 +15,9 @@ #include "bsp/esp-bsp.h" #include "adc_battery_estimation.h" -int g_battery_percent; - static const char *TAG = "BATTERY-ADC"; static TaskHandle_t battery_monitor_task_handle; - static void battery_monitor_task(void *pvParameters); /* Pull up resistor value. Unit: KOhm */