M5Stack StickS3 - New Tab5 - driver modules (#516)

Font size set to 18 for 800x480 displays
Fix web server dashboard not rendering when sdcard isn't present

Added new driver modules
-  BM8563 RTC
- RX8130CE RTC
- MPU6886 IMU
- QMI8658 IMU
- M5PM1 Power Management Chip

Applied the above modules to applicable devicetrees.

Added new device: M5Stack StickS3

Added new M5Stack Tab5 St7123 variant.

ButtonControl changed to use interupts and xQueue, added AppClose action.

And some bonus symbols of course, the apps are hungry for symbols.
This commit is contained in:
Shadowtrance
2026-03-20 19:07:57 +10:00
committed by GitHub
parent e560cc7df2
commit e64f4ff16b
113 changed files with 3690 additions and 102 deletions
@@ -0,0 +1,26 @@
#include "devices/Display.h"
#include "devices/Power.h"
#include <driver/gpio.h>
#include <Tactility/hal/Configuration.h>
#include <ButtonControl.h>
#include <PwmBacklight.h>
using namespace tt::hal;
bool initBoot() {
return driver::pwmbacklight::init(GPIO_NUM_38, 512);
}
static DeviceVector createDevices() {
return {
createPower(),
ButtonControl::createTwoButtonControl(11, 12), // top button, side button
createDisplay()
};
}
extern const Configuration hardwareConfiguration = {
.initBoot = initBoot,
.createDevices = createDevices
};
@@ -0,0 +1,32 @@
#include "Display.h"
#include <PwmBacklight.h>
#include <St7789Display.h>
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
St7789Display::Configuration panel_configuration = {
.horizontalResolution = LCD_HORIZONTAL_RESOLUTION,
.verticalResolution = LCD_VERTICAL_RESOLUTION,
.gapX = 52,
.gapY = 40,
.swapXY = false,
.mirrorX = false,
.mirrorY = false,
.invertColor = true,
.bufferSize = LCD_BUFFER_SIZE,
.touch = nullptr,
.backlightDutyFunction = driver::pwmbacklight::setBacklightDuty,
.resetPin = LCD_PIN_RESET,
.lvglSwapBytes = false
};
auto spi_configuration = std::make_shared<St7789Display::SpiConfiguration>(St7789Display::SpiConfiguration {
.spiHostDevice = LCD_SPI_HOST,
.csPin = LCD_PIN_CS,
.dcPin = LCD_PIN_DC,
.pixelClockFrequency = 40'000'000,
.transactionQueueDepth = 10
});
return std::make_shared<St7789Display>(panel_configuration, spi_configuration);
}
@@ -0,0 +1,17 @@
#pragma once
#include "Tactility/hal/display/DisplayDevice.h"
#include <memory>
#include <driver/gpio.h>
#include <driver/spi_common.h>
constexpr auto LCD_SPI_HOST = SPI2_HOST;
constexpr auto LCD_PIN_CS = GPIO_NUM_41;
constexpr auto LCD_PIN_DC = GPIO_NUM_45;
constexpr auto LCD_PIN_RESET = GPIO_NUM_21;
constexpr auto LCD_HORIZONTAL_RESOLUTION = 135;
constexpr auto LCD_VERTICAL_RESOLUTION = 240;
constexpr auto LCD_BUFFER_HEIGHT = LCD_VERTICAL_RESOLUTION / 3;
constexpr auto LCD_BUFFER_SIZE = LCD_HORIZONTAL_RESOLUTION * LCD_BUFFER_HEIGHT;
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();
@@ -0,0 +1,94 @@
#include "Power.h"
#include <Tactility/hal/power/PowerDevice.h>
#include <drivers/m5pm1.h>
#include <tactility/device.h>
#include <tactility/log.h>
using namespace tt::hal::power;
static constexpr auto* TAG = "StickS3Power";
static constexpr float MIN_BATTERY_VOLTAGE_MV = 3300.0f;
static constexpr float MAX_BATTERY_VOLTAGE_MV = 4200.0f;
class StickS3Power final : public PowerDevice {
public:
explicit StickS3Power(::Device* m5pm1Device) : m5pm1(m5pm1Device) {}
std::string getName() const override { return "M5Stack StickS3 Power"; }
std::string getDescription() const override { return "Battery monitoring via M5PM1 over I2C"; }
bool supportsMetric(MetricType type) const override {
switch (type) {
using enum MetricType;
case BatteryVoltage:
case ChargeLevel:
case IsCharging:
return true;
default:
return false;
}
}
bool getMetric(MetricType type, MetricData& data) override {
switch (type) {
using enum MetricType;
case BatteryVoltage: {
uint16_t mv = 0;
if (m5pm1_get_battery_voltage(m5pm1, &mv) != ERROR_NONE) return false;
data.valueAsUint32 = mv;
return true;
}
case ChargeLevel: {
uint16_t mv = 0;
if (m5pm1_get_battery_voltage(m5pm1, &mv) != ERROR_NONE) return false;
float voltage = static_cast<float>(mv);
if (voltage >= MAX_BATTERY_VOLTAGE_MV) {
data.valueAsUint8 = 100;
} else if (voltage <= MIN_BATTERY_VOLTAGE_MV) {
data.valueAsUint8 = 0;
} else {
float factor = (voltage - MIN_BATTERY_VOLTAGE_MV) / (MAX_BATTERY_VOLTAGE_MV - MIN_BATTERY_VOLTAGE_MV);
data.valueAsUint8 = static_cast<uint8_t>(factor * 100.0f);
}
return true;
}
case IsCharging: {
bool charging = false;
if (m5pm1_is_charging(m5pm1, &charging) != ERROR_NONE) {
LOG_W(TAG, "Failed to read charging status");
return false;
}
data.valueAsBool = charging;
return true;
}
default:
return false;
}
}
bool supportsPowerOff() const override { return true; }
void powerOff() override {
LOG_W(TAG, "Powering off via M5PM1");
if (m5pm1_shutdown(m5pm1) != ERROR_NONE) {
LOG_E(TAG, "Failed to send power-off command");
}
}
private:
::Device* m5pm1;
};
std::shared_ptr<PowerDevice> createPower() {
auto* m5pm1 = device_find_by_name("m5pm1");
if (m5pm1 == nullptr) {
LOG_E(TAG, "m5pm1 device not found");
}
return std::make_shared<StickS3Power>(m5pm1);
}
@@ -0,0 +1,6 @@
#pragma once
#include <memory>
#include <Tactility/hal/power/PowerDevice.h>
std::shared_ptr<tt::hal::power::PowerDevice> createPower();
+23
View File
@@ -0,0 +1,23 @@
#include <tactility/module.h>
extern "C" {
static error_t start() {
// Empty for now
return ERROR_NONE;
}
static error_t stop() {
// Empty for now
return ERROR_NONE;
}
struct Module m5stack_sticks3_module = {
.name = "m5stack-sticks3",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
};
}