Migrate devices, create drivers, other improvements & fixes (#574)

Migrated devices to kernel drivers:

- guition-jc3248w535c
- m5stack-core2
- m5stack-cores3
- m5stack-papers3

New drivers:

- axp192-module
- axp2101-module

Fixes:

- Fix SD card LDO for P4 devices
- Updated PowerOff app to work with kernel displays
- Fix for `lvgl_try_lock()` timing
- Fix for touch events with slow updating displays

Improvements:

- `GuiService` now keeps trying to lock to prevent silent failures caused by drivers.
- `GuiService` now uses lvgl-module calls for locking/unlocking
- display driver now has capability `DISPLAY_CAPABILITY_SLOW_REFRESH`
This commit is contained in:
Ken Van Hoeylandt
2026-07-19 00:39:26 +02:00
committed by GitHub
parent 5f54f7ca3d
commit f9453d8956
119 changed files with 3327 additions and 3994 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 esp_lvgl_port ILI934x FT5x06 AXP2101 AW9523 driver vfs fatfs
REQUIRES TactilityKernel axp2101-module
)
@@ -1,21 +0,0 @@
#include "InitBoot.h"
#include "devices/Display.h"
#include <Tactility/hal/Configuration.h>
#include <Axp2101Power.h>
using namespace tt::hal;
static DeviceVector createDevices() {
return {
axp2101,
aw9523,
std::make_shared<Axp2101Power>(axp2101),
createDisplay()
};
}
extern const Configuration hardwareConfiguration = {
.initBoot = initBoot,
.createDevices = createDevices
};
-154
View File
@@ -1,154 +0,0 @@
#include "InitBoot.h"
#include <Tactility/kernel/Kernel.h>
#include <tactility/log.h>
constexpr auto* TAG = "CoreS3";
std::shared_ptr<Axp2101> axp2101;
std::shared_ptr<Aw9523> aw9523;
/**
* For details see https://github.com/espressif/esp-bsp/blob/master/bsp/m5stack_core_s3/m5stack_core_s3.c
* and schematic: https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/datasheet/core/K128%20CoreS3/Sch_M5_CoreS3_v1.0.pdf
*/
bool initGpioExpander() {
LOG_I(TAG, "AW9523 init");
/**
* P0 pins:
* 0: Touch reset
* 1: Bus out enable
* 2: AW88298 reset (I2S)
* 3: ES7210 interrupt (Audio ADC)
* 4: SD Card SW(itch on?)
* 5: USB OTG enable
* 6: /
* 7: /
*/
/**
* P1 pins:
* 0: Cam reset
* 1: LCD reset
* 2: Touch interrupt
* 3: AW88298 interrupt (I2S)
* 4: /
* 5: /
* 6: /
* 7: Boost enable
*/
uint8_t p0_state = 0U;
uint8_t p1_state = 0U;
// Enable touch
p0_state |= (1U);
// Bus out enable
p0_state |= (1U << 1U);
// I2S
p0_state |= (1U << 2U);
// SD card
p0_state |= (1U << 4U);
// Enable LCD
p1_state |= (1U << 1U);
// Boost enable
p1_state |= (1U << 7U);
/* AW9523 P0 is in push-pull mode */
if (!aw9523->writeCTL(0x10)) {
LOG_E(TAG, "AW9523: Failed to set CTL");
return false;
}
if (!aw9523->writeP0(p0_state)) {
LOG_E(TAG, "AW9523: Failed to set P0");
return false;
}
if (!aw9523->writeP1(p1_state)) {
LOG_E(TAG, "AW9523: Failed to set P1");
return false;
}
if (axp2101->isVBus()) {
float voltage = 0.0f;
axp2101->getVBusVoltage(voltage);
LOG_I(TAG, "AXP2101: VBus at %.2f", voltage);
} else {
LOG_W(TAG, "AXP2101: VBus disabled");
}
return true;
}
bool initPowerControl() {
LOG_I(TAG, "Init power control (AXP2101)");
// Source: https://github.com/m5stack/M5Unified/blob/b8cfec7fed046242da7f7b8024a4e92004a51ff7/src/utility/Power_Class.cpp#L61
aw9523->bitOnP1(0b10000000); // SY7088 boost enable
/** AXP2101 usage
Source: https://github.com/m5stack/M5Unified/blob/b8cfec7fed046242da7f7b8024a4e92004a51ff7/README.md?plain=1#L223
| |M5Stack<BR>CoreS3<BR>CoreS3SE| |
|:---------:|:-----------------:|:---------:|
| ALDO1 |VDD 1v8 | ALDO1 |
| ALDO2 |VDDA 3v3 | ALDO2 |
| ALDO3 |CAM 3v3 | ALDO3 |
| ALDO4 |TF 3v3 | ALDO4 |
| BLDO1 |AVDD | BLDO1 |
| BLDO2 |DVDD | BLDO2 |
| DLDO1/DC1 |LCD BL | DLDO1/DC1 |
| DLDO2/DC2 | --- | DLDO2/DC2 |
| BACKUP |RTC BAT | BACKUP |
*/
/**
* 0x92 = ALD01
* 0x93 = ALD02
* 0x94 = ALD03
* 0x95 = ALD04
* 0x96 = BLD01
* 0x97 = BLD02
*
* DCDC1 : 0.7-3.5V 25mV/step 1200mA
* DCDC2 : 0.7-2.275V25mV/step 1600mA
* DCDC3 : 0.7-3.5V 25mV/step 700mA
* LDOio0: 1.8-3.3V, 100mV/step 50mA
* LDO1 : 30mA always on
* LDO2 : 1.8-3.3V 100mV/step 200mA
* LDO3 : 1.8-3.3V 100mV/step 200mA
*/
// Source: https://github.com/m5stack/M5Unified/blob/b8cfec7fed046242da7f7b8024a4e92004a51ff7/src/utility/Power_Class.cpp#L64
static constexpr uint8_t reg_data_array[] = {
0x90U, 0xBFU, // LDOS ON/OFF control 0 (backlight)
0x92U, 18U -5U, // ALDO1 set to 1.8v // for AW88298
0x93U, 33U -5U, // ALDO2 set to 3.3v // for ES7210
0x94U, 33U -5U, // ALDO3 set to 3.3v // for camera
0x95U, 33U -5U, // ALDO3 set to 3.3v // for TF card slot
0x27, 0x00, // PowerKey Hold=1sec / PowerOff=4sec
0x69, 0x11, // CHGLED setting
0x10, 0x30, // PMU common config
0x30, 0x0F // ADC enabled (for voltage measurement)
};
if (axp2101->setRegisters((uint8_t*)reg_data_array, sizeof(reg_data_array))) {
LOG_I(TAG, "AXP2101 initialized with %d registers", (int)(sizeof(reg_data_array) / 2));
return true;
} else {
LOG_E(TAG, "AXP2101: Failed to set registers");
return false;
}
}
bool initBoot() {
LOG_I(TAG, "initBoot()");
auto controller = device_find_by_name("i2c_internal");
axp2101 = std::make_shared<Axp2101>(controller);
aw9523 = std::make_shared<Aw9523>(controller);
return initPowerControl() && initGpioExpander();
}
-9
View File
@@ -1,9 +0,0 @@
#pragma once
#include <Axp2101.h>
#include <Aw9523.h>
extern std::shared_ptr<Axp2101> axp2101;
extern std::shared_ptr<Aw9523> aw9523;
bool initBoot();
@@ -1,59 +0,0 @@
#include "Display.h"
#include <Axp2101.h>
#include <Ft5x06Touch.h>
#include <Ili934xDisplay.h>
#include <tactility/check.h>
#include <tactility/log.h>
constexpr auto* TAG = "CoreS3Display";
static void setBacklightDuty(uint8_t backlightDuty) {
const uint8_t voltage = 20 + ((8 * backlightDuty) / 255); // [0b00000, 0b11100] - under 20 is too dark
// TODO: Refactor to use Axp2102 driver subproject. Reference: https://github.com/m5stack/M5Unified/blob/b8cfec7fed046242da7f7b8024a4e92004a51ff7/src/utility/AXP2101_Class.cpp#L42
auto controller = device_find_by_name("i2c_internal");
check(controller);
if (i2c_controller_write_register(controller, AXP2101_ADDRESS, 0x99, &voltage, 1, 1000) != ERROR_NONE) { // Sets DLD01
LOG_E(TAG, "Failed to set display backlight voltage");
}
}
static std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
auto configuration = std::make_unique<Ft5x06Touch::Configuration>(
I2C_NUM_0,
319,//LCD_HORIZONTAL_RESOLUTION,
239//LCD_VERTICAL_RESOLUTION,
);
return std::make_shared<Ft5x06Touch>(std::move(configuration));
}
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
Ili934xDisplay::Configuration panel_configuration = {
.horizontalResolution = LCD_HORIZONTAL_RESOLUTION,
.verticalResolution = LCD_VERTICAL_RESOLUTION,
.gapX = 0,
.gapY = 0,
.swapXY = false,
.mirrorX = false,
.mirrorY = false,
.invertColor = true,
.swapBytes = true,
.bufferSize = LCD_BUFFER_SIZE,
.touch = createTouch(),
.backlightDutyFunction = ::setBacklightDuty,
.resetPin = GPIO_NUM_NC,
.rgbElementOrder = LCD_RGB_ELEMENT_ORDER_BGR
};
auto spi_configuration = std::make_shared<Ili934xDisplay::SpiConfiguration>(Ili934xDisplay::SpiConfiguration {
.spiHostDevice = LCD_SPI_HOST,
.csPin = LCD_PIN_CS,
.dcPin = LCD_PIN_DC,
.pixelClockFrequency = 40'000'000,
.transactionQueueDepth = 10
});
return std::make_shared<Ili934xDisplay>(panel_configuration, spi_configuration, true);
}
@@ -1,17 +0,0 @@
#pragma once
#include <Tactility/hal/display/DisplayDevice.h>
#include <driver/gpio.h>
#include <driver/spi_common.h>
// Display
constexpr auto LCD_SPI_HOST = SPI2_HOST;
constexpr auto LCD_PIN_CS = GPIO_NUM_3;
constexpr auto LCD_PIN_DC = GPIO_NUM_35;
constexpr auto LCD_HORIZONTAL_RESOLUTION = 320;
constexpr auto LCD_VERTICAL_RESOLUTION = 240;
constexpr auto LCD_BUFFER_HEIGHT = LCD_VERTICAL_RESOLUTION / 10;
constexpr auto LCD_BUFFER_SIZE = LCD_HORIZONTAL_RESOLUTION * LCD_BUFFER_HEIGHT;
constexpr auto LCD_SPI_TRANSFER_SIZE_LIMIT = LCD_BUFFER_SIZE * LV_COLOR_DEPTH / 8;
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();
-23
View File
@@ -1,23 +0,0 @@
#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_cores3_module = {
.name = "m5stack-cores3",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
};
}
+3 -1
View File
@@ -12,7 +12,9 @@ hardware.tinyUsb=true
hardware.esptoolFlashFreq=120M
hardware.bluetooth=true
storage.userDataLocation=SD
storage.userDataLocation=Internal
dependencies.useDeprecatedHal=false
display.size=2"
display.shape=rectangle
+4
View File
@@ -2,4 +2,8 @@ dependencies:
- Platforms/platform-esp32
- Drivers/bmi270-module
- Drivers/bm8563-module
- Drivers/axp2101-module
- Drivers/aw9523b-module
- Drivers/ft5x06-module
- Drivers/ili9341-module
dts: m5stack,cores3.dts
+72 -8
View File
@@ -11,8 +11,16 @@
#include <tactility/bindings/esp32_uart.h>
#include <bindings/bmi270.h>
#include <bindings/bm8563.h>
#include <bindings/axp2101.h>
#include <bindings/axp2101_backlight.h>
#include <bindings/aw9523b.h>
#include <bindings/ft5x06.h>
#include <bindings/ili9341.h>
#include <tactility/bindings/esp32_sdspi.h>
#include <tactility/bindings/display_placeholder.h>
#include <tactility/bindings/gpio_hog.h>
// SD card is not supported because of a hardware problem:
// The display uses pin 35 as input (MISO), but the SPI bus (and SD card) uses the same pin as DC (output).
// Reference: https://docs.m5stack.com/en/core/CoreS3
/ {
@@ -50,6 +58,61 @@
compatible = "belling,bm8563";
reg = <0x51>;
};
// P0_0 = touch reset, P0_1 = bus-out enable, P0_2 = AW88298 reset,
// P0_4 = SD card switch, P1_1 = LCD reset, P1_7 = boost enable (SY7088)
aw9523b: aw9523b {
compatible = "awinic,aw9523b";
reg = <0x58>;
};
axp2101: axp2101 {
compatible = "x-powers,axp2101";
reg = <0x34>;
// LCD backlight (DLDO1). Raw register codes [20,28] map to [2500,3300]mV;
// below 2500mV the backlight was considered "too dark" to be useful.
backlight {
compatible = "axp2101-backlight";
ldo = <AXP2101_DLDO1>;
min-millivolt = <2500>;
max-millivolt = <3300>;
};
};
touch {
compatible = "focaltech,ft5x06";
reg = <0x38>;
x-max = <320>;
y-max = <240>;
pin-reset = <&aw9523b 0 GPIO_FLAG_NONE>;
};
};
// Bus-out enable, AW88298 (audio amp) reset, SD card power switch and boost enable
// (SY7088) are AW9523B pins with no owning peripheral driver yet.
aw9523_bus_out_enable {
compatible = "gpio-hog";
pin = <&aw9523b 1 GPIO_FLAG_NONE>;
mode = <GPIO_HOG_MODE_OUTPUT_HIGH>;
};
aw9523_aw88298_reset {
compatible = "gpio-hog";
pin = <&aw9523b 2 GPIO_FLAG_NONE>;
mode = <GPIO_HOG_MODE_OUTPUT_HIGH>;
};
aw9523_sdcard_switch {
compatible = "gpio-hog";
pin = <&aw9523b 4 GPIO_FLAG_NONE>;
mode = <GPIO_HOG_MODE_OUTPUT_HIGH>;
};
aw9523_boost_enable {
compatible = "gpio-hog";
pin = <&aw9523b 15 GPIO_FLAG_NONE>;
mode = <GPIO_HOG_MODE_OUTPUT_HIGH>;
};
port_a: grove0 {
@@ -92,13 +155,14 @@
pin-sclk = <&gpio0 36 GPIO_FLAG_NONE>;
display@0 {
compatible = "display-placeholder";
};
sdcard@1 {
compatible = "espressif,esp32-sdspi";
status = "disabled"; // Must be started after display
frequency-khz = <20000>;
compatible = "ilitek,ili9341";
horizontal-resolution = <320>;
vertical-resolution = <240>;
invert-color;
bgr-order;
pixel-clock-hz = <40000000>;
pin-dc = <&gpio0 35 GPIO_FLAG_NONE>;
pin-reset = <&aw9523b 9 GPIO_FLAG_NONE>;
};
};
+55
View File
@@ -0,0 +1,55 @@
#include <drivers/axp2101.h>
#include <tactility/check.h>
#include <tactility/device.h>
#include <tactility/device_listener.h>
#include <tactility/module.h>
#include <cstring>
extern "C" {
// M5Stack CoreS3 AXP2101 rail setup, ported from the board's old deprecated-HAL
// initPowerControl() (source: M5Unified's Power_Class.cpp). ALDO1 powers the AW88298 audio
// amp, ALDO2 the ES7210 microphone ADC, ALDO3 the GC0308 camera, ALDO4 the TF/SD card slot.
// DLDO1 (LCD backlight) is left to the axp2101-backlight child device.
static void configure_axp2101(Device* axp2101) {
check(axp2101_set_ldo_voltage(axp2101, AXP2101_ALDO1, 1800) == ERROR_NONE);
check(axp2101_set_ldo_voltage(axp2101, AXP2101_ALDO2, 3300) == ERROR_NONE);
check(axp2101_set_ldo_voltage(axp2101, AXP2101_ALDO3, 3300) == ERROR_NONE);
check(axp2101_set_ldo_voltage(axp2101, AXP2101_ALDO4, 3300) == ERROR_NONE);
check(axp2101_set_ldo_enabled(axp2101, AXP2101_ALDO1, true) == ERROR_NONE);
check(axp2101_set_ldo_enabled(axp2101, AXP2101_ALDO2, true) == ERROR_NONE);
check(axp2101_set_ldo_enabled(axp2101, AXP2101_ALDO3, true) == ERROR_NONE);
check(axp2101_set_ldo_enabled(axp2101, AXP2101_ALDO4, true) == ERROR_NONE);
check(axp2101_set_ldo_enabled(axp2101, AXP2101_BLDO1, true) == ERROR_NONE);
check(axp2101_set_ldo_enabled(axp2101, AXP2101_BLDO2, true) == ERROR_NONE);
}
static void on_device_event(Device* device, DeviceEvent event, void* context) {
(void)context;
if (event == DEVICE_EVENT_STARTED && strcmp(device->name, "axp2101") == 0) {
configure_axp2101(device);
}
}
static error_t start() {
device_listener_add(on_device_event, nullptr);
return ERROR_NONE;
}
static error_t stop() {
device_listener_remove(on_device_event);
return ERROR_NONE;
}
struct Module m5stack_cores3_module = {
.name = "m5stack-cores3",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
};
}