SPI device migration (#490)

- Implement SPI devices in dts files for all devices
- Removed `tt::hal::spi` HAL and its configurations
- Fix for devicetree generator "boolean" support
- Remove unused custom locks in all `DisplayDevice` implementations
- Fixed some bugs with devices
- Updated XPT2046 driver
- Fix for `WifiEsp` deadlock
- Export a lot of new `math.h` symbols with `tt_init.cpp`
- Created `SpiDeviceLock` in `TactilityCore` as a wrapper for kernel SPI locking
- Improved `TactilityKernel` SPI driver.
This commit is contained in:
Ken Van Hoeylandt
2026-02-08 22:14:18 +01:00
committed by GitHub
parent 74127a5f6c
commit d27404964a
177 changed files with 1091 additions and 2205 deletions
@@ -121,7 +121,6 @@ std::shared_ptr<tt::hal::display::DisplayDriver> EspLcdDisplay::getDisplayDriver
displayDriver = std::make_shared<EspLcdDisplayDriver>(
panelHandle,
lock,
lvgl_port_config.hres,
lvgl_port_config.vres,
color_format
+3 -6
View File
@@ -1,6 +1,5 @@
#pragma once
#include <Tactility/Lock.h>
#include <tactility/check.h>
#include <Tactility/hal/display/DisplayDevice.h>
@@ -14,8 +13,8 @@ class EspLcdDisplay : public tt::hal::display::DisplayDevice {
esp_lcd_panel_handle_t panelHandle = nullptr;
lv_display_t* lvglDisplay = nullptr;
std::shared_ptr<tt::hal::display::DisplayDriver> displayDriver;
std::shared_ptr<tt::Lock> lock;
lcd_rgb_element_order_t rgbElementOrder;
/** @warning This is never changed, so a driver that needs BGR is not supported */
lcd_rgb_element_order_t rgbElementOrder = LCD_RGB_ELEMENT_ORDER_RGB;
protected:
@@ -34,12 +33,10 @@ protected:
public:
EspLcdDisplay(std::shared_ptr<tt::Lock> lock) : lock(lock) {}
EspLcdDisplay() = default;
~EspLcdDisplay() override;
std::shared_ptr<tt::Lock> getLock() const { return lock; }
bool start() final;
bool stop() final;
@@ -1,6 +1,5 @@
#pragma once
#include <Tactility/Mutex.h>
#include <Tactility/hal/display/DisplayDriver.h>
#include <esp_lcd_panel_ops.h>
@@ -8,7 +7,6 @@
class EspLcdDisplayDriver : public tt::hal::display::DisplayDriver {
esp_lcd_panel_handle_t panelHandle;
std::shared_ptr<tt::Lock> lock;
uint16_t hRes;
uint16_t vRes;
tt::hal::display::ColorFormat colorFormat;
@@ -17,11 +15,10 @@ public:
EspLcdDisplayDriver(
esp_lcd_panel_handle_t panelHandle,
std::shared_ptr<tt::Lock> lock,
uint16_t hRes,
uint16_t vRes,
tt::hal::display::ColorFormat colorFormat
) : panelHandle(panelHandle), lock(lock), hRes(hRes), vRes(vRes), colorFormat(colorFormat) {}
) : panelHandle(panelHandle), hRes(hRes), vRes(vRes), colorFormat(colorFormat) {}
tt::hal::display::ColorFormat getColorFormat() const override {
return colorFormat;
@@ -35,6 +32,4 @@ public:
uint16_t getPixelWidth() const override { return hRes; }
uint16_t getPixelHeight() const override { return vRes; }
std::shared_ptr<tt::Lock> getLock() const override { return lock; }
};
@@ -221,7 +221,6 @@ std::shared_ptr<tt::hal::display::DisplayDriver> EspLcdDisplayV2::getDisplayDriv
displayDriver = std::make_shared<EspLcdDisplayDriver>(
panelHandle,
lock,
lvgl_port_config.hres,
lvgl_port_config.vres,
color_format
+2 -10
View File
@@ -1,6 +1,5 @@
#pragma once
#include <Tactility/Lock.h>
#include <tactility/check.h>
#include <Tactility/hal/display/DisplayDevice.h>
#include <esp_lcd_panel_dev.h>
@@ -35,7 +34,6 @@ class EspLcdDisplayV2 : public tt::hal::display::DisplayDevice {
esp_lcd_panel_handle_t _Nullable panelHandle = nullptr;
lv_display_t* _Nullable lvglDisplay = nullptr;
std::shared_ptr<tt::hal::display::DisplayDriver> _Nullable displayDriver;
std::shared_ptr<tt::Lock> lock;
std::shared_ptr<EspLcdConfiguration> configuration;
bool applyConfiguration() const;
@@ -67,18 +65,12 @@ protected:
public:
EspLcdDisplayV2(const std::shared_ptr<EspLcdConfiguration>& configuration, const std::shared_ptr<tt::Lock>& lock) :
lock(lock),
explicit EspLcdDisplayV2(const std::shared_ptr<EspLcdConfiguration>& configuration) :
configuration(configuration)
{
assert(configuration != nullptr);
assert(lock != nullptr);
}
{}
~EspLcdDisplayV2() override;
std::shared_ptr<tt::Lock> getLock() const { return lock; }
bool start() final;
bool stop() final;
@@ -1,7 +1,8 @@
#pragma once
#include "EspLcdDisplayV2.h"
#include <Tactility/hal/spi/Spi.h>
#include <driver/spi_common.h>
#include <esp_lcd_io_spi.h>
#include <esp_lcd_types.h>
@@ -23,7 +24,7 @@ public:
};
explicit EspLcdSpiDisplay(const std::shared_ptr<EspLcdConfiguration>& configuration, const std::shared_ptr<SpiConfiguration> spiConfiguration, int gammaCurveCount) :
EspLcdDisplayV2(configuration, tt::hal::spi::getLock(spiConfiguration->spiHostDevice)),
EspLcdDisplayV2(configuration),
spiConfiguration(spiConfiguration),
gammaCurveCount(gammaCurveCount)
{}
+2 -9
View File
@@ -1,11 +1,10 @@
#pragma once
#include "Tactility/hal/spi/Spi.h"
#include <EspLcdDisplay.h>
#include <Tactility/hal/display/DisplayDevice.h>
#include <driver/gpio.h>
#include <driver/spi_common.h>
#include <esp_lcd_panel_io.h>
#include <esp_lcd_types.h>
#include <functional>
@@ -13,8 +12,6 @@
class Gc9a01Display final : public EspLcdDisplay {
std::shared_ptr<tt::Lock> lock;
public:
class Configuration {
@@ -83,12 +80,8 @@ private:
public:
explicit Gc9a01Display(std::unique_ptr<Configuration> inConfiguration) :
EspLcdDisplay(tt::hal::spi::getLock(inConfiguration->spiHostDevice)),
configuration(std::move(inConfiguration)
) {
assert(configuration != nullptr);
assert(getLock() != nullptr);
}
) {}
std::string getName() const override { return "GC9A01"; }
-2
View File
@@ -8,8 +8,6 @@
class Ili934xDisplay final : public EspLcdSpiDisplay {
std::shared_ptr<tt::Lock> lock;
public:
/** Minimal set of overrides for EspLcdConfiguration */
+2 -3
View File
@@ -1,7 +1,7 @@
#pragma once
#include <Tactility/hal/display/DisplayDevice.h>
#include <Tactility/hal/spi/Spi.h>
#include <driver/spi_common.h>
#include <EspLcdDisplay.h>
@@ -28,7 +28,7 @@ public:
bool mirrorX = false,
bool mirrorY = false,
bool invertColor = false,
uint32_t bufferSize = 0 // Size in pixel count. 0 means default, which is 1/20 of the screen size
uint32_t bufferSize = 0 // Size in pixel count. 0 means default, which is 1/10 of the screen size
) : spiHostDevice(spiHostDevice),
csPin(csPin),
dcPin(dcPin),
@@ -75,7 +75,6 @@ private:
public:
explicit Ili9488Display(std::unique_ptr<Configuration> inConfiguration) :
EspLcdDisplay(tt::hal::spi::getLock(inConfiguration->spiHostDevice)),
configuration(std::move(inConfiguration)
) {
assert(configuration != nullptr);
+2 -5
View File
@@ -1,15 +1,12 @@
#pragma once
#include <Tactility/hal/display/DisplayDevice.h>
#include <Tactility/RecursiveMutex.h>
#include <EspLcdDisplayDriver.h>
#include <esp_lcd_panel_rgb.h>
#include <esp_lvgl_port_disp.h>
class RgbDisplay final : public tt::hal::display::DisplayDevice {
std::shared_ptr<tt::Lock> lock = std::make_shared<tt::RecursiveMutex>();
public:
struct BufferConfiguration final {
@@ -75,7 +72,7 @@ public:
assert(configuration != nullptr);
}
~RgbDisplay();
~RgbDisplay() override;
std::string getName() const override { return "RGB Display"; }
std::string getDescription() const override { return "RGB Display"; }
@@ -108,7 +105,7 @@ public:
std::shared_ptr<tt::hal::display::DisplayDriver> _Nullable getDisplayDriver() override {
if (displayDriver == nullptr) {
auto config = getLvglPortDisplayConfig();
displayDriver = std::make_shared<EspLcdDisplayDriver>(panelHandle, lock, config.hres, config.vres, tt::hal::display::ColorFormat::RGB888);
displayDriver = std::make_shared<EspLcdDisplayDriver>(panelHandle, config.hres, config.vres, tt::hal::display::ColorFormat::RGB888);
}
return displayDriver;
}
-1
View File
@@ -57,7 +57,6 @@ private:
public:
explicit Ssd1306Display(std::unique_ptr<Configuration> inConfiguration) :
EspLcdDisplay(nullptr),
configuration(std::move(inConfiguration))
{
assert(configuration != nullptr);
+2 -9
View File
@@ -1,11 +1,10 @@
#pragma once
#include "Tactility/hal/spi/Spi.h"
#include <EspLcdDisplay.h>
#include <Tactility/hal/display/DisplayDevice.h>
#include <driver/gpio.h>
#include <driver/spi_common.h>
#include <esp_lcd_panel_io.h>
#include <esp_lcd_types.h>
#include <functional>
@@ -13,8 +12,6 @@
class St7735Display final : public EspLcdDisplay {
std::shared_ptr<tt::Lock> lock;
public:
class Configuration {
@@ -88,12 +85,8 @@ private:
public:
explicit St7735Display(std::unique_ptr<Configuration> inConfiguration) :
EspLcdDisplay(tt::hal::spi::getLock(inConfiguration->spiHostDevice)),
configuration(std::move(inConfiguration)
) {
assert(configuration != nullptr);
assert(getLock() != nullptr);
}
) {}
std::string getName() const override { return "ST7735"; }
-2
View File
@@ -8,8 +8,6 @@
class St7789Display final : public EspLcdSpiDisplay {
std::shared_ptr<tt::Lock> lock;
public:
/** Minimal set of overrides for EspLcdConfiguration */
+1 -2
View File
@@ -1,7 +1,7 @@
#pragma once
#include <Tactility/hal/display/DisplayDevice.h>
#include <Tactility/hal/spi/Spi.h>
#include <driver/spi_common.h>
#include <EspLcdDisplay.h>
#include <functional>
@@ -78,7 +78,6 @@ private:
public:
explicit St7796Display(std::unique_ptr<Configuration> inConfiguration) :
EspLcdDisplay(tt::hal::spi::getLock(inConfiguration->spiHostDevice)),
configuration(std::move(inConfiguration)
) {
assert(configuration != nullptr);
-105
View File
@@ -1,105 +0,0 @@
#include "Xpt2046Power.h"
#include "Xpt2046Touch.h"
#include <Tactility/Logger.h>
#include <tactility/hal/Device.h>
static const auto LOGGER = tt::Logger("Xpt2046Power");
constexpr auto BATTERY_VOLTAGE_MIN = 3.2f;
constexpr auto BATTERY_VOLTAGE_MAX = 4.2f;
constexpr auto MAX_VOLTAGE_SAMPLES = 15;
static std::shared_ptr<Xpt2046Touch> findXp2046TouchDevice() {
// Make a safe copy
auto touch = tt::hal::findFirstDevice<tt::hal::touch::TouchDevice>(tt::hal::Device::Type::Touch);
if (touch == nullptr) {
LOGGER.error("Touch device not found");
return nullptr;
}
if (touch->getName() != "XPT2046") {
LOGGER.error("Touch device name mismatch");
return nullptr;
}
return std::reinterpret_pointer_cast<Xpt2046Touch>(touch);
}
static uint8_t estimateChargeLevelFromVoltage(uint32_t milliVolt) {
float volts = std::min((float)milliVolt / 1000.f, BATTERY_VOLTAGE_MAX);
float voltage_percentage = (volts - BATTERY_VOLTAGE_MIN) / (BATTERY_VOLTAGE_MAX - BATTERY_VOLTAGE_MIN);
float voltage_factor = std::min(1.0f, voltage_percentage);
auto charge_level = (uint8_t) (voltage_factor * 100.f);
LOGGER.verbose("mV = {}, scaled = {}, factor = {}, result = {}", milliVolt, volts, voltage_factor, charge_level);
return charge_level;
}
bool Xpt2046Power::supportsMetric(MetricType type) const {
switch (type) {
using enum MetricType;
case BatteryVoltage:
case ChargeLevel:
return true;
default:
return false;
}
}
bool Xpt2046Power::getMetric(MetricType type, MetricData& data) {
switch (type) {
using enum MetricType;
case BatteryVoltage:
return readBatteryVoltageSampled(data.valueAsUint32);
case ChargeLevel: {
uint32_t milli_volt;
if (readBatteryVoltageSampled(milli_volt)) {
data.valueAsUint8 = estimateChargeLevelFromVoltage(milli_volt);
return true;
} else {
return false;
}
}
default:
return false;
}
}
bool Xpt2046Power::readBatteryVoltageOnce(uint32_t& output) {
if (xptTouch == nullptr) {
xptTouch = findXp2046TouchDevice();
if (xptTouch == nullptr) {
LOGGER.error("XPT2046 touch device not found");
return false;
}
}
float vbat;
if (!xptTouch->getVBat(vbat)) {
return false;
}
// Convert to mV
output = (uint32_t)(vbat * 1000.f);
return true;
}
bool Xpt2046Power::readBatteryVoltageSampled(uint32_t& output) {
size_t samples_read = 0;
uint32_t sample_accumulator = 0;
uint32_t sample_read_buffer;
for (size_t i = 0; i < MAX_VOLTAGE_SAMPLES; ++i) {
if (readBatteryVoltageOnce(sample_read_buffer)) {
sample_accumulator += sample_read_buffer;
samples_read++;
}
}
if (samples_read > 0) {
output = sample_accumulator / samples_read;
return true;
} else {
return false;
}
}
-28
View File
@@ -1,28 +0,0 @@
#pragma once
#include <Tactility/hal/power/PowerDevice.h>
class Xpt2046Touch;
using tt::hal::power::PowerDevice;
/**
* Power management based on the voltage measurement at the LCD panel.
* This estimates the battery power left.
*/
class Xpt2046Power : public PowerDevice {
std::shared_ptr<Xpt2046Touch> xptTouch;
bool readBatteryVoltageOnce(uint32_t& output);
bool readBatteryVoltageSampled(uint32_t& output);
public:
~Xpt2046Power() override = default;
std::string getName() const final { return "XPT2046 Power Measurement"; }
std::string getDescription() const final { return "Power interface via XPT2046 voltage measurement"; }
bool supportsMetric(MetricType type) const override;
bool getMetric(MetricType type, MetricData& data) override;
};
-16
View File
@@ -35,19 +35,3 @@ esp_lcd_touch_config_t Xpt2046Touch::createEspLcdTouchConfig() {
.driver_data = nullptr
};
}
bool Xpt2046Touch::getVBat(float& outputVbat) {
auto touch_handle = getTouchHandle();
if (touch_handle == nullptr) {
return false;
}
// Shares the SPI bus with the display, so we have to sync/lock as this method might be called from anywhere
if (!tt::lvgl::lock(50 / portTICK_PERIOD_MS)) {
return false;
}
esp_lcd_touch_xpt2046_read_battery_level(touch_handle, &outputVbat);
tt::lvgl::unlock();
return true;
}
-2
View File
@@ -56,6 +56,4 @@ public:
std::string getName() const final { return "XPT2046"; }
std::string getDescription() const final { return "XPT2046 I2C touch driver"; }
bool getVBat(float& outputVbat);
};