diff --git a/Devices/lilygo-thmi-s3/Source/Configuration.cpp b/Devices/lilygo-thmi-s3/Source/Configuration.cpp index 817da37e..8d04e56f 100644 --- a/Devices/lilygo-thmi-s3/Source/Configuration.cpp +++ b/Devices/lilygo-thmi-s3/Source/Configuration.cpp @@ -11,9 +11,9 @@ using namespace tt::hal; static std::vector> createDevices() { return { - createPower(), createSdCard(), createDisplay(), + std::make_shared(), ButtonControl::createOneButtonControl(0) }; } diff --git a/Devices/lilygo-thmi-s3/Source/devices/Power.cpp b/Devices/lilygo-thmi-s3/Source/devices/Power.cpp index febacad1..b24a9411 100644 --- a/Devices/lilygo-thmi-s3/Source/devices/Power.cpp +++ b/Devices/lilygo-thmi-s3/Source/devices/Power.cpp @@ -1,12 +1,90 @@ #include "Power.h" -#include -#include +#include +#include -std::shared_ptr createPower() { - ChargeFromAdcVoltage::Configuration configuration; - // 2.0 ratio, but +.11 added as display voltage sag compensation. - configuration.adcMultiplier = 2.11; +static const auto LOGGER = tt::Logger("Power"); - return std::make_shared(configuration); -} \ No newline at end of file +bool Power::adcInitCalibration() { + bool calibrated = false; + + esp_err_t efuse_read_result = esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP_FIT); + if (efuse_read_result == ESP_ERR_NOT_SUPPORTED) { + LOGGER.warn("Calibration scheme not supported, skip software calibration"); + } else if (efuse_read_result == ESP_ERR_INVALID_VERSION) { + LOGGER.warn("eFuse not burnt, skip software calibration"); + } else if (efuse_read_result == ESP_OK) { + calibrated = true; + LOGGER.info("Calibration success"); + esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, static_cast(ADC_WIDTH_BIT_DEFAULT), 0, &adcCharacteristics); + } else { + LOGGER.warn("eFuse read failed, skipping calibration"); + } + + return calibrated; +} + +uint32_t Power::adcReadValue() const { + int adc_raw = adc1_get_raw(ADC1_CHANNEL_4); + LOGGER.debug("Raw data: {}", adc_raw); + + uint32_t voltage; + + if (calibrated) { + voltage = esp_adc_cal_raw_to_voltage(adc_raw, &adcCharacteristics); + LOGGER.debug("Calibrated data: {} mV", voltage); + } else { + voltage = (adc_raw * 3300) / 4095; // fallback + LOGGER.debug("Estimated data: {} mV", voltage); + } + + return voltage; +} + +bool Power::ensureInitialized() { + if (!initialized) { + + if (adc1_config_width(ADC_WIDTH_BIT_12) != ESP_OK) { + LOGGER.error("ADC1 config width failed"); + return false; + } + + if (adc1_config_channel_atten(ADC1_CHANNEL_4, ADC_ATTEN_DB_11) != ESP_OK) { + LOGGER.error("ADC1 config attenuation failed"); + return false; + } + + calibrated = adcInitCalibration(); + + initialized = true; + } + return true; +} + +bool Power::supportsMetric(MetricType type) const { + switch (type) { + using enum MetricType; + case BatteryVoltage: + case ChargeLevel: + return true; + default: + return false; + } +} + +bool Power::getMetric(MetricType type, MetricData& data) { + if (!ensureInitialized()) { + return false; + } + + switch (type) { + case MetricType::BatteryVoltage: + data.valueAsUint32 = adcReadValue() * 2; + return true; + case MetricType::ChargeLevel: + data.valueAsUint8 = chargeFromAdcVoltage.estimateCharge(adcReadValue() * 2); + return true; + default: + return false; + } +} diff --git a/Devices/lilygo-thmi-s3/Source/devices/Power.h b/Devices/lilygo-thmi-s3/Source/devices/Power.h index f54de935..ed7be56f 100644 --- a/Devices/lilygo-thmi-s3/Source/devices/Power.h +++ b/Devices/lilygo-thmi-s3/Source/devices/Power.h @@ -1,10 +1,33 @@ #pragma once -#include -#include +#include +#include #include +#include +#include constexpr auto THMI_S3_POWEREN_GPIO = GPIO_NUM_10; constexpr auto THMI_S3_POWERON_GPIO = GPIO_NUM_14; -std::shared_ptr createPower(); +using tt::hal::power::PowerDevice; + +class Power final : public PowerDevice { + + ChargeFromVoltage chargeFromAdcVoltage = ChargeFromVoltage(3.3f, 4.2f); + bool initialized = false; + esp_adc_cal_characteristics_t adcCharacteristics; + bool calibrated = false; + + bool adcInitCalibration(); + uint32_t adcReadValue() const; + + bool ensureInitialized(); + +public: + + std::string getName() const override { return "T-hmi Power"; } + std::string getDescription() const override { return "Power measurement via ADC"; } + + bool supportsMetric(MetricType type) const override; + bool getMetric(MetricType type, MetricData& data) override; +};