Implement CardputerPower and improve EstimatedPower driver (#335)
This commit is contained in:
parent
d5c94c7a8a
commit
ce8ac61d42
@ -3,5 +3,5 @@ file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
|
||||
idf_component_register(
|
||||
SRCS ${SOURCE_FILES}
|
||||
INCLUDE_DIRS "Source"
|
||||
REQUIRES Tactility esp_lvgl_port esp_lcd ST7789 PwmBacklight driver vfs fatfs
|
||||
REQUIRES Tactility esp_lvgl_port esp_lcd ST7789 PwmBacklight driver esp_adc EstimatedPower vfs fatfs
|
||||
)
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include "devices/SdCard.h"
|
||||
#include "devices/CardputerEncoder.h"
|
||||
#include "devices/CardputerKeyboard.h"
|
||||
#include "devices/CardputerPower.h"
|
||||
|
||||
#include <lvgl.h>
|
||||
#include <Tactility/lvgl/LvglSync.h>
|
||||
@ -17,7 +18,8 @@ static DeviceVector createDevices() {
|
||||
createSdCard(),
|
||||
createDisplay(),
|
||||
std::make_shared<CardputerKeyboard>(),
|
||||
std::make_shared<CardputerEncoder>()
|
||||
std::make_shared<CardputerEncoder>(),
|
||||
std::make_shared<CardputerPower>()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
85
Boards/M5stackCardputer/Source/devices/CardputerPower.cpp
Normal file
85
Boards/M5stackCardputer/Source/devices/CardputerPower.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
#include "CardputerPower.h"
|
||||
|
||||
#include <Tactility/Log.h>
|
||||
#include <driver/adc.h>
|
||||
|
||||
constexpr auto* TAG = "CardputerPower";
|
||||
|
||||
bool CardputerPower::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) {
|
||||
TT_LOG_W(TAG, "Calibration scheme not supported, skip software calibration");
|
||||
} else if (efuse_read_result == ESP_ERR_INVALID_VERSION) {
|
||||
TT_LOG_W(TAG, "eFuse not burnt, skip software calibration");
|
||||
} else if (efuse_read_result == ESP_OK) {
|
||||
calibrated = true;
|
||||
TT_LOG_I(TAG, "Calibration success");
|
||||
esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, static_cast<adc_bits_width_t>(ADC_WIDTH_BIT_DEFAULT), 0, &adcCharacteristics);
|
||||
} else {
|
||||
TT_LOG_W(TAG, "eFuse read failed, skipping calibration");
|
||||
}
|
||||
|
||||
return calibrated;
|
||||
}
|
||||
|
||||
uint32_t CardputerPower::adcReadValue() const {
|
||||
int adc_raw = adc1_get_raw(ADC1_CHANNEL_9);
|
||||
TT_LOG_D(TAG, "Raw data: %d", adc_raw);
|
||||
float voltage;
|
||||
if (calibrated) {
|
||||
voltage = esp_adc_cal_raw_to_voltage(adc_raw, &adcCharacteristics);
|
||||
TT_LOG_D(TAG, "Calibrated data: %d mV", voltage);
|
||||
} else {
|
||||
voltage = 0.0f;
|
||||
}
|
||||
return voltage;
|
||||
}
|
||||
|
||||
bool CardputerPower::ensureInitialized() {
|
||||
if (!initialized) {
|
||||
calibrated = adcInitCalibration();
|
||||
|
||||
if (adc1_config_width(static_cast<adc_bits_width_t>(ADC_WIDTH_BIT_DEFAULT)) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "ADC1 config width failed");
|
||||
return false;
|
||||
}
|
||||
if (adc1_config_channel_atten(ADC1_CHANNEL_9, ADC_ATTEN_DB_11) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "ADC1 config attenuation failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CardputerPower::supportsMetric(MetricType type) const {
|
||||
switch (type) {
|
||||
using enum MetricType;
|
||||
case BatteryVoltage:
|
||||
case ChargeLevel:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CardputerPower::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;
|
||||
}
|
||||
}
|
||||
28
Boards/M5stackCardputer/Source/devices/CardputerPower.h
Normal file
28
Boards/M5stackCardputer/Source/devices/CardputerPower.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <Tactility/hal/power/PowerDevice.h>
|
||||
#include <ChargeFromVoltage.h>
|
||||
#include <esp_adc_cal.h>
|
||||
|
||||
using tt::hal::power::PowerDevice;
|
||||
|
||||
class CardputerPower 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 "Cardputer Power"; }
|
||||
std::string getDescription() const override { return "Power measurement via ADC"; }
|
||||
|
||||
bool supportsMetric(MetricType type) const override;
|
||||
bool getMetric(MetricType type, MetricData& data) override;
|
||||
};
|
||||
@ -2,19 +2,14 @@
|
||||
#include <Tactility/Log.h>
|
||||
#include <algorithm>
|
||||
|
||||
constexpr auto TAG = "EstimatePower";
|
||||
constexpr auto TAG = "ChargeFromAdcV";
|
||||
constexpr auto MAX_VOLTAGE_SAMPLES = 15;
|
||||
|
||||
uint8_t ChargeFromAdcVoltage::estimateChargeLevelFromVoltage(uint32_t milliVolt) const {
|
||||
const float volts = std::min((float)milliVolt / 1000.f, configuration.batteryVoltageMax);
|
||||
const float voltage_percentage = (volts - configuration.batteryVoltageMin) / (configuration.batteryVoltageMax - configuration.batteryVoltageMin);
|
||||
const float voltage_factor = std::min(1.0f, voltage_percentage);
|
||||
const auto charge_level = (uint8_t) (voltage_factor * 100.f);
|
||||
TT_LOG_V(TAG, "mV = %lu, scaled = %.2f, factor = %.2f, result = %d", milliVolt, volts, voltage_factor, charge_level);
|
||||
return charge_level;
|
||||
}
|
||||
|
||||
ChargeFromAdcVoltage::ChargeFromAdcVoltage(const Configuration& configuration) : configuration(configuration) {
|
||||
ChargeFromAdcVoltage::ChargeFromAdcVoltage(
|
||||
const Configuration& configuration,
|
||||
float voltageMin,
|
||||
float voltageMax
|
||||
) : configuration(configuration), chargeFromVoltage(voltageMin, voltageMax) {
|
||||
if (adc_oneshot_new_unit(&configuration.adcConfig, &adcHandle) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "ADC config failed");
|
||||
return;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <ChargeFromVoltage.h>
|
||||
#include <esp_adc/adc_oneshot.h>
|
||||
|
||||
class ChargeFromAdcVoltage {
|
||||
@ -7,11 +8,9 @@ class ChargeFromAdcVoltage {
|
||||
public:
|
||||
|
||||
struct Configuration {
|
||||
adc_channel_t adcChannel = ADC_CHANNEL_3;
|
||||
float adcMultiplier = 1.0f;
|
||||
float adcRefVoltage = 3.3f;
|
||||
float batteryVoltageMin = 3.2f;
|
||||
float batteryVoltageMax = 4.2f;
|
||||
adc_channel_t adcChannel = ADC_CHANNEL_3;
|
||||
adc_oneshot_unit_init_cfg_t adcConfig = {
|
||||
.unit_id = ADC_UNIT_1,
|
||||
.clk_src = ADC_RTC_CLK_SRC_DEFAULT,
|
||||
@ -27,16 +26,17 @@ private:
|
||||
|
||||
adc_oneshot_unit_handle_t adcHandle = nullptr;
|
||||
Configuration configuration;
|
||||
ChargeFromVoltage chargeFromVoltage;
|
||||
|
||||
public:
|
||||
|
||||
explicit ChargeFromAdcVoltage(const Configuration& configuration);
|
||||
explicit ChargeFromAdcVoltage(const Configuration& configuration, float voltageMin = 3.2f, float voltageMax = 4.2f);
|
||||
|
||||
~ChargeFromAdcVoltage();
|
||||
|
||||
uint8_t estimateChargeLevelFromVoltage(uint32_t milliVolt) const;
|
||||
|
||||
bool readBatteryVoltageSampled(uint32_t& output) const;
|
||||
|
||||
bool readBatteryVoltageOnce(uint32_t& output) const;
|
||||
|
||||
uint8_t estimateChargeLevelFromVoltage(uint32_t milliVolt) const { return chargeFromVoltage.estimateCharge(milliVolt); }
|
||||
};
|
||||
|
||||
16
Drivers/EstimatedPower/Source/ChargeFromVoltage.cpp
Normal file
16
Drivers/EstimatedPower/Source/ChargeFromVoltage.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
#include "ChargeFromVoltage.h"
|
||||
#include <Tactility/Log.h>
|
||||
|
||||
constexpr auto* TAG = "ChargeFromVoltage";
|
||||
|
||||
uint8_t ChargeFromVoltage::estimateCharge(uint32_t milliVolt) const {
|
||||
const float volts = std::min((float)milliVolt / 1000.f, batteryVoltageMax);
|
||||
if (volts < batteryVoltageMin) {
|
||||
return 0;
|
||||
}
|
||||
const float voltage_percentage = (volts - batteryVoltageMin) / (batteryVoltageMax - batteryVoltageMin);
|
||||
const float voltage_factor = std::min(1.0f, voltage_percentage);
|
||||
const auto charge_level = (uint8_t) (voltage_factor * 100.f);
|
||||
TT_LOG_D(TAG, "mV = %lu, scaled = %.2f, factor = %.2f, result = %d", milliVolt, volts, voltage_factor, charge_level);
|
||||
return charge_level;
|
||||
}
|
||||
22
Drivers/EstimatedPower/Source/ChargeFromVoltage.h
Normal file
22
Drivers/EstimatedPower/Source/ChargeFromVoltage.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class ChargeFromVoltage {
|
||||
|
||||
float batteryVoltageMin;
|
||||
float batteryVoltageMax;
|
||||
|
||||
public:
|
||||
|
||||
explicit ChargeFromVoltage(float voltageMin = 3.2f, float voltageMax = 4.2f) :
|
||||
batteryVoltageMin(voltageMin),
|
||||
batteryVoltageMax(voltageMax)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @param milliVolt
|
||||
* @return a value in the rage of [0, 100] which represents [0%, 100%] charge
|
||||
*/
|
||||
uint8_t estimateCharge(uint32_t milliVolt) const;
|
||||
};
|
||||
@ -31,8 +31,6 @@ std::shared_ptr<PowerApp> _Nullable optApp() {
|
||||
|
||||
class PowerApp : public App {
|
||||
|
||||
private:
|
||||
|
||||
Timer update_timer = Timer(Timer::Type::Periodic, []() { onTimer(); });
|
||||
|
||||
std::shared_ptr<hal::power::PowerDevice> power;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user