From 3a0c42f9240eedfbc6a1e94ad3a59c52664fb5b5 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Mon, 28 Aug 2023 13:26:53 +1000 Subject: Move battery measurement to its own class --- src/drivers/CMakeLists.txt | 2 +- src/drivers/adc.cpp | 67 ++++++++++++++++++++++++++++ src/drivers/battery.cpp | 97 ----------------------------------------- src/drivers/include/adc.hpp | 37 ++++++++++++++++ src/drivers/include/battery.hpp | 39 ----------------- 5 files changed, 105 insertions(+), 137 deletions(-) create mode 100644 src/drivers/adc.cpp delete mode 100644 src/drivers/battery.cpp create mode 100644 src/drivers/include/adc.hpp delete mode 100644 src/drivers/include/battery.hpp (limited to 'src/drivers') diff --git a/src/drivers/CMakeLists.txt b/src/drivers/CMakeLists.txt index a64495f0..1df58f72 100644 --- a/src/drivers/CMakeLists.txt +++ b/src/drivers/CMakeLists.txt @@ -3,7 +3,7 @@ # SPDX-License-Identifier: GPL-3.0-only idf_component_register( - SRCS "touchwheel.cpp" "i2s_dac.cpp" "gpios.cpp" "battery.cpp" "storage.cpp" "i2c.cpp" + SRCS "touchwheel.cpp" "i2s_dac.cpp" "gpios.cpp" "adc.cpp" "storage.cpp" "i2c.cpp" "spi.cpp" "display.cpp" "display_init.cpp" "samd.cpp" "relative_wheel.cpp" "wm8523.cpp" "nvs.cpp" "bluetooth.cpp" INCLUDE_DIRS "include" diff --git a/src/drivers/adc.cpp b/src/drivers/adc.cpp new file mode 100644 index 00000000..56d2cbb4 --- /dev/null +++ b/src/drivers/adc.cpp @@ -0,0 +1,67 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include "adc.hpp" +#include + +#include "esp_adc/adc_cali.h" +#include "esp_adc/adc_cali_scheme.h" +#include "esp_adc/adc_oneshot.h" +#include "hal/adc_types.h" + +namespace drivers { + +static const adc_bitwidth_t kAdcBitWidth = ADC_BITWIDTH_12; +static const adc_unit_t kAdcUnit = ADC_UNIT_1; +// Max battery voltage should be a little over 2V due to our divider, so we need +// the max attenuation to properly handle the full range. +static const adc_atten_t kAdcAttenuation = ADC_ATTEN_DB_11; +// Corresponds to SENSOR_VP. +static const adc_channel_t kAdcChannel = ADC_CHANNEL_0; + +AdcBattery::AdcBattery() { + adc_oneshot_unit_init_cfg_t unit_config = { + .unit_id = kAdcUnit, + }; + ESP_ERROR_CHECK(adc_oneshot_new_unit(&unit_config, &adc_handle_)); + + adc_oneshot_chan_cfg_t channel_config = { + .atten = kAdcAttenuation, + .bitwidth = kAdcBitWidth, + }; + ESP_ERROR_CHECK( + adc_oneshot_config_channel(adc_handle_, kAdcChannel, &channel_config)); + + // calibrate + // TODO: compile-time assert our scheme is available + adc_cali_line_fitting_config_t calibration_config = { + .unit_id = kAdcUnit, + .atten = kAdcAttenuation, + .bitwidth = kAdcBitWidth, + }; + ESP_ERROR_CHECK(adc_cali_create_scheme_line_fitting( + &calibration_config, &adc_calibration_handle_)); +} + +AdcBattery::~AdcBattery() { + adc_cali_delete_scheme_line_fitting(adc_calibration_handle_); + ESP_ERROR_CHECK(adc_oneshot_del_unit(adc_handle_)); +} + +auto AdcBattery::Millivolts() -> uint32_t { + // GPIO 34 + int raw = 0; + ESP_ERROR_CHECK(adc_oneshot_read(adc_handle_, kAdcChannel, &raw)); + + int voltage = 0; + ESP_ERROR_CHECK( + adc_cali_raw_to_voltage(adc_calibration_handle_, raw, &voltage)); + + // Voltage divider halves the battery voltage to get it into the ADC's range. + return voltage * 2; +} + +} // namespace drivers diff --git a/src/drivers/battery.cpp b/src/drivers/battery.cpp deleted file mode 100644 index 1755fd64..00000000 --- a/src/drivers/battery.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#include "battery.hpp" -#include - -#include "esp_adc/adc_cali.h" -#include "esp_adc/adc_cali_scheme.h" -#include "esp_adc/adc_oneshot.h" -#include "hal/adc_types.h" - -namespace drivers { - -/* - * Battery voltage, in millivolts, at which the battery charger IC will stop - * charging. - */ -static const uint32_t kFullChargeMilliVolts = 4200; - -/* - * Battery voltage, in millivolts, at which *we* will consider the battery to - * be completely discharged. This is intentionally higher than the charger IC - * cut-off and the protection on the battery itself; we want to make sure we - * finish up and have everything unmounted and snoozing before the BMS cuts us - * off. - */ -static const uint32_t kEmptyChargeMilliVolts = 3200; // BMS limit is 3100. - -static const adc_bitwidth_t kAdcBitWidth = ADC_BITWIDTH_12; -static const adc_unit_t kAdcUnit = ADC_UNIT_1; -// Max battery voltage should be a little over 2V due to our divider, so we need -// the max attenuation to properly handle the full range. -static const adc_atten_t kAdcAttenuation = ADC_ATTEN_DB_11; -// Corresponds to SENSOR_VP. -static const adc_channel_t kAdcChannel = ADC_CHANNEL_0; - -Battery::Battery() { - adc_oneshot_unit_init_cfg_t unit_config = { - .unit_id = kAdcUnit, - }; - ESP_ERROR_CHECK(adc_oneshot_new_unit(&unit_config, &adc_handle_)); - - adc_oneshot_chan_cfg_t channel_config = { - .atten = kAdcAttenuation, - .bitwidth = kAdcBitWidth, - }; - ESP_ERROR_CHECK( - adc_oneshot_config_channel(adc_handle_, kAdcChannel, &channel_config)); - - // calibrate - // TODO: compile-time assert our scheme is available - adc_cali_line_fitting_config_t calibration_config = { - .unit_id = kAdcUnit, - .atten = kAdcAttenuation, - .bitwidth = kAdcBitWidth, - }; - ESP_ERROR_CHECK(adc_cali_create_scheme_line_fitting( - &calibration_config, &adc_calibration_handle_)); - - UpdatePercent(); -} - -Battery::~Battery() { - adc_cali_delete_scheme_line_fitting(adc_calibration_handle_); - ESP_ERROR_CHECK(adc_oneshot_del_unit(adc_handle_)); -} - -auto Battery::Millivolts() -> uint32_t { - // GPIO 34 - int raw = 0; - ESP_ERROR_CHECK(adc_oneshot_read(adc_handle_, kAdcChannel, &raw)); - - int voltage = 0; - ESP_ERROR_CHECK( - adc_cali_raw_to_voltage(adc_calibration_handle_, raw, &voltage)); - - // Voltage divider halves the battery voltage to get it into the ADC's range. - return voltage * 2; -} - -auto Battery::UpdatePercent() -> bool { - auto old_percent = percent_; - // FIXME: So what we *should* do here is measure the actual real-life - // time from full battery -> empty battery, store it in NVS, then rely on - // that. If someone could please do this, it would be lovely. Thanks! - uint32_t mV = std::max(Millivolts(), kEmptyChargeMilliVolts); - percent_ = static_cast(std::min( - std::max(0.0, mV - kEmptyChargeMilliVolts) / - (kFullChargeMilliVolts - kEmptyChargeMilliVolts) * 100.0, - 100.0)); - return old_percent != percent_; -} - -} // namespace drivers diff --git a/src/drivers/include/adc.hpp b/src/drivers/include/adc.hpp new file mode 100644 index 00000000..3e94a9ee --- /dev/null +++ b/src/drivers/include/adc.hpp @@ -0,0 +1,37 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include + +#include "esp_adc/adc_cali.h" +#include "esp_adc/adc_oneshot.h" +#include "esp_err.h" +#include "result.hpp" + +namespace drivers { + +/* + * Handles measuring the battery's current voltage. + */ +class AdcBattery { + public: + static auto Create() -> AdcBattery* { return new AdcBattery(); } + AdcBattery(); + ~AdcBattery(); + + /** + * Returns the current battery level in millivolts. + */ + auto Millivolts() -> uint32_t; + + private: + adc_oneshot_unit_handle_t adc_handle_; + adc_cali_handle_t adc_calibration_handle_; +}; + +} // namespace drivers diff --git a/src/drivers/include/battery.hpp b/src/drivers/include/battery.hpp deleted file mode 100644 index 64a00135..00000000 --- a/src/drivers/include/battery.hpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2023 jacqueline - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#pragma once - -#include - -#include "esp_adc/adc_cali.h" -#include "esp_adc/adc_oneshot.h" -#include "esp_err.h" -#include "result.hpp" - -namespace drivers { - -class Battery { - public: - static auto Create() -> Battery* { return new Battery(); } - Battery(); - ~Battery(); - - /** - * Returns the current battery level in millivolts. - */ - auto Millivolts() -> uint32_t; - - auto UpdatePercent() -> bool; - auto Percent() -> uint_fast8_t { return percent_; } - - private: - adc_oneshot_unit_handle_t adc_handle_; - adc_cali_handle_t adc_calibration_handle_; - - uint_fast8_t percent_; -}; - -} // namespace drivers -- cgit v1.2.3