New kernel drivers and device migrations (#563)

This commit is contained in:
Ken Van Hoeylandt
2026-07-14 20:26:57 +02:00
committed by GitHub
parent 955416dac8
commit 8af6204ba1
215 changed files with 6359 additions and 3633 deletions
+2 -3
View File
@@ -1,7 +1,6 @@
file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
file(GLOB_RECURSE SOURCE_FILES source/*.c*)
idf_component_register(
SRCS ${SOURCE_FILES}
INCLUDE_DIRS "Source"
REQUIRES Tactility ButtonControl XPT2046SoftSPI PwmBacklight EstimatedPower ST7789-i8080 driver vfs fatfs
REQUIRES TactilityKernel driver
)
@@ -1,22 +0,0 @@
#include "devices/Power.h"
#include "devices/Display.h"
#include <ButtonControl.h>
#include <Tactility/hal/Configuration.h>
bool initBoot();
using namespace tt::hal;
static std::vector<std::shared_ptr<tt::hal::Device>> createDevices() {
return {
createDisplay(),
std::make_shared<Power>(),
ButtonControl::createOneButtonControl(0)
};
}
extern const Configuration hardwareConfiguration = {
.initBoot = initBoot,
.createDevices = createDevices
};
-48
View File
@@ -1,48 +0,0 @@
#include "devices/Power.h"
#include "devices/Display.h"
#include "PwmBacklight.h"
#include <Tactility/SystemEvents.h>
#include <tactility/log.h>
#include <Tactility/TactilityCore.h>
#define TAG "thmi"
static bool powerOn() {
gpio_config_t power_signal_config = {
.pin_bit_mask = (1ULL << THMI_POWERON_GPIO) | (1ULL << THMI_POWEREN_GPIO),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
if (gpio_config(&power_signal_config) != ESP_OK) {
return false;
}
if (gpio_set_level(THMI_POWERON_GPIO, 1) != ESP_OK) {
return false;
}
if (gpio_set_level(THMI_POWEREN_GPIO, 1) != ESP_OK) {
return false;
}
return true;
}
bool initBoot() {
LOG_I(TAG, "Powering on the board...");
if (!powerOn()) {
LOG_E(TAG, "Failed to power on the board.");
return false;
}
if (!driver::pwmbacklight::init(DISPLAY_BL, 30000)) {
LOG_E(TAG, "Failed to initialize backlight.");
return false;
}
return true;
}
@@ -1,45 +0,0 @@
#include <Xpt2046SoftSpi.h>
#include <Tactility/hal/touch/TouchDevice.h>
#include "Display.h"
#include "PwmBacklight.h"
#include "St7789i8080Display.h"
static bool touchSpiInitialized = false;
static std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
auto config = std::make_unique<Xpt2046SoftSpi::Configuration>(
TOUCH_MOSI_PIN,
TOUCH_MISO_PIN,
TOUCH_SCK_PIN,
TOUCH_CS_PIN,
DISPLAY_HORIZONTAL_RESOLUTION,
DISPLAY_VERTICAL_RESOLUTION
);
return std::make_shared<Xpt2046SoftSpi>(std::move(config));
}
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
// Create configuration
auto config = St7789i8080Display::Configuration(
DISPLAY_CS, // CS
DISPLAY_DC, // DC
DISPLAY_WR, // WR
DISPLAY_RD, // RD
{ DISPLAY_I80_D0, DISPLAY_I80_D1, DISPLAY_I80_D2, DISPLAY_I80_D3,
DISPLAY_I80_D4, DISPLAY_I80_D5, DISPLAY_I80_D6, DISPLAY_I80_D7 }, // D0..D7
DISPLAY_RST, // RST
DISPLAY_BL // BL
);
// Set resolution explicitly
config.horizontalResolution = DISPLAY_HORIZONTAL_RESOLUTION;
config.verticalResolution = DISPLAY_VERTICAL_RESOLUTION;
config.backlightDutyFunction = driver::pwmbacklight::setBacklightDuty;
config.touch = createTouch();
config.invertColor = false;
auto display = std::make_shared<St7789i8080Display>(config);
return display;
}
@@ -1,35 +0,0 @@
#pragma once
#include <driver/gpio.h>
#include <Tactility/hal/display/DisplayDevice.h>
#include "driver/spi_common.h"
class St7789i8080Display;
constexpr auto DISPLAY_CS = GPIO_NUM_6;
constexpr auto DISPLAY_DC = GPIO_NUM_7;
constexpr auto DISPLAY_WR = GPIO_NUM_8;
constexpr auto DISPLAY_RD = GPIO_NUM_NC;
constexpr auto DISPLAY_RST = GPIO_NUM_NC;
constexpr auto DISPLAY_BL = GPIO_NUM_38;
constexpr auto DISPLAY_I80_D0 = GPIO_NUM_48;
constexpr auto DISPLAY_I80_D1 = GPIO_NUM_47;
constexpr auto DISPLAY_I80_D2 = GPIO_NUM_39;
constexpr auto DISPLAY_I80_D3 = GPIO_NUM_40;
constexpr auto DISPLAY_I80_D4 = GPIO_NUM_41;
constexpr auto DISPLAY_I80_D5 = GPIO_NUM_42;
constexpr auto DISPLAY_I80_D6 = GPIO_NUM_45;
constexpr auto DISPLAY_I80_D7 = GPIO_NUM_46;
constexpr auto DISPLAY_HORIZONTAL_RESOLUTION = 240;
constexpr auto DISPLAY_VERTICAL_RESOLUTION = 320;
// Touch (XPT2046, resistive)
constexpr auto TOUCH_SPI_HOST = SPI2_HOST;
constexpr auto TOUCH_MISO_PIN = GPIO_NUM_4;
constexpr auto TOUCH_MOSI_PIN = GPIO_NUM_3;
constexpr auto TOUCH_SCK_PIN = GPIO_NUM_1;
constexpr auto TOUCH_CS_PIN = GPIO_NUM_2;
constexpr auto TOUCH_IRQ_PIN = GPIO_NUM_9;
// Factory function for registration
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();
@@ -1,90 +0,0 @@
#include "Power.h"
#include <driver/adc.h>
#include <tactility/log.h>
constexpr auto* TAG = "Power";
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) {
LOG_W(TAG, "Calibration scheme not supported, skip software calibration");
} else if (efuse_read_result == ESP_ERR_INVALID_VERSION) {
LOG_W(TAG, "eFuse not burnt, skip software calibration");
} else if (efuse_read_result == ESP_OK) {
calibrated = true;
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 {
LOG_W(TAG, "eFuse read failed, skipping calibration");
}
return calibrated;
}
uint32_t Power::adcReadValue() const {
int adc_raw = adc1_get_raw(ADC1_CHANNEL_4);
LOG_D(TAG, "Raw data: %d", adc_raw);
uint32_t voltage;
if (calibrated) {
voltage = esp_adc_cal_raw_to_voltage(adc_raw, &adcCharacteristics);
LOG_D(TAG, "Calibrated data: %d mV", (int)voltage);
} else {
voltage = (adc_raw * 3300) / 4095; // fallback
LOG_D(TAG, "Estimated data: %d mV", (int)voltage);
}
return voltage;
}
bool Power::ensureInitialized() {
if (!initialized) {
if (adc1_config_width(ADC_WIDTH_BIT_12) != ESP_OK) {
LOG_E(TAG, "ADC1 config width failed");
return false;
}
if (adc1_config_channel_atten(ADC1_CHANNEL_4, ADC_ATTEN_DB_11) != ESP_OK) {
LOG_E(TAG, "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;
}
}
@@ -1,33 +0,0 @@
#pragma once
#include <string>
#include <esp_adc_cal.h>
#include <driver/gpio.h>
#include <ChargeFromVoltage.h>
#include <Tactility/hal/power/PowerDevice.h>
constexpr auto THMI_POWEREN_GPIO = GPIO_NUM_10;
constexpr auto THMI_POWERON_GPIO = GPIO_NUM_14;
using tt::hal::power::PowerDevice;
class Power final : public PowerDevice {
ChargeFromVoltage chargeFromAdcVoltage = ChargeFromVoltage(3.3f, 4.2f);
esp_adc_cal_characteristics_t adcCharacteristics;
bool initialized = false;
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;
};
+5
View File
@@ -12,10 +12,15 @@ hardware.tinyUsb=true
hardware.esptoolFlashFreq=120M
hardware.bluetooth=true
dependencies.useDeprecatedHal=false
storage.userDataLocation=SD
display.size=2.8"
display.shape=rectangle
display.dpi=125
touch.calibrationSupported=true
touch.calibrationRequired=false
lvgl.colorDepth=16
+3
View File
@@ -1,3 +1,6 @@
dependencies:
- Platforms/platform-esp32
- Drivers/xpt2046-softspi-module
- Drivers/st7789-i8080-module
- Drivers/button-control-module
dts: lilygo,thmi.dts
+82 -16
View File
@@ -1,14 +1,19 @@
/dts-v1/;
#include <tactility/bindings/root.h>
#include <tactility/bindings/battery_sense.h>
#include <tactility/bindings/esp32_adc_oneshot.h>
#include <tactility/bindings/esp32_ble.h>
#include <tactility/bindings/esp32_wifi_pinned.h>
#include <tactility/bindings/esp32_gpio.h>
#include <tactility/bindings/esp32_i2c.h>
#include <tactility/bindings/esp32_sdmmc.h>
#include <tactility/bindings/esp32_spi.h>
#include <tactility/bindings/display_placeholder.h>
#include <tactility/bindings/pointer_placeholder.h>
#include <tactility/bindings/esp32_i8080.h>
#include <tactility/bindings/esp32_ledc_backlight.h>
#include <tactility/bindings/gpio_hog.h>
#include <bindings/button_control.h>
#include <bindings/st7789_i8080.h>
#include <bindings/xpt2046_softspi.h>
/ {
compatible = "root";
@@ -28,23 +33,84 @@
compatible = "espressif,esp32-gpio";
gpio-count = <49>;
};
spi0 {
compatible = "espressif,esp32-spi";
host = <SPI2_HOST>;
cs-gpios = <&gpio0 6 GPIO_FLAG_NONE>, // Display
<&gpio0 2 GPIO_FLAG_NONE>; // Touch
pin-mosi = <&gpio0 3 GPIO_FLAG_NONE>;
pin-miso = <&gpio0 4 GPIO_FLAG_NONE>;
pin-sclk = <&gpio0 1 GPIO_FLAG_NONE>;
// Board power-enable pins. Must be asserted before the i8080 bus/display below start, since
// devicetree devices are constructed and started earlier (kernel_init()) than the deprecated
// HAL's initBoot() used to run. gpio-hog nodes run in declaration order, so they must stay
// before the i8080 bus node.
power_on {
compatible = "tactility,gpio-hog";
pin = <&gpio0 14 GPIO_FLAG_NONE>;
mode = <GPIO_HOG_MODE_OUTPUT_HIGH>;
};
power_en {
compatible = "tactility,gpio-hog";
pin = <&gpio0 10 GPIO_FLAG_NONE>;
mode = <GPIO_HOG_MODE_OUTPUT_HIGH>;
};
adc0 {
compatible = "espressif,esp32-adc-oneshot";
unit-id = <ADC_UNIT_1>;
channels = <ADC_CHANNEL_4 ADC_ATTEN_DB_12 ADC_BITWIDTH_DEFAULT>;
};
// Battery voltage sits behind a 2:1 divider before reaching the ADC (see the deprecated HAL's
// old Power.cpp: adcReadValue() * 2). 3300mV matches its uncalibrated fallback reference
// voltage. Charge-percent curve is battery-sense's own fixed 3200-4200mV estimate (see
// TactilityKernel/source/drivers/battery_sense.cpp) rather than the old driver's 3300-4200mV
// ChargeFromVoltage curve - a shared kernel driver, not a per-board tunable.
battery-sense {
compatible = "battery-sense";
io-channel = <&adc0 0>;
reference-voltage-mv = <3300>;
multiplier = <2000>;
};
display_backlight {
compatible = "espressif,esp32-ledc-backlight";
// Off by default so display power-on won't show the screen from before the last power loss.
// The display backlight is turned on during the boot process.
status = "disabled";
pin-backlight = <&gpio0 38 GPIO_FLAG_NONE>;
frequency-hz = <30000>;
};
i8080_0 {
compatible = "espressif,esp32-i8080";
pin-dc = <&gpio0 7 GPIO_FLAG_NONE>;
pin-wr = <&gpio0 8 GPIO_FLAG_NONE>;
pin-d0 = <&gpio0 48 GPIO_FLAG_NONE>;
pin-d1 = <&gpio0 47 GPIO_FLAG_NONE>;
pin-d2 = <&gpio0 39 GPIO_FLAG_NONE>;
pin-d3 = <&gpio0 40 GPIO_FLAG_NONE>;
pin-d4 = <&gpio0 41 GPIO_FLAG_NONE>;
pin-d5 = <&gpio0 42 GPIO_FLAG_NONE>;
pin-d6 = <&gpio0 45 GPIO_FLAG_NONE>;
pin-d7 = <&gpio0 46 GPIO_FLAG_NONE>;
// horizontal-resolution * vertical-resolution / 10 (partial buffer) * 2 bytes/pixel
max-transfer-bytes = <15360>;
cs-gpios = <&gpio0 6 GPIO_FLAG_NONE>;
display@0 {
compatible = "display-placeholder";
compatible = "sitronix,st7789-i8080";
horizontal-resolution = <240>;
vertical-resolution = <320>;
pixel-clock-hz = <16000000>;
backlight = <&display_backlight>;
gamma-curve = <2>;
};
};
touch@1 {
compatible = "pointer-placeholder";
};
touch {
compatible = "xptek,xpt2046-softspi";
pin-mosi = <&gpio0 3 GPIO_FLAG_NONE>;
pin-miso = <&gpio0 4 GPIO_FLAG_NONE>;
pin-sck = <&gpio0 1 GPIO_FLAG_NONE>;
pin-cs = <&gpio0 2 GPIO_FLAG_NONE>;
x-max = <240>;
y-max = <320>;
};
sdmmc0 {