Compare commits

...

15 Commits

Author SHA1 Message Date
Adolfo Reyna 5643ba5a2c Add ES3C35P board support 2026-07-24 20:32:19 -04:00
Adolfo Reyna 642847be41 fix(mcp): implement startMcpScreensaver - missing method caused linker error
- Was declared in DisplayIdleService.h but not defined in clean refactored branch
- Implementation taken from original 8970143f: locks LVGL, checks overlay, ensures backlight, creates McpScreensaver
- Fixes build of feature/local-all-rebased on es3c28p
2026-07-23 22:56:17 -04:00
Adolfo Reyna 0367b95f27 feat(app): allow external apps to hide statusbar via manifest flags
- Add parseAppFlagsString() in AppManifestParsing.cpp to parse comma-separated flags (HideStatusBar, Hidden, None)
- Parse [app]flags in V1 and app.flags in V2 manifests
- Loader already supports HideStatusBar, GuiService hides statusbarWidget when set
- Enables fullscreen for ELF apps (e.g. BibleVerse, BookPlayer) without firmware recompilation of internal manifests
- Add tests for flag parsing (38 tests passing)
- Tested on es3c28p /dev/cu.usbmodem1101 @ 192.168.68.133 with HelloWorld app
2026-07-23 22:56:17 -04:00
Adolfo Reyna 17773825fa fix(audio): ES8311 BOTH complementary open + audio-stream close ref-count + mic unmute
- es8311 driver open() now allows OUTPUT->INPUT complementary (promotes to BOTH) when same native rate 44100
- audio-stream close_stream() ref-counts shared BOTH codec (don't close if other direction still open)
- MCP recordVoice + VoiceRecorder app explicitly unmute and set 100% gain

Fixes mic input not working - was returning ERROR_RESOURCE when output already open
2026-07-23 22:56:17 -04:00
Adolfo Reyna 3115a685e2 fix(files): launch mp3 player from file explorer - audio support
- SupportedFiles: add isSupportedAudioFile (.mp3/.wav/.ogg/.flac)
- Files View::viewFile: if audio file, loader->start one.tactility.mp3player with file bundle
- Tactility.cpp: hide mcpoverride (screensaver internal), keep mcpsettings visible
- Fixes MP3 no longer running from file explorer, plus audio fast playback already fixed via audio-stream (Mp3Player/BookPlayer/VoiceRecorder use audio_stream_open_output not direct i2s_controller_write)
- MCP dev coexistence already fixed: DisplayIdle lock inversion 3629ffef, WebServer serverEnabled=ws||mcp, unauth /api/mcp, video 8081/8083 vs dev 6666
2026-07-23 22:56:17 -04:00
Adolfo Reyna ad4a15dce8 feat(mcp): restore MCP service with display charging toggle
- Restore MCP system (McpSystem 1900+ LOC, McpHandler, McpScreensaver, McpSettings, McpOverride apps)
- Use audio-stream instead of direct I2S for MP3 playback (fixes fast playback, uses native resampler)
- Register McpSettings + McpOverride in Tactility.cpp so Settings shows MCP Screen
- DisplaySettings: add ScreensaverType::McpScreen and disableScreensaverWhenCharging flag
- Display app: add 'Disable on charging' toggle, handles McpScreen screensaver type
- DisplayIdle: skip screensaver while charging, support McpScreen screensaver, isDeviceCharging check via PowerDevice
- WebServer: coexistence with MCP (McpHandler)
- Avoid formatting churn from previous commits

Squashed from range eaa248b0..8970143f (6 commits) into single clean commit
2026-07-23 22:56:17 -04:00
Ken Van Hoeylandt 29e80cfd65 T-Deck Max & Pro support updates (#582)
- Created kernel driver for T-Deck Max & Pro display (needs work, doesn't refresh reliably on T-Deck Pro)
- Created T-Deck Pro device implementation (incubating)
2026-07-24 00:17:48 +02:00
Ken Van Hoeylandt 429125734a Add drivers to module and make start/stop optional (#580) 2026-07-23 23:28:09 +02:00
Shadowtrance 08eac48e64 Fix Tab5 Display Issues (#579)
And add PPA rotation to lvgl_display
2026-07-22 23:58:34 +02:00
Ken Van Hoeylandt 8b92aa8e5a GPIO descriptor fixes (#578) 2026-07-22 22:43:34 +02:00
Ken Van Hoeylandt a3fda9ad8f Device migrations and driver improvements (#576) 2026-07-22 21:11:12 +02:00
Ken Van Hoeylandt 2fbc44466a Device migrations, driver migrations and more (#575) 2026-07-20 23:43:17 +02:00
Shadowtrance 2d768ef3a1 ESP-NOW bridge for P4 (#573) 2026-07-19 09:23:20 +02:00
reyna-b bd30aa046a Add ES3C28P device (#569) 2026-07-19 09:17:19 +02:00
Ken Van Hoeylandt f9453d8956 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`
2026-07-19 00:39:26 +02:00
686 changed files with 22777 additions and 14726 deletions
+2 -14
View File
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module btt_panda_touch_module = {
return ERROR_NONE; .name = "btt-panda-touch"
}
static error_t stop() {
return ERROR_NONE;
}
struct Module btt_panda_touch_module = {
.name = "btt-panda-touch",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
-12
View File
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() {
return ERROR_NONE;
}
static error_t stop() {
return ERROR_NONE;
}
Module cyd_2432s024c_module = { Module cyd_2432s024c_module = {
.name = "cyd-2432s024c", .name = "cyd-2432s024c",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
+2 -14
View File
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module cyd_2432s024r_module = {
return ERROR_NONE; .name = "cyd-2432s024r"
}
static error_t stop() {
return ERROR_NONE;
}
struct Module cyd_2432s024r_module = {
.name = "cyd-2432s024r",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
+2 -14
View File
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module cyd_2432s028r_module = {
return ERROR_NONE; .name = "cyd-2432s028r"
}
static error_t stop() {
return ERROR_NONE;
}
struct Module cyd_2432s028r_module = {
.name = "cyd-2432s028r",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
+2 -14
View File
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module cyd_2432s028rv3_module = {
return ERROR_NONE; .name = "cyd-2432s028rv3"
}
static error_t stop() {
return ERROR_NONE;
}
struct Module cyd_2432s028rv3_module = {
.name = "cyd-2432s028rv3",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
+2 -14
View File
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module cyd_2432s032c_module = {
return ERROR_NONE; .name = "cyd-2432s032c"
}
static error_t stop() {
return ERROR_NONE;
}
struct Module cyd_2432s032c_module = {
.name = "cyd-2432s032c",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
+2 -14
View File
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module cyd_3248s035c_module = {
return ERROR_NONE; .name = "cyd-3248s035c"
}
static error_t stop() {
return ERROR_NONE;
}
struct Module cyd_3248s035c_module = {
.name = "cyd-3248s035c",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
+2 -14
View File
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module cyd_4848s040c_module = {
return ERROR_NONE; .name = "cyd-4848s040c"
}
static error_t stop() {
return ERROR_NONE;
}
struct Module cyd_4848s040c_module = {
.name = "cyd-4848s040c",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
+2 -14
View File
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module cyd_8048s043c_module = {
return ERROR_NONE; .name = "cyd-8048s043c"
}
static error_t stop() {
return ERROR_NONE;
}
struct Module cyd_8048s043c_module = {
.name = "cyd-8048s043c",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
+2 -14
View File
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module cyd_e32r28t_module = {
return ERROR_NONE; .name = "cyd-e32r28t"
}
static error_t stop() {
return ERROR_NONE;
}
struct Module cyd_e32r28t_module = {
.name = "cyd-e32r28t",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
+2 -14
View File
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module cyd_e32r32p_module = {
return ERROR_NONE; .name = "cyd-e32r32p"
}
static error_t stop() {
return ERROR_NONE;
}
struct Module cyd_e32r32p_module = {
.name = "cyd-e32r32p",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
@@ -2,19 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module elecrow_crowpanel_advance_28_module = {
return ERROR_NONE; .name = "elecrow-crowpanel-advance-28"
}
static error_t stop() {
return ERROR_NONE;
}
struct Module elecrow_crowpanel_advance_28_module = {
.name = "elecrow-crowpanel-advance-28",
.start = start,
.stop = stop,
.symbols = nullptr
}; };
} }
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() {
return ERROR_NONE;
}
static error_t stop() {
return ERROR_NONE;
}
Module elecrow_crowpanel_advance_35_module = { Module elecrow_crowpanel_advance_35_module = {
.name = "elecrow-crowpanel-advance-35", .name = "elecrow-crowpanel-advance-35"
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
@@ -86,9 +86,7 @@
vsync-back-porch = <8>; vsync-back-porch = <8>;
vsync-front-porch = <8>; vsync-front-porch = <8>;
pclk-active-neg; pclk-active-neg;
num-fbs = <2>; bounce-buffer-size-px = <4000>;
double-fb;
bounce-buffer-size-px = <8000>;
pin-hsync = <&gpio0 40 GPIO_FLAG_NONE>; pin-hsync = <&gpio0 40 GPIO_FLAG_NONE>;
pin-vsync = <&gpio0 41 GPIO_FLAG_NONE>; pin-vsync = <&gpio0 41 GPIO_FLAG_NONE>;
pin-de = <&gpio0 42 GPIO_FLAG_NONE>; pin-de = <&gpio0 42 GPIO_FLAG_NONE>;
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module elecrow_crowpanel_advance_50_module = {
return ERROR_NONE; .name = "elecrow-crowpanel-advance-50"
}
static error_t stop() {
return ERROR_NONE;
}
struct Module elecrow_crowpanel_advance_50_module = {
.name = "elecrow-crowpanel-advance-50",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module elecrow_crowpanel_basic_28_module = {
return ERROR_NONE; .name = "elecrow-crowpanel-basic-28"
}
static error_t stop() {
return ERROR_NONE;
}
struct Module elecrow_crowpanel_basic_28_module = {
.name = "elecrow-crowpanel-basic-28",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() {
return ERROR_NONE;
}
static error_t stop() {
return ERROR_NONE;
}
Module elecrow_crowpanel_basic_35_module = { Module elecrow_crowpanel_basic_35_module = {
.name = "elecrow-crowpanel-basic-35", .name = "elecrow-crowpanel-basic-35"
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
@@ -89,9 +89,7 @@
vsync-back-porch = <12>; vsync-back-porch = <12>;
vsync-front-porch = <8>; vsync-front-porch = <8>;
pclk-active-neg; pclk-active-neg;
num-fbs = <2>; bounce-buffer-size-px = <4000>;
double-fb;
bounce-buffer-size-px = <8000>;
pin-hsync = <&gpio0 39 GPIO_FLAG_NONE>; pin-hsync = <&gpio0 39 GPIO_FLAG_NONE>;
pin-vsync = <&gpio0 41 GPIO_FLAG_NONE>; pin-vsync = <&gpio0 41 GPIO_FLAG_NONE>;
pin-de = <&gpio0 40 GPIO_FLAG_NONE>; pin-de = <&gpio0 40 GPIO_FLAG_NONE>;
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module elecrow_crowpanel_basic_50_module = {
return ERROR_NONE; .name = "elecrow-crowpanel-basic-50"
}
static error_t stop() {
return ERROR_NONE;
}
struct Module elecrow_crowpanel_basic_50_module = {
.name = "elecrow-crowpanel-basic-50",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
+4
View File
@@ -0,0 +1,4 @@
idf_component_register(
SRCS "source/module.cpp"
REQUIRES TactilityKernel
)
@@ -1,5 +1,5 @@
general.vendor=Guition general.vendor=CYD
general.name=JC3248W535C general.name=ES3C28P
apps.launcherAppId=Launcher apps.launcherAppId=Launcher
@@ -8,18 +8,16 @@ hardware.flashSize=16MB
hardware.spiRam=true hardware.spiRam=true
hardware.spiRamMode=OCT hardware.spiRamMode=OCT
hardware.spiRamSpeed=120M hardware.spiRamSpeed=120M
hardware.tinyUsb=true
hardware.esptoolFlashFreq=120M hardware.esptoolFlashFreq=120M
hardware.tinyUsb=true
hardware.bluetooth=true hardware.bluetooth=true
dependencies.useDeprecatedHal=false display.size=2.8"
storage.userDataLocation=SD
display.size=3.5"
display.shape=rectangle display.shape=rectangle
display.dpi=165 display.dpi=143
lvgl.colorDepth=16 lvgl.colorDepth=16
sdkconfig.CONFIG_CODEC_DUMMY_SUPPORT=y storage.userDataLocation=SD
dependencies.useDeprecatedHal=false
+7
View File
@@ -0,0 +1,7 @@
dependencies:
- Platforms/platform-esp32
- Drivers/ili9341-module
- Drivers/ft5x06-module
- Drivers/es8311-module
- Drivers/audio-stream-module
dts: es3c28p.dts
+142
View File
@@ -0,0 +1,142 @@
/dts-v1/;
#include <tactility/bindings/root.h>
#include <tactility/bindings/esp32_adc_oneshot.h>
#include <tactility/bindings/esp32_ble.h>
#include <tactility/bindings/esp32_gpio.h>
#include <tactility/bindings/esp32_i2c.h>
#include <tactility/bindings/esp32_i2s.h>
#include <tactility/bindings/esp32_pwm_ledc.h>
#include <tactility/bindings/esp32_sdmmc.h>
#include <tactility/bindings/esp32_spi.h>
#include <tactility/bindings/esp32_wifi_pinned.h>
#include <tactility/bindings/battery_sense.h>
#include <tactility/bindings/gpio_hog.h>
#include <tactility/bindings/pwm_backlight.h>
#include <bindings/ili9341.h>
#include <bindings/ft5x06.h>
#include <bindings/es8311.h>
/ {
compatible = "root";
model = "LCDWIKI ES3C28P";
wifi0 {
compatible = "espressif,esp32-wifi-pinned";
status = "disabled";
};
ble0 {
compatible = "espressif,esp32-ble";
status = "disabled";
};
gpio0 {
compatible = "espressif,esp32-gpio";
gpio-count = <49>;
};
/* FM8002E speaker amp enable, active-low on GPIO1 */
amp_enable {
compatible = "gpio-hog";
pin = <&gpio0 1 GPIO_FLAG_NONE>;
mode = <GPIO_HOG_MODE_OUTPUT_LOW>;
};
adc0 {
compatible = "espressif,esp32-adc-oneshot";
unit-id = <ADC_UNIT_1>;
clk-src = <ADC_RTC_CLK_SRC_DEFAULT>;
channels = <ADC_CHANNEL_8 ADC_ATTEN_DB_12 ADC_BITWIDTH_DEFAULT>;
};
/* BAT+ through 200K/200K divider into GPIO9 ADC1_CH8 */
battery-sense {
compatible = "battery-sense";
io-channel = <&adc0 0>;
reference-voltage-mv = <3300>;
multiplier = <2000>;
};
/* i2s0 must be before i2c0 so codec can reference it */
i2s0 {
compatible = "espressif,esp32-i2s";
port = <I2S_NUM_0>;
pin-bclk = <&gpio0 5 GPIO_FLAG_NONE>;
pin-ws = <&gpio0 7 GPIO_FLAG_NONE>;
pin-data-out = <&gpio0 8 GPIO_FLAG_NONE>;
pin-data-in = <&gpio0 6 GPIO_FLAG_NONE>;
pin-mclk = <&gpio0 4 GPIO_FLAG_NONE>;
};
i2c0 {
compatible = "espressif,esp32-i2c";
port = <I2C_NUM_0>;
clock-frequency = <100000>;
pin-sda = <&gpio0 16 GPIO_FLAG_NONE>;
pin-scl = <&gpio0 15 GPIO_FLAG_NONE>;
ft5x06@38 {
compatible = "focaltech,ft5x06";
reg = <0x38>;
x-max = <240>;
y-max = <320>;
swap-xy;
mirror-x;
pin-reset = <&gpio0 18 GPIO_FLAG_NONE>;
pin-interrupt = <&gpio0 17 GPIO_FLAG_NONE>;
};
es8311: es8311@18 {
compatible = "everest,es8311";
reg = <0x18>;
i2s = <&i2s0>;
};
};
display_backlight_pwm {
compatible = "espressif,esp32-pwm-ledc";
pin = <&gpio0 45 GPIO_FLAG_NONE>;
period-ns = <500000>;
ledc-timer = <0>;
ledc-channel = <0>;
};
display_backlight {
compatible = "pwm-backlight";
status = "disabled";
pwm = <&display_backlight_pwm>;
};
spi0 {
compatible = "espressif,esp32-spi";
host = <SPI2_HOST>;
pin-mosi = <&gpio0 11 GPIO_FLAG_NONE>;
pin-sclk = <&gpio0 12 GPIO_FLAG_NONE>;
cs-gpios = <&gpio0 10 GPIO_FLAG_NONE>;
display@0 {
compatible = "ilitek,ili9341";
horizontal-resolution = <320>;
vertical-resolution = <240>;
swap-xy;
invert-color;
bgr-order;
pixel-clock-hz = <40000000>;
pin-dc = <&gpio0 46 GPIO_FLAG_NONE>;
backlight = <&display_backlight>;
};
};
sdmmc0 {
compatible = "espressif,esp32-sdmmc";
pin-clk = <&gpio0 38 GPIO_FLAG_NONE>;
pin-cmd = <&gpio0 40 GPIO_FLAG_NONE>;
pin-d0 = <&gpio0 39 GPIO_FLAG_NONE>;
pin-d1 = <&gpio0 41 GPIO_FLAG_NONE>;
pin-d2 = <&gpio0 48 GPIO_FLAG_NONE>;
pin-d3 = <&gpio0 47 GPIO_FLAG_NONE>;
slot = <SDMMC_HOST_SLOT_1>;
bus-width = <4>;
};
};
+9
View File
@@ -0,0 +1,9 @@
#include <tactility/module.h>
extern "C" {
Module es3c28p_module = {
.name = "es3c28p"
};
}
+4
View File
@@ -0,0 +1,4 @@
idf_component_register(
SRCS "source/module.cpp"
REQUIRES TactilityKernel
)
+23
View File
@@ -0,0 +1,23 @@
general.vendor=LCDWIKI/Hosyond
general.name=ES3C35P
apps.launcherAppId=Launcher
hardware.target=ESP32S3
hardware.flashSize=16MB
hardware.spiRam=true
hardware.spiRamMode=OCT
hardware.spiRamSpeed=80M
hardware.esptoolFlashFreq=80M
hardware.tinyUsb=true
hardware.bluetooth=true
display.size=3.5"
display.shape=rectangle
display.dpi=165
lvgl.colorDepth=16
storage.userDataLocation=SD
dependencies.useDeprecatedHal=false
+6
View File
@@ -0,0 +1,6 @@
dependencies:
- Platforms/platform-esp32
- Drivers/st77922-module
- Drivers/es8311-module
- Drivers/audio-stream-module
dts: es3c35p.dts
+143
View File
@@ -0,0 +1,143 @@
/dts-v1/;
#include <tactility/bindings/root.h>
#include <tactility/bindings/esp32_adc_oneshot.h>
#include <tactility/bindings/esp32_ble.h>
#include <tactility/bindings/esp32_gpio.h>
#include <tactility/bindings/esp32_i2c.h>
#include <tactility/bindings/esp32_i2s.h>
#include <tactility/bindings/esp32_pwm_ledc.h>
#include <tactility/bindings/esp32_sdmmc.h>
#include <tactility/bindings/esp32_spi.h>
#include <tactility/bindings/esp32_wifi_pinned.h>
#include <tactility/bindings/battery_sense.h>
#include <tactility/bindings/gpio_hog.h>
#include <tactility/bindings/pwm_backlight.h>
#include <bindings/st77922.h>
#include <bindings/st77922_touch.h>
#include <bindings/es8311.h>
/ {
compatible = "root";
model = "LCDWIKI/Hosyond ES3C35P";
wifi0 {
compatible = "espressif,esp32-wifi-pinned";
status = "disabled";
};
ble0 {
compatible = "espressif,esp32-ble";
status = "disabled";
};
gpio0 {
compatible = "espressif,esp32-gpio";
gpio-count = <49>;
};
/* FM8002E speaker amplifier enable, active-low on GPIO1. */
amp_enable {
compatible = "gpio-hog";
pin = <&gpio0 1 GPIO_FLAG_NONE>;
mode = <GPIO_HOG_MODE_OUTPUT_LOW>;
};
adc0 {
compatible = "espressif,esp32-adc-oneshot";
unit-id = <ADC_UNIT_1>;
clk-src = <ADC_RTC_CLK_SRC_DEFAULT>;
channels = <ADC_CHANNEL_7 ADC_ATTEN_DB_12 ADC_BITWIDTH_DEFAULT>;
};
/* BAT+ through a 200K/200K divider into GPIO8 / ADC1_CH7. */
battery-sense {
compatible = "battery-sense";
io-channel = <&adc0 0>;
reference-voltage-mv = <3300>;
multiplier = <2000>;
};
i2s0 {
compatible = "espressif,esp32-i2s";
port = <I2S_NUM_0>;
pin-bclk = <&gpio0 18 GPIO_FLAG_NONE>;
pin-ws = <&gpio0 21 GPIO_FLAG_NONE>;
pin-data-out = <&gpio0 15 GPIO_FLAG_NONE>;
pin-data-in = <&gpio0 16 GPIO_FLAG_NONE>;
pin-mclk = <&gpio0 17 GPIO_FLAG_NONE>;
};
i2c0 {
compatible = "espressif,esp32-i2c";
port = <I2C_NUM_0>;
clock-frequency = <400000>;
pin-sda = <&gpio0 38 GPIO_FLAG_NONE>;
pin-scl = <&gpio0 39 GPIO_FLAG_NONE>;
touch@55 {
compatible = "sitronix,st77922-touch";
reg = <0x55>;
x-max = <320>;
y-max = <480>;
pin-reset = <&gpio0 48 GPIO_FLAG_NONE>;
pin-interrupt = <&gpio0 47 GPIO_FLAG_NONE>;
};
es8311: es8311@18 {
compatible = "everest,es8311";
reg = <0x18>;
i2s = <&i2s0>;
};
};
display_backlight_pwm {
compatible = "espressif,esp32-pwm-ledc";
pin = <&gpio0 41 GPIO_FLAG_NONE>;
period-ns = <200000>;
ledc-timer = <0>;
ledc-channel = <0>;
};
display_backlight {
compatible = "pwm-backlight";
status = "disabled";
pwm = <&display_backlight_pwm>;
};
spi0 {
compatible = "espressif,esp32-spi";
host = <SPI2_HOST>;
pin-sclk = <&gpio0 12 GPIO_FLAG_NONE>;
pin-mosi = <&gpio0 11 GPIO_FLAG_NONE>;
pin-miso = <&gpio0 13 GPIO_FLAG_NONE>;
pin-wp = <&gpio0 14 GPIO_FLAG_NONE>;
pin-hd = <&gpio0 9 GPIO_FLAG_NONE>;
cs-gpios = <&gpio0 10 GPIO_FLAG_NONE>;
/* Accommodate the driver's 1/10-frame DMA staging transfers, matching
* the vendor LVGL port's full-frame refresh path. */
max-transfer-size = <65536>;
display@0 {
compatible = "sitronix,st77922";
horizontal-resolution = <320>;
vertical-resolution = <480>;
/* 80 MHz works in the vendor demo, but produces visible QSPI corruption on
* some modules/cables. The component's 40 MHz default is reliably clean. */
pixel-clock-hz = <40000000>;
backlight = <&display_backlight>;
};
};
sdmmc0 {
compatible = "espressif,esp32-sdmmc";
pin-clk = <&gpio0 5 GPIO_FLAG_NONE>;
pin-cmd = <&gpio0 4 GPIO_FLAG_NONE>;
pin-d0 = <&gpio0 6 GPIO_FLAG_NONE>;
pin-d1 = <&gpio0 7 GPIO_FLAG_NONE>;
pin-d2 = <&gpio0 2 GPIO_FLAG_NONE>;
pin-d3 = <&gpio0 3 GPIO_FLAG_NONE>;
slot = <SDMMC_HOST_SLOT_1>;
bus-width = <4>;
};
};
+9
View File
@@ -0,0 +1,9 @@
#include <tactility/module.h>
extern "C" {
Module es3c35p_module = {
.name = "es3c35p"
};
}
+2 -14
View File
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module generic_esp32_module = {
return ERROR_NONE; .name = "generic-esp32"
}
static error_t stop() {
return ERROR_NONE;
}
struct Module generic_esp32_module = {
.name = "generic-esp32",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
+2 -14
View File
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module generic_esp32c6_module = {
return ERROR_NONE; .name = "generic-esp32c6"
}
static error_t stop() {
return ERROR_NONE;
}
struct Module generic_esp32c6_module = {
.name = "generic-esp32c6",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
+2 -14
View File
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module generic_esp32p4_module = {
return ERROR_NONE; .name = "generic-esp32p4"
}
static error_t stop() {
return ERROR_NONE;
}
struct Module generic_esp32p4_module = {
.name = "generic-esp32p4",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
+2 -14
View File
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module generic_esp32s3_module = {
return ERROR_NONE; .name = "generic-esp32s3"
}
static error_t stop() {
return ERROR_NONE;
}
struct Module generic_esp32s3_module = {
.name = "generic-esp32s3",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() {
return ERROR_NONE;
}
static error_t stop() {
return ERROR_NONE;
}
Module guition_jc1060p470ciwy_module = { Module guition_jc1060p470ciwy_module = {
.name = "guition-jc1060p470ciwy", .name = "guition-jc1060p470ciwy"
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
+2 -14
View File
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module guition_jc2432w328c_module = {
return ERROR_NONE; .name = "guition-jc2432w328c"
}
static error_t stop() {
return ERROR_NONE;
}
struct Module guition_jc2432w328c_module = {
.name = "guition-jc2432w328c",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
@@ -1,6 +0,0 @@
dependencies:
- Platforms/platform-esp32
- Drivers/dummy-i2s-amp-module
- Drivers/audio-stream-module
- Drivers/axs15231b-module
dts: guition,jc3248w535c.dts
@@ -1,182 +0,0 @@
/dts-v1/;
#include <tactility/bindings/root.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_i2s.h>
#include <tactility/bindings/esp32_spi.h>
#include <tactility/bindings/esp32_uart.h>
#include <tactility/bindings/esp32_sdspi.h>
#include <tactility/bindings/esp32_pwm_ledc.h>
#include <tactility/bindings/pwm_backlight.h>
#include <bindings/dummy_i2s_amp.h>
#include <bindings/axs15231b_display.h>
#include <bindings/axs15231b_touch.h>
/ {
compatible = "root";
model = "Guition JC3248W535C";
wifi0 {
compatible = "espressif,esp32-wifi-pinned";
status = "disabled";
};
ble0 {
compatible = "espressif,esp32-ble";
status = "disabled";
};
gpio0 {
compatible = "espressif,esp32-gpio";
gpio-count = <49>;
};
i2c_external: i2c1 {
compatible = "espressif,esp32-i2c";
port = <I2C_NUM_1>;
clock-frequency = <400000>;
pin-sda = <&gpio0 17 GPIO_FLAG_NONE>;
pin-scl = <&gpio0 18 GPIO_FLAG_NONE>;
};
i2s0 {
compatible = "espressif,esp32-i2s";
port = <I2S_NUM_0>;
pin-bclk = <&gpio0 42 GPIO_FLAG_NONE>;
pin-ws = <&gpio0 2 GPIO_FLAG_NONE>;
pin-data-out = <&gpio0 41 GPIO_FLAG_NONE>;
};
speaker0 {
compatible = "nsiway,ns4168";
i2s = <&i2s0>;
};
display_backlight_pwm {
compatible = "espressif,esp32-pwm-ledc";
pin = <&gpio0 1 GPIO_FLAG_NONE>;
period-ns = <25000>;
ledc-timer = <0>;
ledc-channel = <0>;
// Matches the deprecated HAL's old PwmBacklight driver, which hardcoded 8-bit duty
// resolution (the binding's own default is 10-bit).
duty-resolution = <8>;
};
display_backlight {
compatible = "pwm-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";
pwm = <&display_backlight_pwm>;
};
spi0 {
compatible = "espressif,esp32-spi";
host = <SPI2_HOST>;
cs-gpios = <&gpio0 45 GPIO_FLAG_NONE>;
pin-mosi = <&gpio0 21 GPIO_FLAG_NONE>;
pin-miso = <&gpio0 48 GPIO_FLAG_NONE>;
pin-sclk = <&gpio0 47 GPIO_FLAG_NONE>;
pin-wp = <&gpio0 40 GPIO_FLAG_NONE>;
pin-hd = <&gpio0 39 GPIO_FLAG_NONE>;
display@0 {
compatible = "axs,axs15231b";
horizontal-resolution = <320>;
vertical-resolution = <480>;
pin-te = <&gpio0 38 GPIO_FLAG_NONE>;
backlight = <&display_backlight>;
// Confirmed on real hardware: a sub-region draw desyncs this panel's row
// auto-increment counter (no QSPI row-address command exists to resync it),
// producing a sheared/doubled image - see requires-full-frame's binding doc.
requires-full-frame;
// Vendor bring-up sequence, carried over unchanged from the deprecated HAL's old
// Axs15231bDisplay.cpp. Framing is [cmd, data-length, delay-ms, data-length bytes of
// data...] - see axs15231b-module's init-sequence binding property for the encoding.
init-sequence = [
0xBB 8 0 0x00 0x00 0x00 0x00 0x00 0x00 0x5A 0xA5
0xA0 17 0 0xC0 0x10 0x00 0x02 0x00 0x00 0x04 0x3F 0x20 0x05 0x3F 0x3F 0x00 0x00 0x00 0x00 0x00
0xA2 31 0 0x30 0x3C 0x24 0x14 0xD0 0x20 0xFF 0xE0 0x40 0x19 0x80 0x80 0x80 0x20 0xf9 0x10 0x02 0xff 0xff 0xF0 0x90 0x01 0x32 0xA0 0x91 0xE0 0x20 0x7F 0xFF 0x00 0x5A
0xD0 30 0 0xE0 0x40 0x51 0x24 0x08 0x05 0x10 0x01 0x20 0x15 0x42 0xC2 0x22 0x22 0xAA 0x03 0x10 0x12 0x60 0x14 0x1E 0x51 0x15 0x00 0x8A 0x20 0x00 0x03 0x3A 0x12
0xA3 22 0 0xA0 0x06 0xAa 0x00 0x08 0x02 0x0A 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x00 0x55 0x55
0xC1 30 0 0x31 0x04 0x02 0x02 0x71 0x05 0x24 0x55 0x02 0x00 0x41 0x00 0x53 0xFF 0xFF 0xFF 0x4F 0x52 0x00 0x4F 0x52 0x00 0x45 0x3B 0x0B 0x02 0x0d 0x00 0xFF 0x40
0xC3 11 0 0x00 0x00 0x00 0x50 0x03 0x00 0x00 0x00 0x01 0x80 0x01
0xC4 29 0 0x00 0x24 0x33 0x80 0x00 0xea 0x64 0x32 0xC8 0x64 0xC8 0x32 0x90 0x90 0x11 0x06 0xDC 0xFA 0x00 0x00 0x80 0xFE 0x10 0x10 0x00 0x0A 0x0A 0x44 0x50
0xC5 23 0 0x18 0x00 0x00 0x03 0xFE 0x3A 0x4A 0x20 0x30 0x10 0x88 0xDE 0x0D 0x08 0x0F 0x0F 0x01 0x3A 0x4A 0x20 0x10 0x10 0x00
0xC6 20 0 0x05 0x0A 0x05 0x0A 0x00 0xE0 0x2E 0x0B 0x12 0x22 0x12 0x22 0x01 0x03 0x00 0x3F 0x6A 0x18 0xC8 0x22
0xC7 20 0 0x50 0x32 0x28 0x00 0xa2 0x80 0x8f 0x00 0x80 0xff 0x07 0x11 0x9c 0x67 0xff 0x24 0x0c 0x0d 0x0e 0x0f
0xC9 4 0 0x33 0x44 0x44 0x01
0xCF 27 0 0x2C 0x1E 0x88 0x58 0x13 0x18 0x56 0x18 0x1E 0x68 0x88 0x00 0x65 0x09 0x22 0xC4 0x0C 0x77 0x22 0x44 0xAA 0x55 0x08 0x08 0x12 0xA0 0x08
0xD5 30 0 0x40 0x8E 0x8D 0x01 0x35 0x04 0x92 0x74 0x04 0x92 0x74 0x04 0x08 0x6A 0x04 0x46 0x03 0x03 0x03 0x03 0x82 0x01 0x03 0x00 0xE0 0x51 0xA1 0x00 0x00 0x00
0xD6 30 0 0x10 0x32 0x54 0x76 0x98 0xBA 0xDC 0xFE 0x93 0x00 0x01 0x83 0x07 0x07 0x00 0x07 0x07 0x00 0x03 0x03 0x03 0x03 0x03 0x03 0x00 0x84 0x00 0x20 0x01 0x00
0xD7 19 0 0x03 0x01 0x0b 0x09 0x0f 0x0d 0x1E 0x1F 0x18 0x1d 0x1f 0x19 0x40 0x8E 0x04 0x00 0x20 0xA0 0x1F
0xD8 12 0 0x02 0x00 0x0a 0x08 0x0e 0x0c 0x1E 0x1F 0x18 0x1d 0x1f 0x19
0xD9 12 0 0x1F 0x1F 0x1F 0x1F 0x1F 0x1F 0x1F 0x1F 0x1F 0x1F 0x1F 0x1F
0xDD 12 0 0x1F 0x1F 0x1F 0x1F 0x1F 0x1F 0x1F 0x1F 0x1F 0x1F 0x1F 0x1F
0xDF 8 0 0x44 0x73 0x4B 0x69 0x00 0x0A 0x02 0x90
0xE0 17 0 0x3B 0x28 0x10 0x16 0x0c 0x06 0x11 0x28 0x5c 0x21 0x0D 0x35 0x13 0x2C 0x33 0x28 0x0D
0xE1 17 0 0x37 0x28 0x10 0x16 0x0b 0x06 0x11 0x28 0x5C 0x21 0x0D 0x35 0x14 0x2C 0x33 0x28 0x0F
0xE2 17 0 0x3B 0x07 0x12 0x18 0x0E 0x0D 0x17 0x35 0x44 0x32 0x0C 0x14 0x14 0x36 0x3A 0x2F 0x0D
0xE3 17 0 0x37 0x07 0x12 0x18 0x0E 0x0D 0x17 0x35 0x44 0x32 0x0C 0x14 0x14 0x36 0x32 0x2F 0x0F
0xE4 17 0 0x3B 0x07 0x12 0x18 0x0E 0x0D 0x17 0x39 0x44 0x2E 0x0C 0x14 0x14 0x36 0x3A 0x2F 0x0D
0xE5 17 0 0x37 0x07 0x12 0x18 0x0E 0x0D 0x17 0x39 0x44 0x2E 0x0C 0x14 0x14 0x36 0x3A 0x2F 0x0F
0xA4 16 0 0x85 0x85 0x95 0x82 0xAF 0xAA 0xAA 0x80 0x10 0x30 0x40 0x40 0x20 0xFF 0x60 0x30
0xA4 4 0 0x85 0x85 0x95 0x85
0xBB 8 0 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x13 0 0
0x35 1 0 0x00
0x11 0 120
0x2C 4 0 0x00 0x00 0x00 0x00
];
};
};
// Declared (and thus started) after display@0 above, not before: the display and touch
// sides of this chip share the same silicon, and the deprecated HAL's old Hal.cpp always
// started the display first, then the touch device second. Starting touch first (as an
// earlier version of this devicetree did) let touch's I2C handshake succeed initially, but
// the display's own reset/init sequence running afterward then reset the whole chip and
// left the touch interface unresponsive - confirmed on real hardware (I2C writes started
// failing consistently right after display bring-up completed).
i2c_internal: i2c0 {
compatible = "espressif,esp32-i2c";
port = <I2C_NUM_0>;
clock-frequency = <400000>;
pin-sda = <&gpio0 4 GPIO_FLAG_NONE>;
pin-scl = <&gpio0 8 GPIO_FLAG_NONE>;
touch {
compatible = "axs,axs15231b-touch";
reg = <0x3B>;
x-max = <320>;
y-max = <480>;
};
};
spi1 {
compatible = "espressif,esp32-spi";
host = <SPI3_HOST>;
cs-gpios = <&gpio0 10 GPIO_FLAG_NONE>;
pin-mosi = <&gpio0 11 GPIO_FLAG_NONE>;
pin-miso = <&gpio0 13 GPIO_FLAG_NONE>;
pin-sclk = <&gpio0 12 GPIO_FLAG_NONE>;
sdcard@0 {
compatible = "espressif,esp32-sdspi";
frequency-khz = <20000>;
};
};
// P1 header
uart0 {
compatible = "espressif,esp32-uart";
port = <UART_NUM_0>;
pin-tx = <&gpio0 43 GPIO_FLAG_NONE>;
pin-rx = <&gpio0 44 GPIO_FLAG_NONE>;
};
};
@@ -1,21 +0,0 @@
#include <tactility/module.h>
extern "C" {
static error_t start() {
return ERROR_NONE;
}
static error_t stop() {
return ERROR_NONE;
}
struct Module guition_jc3248w535c_module = {
.name = "guition-jc3248w535c",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
};
}
+2 -14
View File
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module guition_jc8048w550c_module = {
return ERROR_NONE; .name = "guition-jc8048w550c"
}
static error_t stop() {
return ERROR_NONE;
}
struct Module guition_jc8048w550c_module = {
.name = "guition-jc8048w550c",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
@@ -2,20 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module heltec_wifi_lora_32_v3_module = {
return ERROR_NONE; .name = "heltec-wifi-lora-32-v3"
}
static error_t stop() {
return ERROR_NONE;
}
struct Module heltec_wifi_lora_32_v3_module = {
.name = "heltec-wifi-lora-32-v3",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
+1 -1
View File
@@ -3,5 +3,5 @@ file(GLOB_RECURSE SOURCE_FILES source/*.c*)
idf_component_register( idf_component_register(
SRCS ${SOURCE_FILES} SRCS ${SOURCE_FILES}
INCLUDE_DIRS "source" INCLUDE_DIRS "source"
REQUIRES Tactility GDEQ031T10 driver REQUIRES TactilityKernel
) )
+8 -5
View File
@@ -1,6 +1,6 @@
general.vendor=LilyGO general.vendor=LilyGO
general.name=T-Deck Max general.name=T-Deck Max
# SD card support is not yet working; remove once it is functional. # SD card support is not yet working, display driver is untested since refactoring; remove once it is functional.
general.incubating=true general.incubating=true
apps.launcherAppId=Launcher apps.launcherAppId=Launcher
@@ -18,14 +18,17 @@ hardware.bluetooth=true
# Internal until the SD card is verified working on this board; switch to SD then. # Internal until the SD card is verified working on this board; switch to SD then.
storage.userDataLocation=Internal storage.userDataLocation=Internal
dependencies.useDeprecatedHal=false
display.size=3.1" display.size=3.1"
display.shape=rectangle display.shape=rectangle
display.dpi=128 display.dpi=128
# The GDEQ031T10 e-paper is monochrome, but its driver renders via lvgl.colorDepth=8
# LV_COLOR_FORMAT_I1 on its own display. The global LVGL color depth must stay
# at 16: esp_lvgl_port refuses to compile with LV_COLOR_DEPTH_1 set.
lvgl.colorDepth=16
# Monochrome theme: the default colour theme renders accent-coloured UI that # Monochrome theme: the default colour theme renders accent-coloured UI that
# thresholds to invisible on a 1bpp panel (enables CONFIG_LV_USE_THEME_MONO). # thresholds to invisible on a 1bpp panel (enables CONFIG_LV_USE_THEME_MONO).
lvgl.theme=Mono lvgl.theme=Mono
cdn.warningMessage=Display not reliably working. Use at your own risk.
sdkconfig.CONFIG_LV_THEME_DEFAULT_TRANSITION_TIME=0
+1
View File
@@ -2,6 +2,7 @@ dependencies:
- Platforms/platform-esp32 - Platforms/platform-esp32
- Drivers/xl9555-module - Drivers/xl9555-module
- Drivers/cst66xx-module - Drivers/cst66xx-module
- Drivers/gdeq031t10-module
- Drivers/tca8418-module - Drivers/tca8418-module
- Drivers/sy6970-module - Drivers/sy6970-module
- Drivers/bq27220-module - Drivers/bq27220-module
@@ -11,6 +11,7 @@
#include <tactility/bindings/pwm_backlight.h> #include <tactility/bindings/pwm_backlight.h>
#include <bindings/xl9555.h> #include <bindings/xl9555.h>
#include <bindings/cst66xx.h> #include <bindings/cst66xx.h>
#include <bindings/gdeq031t10.h>
#include <bindings/tca8418.h> #include <bindings/tca8418.h>
#include <bindings/sy6970.h> #include <bindings/sy6970.h>
#include <bindings/bq27220.h> #include <bindings/bq27220.h>
@@ -143,6 +144,17 @@
// exceeds the default ~4 KB transfer limit. Raise the bus limit to fit it. // exceeds the default ~4 KB transfer limit. Raise the bus limit to fit it.
max-transfer-size = <65536>; max-transfer-size = <65536>;
display@0 {
compatible = "gooddisplay,gdeq031t10";
pin-dc = <&gpio0 35 GPIO_FLAG_NONE>;
pin-reset = <&gpio0 9 GPIO_FLAG_NONE>;
pin-busy = <&gpio0 37 GPIO_FLAG_NONE>;
clock-speed-hz = <10000000>;
// Default to a fast (~1s) refresh for the automatic ghost-clears so the
// full-screen flash they cause is as short as possible.
refresh-mode = <GDEQ031T10_REFRESH_FAST>;
};
sdcard@1 { sdcard@1 {
compatible = "espressif,esp32-sdspi"; compatible = "espressif,esp32-sdspi";
status = "disabled"; status = "disabled";
@@ -1,35 +0,0 @@
#include "devices/Display.h"
#include <Tactility/hal/Configuration.h>
#include <tactility/check.h>
#include <tactility/device.h>
#include <tactility/drivers/esp32_spi.h>
using namespace tt::hal;
static bool initBoot() {
// The LoRa and SD chip-selects share the EPD's SPI bus but aren't wired up
// yet. spi0's start() already drives every cs-gpio high during kernel init;
// re-assert deselection before the EPD driver first transacts, as a cheap
// guard against either chip latching stray EPD command bytes (same pattern
// as the esp32_sdspi mount path).
auto* spi0 = device_find_by_name("spi0");
check(spi0 != nullptr);
esp32_spi_deselect_all_cs(spi0);
return true;
}
static DeviceVector createDevices() {
// Touch, keyboard and battery/charging are kernel drivers (cst66xx, tca8418, sy6970,
// bq27220 - see the .dts), started independently of this HAL layer. Only the EPD
// display remains on the deprecated HAL.
return DeviceVector {
createDisplay()
};
}
extern const Configuration hardwareConfiguration = {
.initBoot = initBoot,
.createDevices = createDevices
};
@@ -1,29 +0,0 @@
#include "Display.h"
#include <Gdeq031t10Display.h>
// Pins from Xinyuan-LilyGO/T-Deck-MAX's lib/TDeckMaxBoard/src/TDeckMaxBoard.h and docs/pinmap.md.
constexpr auto EPD_SPI_HOST = SPI2_HOST;
constexpr auto EPD_PIN_CS = GPIO_NUM_34;
constexpr auto EPD_PIN_DC = GPIO_NUM_35;
constexpr auto EPD_PIN_RST = GPIO_NUM_9;
constexpr auto EPD_PIN_BUSY = GPIO_NUM_37;
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
// Touch is a kernel driver (hynitron,cst66xx - see the .dts), discovered and fed to LVGL
// independently of this display, so no touch device is passed into the configuration here.
auto configuration = std::make_unique<Gdeq031t10Display::Configuration>(
EPD_SPI_HOST,
EPD_PIN_CS,
EPD_PIN_DC,
EPD_PIN_RST,
EPD_PIN_BUSY,
nullptr,
10'000'000,
// Default to a fast (~1s) refresh for the automatic ghost-clears so the
// full-screen flash they cause is as short as possible.
Gdeq031t10Display::RefreshMode::Fast
);
return std::make_shared<Gdeq031t10Display>(std::move(configuration));
}
@@ -1,5 +0,0 @@
#pragma once
#include <Tactility/hal/display/DisplayDevice.h>
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();
+2 -16
View File
@@ -2,22 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module lilygo_tdeck_max_module = {
// Empty for now .name = "lilygo-tdeck-max"
return ERROR_NONE;
}
static error_t stop() {
// Empty for now
return ERROR_NONE;
}
struct Module lilygo_tdeck_max_module = {
.name = "lilygo-tdeck-max",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
@@ -12,6 +12,8 @@ hardware.tinyUsb=true
hardware.esptoolFlashFreq=120M hardware.esptoolFlashFreq=120M
hardware.bluetooth=true hardware.bluetooth=true
dependencies.useDeprecatedHal=false
storage.userDataLocation=SD storage.userDataLocation=SD
display.size=2.8" display.size=2.8"
@@ -19,9 +19,6 @@
constexpr auto* TAG = "tdeck-plus"; constexpr auto* TAG = "tdeck-plus";
// Legacy placeholder (required until legacy HAL is cleaned up everywhere)
extern const tt::hal::Configuration hardwareConfiguration = {};
extern "C" { extern "C" {
void subscribe_events() { void subscribe_events() {
@@ -2,5 +2,6 @@ file(GLOB_RECURSE SOURCE_FILES source/*.c*)
idf_component_register( idf_component_register(
SRCS ${SOURCE_FILES} SRCS ${SOURCE_FILES}
REQUIRES TactilityKernel driver INCLUDE_DIRS "source"
REQUIRES TactilityKernel
) )
@@ -0,0 +1,33 @@
general.vendor=LilyGO
general.name=T-Deck Pro
# The display driver is not reliable yet
general.incubating=true
apps.launcherAppId=Launcher
hardware.target=ESP32S3
hardware.flashSize=16MB
hardware.flashMode=DIO
hardware.spiRam=true
hardware.spiRamMode=AUTO
hardware.spiRamSpeed=80M
hardware.tinyUsb=true
hardware.esptoolFlashFreq=80M
hardware.bluetooth=true
storage.userDataLocation=SD
dependencies.useDeprecatedHal=false
display.size=3.1"
display.shape=rectangle
display.dpi=128
lvgl.colorDepth=8
# Monochrome theme: the default colour theme renders accent-coloured UI that
# thresholds to invisible on a 1bpp panel (enables CONFIG_LV_USE_THEME_MONO).
lvgl.theme=Mono
cdn.warningMessage=Only for hardware revision 1.0! Display not reliably working. Use at your own risk.
sdkconfig.CONFIG_LV_THEME_DEFAULT_TRANSITION_TIME=0
+8
View File
@@ -0,0 +1,8 @@
dependencies:
- Platforms/platform-esp32
- Drivers/cst328-module
- Drivers/gdeq031t10-module
- Drivers/tca8418-module
- Drivers/sy6970-module
- Drivers/bq25896-module
dts: lilygo,tdeck-pro.dts
@@ -0,0 +1,138 @@
/dts-v1/;
#include <tactility/bindings/root.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_master.h>
#include <tactility/bindings/esp32_spi.h>
#include <tactility/bindings/esp32_sdspi.h>
#include <tactility/bindings/esp32_pwm_ledc.h>
#include <tactility/bindings/pwm_backlight.h>
#include <bindings/cst328.h>
#include <bindings/gdeq031t10.h>
#include <bindings/tca8418.h>
#include <bindings/bq25896.h>
// Reference for V1.0 (not V1.1!): https://github.com/Xinyuan-LilyGO/T-Deck-Pro/tree/HD-V1-250326
// lib/TDeckMaxBoard/src/TDeckMaxBoard.h, docs/pinmap.md
/ {
compatible = "root";
model = "LilyGO T-Deck Pro";
wifi0 {
compatible = "espressif,esp32-wifi-pinned";
status = "disabled";
};
ble0 {
compatible = "espressif,esp32-ble";
};
gpio0 {
compatible = "espressif,esp32-gpio";
gpio-count = <49>;
};
i2c0 {
compatible = "espressif,esp32-i2c-master";
port = <I2C_NUM_0>;
clock-frequency = <100000>;
pin-sda = <&gpio0 13 GPIO_FLAG_NONE>;
pin-scl = <&gpio0 14 GPIO_FLAG_NONE>;
touch {
compatible = "hynitron,cst328";
reg = <0x1A>;
pin-reset = <&gpio0 45 GPIO_FLAG_NONE>;
};
// TCA8418 4x10 matrix scanner. Keymaps are written in the vendor's row/column
// orientation (Xinyuan-LilyGO/T-Deck-MAX examples/factory/peri_keypad.cpp); the
// TCA8418 columns are wired in reverse of that order, hence reverse-columns.
// ALT (shift/uppercase) is row 2 col 0; SYM (symbol layer) is row 3 col 8.
keyboard {
compatible = "ti,tca8418";
reg = <0x34>;
rows = <4>;
columns = <10>;
reverse-columns;
keymap-lc = [
113 119 101 114 116 121 117 105 111 112 // q w e r t y u i o p
97 115 100 102 103 104 106 107 108 8 // a s d f g h j k l BACKSPACE
0 122 120 99 118 98 110 109 36 10 // z x c v b n m $ ENTER
0 0 0 0 0 11 48 32 0 9 // PREV 0 SPC NEXT
];
keymap-uc = [
81 87 69 82 84 89 85 73 79 80 // Q W E R T Y U I O P
65 83 68 70 71 72 74 75 76 8 // A S D F G H J K L BACKSPACE
0 90 88 67 86 66 78 77 36 10 // Z X C V B N M $ ENTER
0 0 0 0 0 11 48 32 0 9 // PREV 0 SPC NEXT
];
keymap-sy = [
49 50 51 52 53 54 55 56 57 48 // 1 2 3 4 5 6 7 8 9 0
64 35 43 45 42 47 40 41 95 8 // @ # + - * / ( ) _ BACKSPACE
0 33 63 59 58 39 34 44 46 10 // ! ? ; : ' " , . ENTER
0 0 0 0 0 11 48 32 0 9 // PREV 0 SPC NEXT
];
shift-row = <2>;
shift-col = <0>;
sym-row = <3>;
sym-col = <8>;
};
bq27220 {
compatible = "ti,bq25896";
reg = <0x6B>;
};
};
// Keyboard backlight (LED_PWM), GPIO42. The keypress-triggered flash/decay effect
// from the pre-migration driver isn't reproduced here - kernel drivers don't have a
// home for that kind of UI policy (same reasoning as the touch driver's dropped bezel
// keys). Off by default; app code can drive brightness via the generic pwm-backlight
// API if desired.
keyboard_backlight_pwm {
compatible = "espressif,esp32-pwm-ledc";
pin = <&gpio0 42 GPIO_FLAG_NONE>;
period-ns = <33333>;
ledc-timer = <0>;
ledc-channel = <0>;
};
keyboard_backlight {
compatible = "pwm-backlight";
status = "disabled";
pwm = <&keyboard_backlight_pwm>;
};
spi0 {
compatible = "espressif,esp32-spi";
host = <SPI2_HOST>;
cs-gpios = <&gpio0 34 GPIO_FLAG_NONE>, // 0: EPD display
<&gpio0 48 GPIO_FLAG_NONE>, // 1: SD card
<&gpio0 3 GPIO_FLAG_NONE>; // 2: LoRa radio (SX1262, not wired up yet)
pin-mosi = <&gpio0 33 GPIO_FLAG_NONE>;
pin-miso = <&gpio0 47 GPIO_FLAG_NONE>;
pin-sclk = <&gpio0 36 GPIO_FLAG_NONE>;
// The EPD pushes its whole 9600-byte framebuffer in one SPI write, which
// exceeds the default ~4 KB transfer limit. Raise the bus limit to fit it.
max-transfer-size = <65536>;
display@0 {
compatible = "gooddisplay,gdeq031t10";
pin-dc = <&gpio0 35 GPIO_FLAG_NONE>;
pin-busy = <&gpio0 37 GPIO_FLAG_NONE>;
clock-speed-hz = <10000000>;
// Default to a fast (~1s) refresh for the automatic ghost-clears so the
// full-screen flash they cause is as short as possible.
refresh-mode = <GDEQ031T10_REFRESH_FAST>;
};
sdcard@1 {
compatible = "espressif,esp32-sdspi";
status = "disabled";
frequency-khz = <20000>;
};
};
};
@@ -0,0 +1,9 @@
#include <tactility/module.h>
extern "C" {
struct Module lilygo_tdeck_pro_module = {
.name = "lilygo-tdeck-pro"
};
}
+2
View File
@@ -12,6 +12,8 @@ hardware.tinyUsb=true
hardware.esptoolFlashFreq=120M hardware.esptoolFlashFreq=120M
hardware.bluetooth=true hardware.bluetooth=true
dependencies.useDeprecatedHal=false
storage.userDataLocation=SD storage.userDataLocation=SD
display.size=2.8" display.size=2.8"
+1 -6
View File
@@ -18,9 +18,6 @@
constexpr auto* TAG = "tdeck"; constexpr auto* TAG = "tdeck";
// Legacy placeholder (required until legacy HAL is cleaned up everywhere)
extern const tt::hal::Configuration hardwareConfiguration = {};
extern "C" { extern "C" {
void subscribe_events() { void subscribe_events() {
@@ -63,9 +60,7 @@ static error_t stop() {
Module lilygo_tdeck_module = { Module lilygo_tdeck_module = {
.name = "lilygo-tdeck", .name = "lilygo-tdeck",
.start = start, .start = start,
.stop = stop, .stop = stop
.symbols = nullptr,
.internal = nullptr
}; };
} }
@@ -39,9 +39,6 @@
channels = <ADC_CHANNEL_3 ADC_ATTEN_DB_12 ADC_BITWIDTH_DEFAULT>; channels = <ADC_CHANNEL_3 ADC_ATTEN_DB_12 ADC_BITWIDTH_DEFAULT>;
}; };
// Matches the deprecated HAL's old Power.cpp (EstimatedPower/ChargeFromAdcVoltage default
// config): ADC1 CH3, 2:1 divider with +0.11 display voltage sag compensation
// (adcMultiplier = 2.11, so multiplier = 2110).
battery-sense { battery-sense {
compatible = "battery-sense"; compatible = "battery-sense";
io-channel = <&adc0 0>; io-channel = <&adc0 0>;
+6 -5
View File
@@ -30,16 +30,17 @@ static error_t start() {
} }
static error_t stop() { static error_t stop() {
// Empty for now if (gpio_set_level(POWER_ON_PIN, 0) != ESP_OK) {
return ERROR_RESOURCE;
}
return ERROR_NONE; return ERROR_NONE;
} }
struct Module lilygo_tdisplay_s3_module = { Module lilygo_tdisplay_s3_module = {
.name = "lilygo-tdisplay-s3", .name = "lilygo-tdisplay-s3",
.start = start, .start = start,
.stop = stop, .stop = stop
.symbols = nullptr,
.internal = nullptr
}; };
} }
+2 -16
View File
@@ -2,22 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module lilygo_tdisplay_module = {
// Empty for now .name = "lilygo-tdisplay"
return ERROR_NONE;
}
static error_t stop() {
// Empty for now
return ERROR_NONE;
}
struct Module lilygo_tdisplay_module = {
.name = "lilygo-tdisplay",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
+2 -16
View File
@@ -2,22 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module lilygo_tdongle_s3_module = {
// Empty for now .name = "lilygo-tdongle-s3"
return ERROR_NONE;
}
static error_t stop() {
// Empty for now
return ERROR_NONE;
}
struct Module lilygo_tdongle_s3_module = {
.name = "lilygo-tdongle-s3",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
+2 -16
View File
@@ -2,22 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module lilygo_thmi_module = {
// Empty for now .name = "lilygo-thmi"
return ERROR_NONE;
}
static error_t stop() {
// Empty for now
return ERROR_NONE;
}
struct Module lilygo_thmi_module = {
.name = "lilygo-thmi",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
@@ -13,6 +13,8 @@ hardware.tinyUsb=true
hardware.esptoolFlashFreq=40M hardware.esptoolFlashFreq=40M
hardware.bluetooth=true hardware.bluetooth=true
dependencies.useDeprecatedHal=false
storage.userDataLocation=SD storage.userDataLocation=SD
display.size=2.33" display.size=2.33"
+8 -16
View File
@@ -15,18 +15,15 @@
constexpr auto* TAG = "T-Lora Pager"; constexpr auto* TAG = "T-Lora Pager";
// Legacy placeholder (required until legacy HAL is cleaned up everywhere). All board
// peripherals are kernel drivers now (see the .dts): display (st7796), battery (bq27220),
// charger power-off (bq25896), haptics (drv2605), keyboard (tca8418) and the encoder wheel
// (lilygo,tpager-encoder, bound to LVGL below).
extern const tt::hal::Configuration hardwareConfiguration = {};
extern "C" { extern "C" {
static void subscribe_events() { tt::kernel::SystemEventSubscription event_subscription;
static error_t start() {
LOG_I(TAG, LOG_MESSAGE_POWER_ON_START); LOG_I(TAG, LOG_MESSAGE_POWER_ON_START);
tt::kernel::subscribeSystemEvent(tt::kernel::SystemEvent::BootSplash, [](tt::kernel::SystemEvent) { event_subscription = tt::kernel::subscribeSystemEvent(tt::kernel::SystemEvent::BootSplash, [](tt::kernel::SystemEvent) {
// The kernel tpager_encoder device is already started by kernel_init(); this just // The kernel tpager_encoder device is already started by kernel_init(); this just
// registers it as an LVGL input device, which requires LVGL to be up first. // registers it as an LVGL input device, which requires LVGL to be up first.
lvgl_lock(); lvgl_lock();
@@ -50,23 +47,18 @@ static void subscribe_events() {
} }
} }
}); });
}
static error_t start() {
subscribe_events();
return ERROR_NONE; return ERROR_NONE;
} }
static error_t stop() { static error_t stop() {
tt::kernel::unsubscribeSystemEvent(event_subscription);
return ERROR_NONE; return ERROR_NONE;
} }
struct Module lilygo_tlora_pager_module = { Module lilygo_tlora_pager_module = {
.name = "lilygo-tlora-pager", .name = "lilygo-tlora-pager",
.start = start, .start = start,
.stop = stop, .stop = stop
.symbols = nullptr,
.internal = nullptr
}; };
} }
@@ -2,22 +2,8 @@
extern "C" { extern "C" {
static error_t start() { Module m5stack_cardputer_adv_module = {
// Empty for now .name = "m5stack-cardputer-adv"
return ERROR_NONE;
}
static error_t stop() {
// Empty for now
return ERROR_NONE;
}
struct Module m5stack_cardputer_adv_module = {
.name = "m5stack-cardputer-adv",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
+1 -15
View File
@@ -2,22 +2,8 @@
extern "C" { extern "C" {
static error_t start() {
// Empty for now
return ERROR_NONE;
}
static error_t stop() {
// Empty for now
return ERROR_NONE;
}
Module m5stack_cardputer_module = { Module m5stack_cardputer_module = {
.name = "m5stack-cardputer", .name = "m5stack-cardputer"
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
}; };
} }
+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( idf_component_register(
SRCS ${SOURCE_FILES} SRCS ${SOURCE_FILES}
INCLUDE_DIRS "Source" REQUIRES TactilityKernel
REQUIRES Tactility esp_lvgl_port esp_lcd AXP192 ILI934x FT6x36 driver vfs fatfs
) )
@@ -1,22 +0,0 @@
#include "devices/Display.h"
#include "devices/Power.h"
#include <Tactility/hal/Configuration.h>
using namespace tt::hal;
static bool initBoot() {
return initAxp();
}
static DeviceVector createDevices() {
return {
getAxp192(),
createDisplay()
};
}
extern const Configuration hardwareConfiguration = {
.initBoot = initBoot,
.createDevices = createDevices
};
@@ -1,48 +0,0 @@
#include "Display.h"
#include <Ft6x36Touch.h>
#include <Ili934xDisplay.h>
std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
auto configuration = std::make_unique<Ft6x36Touch::Configuration>(
I2C_NUM_0,
LCD_HORIZONTAL_RESOLUTION,
LCD_VERTICAL_RESOLUTION,
false,
false,
false,
GPIO_NUM_NC,
GPIO_NUM_39
);
return std::make_shared<Ft6x36Touch>(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 = nullptr,
.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,16 +0,0 @@
#pragma once
#include <Tactility/hal/display/DisplayDevice.h>
#include <driver/gpio.h>
#include <driver/spi_common.h>
#include <memory>
constexpr auto LCD_SPI_HOST = SPI2_HOST;
constexpr auto LCD_PIN_CS = GPIO_NUM_5;
constexpr auto LCD_PIN_DC = GPIO_NUM_15;
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;
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();
@@ -1,36 +0,0 @@
#include <Axp192.h>
#include <tactility/device.h>
static std::shared_ptr<Axp192> axp192 = nullptr;
std::shared_ptr<Axp192> createAxp192() {
assert(axp192 == nullptr);
auto configuration = std::make_unique<Axp192::Configuration>(device_find_by_name("i2c_internal"));
axp192 = std::make_shared<Axp192>(std::move(configuration));
return axp192;
}
std::shared_ptr<Axp192> getAxp192() {
assert(axp192 != nullptr);
return axp192;
}
bool initAxp() {
const auto axp = createAxp192();
return axp->init([](auto* driver) {
axp192_ioctl(driver, AXP192_LDO2_SET_VOLTAGE, 3300); // LCD + SD
axp192_ioctl(driver, AXP192_LDO3_SET_VOLTAGE, 0); // VIB_MOTOR STOP
axp192_ioctl(driver, AXP192_DCDC3_SET_VOLTAGE, 3300);
axp192_ioctl(driver, AXP192_LDO2_ENABLE);
axp192_ioctl(driver, AXP192_LDO3_DISABLE);
axp192_ioctl(driver, AXP192_DCDC3_ENABLE);
axp192_write(driver, AXP192_PWM1_DUTY_CYCLE_2, 255); // PWM 255 (LED OFF)
axp192_write(driver, AXP192_GPIO1_CONTROL, 0x02); // GPIO1 PWM
// TODO: We could charge at 390mA according to the M5Unified code, but the AXP driver in M5Unified limits to 132mA, so it's unclear what the AXP supports.
return true;
});
}
@@ -1,9 +0,0 @@
#pragma once
#include <Axp192.h>
bool initAxp();
// Must call initAxp() first before this returns a non-nullptr response
std::shared_ptr<Axp192> getAxp192();
-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_core2_module = {
.name = "m5stack-core2",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
};
}
+4
View File
@@ -12,6 +12,8 @@ hardware.esptoolFlashFreq=80M
storage.userDataLocation=SD storage.userDataLocation=SD
dependencies.useDeprecatedHal=false
display.size=2" display.size=2"
display.shape=rectangle display.shape=rectangle
display.dpi=200 display.dpi=200
@@ -19,3 +21,5 @@ display.dpi=200
cdn.warningMessage=This board implementation concerns the original Core2 hardware and **not** the v1.1 variant cdn.warningMessage=This board implementation concerns the original Core2 hardware and **not** the v1.1 variant
lvgl.colorDepth=16 lvgl.colorDepth=16
sdkconfig.CONFIG_CODEC_DUMMY_SUPPORT=y
+6
View File
@@ -1,5 +1,11 @@
dependencies: dependencies:
- Platforms/platform-esp32 - Platforms/platform-esp32
- Drivers/audio-stream-module
- Drivers/pdm-mic-module
- Drivers/dummy-i2s-amp-module
- Drivers/mpu6886-module - Drivers/mpu6886-module
- Drivers/bm8563-module - Drivers/bm8563-module
- Drivers/axp192-module
- Drivers/ft5x06-module
- Drivers/ili9341-module
dts: m5stack,core2.dts dts: m5stack,core2.dts
+50 -6
View File
@@ -6,12 +6,16 @@
#include <tactility/bindings/esp32_grove.h> #include <tactility/bindings/esp32_grove.h>
#include <tactility/bindings/esp32_i2c.h> #include <tactility/bindings/esp32_i2c.h>
#include <tactility/bindings/esp32_i2s.h> #include <tactility/bindings/esp32_i2s.h>
#include <tactility/bindings/esp32_sdspi.h>
#include <tactility/bindings/esp32_spi.h> #include <tactility/bindings/esp32_spi.h>
#include <tactility/bindings/esp32_uart.h> #include <tactility/bindings/esp32_uart.h>
#include <bindings/mpu6886.h> #include <bindings/mpu6886.h>
#include <bindings/bm8563.h> #include <bindings/bm8563.h>
#include <tactility/bindings/esp32_sdspi.h> #include <bindings/axp192.h>
#include <tactility/bindings/display_placeholder.h> #include <bindings/ft5x06.h>
#include <bindings/ili9341.h>
#include <bindings/dummy_i2s_amp.h>
#include <bindings/pdm_mic.h>
// Reference: https://docs.m5stack.com/en/core/Core2 // Reference: https://docs.m5stack.com/en/core/Core2
/ { / {
@@ -44,6 +48,32 @@
compatible = "belling,bm8563"; compatible = "belling,bm8563";
reg = <0x51>; reg = <0x51>;
}; };
axp192 {
compatible = "x-powers,axp192";
reg = <0x34>;
dcdc1-enable; // ESP32 + peripherals main 3V3 rail - must stay on
dcdc1-voltage = <3300>;
dcdc3-enable; // LCD backlight
dcdc3-voltage = <3300>;
ldo2-enable; // LCD logic + SD card
ldo2-voltage = <3300>;
// ldo3 (vibration motor) intentionally left disabled
exten-enable; // 5V boost (speaker amp etc.)
gpio1-pwm; // GPIO1 as PWM1 output, drives the notification LED
gpio1-pwm1-duty-cycle = <255>; // 255 = LED off
};
// FT6x36 driver doesn't reliably work when power cycling,
// or when the driver was powering on with its own power supply (not USB-C).
// The driver would not find the device and init would fail.
touch {
compatible = "focaltech,ft5x06";
reg = <0x38>;
x-max = <320>;
y-max = <240>;
pin-interrupt = <&gpio0 39 GPIO_FLAG_NONE>;
};
}; };
port_a: grove0 { port_a: grove0 {
@@ -66,18 +96,21 @@
pin-sclk = <&gpio0 18 GPIO_FLAG_NONE>; pin-sclk = <&gpio0 18 GPIO_FLAG_NONE>;
display@0 { display@0 {
compatible = "display-placeholder"; compatible = "ilitek,ili9341";
horizontal-resolution = <320>;
vertical-resolution = <240>;
invert-color;
bgr-order;
pixel-clock-hz = <40000000>;
pin-dc = <&gpio0 15 GPIO_FLAG_NONE>;
}; };
sdcard@1 { sdcard@1 {
compatible = "espressif,esp32-sdspi"; compatible = "espressif,esp32-sdspi";
status = "disabled"; // Must be started after display
frequency-khz = <20000>; frequency-khz = <20000>;
}; };
}; };
// NS4168: Speaker and microphone
// TODO: Init microphone via I2C: https://github.com/m5stack/M5Unified/blob/a6256725481f1bc366655fa48cf03b6095e30ad1/src/M5Unified.cpp#L391C19-L391C44
i2s0 { i2s0 {
compatible = "espressif,esp32-i2s"; compatible = "espressif,esp32-i2s";
port = <I2S_NUM_0>; port = <I2S_NUM_0>;
@@ -86,4 +119,15 @@
pin-data-out = <&gpio0 2 GPIO_FLAG_NONE>; pin-data-out = <&gpio0 2 GPIO_FLAG_NONE>;
pin-data-in = <&gpio0 34 GPIO_FLAG_NONE>; pin-data-in = <&gpio0 34 GPIO_FLAG_NONE>;
}; };
speaker0 {
compatible = "nsiway,ns4168";
i2s = <&i2s0>;
};
mic0 {
compatible = "generic,spm1423";
i2s = <&i2s0>;
channels = <1>;
};
}; };
+12
View File
@@ -0,0 +1,12 @@
#include <tactility/module.h>
extern "C" {
// AXP192 rail/GPIO1 bring-up is now devicetree-configured (see m5stack,core2.dts's axp192 node
// and axp192-module's start()), replacing what used to be done by hand here via a
// DEVICE_EVENT_STARTED device_listener.
Module m5stack_core2_module = {
.name = "m5stack-core2"
};
}
+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( idf_component_register(
SRCS ${SOURCE_FILES} SRCS ${SOURCE_FILES}
INCLUDE_DIRS "Source" REQUIRES TactilityKernel axp2101-module
REQUIRES Tactility esp_lvgl_port ILI934x FT5x06 AXP2101 AW9523 driver vfs fatfs
) )
@@ -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.esptoolFlashFreq=120M
hardware.bluetooth=true hardware.bluetooth=true
storage.userDataLocation=SD storage.userDataLocation=Internal
dependencies.useDeprecatedHal=false
display.size=2" display.size=2"
display.shape=rectangle display.shape=rectangle
+8 -1
View File
@@ -1,5 +1,12 @@
dependencies: dependencies:
- Platforms/platform-esp32 - Platforms/platform-esp32
- Drivers/bmi270-module - Drivers/audio-stream-module
- Drivers/aw88298-module
- Drivers/aw9523b-module
- Drivers/axp2101-module
- Drivers/bm8563-module - Drivers/bm8563-module
- Drivers/bmi270-module
- Drivers/es7210-module
- Drivers/ft5x06-module
- Drivers/ili9341-module
dts: m5stack,cores3.dts dts: m5stack,cores3.dts
+113 -23
View File
@@ -9,10 +9,19 @@
#include <tactility/bindings/esp32_i2s.h> #include <tactility/bindings/esp32_i2s.h>
#include <tactility/bindings/esp32_spi.h> #include <tactility/bindings/esp32_spi.h>
#include <tactility/bindings/esp32_uart.h> #include <tactility/bindings/esp32_uart.h>
#include <tactility/bindings/gpio_hog.h>
#include <bindings/aw88298.h>
#include <bindings/aw9523b.h>
#include <bindings/axp2101.h>
#include <bindings/axp2101_backlight.h>
#include <bindings/bmi270.h> #include <bindings/bmi270.h>
#include <bindings/bm8563.h> #include <bindings/bm8563.h>
#include <tactility/bindings/esp32_sdspi.h> #include <bindings/es7210.h>
#include <tactility/bindings/display_placeholder.h> #include <bindings/ft5x06.h>
#include <bindings/ili9341.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 // Reference: https://docs.m5stack.com/en/core/CoreS3
/ { / {
@@ -34,6 +43,18 @@
gpio-count = <49>; gpio-count = <49>;
}; };
i2s0 {
// Note: M5Unified sets the following for speaker: magnification = 2, oversampling = 1
// Note: M5Unified sets the following for microphone: magnification = 4
compatible = "espressif,esp32-i2s";
port = <I2S_NUM_0>;
pin-bclk = <&gpio0 34 GPIO_FLAG_NONE>;
pin-ws = <&gpio0 33 GPIO_FLAG_NONE>;
pin-data-out = <&gpio0 13 GPIO_FLAG_NONE>;
pin-data-in = <&gpio0 14 GPIO_FLAG_NONE>;
pin-mclk = <&gpio0 0 GPIO_FLAG_NONE>;
};
i2c_internal { i2c_internal {
compatible = "espressif,esp32-i2c"; compatible = "espressif,esp32-i2c";
port = <I2C_NUM_0>; port = <I2C_NUM_0>;
@@ -50,6 +71,87 @@
compatible = "belling,bm8563"; compatible = "belling,bm8563";
reg = <0x51>; 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 {
compatible = "awinic,aw9523b";
reg = <0x58>;
// 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_sdcard_switch {
compatible = "gpio-hog";
pin = <&aw9523b 4 GPIO_FLAG_NONE>;
mode = <GPIO_HOG_MODE_INPUT>;
};
aw9523_boost_enable {
compatible = "gpio-hog";
pin = <&aw9523b 15 GPIO_FLAG_NONE>;
mode = <GPIO_HOG_MODE_OUTPUT_HIGH>;
};
};
aw88298 {
compatible = "awinic,aw88298";
reg = <0x36>;
i2s = <&i2s0>;
pin-reset = <&aw9523b 2 GPIO_FLAG_NONE>;
};
axp2101: axp2101 {
compatible = "x-powers,axp2101";
reg = <0x34>;
aldo1-millivolt = <1800>;
aldo1-enabled;
aldo2-millivolt = <3300>;
aldo2-enabled;
aldo3-millivolt = <3300>;
aldo3-enabled;
aldo4-millivolt = <3300>;
aldo4-enabled;
bldo1-enabled;
bldo2-enabled;
// LCD backlight (DLDO1). Raw register codes [20,28] map to [2500,3300]mV;
// below 2500mV the backlight was considered "too dark" to be useful.
display_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>;
};
es7210 {
compatible = "everest,es7210";
reg = <0x40>;
i2s = <&i2s0>;
// Only MIC1/MIC2 are wired to real capsules (see schematic); MIC3/MIC4
// slots carry AEC_P/AEC_N reference signal, not microphone audio.
mic-mask = <3>;
// M5Unified applies a 4x post-gain "magnification" for this exact mic
// wiring (see M5Unified.cpp _mic_data_cb_cores3): the ES7210's own
// hardware ADC gain (already near-max via the default 90% input volume
// setting, ~34dB of its 0-37.5dB range) still isn't enough for these
// capsules on their own.
input-gain-percent = <400>;
};
}; };
port_a: grove0 { port_a: grove0 {
@@ -92,27 +194,15 @@
pin-sclk = <&gpio0 36 GPIO_FLAG_NONE>; pin-sclk = <&gpio0 36 GPIO_FLAG_NONE>;
display@0 { display@0 {
compatible = "display-placeholder"; 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>;
backlight = <&display_backlight>;
}; };
sdcard@1 {
compatible = "espressif,esp32-sdspi";
status = "disabled"; // Must be started after display
frequency-khz = <20000>;
};
};
// TODO: Enable speaker via ES7210 I2C: https://github.com/m5stack/M5Unified/blob/a6256725481f1bc366655fa48cf03b6095e30ad1/src/M5Unified.cpp#L417
// TODO: Enable microphone via ES7210 I2C: https://github.com/m5stack/M5Unified/blob/a6256725481f1bc366655fa48cf03b6095e30ad1/src/M5Unified.cpp#L616
i2s0 {
// Note: M5Unified sets the following for speaker: magnification = 2, oversampling = 1
// Note: M5Unified sets the following for microphone: magnification = 4
compatible = "espressif,esp32-i2s";
port = <I2S_NUM_0>;
pin-bclk = <&gpio0 34 GPIO_FLAG_NONE>;
pin-ws = <&gpio0 33 GPIO_FLAG_NONE>;
pin-data-out = <&gpio0 13 GPIO_FLAG_NONE>;
pin-data-in = <&gpio0 14 GPIO_FLAG_NONE>;
pin-mclk = <&gpio0 0 GPIO_FLAG_NONE>;
}; };
}; };
+9
View File
@@ -0,0 +1,9 @@
#include <tactility/module.h>
extern "C" {
Module m5stack_cores3_module = {
.name = "m5stack-cores3"
};
}
+5 -4
View File
@@ -1,6 +1,7 @@
file(GLOB_RECURSE SOURCE_FILES Source/*.c*) file(GLOB_RECURSE SOURCE_FILES source/*.c*)
idf_component_register(SRCS ${SOURCE_FILES} idf_component_register(
INCLUDE_DIRS "Source" SRCS ${SOURCE_FILES}
REQUIRES EPDiyDisplay GT911 Tactility driver EstimatedPower INCLUDE_DIRS "source"
REQUIRES TactilityKernel epdiy
) )
@@ -1,20 +0,0 @@
#include "devices/Display.h"
#include "devices/Power.h"
#include <Tactility/hal/Configuration.h>
using namespace tt::hal;
bool initBoot();
static DeviceVector createDevices() {
return {
createPower(),
createDisplay(),
};
}
extern const Configuration hardwareConfiguration = {
.initBoot = initBoot,
.createDevices = createDevices
};
-48
View File
@@ -1,48 +0,0 @@
#include <driver/gpio.h>
#include <tactility/log.h>
constexpr auto* TAG = "Paper S3";
constexpr gpio_num_t VBAT_PIN = GPIO_NUM_3;
constexpr gpio_num_t CHARGE_STATUS_PIN = GPIO_NUM_4;
constexpr gpio_num_t USB_DETECT_PIN = GPIO_NUM_5;
static bool powerOn() {
if (gpio_reset_pin(CHARGE_STATUS_PIN) != ESP_OK) {
LOG_E(TAG, "Failed to reset CHARGE_STATUS_PIN");
return false;
}
if (gpio_set_direction(CHARGE_STATUS_PIN, GPIO_MODE_INPUT) != ESP_OK) {
LOG_E(TAG, "Failed to set direction for CHARGE_STATUS_PIN");
return false;
}
if (gpio_reset_pin(USB_DETECT_PIN) != ESP_OK) {
LOG_E(TAG, "Failed to reset USB_DETECT_PIN");
return false;
}
if (gpio_set_direction(USB_DETECT_PIN, GPIO_MODE_INPUT) != ESP_OK) {
LOG_E(TAG, "Failed to set direction for USB_DETECT_PIN");
return false;
}
// VBAT_PIN is used as ADC input; only reset it here to clear any previous
// configuration. The ADC driver (ChargeFromAdcVoltage) configures it for ADC use.
if (gpio_reset_pin(VBAT_PIN) != ESP_OK) {
LOG_E(TAG, "Failed to reset VBAT_PIN");
return false;
}
return true;
}
bool initBoot() {
LOG_I(TAG, "Power on");
if (!powerOn()) {
LOG_E(TAG, "Power on failed");
return false;
}
return true;
}
@@ -1,27 +0,0 @@
#include "Display.h"
#include <Gt911Touch.h>
#include <EpdiyDisplayHelper.h>
#include <tactility/check.h>
#include <tactility/device.h>
std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
auto* i2c = device_find_by_name("i2c_internal");
check(i2c);
auto configuration = std::make_unique<Gt911Touch::Configuration>(
i2c,
540,
960,
true, // swapXy
true, // mirrorX
false, // mirrorY
GPIO_NUM_NC, // pinReset
GPIO_NUM_NC //48 pinInterrupt
);
return std::make_shared<Gt911Touch>(std::move(configuration));
}
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
auto touch = createTouch();
return EpdiyDisplayHelper::createM5PaperS3Display(touch);
}
@@ -1,6 +0,0 @@
#pragma once
#include <memory>
#include <Tactility/hal/display/DisplayDevice.h>
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();
@@ -1,282 +0,0 @@
#include "Power.h"
#include <tactility/log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <driver/ledc.h>
using namespace tt::hal::power;
constexpr auto* TAG = "PaperS3Power";
// M5Stack PaperS3 hardware pin definitions
constexpr gpio_num_t VBAT_PIN = GPIO_NUM_3; // Battery voltage with 2x divider
constexpr adc_channel_t VBAT_ADC_CHANNEL = ADC_CHANNEL_2; // GPIO3 = ADC1_CHANNEL_2
constexpr gpio_num_t CHARGE_STATUS_PIN = GPIO_NUM_4; // Charge IC status: 0 = charging, 1 = full/no USB
constexpr gpio_num_t USB_DETECT_PIN = GPIO_NUM_5; // USB detect: 1 = USB connected
constexpr gpio_num_t POWER_OFF_PIN = GPIO_NUM_44; // Pull high to trigger shutdown
constexpr gpio_num_t BUZZER_PIN = GPIO_NUM_21;
// Battery voltage divider ratio (voltage is divided by 2)
constexpr float VOLTAGE_DIVIDER_MULTIPLIER = 2.0f;
// Battery voltage range for LiPo batteries
constexpr float MIN_BATTERY_VOLTAGE = 3.3f;
constexpr float MAX_BATTERY_VOLTAGE = 4.2f;
// Power-off signal timing
constexpr int POWER_OFF_PULSE_COUNT = 5;
constexpr int POWER_OFF_PULSE_DURATION_MS = 100;
constexpr uint32_t BUZZER_DUTY_50_PERCENT = 4096; // 50% of 13-bit (8192)
PaperS3Power::PaperS3Power(
std::unique_ptr<ChargeFromAdcVoltage> chargeFromAdcVoltage,
gpio_num_t powerOffPin
)
: chargeFromAdcVoltage(std::move(chargeFromAdcVoltage)),
powerOffPin(powerOffPin) {
LOG_I(TAG, "Initialized M5Stack PaperS3 power management");
}
void PaperS3Power::buzzerLedcInit() {
if (buzzerInitialized) {
LOG_I(TAG, "Buzzer already initialized");
return;
}
ledc_timer_config_t timer_cfg = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.duty_resolution = LEDC_TIMER_13_BIT,
.timer_num = LEDC_TIMER_0,
.freq_hz = 1000,
.clk_cfg = LEDC_AUTO_CLK,
.deconfigure = false
};
esp_err_t err = ledc_timer_config(&timer_cfg);
if (err != ESP_OK) {
LOG_E(TAG, "LEDC timer config failed: %s", esp_err_to_name(err));
return;
}
ledc_channel_config_t channel_cfg = {
.gpio_num = BUZZER_PIN,
.speed_mode = LEDC_LOW_SPEED_MODE,
.channel = LEDC_CHANNEL_0,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = LEDC_TIMER_0,
.duty = 0,
.hpoint = 0,
.sleep_mode = LEDC_SLEEP_MODE_NO_ALIVE_NO_PD,
.flags = {
.output_invert = 0
}
};
err = ledc_channel_config(&channel_cfg);
if (err != ESP_OK) {
LOG_E(TAG, "LEDC channel config failed: %s", esp_err_to_name(err));
return;
}
buzzerInitialized = true;
}
void PaperS3Power::initializePowerOff() {
if (powerOffInitialized) {
return;
}
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << powerOffPin),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
esp_err_t err = gpio_config(&io_conf);
if (err != ESP_OK) {
LOG_E(TAG, "Failed to configure power-off pin GPIO%d: %s", powerOffPin, esp_err_to_name(err));
return;
}
gpio_set_level(powerOffPin, 0);
powerOffInitialized = true;
LOG_I(TAG, "Power-off control initialized on GPIO%d", powerOffPin);
buzzerLedcInit();
}
// TODO: Fix USB Detection
bool PaperS3Power::isUsbConnected() {
// USB_DETECT_PIN is configured as input with pull-down by initBoot() in Init.cpp.
// Level 1 = USB VBUS present (per M5PaperS3 hardware spec).
bool usbConnected = gpio_get_level(USB_DETECT_PIN) == 1;
LOG_D(TAG, "USB_STATUS(GPIO%d)=%d", USB_DETECT_PIN, (int)usbConnected);
return usbConnected;
}
bool PaperS3Power::isCharging() {
// CHARGE_STATUS_PIN is configured as GPIO_MODE_INPUT by initBoot() in Init.cpp.
int chargePin = gpio_get_level(CHARGE_STATUS_PIN);
LOG_D(TAG, "CHG_STATUS(GPIO%d)=%d", CHARGE_STATUS_PIN, chargePin);
return chargePin == 0;
}
bool PaperS3Power::supportsMetric(MetricType type) const {
switch (type) {
using enum MetricType;
case BatteryVoltage:
case ChargeLevel:
case IsCharging:
return true;
default:
return false;
}
}
bool PaperS3Power::getMetric(MetricType type, MetricData& data) {
switch (type) {
using enum MetricType;
case BatteryVoltage:
return chargeFromAdcVoltage->readBatteryVoltageSampled(data.valueAsUint32);
case ChargeLevel: {
uint32_t voltage = 0;
if (chargeFromAdcVoltage->readBatteryVoltageSampled(voltage)) {
data.valueAsUint8 = chargeFromAdcVoltage->estimateChargeLevelFromVoltage(voltage);
return true;
}
return false;
}
case IsCharging:
// isUsbConnected() is tracked separately but not used as a gate here:
// when USB is absent the charge IC's CHG pin is inactive (high), so
// isCharging() already returns false correctly.
data.valueAsBool = isCharging();
return true;
default:
return false;
}
}
void PaperS3Power::toneOn(int frequency, int duration) {
if (!buzzerInitialized) {
LOG_I(TAG, "Buzzer not initialized");
return;
}
if (frequency <= 0) {
LOG_I(TAG, "Invalid frequency: %d", frequency);
return;
}
esp_err_t err = ledc_set_freq(LEDC_LOW_SPEED_MODE, LEDC_TIMER_0, frequency);
if (err != ESP_OK) {
LOG_E(TAG, "LEDC set freq failed: %s", esp_err_to_name(err));
return;
}
err = ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, BUZZER_DUTY_50_PERCENT);
if (err != ESP_OK) {
LOG_E(TAG, "LEDC set duty failed: %s", esp_err_to_name(err));
return;
}
err = ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
if (err != ESP_OK) {
LOG_E(TAG, "LEDC update duty failed: %s", esp_err_to_name(err));
return;
}
if (duration > 0) {
vTaskDelay(pdMS_TO_TICKS(duration));
toneOff();
}
}
void PaperS3Power::toneOff() {
if (!buzzerInitialized) {
LOG_I(TAG, "Buzzer not initialized");
return;
}
esp_err_t err = ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0);
if (err != ESP_OK) {
LOG_E(TAG, "LEDC set duty failed: %s", esp_err_to_name(err));
return;
}
err = ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
if (err != ESP_OK) {
LOG_E(TAG, "LEDC update duty failed: %s", esp_err_to_name(err));
return;
}
}
void PaperS3Power::powerOff() {
LOG_W(TAG, "Power-off requested");
// Note: callers are responsible for stopping the display (e.g. EPD refresh) before
// calling powerOff(). The beep sequence below (~500 ms) provides some lead time,
// but a full EPD refresh can take up to ~1500 ms. If a refresh is still in flight
// when GPIO44 cuts power, the current frame will be incomplete; the display will
// recover correctly on next boot via a full-screen clear.
if (!powerOffInitialized) {
initializePowerOff();
if (!powerOffInitialized) {
LOG_E(TAG, "Power-off failed: GPIO not initialized");
return;
}
}
//beep on
toneOn(440, 200);
vTaskDelay(pdMS_TO_TICKS(100));
//beep on
toneOn(440, 200);
LOG_W(TAG, "Triggering shutdown via GPIO%d (sending %d pulses)...", powerOffPin, POWER_OFF_PULSE_COUNT);
for (int i = 0; i < POWER_OFF_PULSE_COUNT; i++) {
gpio_set_level(powerOffPin, 1);
vTaskDelay(pdMS_TO_TICKS(POWER_OFF_PULSE_DURATION_MS));
gpio_set_level(powerOffPin, 0);
vTaskDelay(pdMS_TO_TICKS(POWER_OFF_PULSE_DURATION_MS));
}
gpio_set_level(powerOffPin, 1); // Final high state
LOG_W(TAG, "Shutdown signal sent. Waiting for power-off...");
vTaskDelay(pdMS_TO_TICKS(1000));
LOG_E(TAG, "Device did not power off as expected");
}
std::shared_ptr<PowerDevice> createPower() {
ChargeFromAdcVoltage::Configuration config = {
.adcMultiplier = VOLTAGE_DIVIDER_MULTIPLIER,
.adcRefVoltage = 3.3f,
.adcChannel = VBAT_ADC_CHANNEL,
.adcConfig = {
.unit_id = ADC_UNIT_1,
.clk_src = ADC_RTC_CLK_SRC_DEFAULT,
.ulp_mode = ADC_ULP_MODE_DISABLE,
},
.adcChannelConfig = {
.atten = ADC_ATTEN_DB_12,
.bitwidth = ADC_BITWIDTH_DEFAULT,
},
};
auto adc = std::make_unique<ChargeFromAdcVoltage>(config, MIN_BATTERY_VOLTAGE, MAX_BATTERY_VOLTAGE);
if (!adc->isInitialized()) {
LOG_E(TAG, "ADC initialization failed; power monitoring unavailable");
return nullptr;
}
return std::make_shared<PaperS3Power>(std::move(adc), POWER_OFF_PIN);
}
@@ -1,55 +0,0 @@
#pragma once
#include <memory>
#include <ChargeFromAdcVoltage.h>
#include <Tactility/hal/power/PowerDevice.h>
#include <driver/gpio.h>
using tt::hal::power::PowerDevice;
/**
* @brief Power management for M5Stack PaperS3
*
* Hardware configuration:
* - Battery voltage: GPIO3 (ADC1_CHANNEL_2) with 2x voltage divider
* - Charge status: GPIO4 - digital signal (0 = charging, 1 = not charging)
* - USB detect: GPIO5 - digital signal (1 = USB connected)
* - Power off: GPIO44 - pull high to trigger shutdown
*/
class PaperS3Power final : public PowerDevice {
private:
std::unique_ptr<::ChargeFromAdcVoltage> chargeFromAdcVoltage;
gpio_num_t powerOffPin;
bool powerOffInitialized = false;
bool buzzerInitialized = false;
public:
explicit PaperS3Power(
std::unique_ptr<::ChargeFromAdcVoltage> chargeFromAdcVoltage,
gpio_num_t powerOffPin
);
~PaperS3Power() override = default;
std::string getName() const override { return "M5Stack PaperS3 Power"; }
std::string getDescription() const override { return "Battery monitoring with charge detection and power-off"; }
bool supportsMetric(MetricType type) const override;
bool getMetric(MetricType type, MetricData& data) override;
bool supportsPowerOff() const override { return true; }
void powerOff() override;
private:
void initializePowerOff();
bool isCharging();
// TODO: Fix USB Detection
bool isUsbConnected();
// Buzzer functions only used for the power off signal sound.
// So the user actually knows the epaper display is turning off.
void buzzerLedcInit();
void toneOn(int frequency, int duration);
void toneOff();
};
std::shared_ptr<tt::hal::power::PowerDevice> createPower();
-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_papers3_module = {
.name = "m5stack-papers3",
.start = start,
.stop = stop,
.symbols = nullptr,
.internal = nullptr
};
}
@@ -0,0 +1,20 @@
description: >
M5Stack PaperS3 E-Ink display (EPDiy library, ED047TC1 panel over the board's dedicated
parallel bus - epd_board_m5papers3 hardcodes all of its pins internally, so this node takes
no pin properties of its own).
compatible: "m5stack,papers3-display"
properties:
temperature-celsius:
type: int
default: 20
description: Ambient temperature in °C, used for waveform timing compensation
draw-mode:
type: int
default: MODE_DU
description: Default EpdDrawMode waveform used for screen updates (e.g. MODE_DU, MODE_GC16)
rotation:
type: int
default: EPD_ROT_PORTRAIT
description: Fixed EpdRotation applied at start - not changeable at runtime (see driver README/comments)
@@ -0,0 +1,23 @@
description: >
M5Stack PaperS3 charge/power control: charge IC status readback and shutdown-pulse power off.
Battery voltage/capacity are handled separately by a generic battery-sense node.
compatible: "m5stack,papers3-power"
properties:
pin-charge-status:
type: phandles
required: true
description: Charge IC status pin (active-low - 0 = charging, 1 = full/no USB)
pin-usb-detect:
type: phandles
required: true
description: USB VBUS detect pin (1 = USB connected)
pin-power-off:
type: phandles
required: true
description: Shutdown control pin - pulled high to trigger power-off
pwm:
type: phandles
required: true
description: Tone generator (PWM_TYPE device) used for the power-off confirmation beep
@@ -15,6 +15,8 @@ hardware.bluetooth=true
storage.userDataLocation=SD storage.userDataLocation=SD
dependencies.useDeprecatedHal=false
display.size=4.7" display.size=4.7"
display.shape=rectangle display.shape=rectangle
display.dpi=235 display.dpi=235
@@ -24,3 +26,4 @@ lvgl.fontSize=24
lvgl.theme=Mono lvgl.theme=Mono
sdkconfig.CONFIG_EPD_DISPLAY_TYPE_ED047TC2=y sdkconfig.CONFIG_EPD_DISPLAY_TYPE_ED047TC2=y
sdkconfig.CONFIG_LV_THEME_DEFAULT_TRANSITION_TIME=0
+2
View File
@@ -2,4 +2,6 @@ dependencies:
- Platforms/platform-esp32 - Platforms/platform-esp32
- Drivers/bmi270-module - Drivers/bmi270-module
- Drivers/bm8563-module - Drivers/bm8563-module
- Drivers/gt911-module
bindings: bindings
dts: m5stack,papers3.dts dts: m5stack,papers3.dts

Some files were not shown because too many files have changed in this diff Show More