Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9a540c644e | |||
| 2fbc44466a | |||
| 2d768ef3a1 | |||
| bd30aa046a | |||
| f9453d8956 |
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module btt_panda_touch_module = {
|
struct Module btt_panda_touch_module = {
|
||||||
.name = "btt-panda-touch",
|
.name = "btt-panda-touch",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
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,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module cyd_2432s024r_module = {
|
struct Module cyd_2432s024r_module = {
|
||||||
.name = "cyd-2432s024r",
|
.name = "cyd-2432s024r",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module cyd_2432s028r_module = {
|
struct Module cyd_2432s028r_module = {
|
||||||
.name = "cyd-2432s028r",
|
.name = "cyd-2432s028r",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module cyd_2432s028rv3_module = {
|
struct Module cyd_2432s028rv3_module = {
|
||||||
.name = "cyd-2432s028rv3",
|
.name = "cyd-2432s028rv3",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
Module cyd_2432s032c_module = {
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module cyd_2432s032c_module = {
|
|
||||||
.name = "cyd-2432s032c",
|
.name = "cyd-2432s032c",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
Module cyd_3248s035c_module = {
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module cyd_3248s035c_module = {
|
|
||||||
.name = "cyd-3248s035c",
|
.name = "cyd-3248s035c",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
Module cyd_4848s040c_module = {
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module cyd_4848s040c_module = {
|
|
||||||
.name = "cyd-4848s040c",
|
.name = "cyd-4848s040c",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
Module cyd_8048s043c_module = {
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module cyd_8048s043c_module = {
|
|
||||||
.name = "cyd-8048s043c",
|
.name = "cyd-8048s043c",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
Module cyd_e32r28t_module = {
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module cyd_e32r28t_module = {
|
|
||||||
.name = "cyd-e32r28t",
|
.name = "cyd-e32r28t",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
Module cyd_e32r32p_module = {
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module cyd_e32r32p_module = {
|
|
||||||
.name = "cyd-e32r32p",
|
.name = "cyd-e32r32p",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
Module elecrow_crowpanel_advance_28_module = {
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module elecrow_crowpanel_advance_28_module = {
|
|
||||||
.name = "elecrow-crowpanel-advance-28",
|
.name = "elecrow-crowpanel-advance-28",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr
|
.symbols = nullptr
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
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,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
Module elecrow_crowpanel_advance_50_module = {
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module elecrow_crowpanel_advance_50_module = {
|
|
||||||
.name = "elecrow-crowpanel-advance-50",
|
.name = "elecrow-crowpanel-advance-50",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
Module elecrow_crowpanel_basic_28_module = {
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module elecrow_crowpanel_basic_28_module = {
|
|
||||||
.name = "elecrow-crowpanel-basic-28",
|
.name = "elecrow-crowpanel-basic-28",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
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,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
Module elecrow_crowpanel_basic_50_module = {
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module elecrow_crowpanel_basic_50_module = {
|
|
||||||
.name = "elecrow-crowpanel-basic-50",
|
.name = "elecrow-crowpanel-basic-50",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
dependencies:
|
||||||
|
- Platforms/platform-esp32
|
||||||
|
- Drivers/ili9341-module
|
||||||
|
- Drivers/ft5x06-module
|
||||||
|
- Drivers/es8311-module
|
||||||
|
- Drivers/audio-stream-module
|
||||||
|
dts: es3c28p.dts
|
||||||
@@ -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>;
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
|
#include <tactility/module.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
Module es3c28p_module = {
|
||||||
|
.name = "es3c28p",
|
||||||
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
|
.symbols = nullptr,
|
||||||
|
.internal = nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
Module generic_esp32_module = {
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module generic_esp32_module = {
|
|
||||||
.name = "generic-esp32",
|
.name = "generic-esp32",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
Module generic_esp32c6_module = {
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module generic_esp32c6_module = {
|
|
||||||
.name = "generic-esp32c6",
|
.name = "generic-esp32c6",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
Module generic_esp32p4_module = {
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module generic_esp32p4_module = {
|
|
||||||
.name = "generic-esp32p4",
|
.name = "generic-esp32p4",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
Module generic_esp32s3_module = {
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module generic_esp32s3_module = {
|
|
||||||
.name = "generic-esp32s3",
|
.name = "generic-esp32s3",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
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,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
Module guition_jc2432w328c_module = {
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module guition_jc2432w328c_module = {
|
|
||||||
.name = "guition-jc2432w328c",
|
.name = "guition-jc2432w328c",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
file(GLOB_RECURSE SOURCE_FILES source/*.c*)
|
|
||||||
|
|
||||||
idf_component_register(
|
|
||||||
SRCS ${SOURCE_FILES}
|
|
||||||
REQUIRES TactilityKernel driver
|
|
||||||
)
|
|
||||||
@@ -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,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
Module guition_jc8048w550c_module = {
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module guition_jc8048w550c_module = {
|
|
||||||
.name = "guition-jc8048w550c",
|
.name = "guition-jc8048w550c",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
Module heltec_wifi_lora_32_v3_module = {
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module heltec_wifi_lora_32_v3_module = {
|
|
||||||
.name = "heltec-wifi-lora-32-v3",
|
.name = "heltec-wifi-lora-32-v3",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = 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>;
|
||||||
|
|||||||
@@ -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 axp192-module
|
||||||
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();
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -2,4 +2,7 @@ dependencies:
|
|||||||
- Platforms/platform-esp32
|
- Platforms/platform-esp32
|
||||||
- Drivers/mpu6886-module
|
- Drivers/mpu6886-module
|
||||||
- Drivers/bm8563-module
|
- Drivers/bm8563-module
|
||||||
|
- Drivers/axp192-module
|
||||||
|
- Drivers/ft6x36-module
|
||||||
|
- Drivers/ili9341-module
|
||||||
dts: m5stack,core2.dts
|
dts: m5stack,core2.dts
|
||||||
|
|||||||
@@ -10,8 +10,10 @@
|
|||||||
#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 <bindings/axp192.h>
|
||||||
|
#include <bindings/ft6x36.h>
|
||||||
|
#include <bindings/ili9341.h>
|
||||||
#include <tactility/bindings/esp32_sdspi.h>
|
#include <tactility/bindings/esp32_sdspi.h>
|
||||||
#include <tactility/bindings/display_placeholder.h>
|
|
||||||
|
|
||||||
// Reference: https://docs.m5stack.com/en/core/Core2
|
// Reference: https://docs.m5stack.com/en/core/Core2
|
||||||
/ {
|
/ {
|
||||||
@@ -44,6 +46,19 @@
|
|||||||
compatible = "belling,bm8563";
|
compatible = "belling,bm8563";
|
||||||
reg = <0x51>;
|
reg = <0x51>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
axp192 {
|
||||||
|
compatible = "x-powers,axp192";
|
||||||
|
reg = <0x34>;
|
||||||
|
};
|
||||||
|
|
||||||
|
touch {
|
||||||
|
compatible = "focaltech,ft6x36";
|
||||||
|
reg = <0x38>;
|
||||||
|
x-max = <320>;
|
||||||
|
y-max = <240>;
|
||||||
|
pin-interrupt = <&gpio0 39 GPIO_FLAG_NONE>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
port_a: grove0 {
|
port_a: grove0 {
|
||||||
@@ -66,12 +81,17 @@
|
|||||||
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>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
#include <drivers/axp192.h>
|
||||||
|
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
#include <tactility/device_listener.h>
|
||||||
|
#include <tactility/module.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
static void configure_axp192(Device* axp192) {
|
||||||
|
check(axp192_set_rail_voltage(axp192, AXP192_RAIL_LDO2, 3300) == ERROR_NONE); // LCD + SD
|
||||||
|
check(axp192_set_rail_voltage(axp192, AXP192_RAIL_DCDC3, 3300) == ERROR_NONE); // LCD backlight
|
||||||
|
|
||||||
|
check(axp192_set_rail_enabled(axp192, AXP192_RAIL_LDO2, true) == ERROR_NONE);
|
||||||
|
check(axp192_set_rail_enabled(axp192, AXP192_RAIL_LDO3, false) == ERROR_NONE); // VIB_MOTOR stop
|
||||||
|
check(axp192_set_rail_enabled(axp192, AXP192_RAIL_DCDC3, true) == ERROR_NONE);
|
||||||
|
|
||||||
|
check(axp192_set_pwm1_duty_cycle(axp192, 255) == ERROR_NONE); // PWM 255 (LED off)
|
||||||
|
check(axp192_set_gpio1_pwm1_output(axp192) == ERROR_NONE); // GPIO1: PWM
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_device_event(Device* device, DeviceEvent event, void* context) {
|
||||||
|
(void)context;
|
||||||
|
if (event == DEVICE_EVENT_STARTED && strcmp(device->name, "axp192") == 0) {
|
||||||
|
configure_axp192(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_core2_module = {
|
||||||
|
.name = "m5stack-core2",
|
||||||
|
.start = start,
|
||||||
|
.stop = stop,
|
||||||
|
.symbols = nullptr,
|
||||||
|
.internal = nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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
|
|
||||||
};
|
|
||||||
@@ -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.275V,25mV/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();
|
|
||||||
}
|
|
||||||
@@ -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();
|
|
||||||
@@ -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
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -2,4 +2,8 @@ dependencies:
|
|||||||
- Platforms/platform-esp32
|
- Platforms/platform-esp32
|
||||||
- Drivers/bmi270-module
|
- Drivers/bmi270-module
|
||||||
- Drivers/bm8563-module
|
- Drivers/bm8563-module
|
||||||
|
- Drivers/axp2101-module
|
||||||
|
- Drivers/aw9523b-module
|
||||||
|
- Drivers/ft5x06-module
|
||||||
|
- Drivers/ili9341-module
|
||||||
dts: m5stack,cores3.dts
|
dts: m5stack,cores3.dts
|
||||||
|
|||||||
@@ -11,8 +11,16 @@
|
|||||||
#include <tactility/bindings/esp32_uart.h>
|
#include <tactility/bindings/esp32_uart.h>
|
||||||
#include <bindings/bmi270.h>
|
#include <bindings/bmi270.h>
|
||||||
#include <bindings/bm8563.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/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
|
// Reference: https://docs.m5stack.com/en/core/CoreS3
|
||||||
/ {
|
/ {
|
||||||
@@ -50,6 +58,61 @@
|
|||||||
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: 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 {
|
port_a: grove0 {
|
||||||
@@ -92,13 +155,14 @@
|
|||||||
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>;
|
||||||
sdcard@1 {
|
invert-color;
|
||||||
compatible = "espressif,esp32-sdspi";
|
bgr-order;
|
||||||
status = "disabled"; // Must be started after display
|
pixel-clock-hz = <40000000>;
|
||||||
frequency-khz = <20000>;
|
pin-dc = <&gpio0 35 GPIO_FLAG_NONE>;
|
||||||
|
pin-reset = <&aw9523b 9 GPIO_FLAG_NONE>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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
|
|
||||||
};
|
|
||||||
@@ -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();
|
|
||||||
@@ -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,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
|
||||||
|
|||||||
@@ -6,9 +6,15 @@
|
|||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
|
#include <tactility/bindings/esp32_adc_oneshot.h>
|
||||||
|
#include <tactility/bindings/esp32_pwm_ledc.h>
|
||||||
|
#include <tactility/bindings/battery_sense.h>
|
||||||
#include <bindings/bmi270.h>
|
#include <bindings/bmi270.h>
|
||||||
#include <bindings/bm8563.h>
|
#include <bindings/bm8563.h>
|
||||||
|
#include <bindings/gt911.h>
|
||||||
#include <tactility/bindings/esp32_sdspi.h>
|
#include <tactility/bindings/esp32_sdspi.h>
|
||||||
|
#include <bindings/papers3_power.h>
|
||||||
|
#include <bindings/papers3_display.h>
|
||||||
|
|
||||||
/ {
|
/ {
|
||||||
compatible = "root";
|
compatible = "root";
|
||||||
@@ -45,6 +51,14 @@
|
|||||||
compatible = "belling,bm8563";
|
compatible = "belling,bm8563";
|
||||||
reg = <0x51>;
|
reg = <0x51>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
touch {
|
||||||
|
compatible = "goodix,gt911";
|
||||||
|
reg = <0x5D>;
|
||||||
|
x-max = <540>;
|
||||||
|
y-max = <960>;
|
||||||
|
pin-interrupt = <&gpio0 48 GPIO_FLAG_NONE>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
spi0 {
|
spi0 {
|
||||||
@@ -55,10 +69,49 @@
|
|||||||
pin-miso = <&gpio0 40 GPIO_FLAG_NONE>;
|
pin-miso = <&gpio0 40 GPIO_FLAG_NONE>;
|
||||||
pin-sclk = <&gpio0 39 GPIO_FLAG_NONE>;
|
pin-sclk = <&gpio0 39 GPIO_FLAG_NONE>;
|
||||||
max-transfer-size = <4096>;
|
max-transfer-size = <4096>;
|
||||||
|
|
||||||
sdcard@0 {
|
sdcard@0 {
|
||||||
compatible = "espressif,esp32-sdspi";
|
compatible = "espressif,esp32-sdspi";
|
||||||
frequency-khz = <20000>;
|
frequency-khz = <20000>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
adc0 {
|
||||||
|
compatible = "espressif,esp32-adc-oneshot";
|
||||||
|
unit-id = <ADC_UNIT_1>;
|
||||||
|
channels = <ADC_CHANNEL_2 ADC_ATTEN_DB_12 ADC_BITWIDTH_DEFAULT>;
|
||||||
|
};
|
||||||
|
|
||||||
|
battery-sense {
|
||||||
|
compatible = "battery-sense";
|
||||||
|
io-channel = <&adc0 0>;
|
||||||
|
reference-voltage-mv = <3300>;
|
||||||
|
multiplier = <2000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
buzzer_pwm {
|
||||||
|
compatible = "espressif,esp32-pwm-ledc";
|
||||||
|
pin = <&gpio0 21 GPIO_FLAG_NONE>;
|
||||||
|
period-ns = <1000000>;
|
||||||
|
ledc-timer = <0>;
|
||||||
|
ledc-channel = <0>;
|
||||||
|
};
|
||||||
|
|
||||||
|
power {
|
||||||
|
compatible = "m5stack,papers3-power";
|
||||||
|
pin-charge-status = <&gpio0 4 GPIO_FLAG_NONE>;
|
||||||
|
pin-usb-detect = <&gpio0 5 GPIO_FLAG_NONE>;
|
||||||
|
pin-power-off = <&gpio0 44 GPIO_FLAG_NONE>;
|
||||||
|
pwm = <&buzzer_pwm>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// M5Stack PaperS3 E-Ink display (EPDiy library, ED047TC1 panel)
|
||||||
|
display {
|
||||||
|
compatible = "m5stack,papers3-display";
|
||||||
|
temperature-celsius = <20>;
|
||||||
|
// EPD_ROT_PORTRAIT rendered 180deg rotated on real hardware; INVERTED_PORTRAIT is
|
||||||
|
// exactly 180deg from it (verified against epdiy's _rotate()) and is this panel's
|
||||||
|
// correct orientation.
|
||||||
|
rotation = <EPD_ROT_INVERTED_PORTRAIT>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <tactility/bindings/bindings.h>
|
||||||
|
#include <drivers/papers3_display.h>
|
||||||
|
|
||||||
|
DEFINE_DEVICETREE(papers3_display, struct Papers3DisplayConfig)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <tactility/bindings/bindings.h>
|
||||||
|
#include <drivers/papers3_power.h>
|
||||||
|
|
||||||
|
DEFINE_DEVICETREE(papers3_power, struct Papers3PowerConfig)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,292 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#include "papers3_display.h"
|
||||||
|
|
||||||
|
#include <tactility/device.h>
|
||||||
|
#include <tactility/driver.h>
|
||||||
|
#include <tactility/drivers/display.h>
|
||||||
|
#include <tactility/error.h>
|
||||||
|
#include <tactility/log.h>
|
||||||
|
#include <tactility/module.h>
|
||||||
|
|
||||||
|
#include <epd_board.h>
|
||||||
|
#include <epdiy.h>
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#define TAG "Papers3Display"
|
||||||
|
#define GET_CONFIG(device) (static_cast<const Papers3DisplayConfig*>((device)->config))
|
||||||
|
|
||||||
|
// Maps each src byte (8px, MSB-first, bit=1 -> white/0x0F) to the 4 packed dst bytes
|
||||||
|
// (2px/byte, EPDiy MODE_PACKING_2PPB nibble order) it produces, replacing a per-pixel
|
||||||
|
// branch loop with a table lookup.
|
||||||
|
static uint32_t s_unpack_lut[256];
|
||||||
|
|
||||||
|
static void init_unpack_lut() {
|
||||||
|
for (uint32_t byte = 0; byte < 256; byte++) {
|
||||||
|
uint8_t dst[4];
|
||||||
|
for (int32_t pair = 0; pair < 4; pair++) {
|
||||||
|
const uint8_t bit0 = (byte >> (7 - pair * 2)) & 0x01U;
|
||||||
|
const uint8_t bit1 = (byte >> (7 - pair * 2 - 1)) & 0x01U;
|
||||||
|
const uint8_t p0 = bit0 ? 0x0FU : 0x00U;
|
||||||
|
const uint8_t p1 = bit1 ? 0x0FU : 0x00U;
|
||||||
|
dst[pair] = static_cast<uint8_t>((p1 << 4U) | p0);
|
||||||
|
}
|
||||||
|
memcpy(&s_unpack_lut[byte], dst, sizeof(dst));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
extern Module m5stack_papers3_module;
|
||||||
|
|
||||||
|
// epd_hl_init() sets an internal already_initialized flag and has no matching deinit, so the
|
||||||
|
// highlevel state (and the framebuffer it owns) must persist across stop()/start() cycles and be
|
||||||
|
// reused rather than recreated - ported from the old deprecated-HAL EpdiyDisplay's identical
|
||||||
|
// s_hlInitialized/s_hlState statics.
|
||||||
|
static bool s_hl_initialized = false;
|
||||||
|
static EpdiyHighlevelState s_hl_state = {};
|
||||||
|
|
||||||
|
struct Papers3DisplayInternal {
|
||||||
|
EpdiyHighlevelState hl_state;
|
||||||
|
uint8_t* framebuffer;
|
||||||
|
// Scratch buffer for the I1(1bpp)->EPDiy(4bpp packed, 2px/byte) conversion in draw_bitmap().
|
||||||
|
uint8_t* packed_buffer;
|
||||||
|
bool powered;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void power_on(Papers3DisplayInternal* internal) {
|
||||||
|
if (!internal->powered) {
|
||||||
|
epd_poweron();
|
||||||
|
internal->powered = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// region DisplayApi
|
||||||
|
|
||||||
|
static error_t papers3_display_reset(Device* device) {
|
||||||
|
auto* internal = static_cast<Papers3DisplayInternal*>(device_get_driver_data(device));
|
||||||
|
// EPD has no discrete reset pin/sequence the way SPI TFT panels do - epd_init() (in start())
|
||||||
|
// already performs the real one-time hardware bring-up. A power-cycle is the closest
|
||||||
|
// equivalent available at runtime.
|
||||||
|
epd_poweroff();
|
||||||
|
internal->powered = false;
|
||||||
|
power_on(internal);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t papers3_display_init(Device* device) {
|
||||||
|
auto* internal = static_cast<Papers3DisplayInternal*>(device_get_driver_data(device));
|
||||||
|
power_on(internal);
|
||||||
|
epd_clear();
|
||||||
|
epd_hl_set_all_white(&internal->hl_state);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LVGL only ever calls this with the full frame: DISPLAY_COLOR_FORMAT_MONOCHROME forces
|
||||||
|
// LV_DISPLAY_RENDER_MODE_FULL in the generic kernel LVGL bridge (lvgl_display.c), and FULL mode
|
||||||
|
// only presents (calls draw_bitmap) once per render cycle, with the complete 0,0..hres,vres rect.
|
||||||
|
static error_t papers3_display_draw_bitmap(Device* device, int32_t x_start, int32_t y_start, int32_t x_end, int32_t y_end, const void* color_data) {
|
||||||
|
auto* internal = static_cast<Papers3DisplayInternal*>(device_get_driver_data(device));
|
||||||
|
const auto* config = GET_CONFIG(device);
|
||||||
|
|
||||||
|
const int32_t width = x_end - x_start;
|
||||||
|
const int32_t height = y_end - y_start;
|
||||||
|
|
||||||
|
// color_data is DISPLAY_COLOR_FORMAT_MONOCHROME: row-major, MSB-first 1bpp (LVGL's LV_COLOR_FORMAT_I1
|
||||||
|
// with the palette header already stripped by the caller). Bit 1 = white/lit (LVGL's I1 blend
|
||||||
|
// sets a bit when the source luminance is above its threshold), bit 0 = black.
|
||||||
|
const auto* src = static_cast<const uint8_t*>(color_data);
|
||||||
|
const size_t src_stride = static_cast<size_t>(width + 7) / 8;
|
||||||
|
const size_t packed_stride = static_cast<size_t>(width + 1) / 2;
|
||||||
|
|
||||||
|
for (int32_t row = 0; row < height; row++) {
|
||||||
|
const uint8_t* src_row = src + static_cast<size_t>(row) * src_stride;
|
||||||
|
uint8_t* dst_row = internal->packed_buffer + static_cast<size_t>(row) * packed_stride;
|
||||||
|
int32_t col = 0;
|
||||||
|
// Bulk path: one LUT lookup + 4-byte copy per 8 source pixels.
|
||||||
|
for (; col + 8 <= width; col += 8) {
|
||||||
|
memcpy(dst_row + col / 2, &s_unpack_lut[src_row[col / 8]], 4);
|
||||||
|
}
|
||||||
|
// Tail: fewer than 8 pixels left (width not a multiple of 8).
|
||||||
|
for (; col < width; col += 2) {
|
||||||
|
const uint8_t bit0 = (src_row[col / 8] >> (7 - (col % 8))) & 0x01U;
|
||||||
|
const uint8_t p0 = bit0 ? 0x0FU : 0x00U;
|
||||||
|
uint8_t p1 = 0;
|
||||||
|
if (col + 1 < width) {
|
||||||
|
const uint8_t bit1 = (src_row[(col + 1) / 8] >> (7 - ((col + 1) % 8))) & 0x01U;
|
||||||
|
p1 = bit1 ? 0x0FU : 0x00U;
|
||||||
|
}
|
||||||
|
dst_row[col / 2] = static_cast<uint8_t>((p1 << 4U) | p0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const EpdRect update_area = {
|
||||||
|
.x = x_start,
|
||||||
|
.y = y_start,
|
||||||
|
.width = static_cast<uint16_t>(width),
|
||||||
|
.height = static_cast<uint16_t>(height)
|
||||||
|
};
|
||||||
|
|
||||||
|
power_on(internal);
|
||||||
|
epd_draw_rotated_image(update_area, internal->packed_buffer, internal->framebuffer);
|
||||||
|
auto draw_result = epd_hl_update_area(
|
||||||
|
&internal->hl_state,
|
||||||
|
static_cast<EpdDrawMode>(config->draw_mode | MODE_PACKING_2PPB),
|
||||||
|
config->temperature_celsius,
|
||||||
|
update_area
|
||||||
|
);
|
||||||
|
|
||||||
|
return draw_result == EPD_DRAW_SUCCESS ? ERROR_NONE : ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t papers3_display_disp_on_off(Device* device, bool on_off) {
|
||||||
|
auto* internal = static_cast<Papers3DisplayInternal*>(device_get_driver_data(device));
|
||||||
|
if (on_off) {
|
||||||
|
power_on(internal);
|
||||||
|
} else if (internal->powered) {
|
||||||
|
epd_poweroff();
|
||||||
|
internal->powered = false;
|
||||||
|
}
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DisplayColorFormat papers3_display_get_color_format(Device*) {
|
||||||
|
return DISPLAY_COLOR_FORMAT_MONOCHROME;
|
||||||
|
}
|
||||||
|
|
||||||
|
// epd_width()/epd_height() are the panel's native, unrotated dimensions (display->width/height in
|
||||||
|
// epdiy.c) - epd_rotated_display_width()/height() swap them for EPD_ROT_PORTRAIT/INVERTED_PORTRAIT.
|
||||||
|
// epd_draw_rotated_image() clamps its input rect against the *rotated* dims and epd_draw_pixel()
|
||||||
|
// applies the rotation transform on top of that (see _rotate() in epdiy.c), so both LVGL's canvas
|
||||||
|
// size and draw_bitmap()'s rect must be in rotated-space, not native-space - using the native
|
||||||
|
// epd_width()/epd_height() here fed rotated-space code a landscape-sized canvas, which produced
|
||||||
|
// exactly the "rotated + landscape" symptom this was fixed for.
|
||||||
|
static uint16_t papers3_display_get_resolution_x(Device*) {
|
||||||
|
return static_cast<uint16_t>(epd_rotated_display_width());
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t papers3_display_get_resolution_y(Device*) {
|
||||||
|
return static_cast<uint16_t>(epd_rotated_display_height());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void papers3_display_get_frame_buffer(Device*, uint8_t, void** out_buffer) {
|
||||||
|
// Not exposed via the generic fb-direct path: EPDiy's framebuffer is its own 4bpp packed
|
||||||
|
// format, not the DISPLAY_COLOR_FORMAT_MONOCHROME (1bpp) this driver reports - see
|
||||||
|
// get_frame_buffer_count() and draw_bitmap()'s conversion.
|
||||||
|
*out_buffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t papers3_display_get_frame_buffer_count(Device*) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
static const DisplayApi papers3_display_api = {
|
||||||
|
.capabilities = DISPLAY_CAPABILITY_ON_OFF | DISPLAY_CAPABILITY_REQUIRES_FULL_FRAME | DISPLAY_CAPABILITY_SLOW_REFRESH,
|
||||||
|
.reset = papers3_display_reset,
|
||||||
|
.init = papers3_display_init,
|
||||||
|
.draw_bitmap = papers3_display_draw_bitmap,
|
||||||
|
.mirror = nullptr,
|
||||||
|
.swap_xy = nullptr,
|
||||||
|
.get_swap_xy = nullptr,
|
||||||
|
.get_mirror_x = nullptr,
|
||||||
|
.get_mirror_y = nullptr,
|
||||||
|
.set_gap = nullptr,
|
||||||
|
.get_gap_x = nullptr,
|
||||||
|
.get_gap_y = nullptr,
|
||||||
|
.invert_color = nullptr,
|
||||||
|
.disp_on_off = papers3_display_disp_on_off,
|
||||||
|
.disp_sleep = nullptr,
|
||||||
|
.get_color_format = papers3_display_get_color_format,
|
||||||
|
.get_resolution_x = papers3_display_get_resolution_x,
|
||||||
|
.get_resolution_y = papers3_display_get_resolution_y,
|
||||||
|
.get_frame_buffer = papers3_display_get_frame_buffer,
|
||||||
|
.get_frame_buffer_count = papers3_display_get_frame_buffer_count,
|
||||||
|
.get_backlight = nullptr,
|
||||||
|
.has_capability = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
// region Driver lifecycle
|
||||||
|
|
||||||
|
static error_t start(Device* device) {
|
||||||
|
const auto* config = GET_CONFIG(device);
|
||||||
|
|
||||||
|
static bool s_lut_initialized = false;
|
||||||
|
if (!s_lut_initialized) {
|
||||||
|
init_unpack_lut();
|
||||||
|
s_lut_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* internal = static_cast<Papers3DisplayInternal*>(malloc(sizeof(Papers3DisplayInternal)));
|
||||||
|
if (internal == nullptr) {
|
||||||
|
return ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
internal->powered = false;
|
||||||
|
|
||||||
|
epd_init(&epd_board_m5papers3, &ED047TC1, static_cast<EpdInitOptions>(EPD_LUT_1K | EPD_FEED_QUEUE_32));
|
||||||
|
epd_set_rotation(config->rotation);
|
||||||
|
|
||||||
|
if (!s_hl_initialized) {
|
||||||
|
s_hl_state = epd_hl_init(EPD_BUILTIN_WAVEFORM);
|
||||||
|
if (s_hl_state.front_fb == nullptr) {
|
||||||
|
LOG_E(TAG, "Failed to initialize EPDiy highlevel state");
|
||||||
|
epd_deinit();
|
||||||
|
free(internal);
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
s_hl_initialized = true;
|
||||||
|
} else {
|
||||||
|
LOG_I(TAG, "Reusing existing EPDiy highlevel state");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal->hl_state = s_hl_state;
|
||||||
|
internal->framebuffer = epd_hl_get_framebuffer(&internal->hl_state);
|
||||||
|
|
||||||
|
// Sized for the rotated (LVGL-facing) resolution - see get_resolution_x()/y()'s comment.
|
||||||
|
const size_t packed_buffer_size = static_cast<size_t>((epd_rotated_display_width() + 1) / 2) * static_cast<size_t>(epd_rotated_display_height());
|
||||||
|
internal->packed_buffer = static_cast<uint8_t*>(malloc(packed_buffer_size));
|
||||||
|
if (internal->packed_buffer == nullptr) {
|
||||||
|
LOG_E(TAG, "Failed to allocate packed pixel buffer");
|
||||||
|
epd_deinit();
|
||||||
|
free(internal);
|
||||||
|
return ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
device_set_driver_data(device, internal);
|
||||||
|
|
||||||
|
LOG_I(TAG, "EPDiy initialized (%dx%d native, %dx%d rotated)", epd_width(), epd_height(), epd_rotated_display_width(), epd_rotated_display_height());
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t stop(Device* device) {
|
||||||
|
auto* internal = static_cast<Papers3DisplayInternal*>(device_get_driver_data(device));
|
||||||
|
|
||||||
|
if (internal->powered) {
|
||||||
|
epd_poweroff();
|
||||||
|
internal->powered = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
epd_deinit();
|
||||||
|
|
||||||
|
free(internal->packed_buffer);
|
||||||
|
free(internal);
|
||||||
|
device_set_driver_data(device, nullptr);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
Driver papers3_display_driver = {
|
||||||
|
.name = "papers3-display",
|
||||||
|
.compatible = (const char*[]) { "m5stack,papers3-display", nullptr },
|
||||||
|
.start_device = start,
|
||||||
|
.stop_device = stop,
|
||||||
|
.api = &papers3_display_api,
|
||||||
|
.device_type = &DISPLAY_TYPE,
|
||||||
|
.owner = &m5stack_papers3_module,
|
||||||
|
.internal = nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <epdiy.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Papers3DisplayConfig {
|
||||||
|
int temperature_celsius;
|
||||||
|
enum EpdDrawMode draw_mode;
|
||||||
|
enum EpdRotation rotation;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,280 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#include "papers3_power.h"
|
||||||
|
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/driver.h>
|
||||||
|
#include <tactility/drivers/gpio_controller.h>
|
||||||
|
#include <tactility/drivers/power_supply.h>
|
||||||
|
#include <tactility/drivers/pwm.h>
|
||||||
|
#include <tactility/log.h>
|
||||||
|
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/task.h>
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#define TAG "Papers3Power"
|
||||||
|
#define GET_CONFIG(device) (static_cast<const Papers3PowerConfig*>((device)->config))
|
||||||
|
|
||||||
|
// Power-off signal timing, ported from the old deprecated-HAL PaperS3Power::powerOff().
|
||||||
|
static constexpr int POWER_OFF_PULSE_COUNT = 5;
|
||||||
|
static constexpr TickType_t POWER_OFF_PULSE_DURATION = pdMS_TO_TICKS(100);
|
||||||
|
static constexpr int BEEP_FREQUENCY_HZ = 440;
|
||||||
|
static constexpr TickType_t BEEP_DURATION = pdMS_TO_TICKS(200);
|
||||||
|
static constexpr TickType_t BEEP_GAP = pdMS_TO_TICKS(100);
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
extern Module m5stack_papers3_module;
|
||||||
|
|
||||||
|
struct Papers3PowerInternal {
|
||||||
|
GpioDescriptor* charge_status_descriptor = nullptr;
|
||||||
|
GpioDescriptor* usb_detect_descriptor = nullptr;
|
||||||
|
GpioDescriptor* power_off_descriptor = nullptr;
|
||||||
|
Device* power_supply_device = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
error_t papers3_power_is_charging(Device* device, bool* charging) {
|
||||||
|
auto* internal = static_cast<Papers3PowerInternal*>(device_get_driver_data(device));
|
||||||
|
bool level;
|
||||||
|
error_t error = gpio_descriptor_get_level(internal->charge_status_descriptor, &level);
|
||||||
|
if (error != ERROR_NONE) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
// Charge IC status is active-low: 0 = charging, 1 = full/no USB.
|
||||||
|
*charging = !level;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t papers3_power_is_usb_connected(Device* device, bool* connected) {
|
||||||
|
auto* internal = static_cast<Papers3PowerInternal*>(device_get_driver_data(device));
|
||||||
|
return gpio_descriptor_get_level(internal->usb_detect_descriptor, connected);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void beep(Device* pwm, int frequency_hz, TickType_t duration) {
|
||||||
|
uint32_t period_ns = 1000000000U / static_cast<uint32_t>(frequency_hz);
|
||||||
|
if (pwm_set_period(pwm, period_ns) != ERROR_NONE ||
|
||||||
|
pwm_set_duty(pwm, period_ns / 2) != ERROR_NONE ||
|
||||||
|
pwm_enable(pwm) != ERROR_NONE) {
|
||||||
|
LOG_E(TAG, "Failed to start buzzer tone");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vTaskDelay(duration);
|
||||||
|
pwm_disable(pwm);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t papers3_power_off(Device* device) {
|
||||||
|
LOG_W(TAG, "Power-off requested");
|
||||||
|
// Note: callers are responsible for stopping the display (e.g. EPD refresh) before calling
|
||||||
|
// this. The beep sequence below (~500ms) provides some lead time, but a full EPD refresh can
|
||||||
|
// take up to ~1500ms; the display recovers correctly on next boot via a full-screen clear.
|
||||||
|
|
||||||
|
auto* internal = static_cast<Papers3PowerInternal*>(device_get_driver_data(device));
|
||||||
|
const auto* config = GET_CONFIG(device);
|
||||||
|
|
||||||
|
beep(config->pwm, BEEP_FREQUENCY_HZ, BEEP_DURATION);
|
||||||
|
vTaskDelay(BEEP_GAP);
|
||||||
|
beep(config->pwm, BEEP_FREQUENCY_HZ, BEEP_DURATION);
|
||||||
|
|
||||||
|
LOG_W(TAG, "Triggering shutdown (sending %d pulses)...", POWER_OFF_PULSE_COUNT);
|
||||||
|
for (int i = 0; i < POWER_OFF_PULSE_COUNT; i++) {
|
||||||
|
gpio_descriptor_set_level(internal->power_off_descriptor, true);
|
||||||
|
vTaskDelay(POWER_OFF_PULSE_DURATION);
|
||||||
|
gpio_descriptor_set_level(internal->power_off_descriptor, false);
|
||||||
|
vTaskDelay(POWER_OFF_PULSE_DURATION);
|
||||||
|
}
|
||||||
|
gpio_descriptor_set_level(internal->power_off_descriptor, true); // 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");
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// region Power supply child device
|
||||||
|
|
||||||
|
static bool ps_supports_property(Device*, PowerSupplyProperty property) {
|
||||||
|
return property == POWER_SUPPLY_PROP_IS_CHARGING;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t ps_get_property(Device* device, PowerSupplyProperty property, PowerSupplyPropertyValue* out_value) {
|
||||||
|
if (property != POWER_SUPPLY_PROP_IS_CHARGING) {
|
||||||
|
return ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
// device_get_parent() here is the papers3-power device itself (this child's parent).
|
||||||
|
bool charging;
|
||||||
|
error_t error = papers3_power_is_charging(device_get_parent(device), &charging);
|
||||||
|
if (error != ERROR_NONE) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
out_value->int_value = charging ? 1 : 0;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ps_supports_charge_control(Device*) { return false; }
|
||||||
|
static bool ps_is_allowed_to_charge(Device*) { return false; }
|
||||||
|
static error_t ps_set_allowed_to_charge(Device*, bool) { return ERROR_NOT_SUPPORTED; }
|
||||||
|
static bool ps_supports_quick_charge(Device*) { return false; }
|
||||||
|
static bool ps_is_quick_charge_enabled(Device*) { return false; }
|
||||||
|
static error_t ps_set_quick_charge_enabled(Device*, bool) { return ERROR_NOT_SUPPORTED; }
|
||||||
|
static bool ps_supports_power_off(Device*) { return true; }
|
||||||
|
static error_t ps_power_off(Device* device) { return papers3_power_off(device_get_parent(device)); }
|
||||||
|
|
||||||
|
static constexpr PowerSupplyApi PAPERS3_POWER_SUPPLY_API = {
|
||||||
|
.supports_property = ps_supports_property,
|
||||||
|
.get_property = ps_get_property,
|
||||||
|
.supports_charge_control = ps_supports_charge_control,
|
||||||
|
.is_allowed_to_charge = ps_is_allowed_to_charge,
|
||||||
|
.set_allowed_to_charge = ps_set_allowed_to_charge,
|
||||||
|
.supports_quick_charge = ps_supports_quick_charge,
|
||||||
|
.is_quick_charge_enabled = ps_is_quick_charge_enabled,
|
||||||
|
.set_quick_charge_enabled = ps_set_quick_charge_enabled,
|
||||||
|
.supports_power_off = ps_supports_power_off,
|
||||||
|
.power_off = ps_power_off,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Registered (driver_construct_add() in module.cpp) so driver_bind() has a valid ->internal, but
|
||||||
|
// never matched against a devicetree node: papers3_power_driver wires it up directly by pointer.
|
||||||
|
Driver papers3_power_supply_driver = {
|
||||||
|
.name = "papers3-power-supply",
|
||||||
|
.compatible = (const char*[]) { "papers3-power-supply", nullptr },
|
||||||
|
.start_device = nullptr,
|
||||||
|
.stop_device = nullptr,
|
||||||
|
.api = &PAPERS3_POWER_SUPPLY_API,
|
||||||
|
.device_type = &POWER_SUPPLY_TYPE,
|
||||||
|
.owner = &m5stack_papers3_module,
|
||||||
|
.internal = nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
static error_t create_power_supply_child(Device* parent, Device*& out_child) {
|
||||||
|
auto* child = new(std::nothrow) Device { .address = 0, .name = "papers3-power-supply", .config = nullptr, .parent = nullptr, .internal = nullptr };
|
||||||
|
if (child == nullptr) {
|
||||||
|
return ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t error = device_construct(child);
|
||||||
|
if (error != ERROR_NONE) {
|
||||||
|
delete child;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
device_set_parent(child, parent);
|
||||||
|
device_set_driver(child, &papers3_power_supply_driver);
|
||||||
|
|
||||||
|
error = device_add(child);
|
||||||
|
if (error != ERROR_NONE) {
|
||||||
|
device_destruct(child);
|
||||||
|
delete child;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = device_start(child);
|
||||||
|
if (error != ERROR_NONE) {
|
||||||
|
device_remove(child);
|
||||||
|
device_destruct(child);
|
||||||
|
delete child;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_child = child;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy_power_supply_child(Device* child) {
|
||||||
|
check(device_stop(child) == ERROR_NONE);
|
||||||
|
check(device_remove(child) == ERROR_NONE);
|
||||||
|
check(device_destruct(child) == ERROR_NONE);
|
||||||
|
delete child;
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Driver lifecycle
|
||||||
|
|
||||||
|
static error_t acquire_input(const GpioPinSpec& pin, GpioDescriptor** out_descriptor) {
|
||||||
|
auto* descriptor = gpio_descriptor_acquire(pin.gpio_controller, pin.pin, GPIO_OWNER_GPIO);
|
||||||
|
if (descriptor == nullptr) {
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
error_t error = gpio_descriptor_set_flags(descriptor, pin.flags | GPIO_FLAG_DIRECTION_INPUT);
|
||||||
|
if (error != ERROR_NONE) {
|
||||||
|
gpio_descriptor_release(descriptor);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
*out_descriptor = descriptor;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t start(Device* device) {
|
||||||
|
const auto* config = GET_CONFIG(device);
|
||||||
|
|
||||||
|
auto* internal = new(std::nothrow) Papers3PowerInternal();
|
||||||
|
if (internal == nullptr) {
|
||||||
|
return ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (acquire_input(config->pin_charge_status, &internal->charge_status_descriptor) != ERROR_NONE) {
|
||||||
|
LOG_E(TAG, "Failed to configure charge-status pin");
|
||||||
|
delete internal;
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (acquire_input(config->pin_usb_detect, &internal->usb_detect_descriptor) != ERROR_NONE) {
|
||||||
|
LOG_E(TAG, "Failed to configure usb-detect pin");
|
||||||
|
gpio_descriptor_release(internal->charge_status_descriptor);
|
||||||
|
delete internal;
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal->power_off_descriptor = gpio_descriptor_acquire(config->pin_power_off.gpio_controller, config->pin_power_off.pin, GPIO_OWNER_GPIO);
|
||||||
|
if (internal->power_off_descriptor == nullptr ||
|
||||||
|
gpio_descriptor_set_flags(internal->power_off_descriptor, config->pin_power_off.flags | GPIO_FLAG_DIRECTION_OUTPUT) != ERROR_NONE) {
|
||||||
|
LOG_E(TAG, "Failed to configure power-off pin");
|
||||||
|
if (internal->power_off_descriptor != nullptr) {
|
||||||
|
gpio_descriptor_release(internal->power_off_descriptor);
|
||||||
|
}
|
||||||
|
gpio_descriptor_release(internal->usb_detect_descriptor);
|
||||||
|
gpio_descriptor_release(internal->charge_status_descriptor);
|
||||||
|
delete internal;
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
gpio_descriptor_set_level(internal->power_off_descriptor, false);
|
||||||
|
|
||||||
|
error_t error = create_power_supply_child(device, internal->power_supply_device);
|
||||||
|
if (error != ERROR_NONE) {
|
||||||
|
gpio_descriptor_release(internal->power_off_descriptor);
|
||||||
|
gpio_descriptor_release(internal->usb_detect_descriptor);
|
||||||
|
gpio_descriptor_release(internal->charge_status_descriptor);
|
||||||
|
delete internal;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
device_set_driver_data(device, internal);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t stop(Device* device) {
|
||||||
|
auto* internal = static_cast<Papers3PowerInternal*>(device_get_driver_data(device));
|
||||||
|
destroy_power_supply_child(internal->power_supply_device);
|
||||||
|
gpio_descriptor_release(internal->power_off_descriptor);
|
||||||
|
gpio_descriptor_release(internal->usb_detect_descriptor);
|
||||||
|
gpio_descriptor_release(internal->charge_status_descriptor);
|
||||||
|
device_set_driver_data(device, nullptr);
|
||||||
|
delete internal;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
Driver papers3_power_driver = {
|
||||||
|
.name = "papers3-power",
|
||||||
|
.compatible = (const char*[]) { "m5stack,papers3-power", nullptr },
|
||||||
|
.start_device = start,
|
||||||
|
.stop_device = stop,
|
||||||
|
.api = nullptr,
|
||||||
|
.device_type = nullptr,
|
||||||
|
.owner = &m5stack_papers3_module,
|
||||||
|
.internal = nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include <tactility/device.h>
|
||||||
|
#include <tactility/drivers/gpio.h>
|
||||||
|
#include <tactility/error.h>
|
||||||
|
|
||||||
|
struct Papers3PowerConfig {
|
||||||
|
struct GpioPinSpec pin_charge_status;
|
||||||
|
struct GpioPinSpec pin_usb_detect;
|
||||||
|
struct GpioPinSpec pin_power_off;
|
||||||
|
/** Tone generator used for the power-off confirmation beep */
|
||||||
|
struct Device* pwm;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Charge IC status: true while the battery is charging. */
|
||||||
|
error_t papers3_power_is_charging(struct Device* device, bool* charging);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Whether USB VBUS is currently present.
|
||||||
|
* @warning Ported as-is from the old deprecated-HAL driver, which never actually wired this into
|
||||||
|
* its metrics and flagged it "TODO: Fix USB Detection" - the read itself hasn't been independently
|
||||||
|
* re-verified against real hardware here either, just carried forward with the same caveat.
|
||||||
|
*/
|
||||||
|
error_t papers3_power_is_usb_connected(struct Device* device, bool* connected);
|
||||||
|
|
||||||
|
/** Beeps twice, then pulses the shutdown pin (does not return on success). */
|
||||||
|
error_t papers3_power_off(struct Device* device);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/driver.h>
|
||||||
|
#include <tactility/error.h>
|
||||||
|
#include <tactility/module.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
extern Driver papers3_power_driver;
|
||||||
|
extern Driver papers3_power_supply_driver;
|
||||||
|
extern Driver papers3_display_driver;
|
||||||
|
|
||||||
|
static error_t start() {
|
||||||
|
check(driver_construct_add(&papers3_power_supply_driver) == ERROR_NONE);
|
||||||
|
check(driver_construct_add(&papers3_power_driver) == ERROR_NONE);
|
||||||
|
check(driver_construct_add(&papers3_display_driver) == ERROR_NONE);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t stop() {
|
||||||
|
check(driver_remove_destruct(&papers3_display_driver) == ERROR_NONE);
|
||||||
|
check(driver_remove_destruct(&papers3_power_driver) == ERROR_NONE);
|
||||||
|
check(driver_remove_destruct(&papers3_power_supply_driver) == ERROR_NONE);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Module m5stack_papers3_module = {
|
||||||
|
.name = "m5stack-papers3",
|
||||||
|
.start = start,
|
||||||
|
.stop = stop,
|
||||||
|
.symbols = nullptr,
|
||||||
|
.internal = nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,19 +1,12 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static error_t start() {
|
Module m5stack_stackchan_module = {
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static error_t stop() {
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Module m5stack_stackchan_module = {
|
|
||||||
.name = "m5stack-stackchan",
|
.name = "m5stack-stackchan",
|
||||||
.start = start,
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
.stop = stop,
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
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"
|
INCLUDE_DIRS "source"
|
||||||
REQUIRES Tactility esp_lvgl_port esp_lcd ST7789 PwmBacklight ButtonControl vfs fatfs m5pm1-module
|
REQUIRES TactilityKernel
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
#include "devices/Display.h"
|
|
||||||
#include "devices/Power.h"
|
|
||||||
|
|
||||||
#include <tactility/device.h>
|
|
||||||
#include <drivers/m5pm1.h>
|
|
||||||
|
|
||||||
#include <Tactility/hal/Configuration.h>
|
|
||||||
#include <ButtonControl.h>
|
|
||||||
#include <PwmBacklight.h>
|
|
||||||
|
|
||||||
using namespace tt::hal;
|
|
||||||
|
|
||||||
static constexpr auto* TAG = "StickS3";
|
|
||||||
|
|
||||||
// Audio codec register programming is owned by the es8311-module driver (registered as an
|
|
||||||
// AUDIO_CODEC_TYPE device, see m5stack,sticks3.dts). This board still needs to drive the
|
|
||||||
// AW8737 speaker amplifier's enable line via m5pm1 (PM1_G3), which is board wiring glue
|
|
||||||
// rather than codec configuration, so it stays here.
|
|
||||||
static void enableSpeakerAmplifier() {
|
|
||||||
auto* m5pm1 = device_find_by_name("m5pm1");
|
|
||||||
if (m5pm1 == nullptr) {
|
|
||||||
LOG_W(TAG, "m5pm1 not found -- speaker amp not enabled");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
error_t error = m5pm1_set_speaker_enable(m5pm1, true);
|
|
||||||
if (error != ERROR_NONE) {
|
|
||||||
LOG_E(TAG, "Failed to enable speaker amplifier: %s", error_to_string(error));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool initBoot() {
|
|
||||||
enableSpeakerAmplifier();
|
|
||||||
return driver::pwmbacklight::init(GPIO_NUM_38, 512);
|
|
||||||
}
|
|
||||||
|
|
||||||
static DeviceVector createDevices() {
|
|
||||||
return {
|
|
||||||
createPower(),
|
|
||||||
ButtonControl::createTwoButtonControl(11, 12), // top button, side button
|
|
||||||
createDisplay(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
extern const Configuration hardwareConfiguration = {
|
|
||||||
.initBoot = initBoot,
|
|
||||||
.createDevices = createDevices
|
|
||||||
};
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
#include "Display.h"
|
|
||||||
|
|
||||||
#include <PwmBacklight.h>
|
|
||||||
#include <St7789Display.h>
|
|
||||||
|
|
||||||
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
|
|
||||||
St7789Display::Configuration panel_configuration = {
|
|
||||||
.horizontalResolution = LCD_HORIZONTAL_RESOLUTION,
|
|
||||||
.verticalResolution = LCD_VERTICAL_RESOLUTION,
|
|
||||||
.gapX = 52,
|
|
||||||
.gapY = 40,
|
|
||||||
.swapXY = false,
|
|
||||||
.mirrorX = false,
|
|
||||||
.mirrorY = false,
|
|
||||||
.invertColor = true,
|
|
||||||
.bufferSize = LCD_BUFFER_SIZE,
|
|
||||||
.touch = nullptr,
|
|
||||||
.backlightDutyFunction = driver::pwmbacklight::setBacklightDuty,
|
|
||||||
.resetPin = LCD_PIN_RESET,
|
|
||||||
.lvglSwapBytes = false
|
|
||||||
};
|
|
||||||
|
|
||||||
auto spi_configuration = std::make_shared<St7789Display::SpiConfiguration>(St7789Display::SpiConfiguration {
|
|
||||||
.spiHostDevice = LCD_SPI_HOST,
|
|
||||||
.csPin = LCD_PIN_CS,
|
|
||||||
.dcPin = LCD_PIN_DC,
|
|
||||||
.pixelClockFrequency = 40'000'000,
|
|
||||||
.transactionQueueDepth = 10
|
|
||||||
});
|
|
||||||
|
|
||||||
return std::make_shared<St7789Display>(panel_configuration, spi_configuration);
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Tactility/hal/display/DisplayDevice.h"
|
|
||||||
#include <memory>
|
|
||||||
#include <driver/gpio.h>
|
|
||||||
#include <driver/spi_common.h>
|
|
||||||
|
|
||||||
constexpr auto LCD_SPI_HOST = SPI2_HOST;
|
|
||||||
constexpr auto LCD_PIN_CS = GPIO_NUM_41;
|
|
||||||
constexpr auto LCD_PIN_DC = GPIO_NUM_45;
|
|
||||||
constexpr auto LCD_PIN_RESET = GPIO_NUM_21;
|
|
||||||
constexpr auto LCD_HORIZONTAL_RESOLUTION = 135;
|
|
||||||
constexpr auto LCD_VERTICAL_RESOLUTION = 240;
|
|
||||||
constexpr auto LCD_BUFFER_HEIGHT = LCD_VERTICAL_RESOLUTION / 3;
|
|
||||||
constexpr auto LCD_BUFFER_SIZE = LCD_HORIZONTAL_RESOLUTION * LCD_BUFFER_HEIGHT;
|
|
||||||
|
|
||||||
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
#include "Power.h"
|
|
||||||
|
|
||||||
#include <Tactility/hal/power/PowerDevice.h>
|
|
||||||
#include <drivers/m5pm1.h>
|
|
||||||
#include <tactility/device.h>
|
|
||||||
#include <tactility/log.h>
|
|
||||||
|
|
||||||
using namespace tt::hal::power;
|
|
||||||
|
|
||||||
static constexpr auto* TAG = "StickS3Power";
|
|
||||||
|
|
||||||
static constexpr float MIN_BATTERY_VOLTAGE_MV = 3300.0f;
|
|
||||||
static constexpr float MAX_BATTERY_VOLTAGE_MV = 4200.0f;
|
|
||||||
|
|
||||||
class StickS3Power final : public PowerDevice {
|
|
||||||
public:
|
|
||||||
explicit StickS3Power(::Device* m5pm1Device) : m5pm1(m5pm1Device) {}
|
|
||||||
|
|
||||||
std::string getName() const override { return "M5Stack StickS3 Power"; }
|
|
||||||
std::string getDescription() const override { return "Battery monitoring via M5PM1 over I2C"; }
|
|
||||||
|
|
||||||
bool supportsMetric(MetricType type) const override {
|
|
||||||
switch (type) {
|
|
||||||
using enum MetricType;
|
|
||||||
case BatteryVoltage:
|
|
||||||
case ChargeLevel:
|
|
||||||
case IsCharging:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getMetric(MetricType type, MetricData& data) override {
|
|
||||||
switch (type) {
|
|
||||||
using enum MetricType;
|
|
||||||
|
|
||||||
case BatteryVoltage: {
|
|
||||||
uint16_t mv = 0;
|
|
||||||
if (m5pm1_get_battery_voltage(m5pm1, &mv) != ERROR_NONE) return false;
|
|
||||||
data.valueAsUint32 = mv;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ChargeLevel: {
|
|
||||||
uint16_t mv = 0;
|
|
||||||
if (m5pm1_get_battery_voltage(m5pm1, &mv) != ERROR_NONE) return false;
|
|
||||||
float voltage = static_cast<float>(mv);
|
|
||||||
if (voltage >= MAX_BATTERY_VOLTAGE_MV) {
|
|
||||||
data.valueAsUint8 = 100;
|
|
||||||
} else if (voltage <= MIN_BATTERY_VOLTAGE_MV) {
|
|
||||||
data.valueAsUint8 = 0;
|
|
||||||
} else {
|
|
||||||
float factor = (voltage - MIN_BATTERY_VOLTAGE_MV) / (MAX_BATTERY_VOLTAGE_MV - MIN_BATTERY_VOLTAGE_MV);
|
|
||||||
data.valueAsUint8 = static_cast<uint8_t>(factor * 100.0f);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case IsCharging: {
|
|
||||||
bool charging = false;
|
|
||||||
if (m5pm1_is_charging(m5pm1, &charging) != ERROR_NONE) {
|
|
||||||
LOG_W(TAG, "Failed to read charging status");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
data.valueAsBool = charging;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool supportsPowerOff() const override { return true; }
|
|
||||||
|
|
||||||
void powerOff() override {
|
|
||||||
LOG_W(TAG, "Powering off via M5PM1");
|
|
||||||
if (m5pm1_shutdown(m5pm1) != ERROR_NONE) {
|
|
||||||
LOG_E(TAG, "Failed to send power-off command");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
::Device* m5pm1;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::shared_ptr<PowerDevice> createPower() {
|
|
||||||
auto* m5pm1 = device_find_by_name("m5pm1");
|
|
||||||
if (m5pm1 == nullptr) {
|
|
||||||
LOG_E(TAG, "m5pm1 device not found");
|
|
||||||
}
|
|
||||||
return std::make_shared<StickS3Power>(m5pm1);
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <Tactility/hal/power/PowerDevice.h>
|
|
||||||
|
|
||||||
std::shared_ptr<tt::hal::power::PowerDevice> createPower();
|
|
||||||
@@ -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_sticks3_module = {
|
|
||||||
.name = "m5stack-sticks3",
|
|
||||||
.start = start,
|
|
||||||
.stop = stop,
|
|
||||||
.symbols = nullptr,
|
|
||||||
.internal = nullptr
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -12,6 +12,8 @@ hardware.esptoolFlashFreq=80M
|
|||||||
hardware.tinyUsb=true
|
hardware.tinyUsb=true
|
||||||
hardware.bluetooth=true
|
hardware.bluetooth=true
|
||||||
|
|
||||||
|
dependencies.useDeprecatedHal=false
|
||||||
|
|
||||||
storage.userDataLocation=Internal
|
storage.userDataLocation=Internal
|
||||||
|
|
||||||
display.size=1.14"
|
display.size=1.14"
|
||||||
|
|||||||
@@ -4,4 +4,6 @@ dependencies:
|
|||||||
- Drivers/m5pm1-module
|
- Drivers/m5pm1-module
|
||||||
- Drivers/es8311-module
|
- Drivers/es8311-module
|
||||||
- Drivers/audio-stream-module
|
- Drivers/audio-stream-module
|
||||||
|
- Drivers/st7789-module
|
||||||
|
- Drivers/button-control-module
|
||||||
dts: m5stack,sticks3.dts
|
dts: m5stack,sticks3.dts
|
||||||
|
|||||||
@@ -11,7 +11,11 @@
|
|||||||
#include <bindings/m5pm1.h>
|
#include <bindings/m5pm1.h>
|
||||||
#include <bindings/es8311.h>
|
#include <bindings/es8311.h>
|
||||||
#include <tactility/bindings/esp32_sdspi.h>
|
#include <tactility/bindings/esp32_sdspi.h>
|
||||||
#include <tactility/bindings/display_placeholder.h>
|
#include <tactility/bindings/esp32_pwm_ledc.h>
|
||||||
|
#include <tactility/bindings/pwm_backlight.h>
|
||||||
|
|
||||||
|
#include <bindings/st7789.h>
|
||||||
|
#include <bindings/button_control.h>
|
||||||
|
|
||||||
/ {
|
/ {
|
||||||
compatible = "root";
|
compatible = "root";
|
||||||
@@ -53,6 +57,8 @@
|
|||||||
m5pm1 {
|
m5pm1 {
|
||||||
compatible = "m5stack,m5pm1";
|
compatible = "m5stack,m5pm1";
|
||||||
reg = <0x6E>;
|
reg = <0x6E>;
|
||||||
|
power-supply-reference-voltage-mv = <4200>;
|
||||||
|
speaker-amp-enable-at-boot;
|
||||||
};
|
};
|
||||||
|
|
||||||
bmi270 {
|
bmi270 {
|
||||||
@@ -75,18 +81,49 @@
|
|||||||
pin-scl = <&gpio0 10 GPIO_FLAG_NONE>;
|
pin-scl = <&gpio0 10 GPIO_FLAG_NONE>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
display_backlight_pwm {
|
||||||
|
compatible = "espressif,esp32-pwm-ledc";
|
||||||
|
pin = <&gpio0 38 GPIO_FLAG_NONE>;
|
||||||
|
period-ns = <1953125>;
|
||||||
|
ledc-timer = <0>;
|
||||||
|
ledc-channel = <0>;
|
||||||
|
};
|
||||||
|
|
||||||
|
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 {
|
spi0 {
|
||||||
compatible = "espressif,esp32-spi";
|
compatible = "espressif,esp32-spi";
|
||||||
host = <SPI2_HOST>;
|
host = <SPI2_HOST>;
|
||||||
cs-gpios = <&gpio0 41 GPIO_FLAG_NONE>;
|
cs-gpios = <&gpio0 41 GPIO_FLAG_NONE>;
|
||||||
pin-mosi = <&gpio0 39 GPIO_FLAG_NONE>;
|
pin-mosi = <&gpio0 39 GPIO_FLAG_NONE>;
|
||||||
pin-sclk = <&gpio0 40 GPIO_FLAG_NONE>;
|
pin-sclk = <&gpio0 40 GPIO_FLAG_NONE>;
|
||||||
|
|
||||||
display {
|
display@0 {
|
||||||
compatible = "display-placeholder";
|
compatible = "sitronix,st7789";
|
||||||
|
horizontal-resolution = <135>;
|
||||||
|
vertical-resolution = <240>;
|
||||||
|
gap-x = <52>;
|
||||||
|
gap-y = <40>;
|
||||||
|
invert-color;
|
||||||
|
pixel-clock-hz = <40000000>;
|
||||||
|
pin-dc = <&gpio0 45 GPIO_FLAG_NONE>;
|
||||||
|
pin-reset = <&gpio0 21 GPIO_FLAG_NONE>;
|
||||||
|
backlight = <&display_backlight>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
buttons {
|
||||||
|
compatible = "tactility,button-control";
|
||||||
|
pin-primary = <&gpio0 11 GPIO_FLAG_NONE>;
|
||||||
|
pin-secondary = <&gpio0 12 GPIO_FLAG_NONE>;
|
||||||
|
};
|
||||||
|
|
||||||
uart_grove: uart1 {
|
uart_grove: uart1 {
|
||||||
compatible = "espressif,esp32-uart";
|
compatible = "espressif,esp32-uart";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#include <tactility/error.h>
|
||||||
|
#include <tactility/module.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
Module m5stack_sticks3_module = {
|
||||||
|
.name = "m5stack-sticks3",
|
||||||
|
.start = [] -> error_t { return ERROR_NONE; },
|
||||||
|
.stop = [] -> error_t { return ERROR_NONE; },
|
||||||
|
.symbols = nullptr,
|
||||||
|
.internal = nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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 esp_lvgl_port esp_lcd EspLcdCompat esp_lcd_ili9881c esp_lcd_st7123 esp_lcd_touch_st7123 GT911 PwmBacklight driver esp_driver_i2c vfs fatfs ina226-module
|
REQUIRES Tactility esp_lvgl_port esp_lcd esp_lcd_ili9881c esp_lcd_st7123 esp_lcd_touch_st7123 esp_lcd_touch_gt911 driver esp_driver_i2c vfs fatfs ina226-module ili9881c-module st7123-module gt911-module
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,205 +0,0 @@
|
|||||||
#include "devices/Display.h"
|
|
||||||
#include "devices/Power.h"
|
|
||||||
#include "devices/Tab5Keyboard.h"
|
|
||||||
|
|
||||||
#include <tactility/drivers/gpio_controller.h>
|
|
||||||
#include <tactility/drivers/i2c_controller.h>
|
|
||||||
|
|
||||||
#include <Tactility/hal/Configuration.h>
|
|
||||||
|
|
||||||
#include <esp_clock_output.h>
|
|
||||||
|
|
||||||
using namespace tt::hal;
|
|
||||||
|
|
||||||
static constexpr auto* TAG = "Tab5";
|
|
||||||
|
|
||||||
static DeviceVector createDevices() {
|
|
||||||
auto* i2c2 = device_find_by_name("i2c2");
|
|
||||||
check(i2c2, "i2c2 not found");
|
|
||||||
return {
|
|
||||||
createPower(),
|
|
||||||
createDisplay(),
|
|
||||||
std::make_shared<Tab5Keyboard>(i2c2)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
PI4IOE5V6408-0 (0x43)
|
|
||||||
- Bit 0: RF internal/external switch
|
|
||||||
- Bit 1: Speaker enable
|
|
||||||
- Bit 2: External 5V bus enable
|
|
||||||
- Bit 3: /
|
|
||||||
- Bit 4: LCD reset
|
|
||||||
- Bit 5: Touch reset
|
|
||||||
- Bit 6: Camera reset
|
|
||||||
- Bit 7: Headphone detect
|
|
||||||
*/
|
|
||||||
constexpr auto GPIO_EXP0_PIN_RF_INTERNAL_EXTERNAL = 0;
|
|
||||||
constexpr auto GPIO_EXP0_PIN_SPEAKER_ENABLE = 1;
|
|
||||||
constexpr auto GPIO_EXP0_PIN_EXTERNAL_5V_BUS_ENABLE = 2;
|
|
||||||
constexpr auto GPIO_EXP0_PIN_LCD_RESET = 4;
|
|
||||||
constexpr auto GPIO_EXP0_PIN_TOUCH_RESET = 5;
|
|
||||||
constexpr auto GPIO_EXP0_PIN_CAMERA_RESET = 6;
|
|
||||||
constexpr auto GPIO_EXP0_PIN_HEADPHONE_DETECT = 7;
|
|
||||||
|
|
||||||
/*
|
|
||||||
PI4IOE5V6408-1 (0x44)
|
|
||||||
- Bit 0: C6 WLAN enable
|
|
||||||
- Bit 1: /
|
|
||||||
- Bit 2: /
|
|
||||||
- Bit 3: USB-A 5V enable
|
|
||||||
- Bit 4: Device power: PWROFF_PLUSE
|
|
||||||
- Bit 5: IP2326: nCHG_QC_EN
|
|
||||||
- Bit 6: IP2326: CHG_STAT_LED
|
|
||||||
- Bit 7: IP2326: CHG_EN
|
|
||||||
*/
|
|
||||||
constexpr auto GPIO_EXP1_PIN_C6_WLAN_ENABLE = 0;
|
|
||||||
constexpr auto GPIO_EXP1_PIN_USB_A_5V_ENABLE = 3;
|
|
||||||
constexpr auto GPIO_EXP1_PIN_DEVICE_POWER = 4;
|
|
||||||
constexpr auto GPIO_EXP1_PIN_IP2326_NCHG_QC_EN = 5;
|
|
||||||
constexpr auto GPIO_EXP1_PIN_IP2326_CHG_STAT_LED = 6;
|
|
||||||
constexpr auto GPIO_EXP1_PIN_IP2326_CHG_EN = 7;
|
|
||||||
|
|
||||||
static void initExpander0(::Device* io_expander0) {
|
|
||||||
auto* rf_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_RF_INTERNAL_EXTERNAL, GPIO_OWNER_GPIO);
|
|
||||||
check(rf_pin);
|
|
||||||
auto* speaker_enable_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_SPEAKER_ENABLE, GPIO_OWNER_GPIO);
|
|
||||||
check(speaker_enable_pin);
|
|
||||||
auto* external_5v_bus_enable_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_EXTERNAL_5V_BUS_ENABLE, GPIO_OWNER_GPIO);
|
|
||||||
check(external_5v_bus_enable_pin);
|
|
||||||
auto* lcd_reset_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_LCD_RESET, GPIO_OWNER_GPIO);
|
|
||||||
check(lcd_reset_pin);
|
|
||||||
auto* touch_reset_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_TOUCH_RESET, GPIO_OWNER_GPIO);
|
|
||||||
check(touch_reset_pin);
|
|
||||||
auto* camera_reset_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_CAMERA_RESET, GPIO_OWNER_GPIO);
|
|
||||||
check(camera_reset_pin);
|
|
||||||
auto* headphone_detect_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_HEADPHONE_DETECT, GPIO_OWNER_GPIO);
|
|
||||||
check(headphone_detect_pin);
|
|
||||||
|
|
||||||
gpio_descriptor_set_flags(rf_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
|
||||||
gpio_descriptor_set_flags(speaker_enable_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
|
||||||
gpio_descriptor_set_flags(external_5v_bus_enable_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
|
||||||
gpio_descriptor_set_flags(lcd_reset_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
|
||||||
gpio_descriptor_set_flags(touch_reset_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
|
||||||
gpio_descriptor_set_flags(camera_reset_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
|
||||||
gpio_descriptor_set_flags(headphone_detect_pin, GPIO_FLAG_DIRECTION_INPUT);
|
|
||||||
|
|
||||||
gpio_descriptor_set_level(rf_pin, false);
|
|
||||||
gpio_descriptor_set_level(speaker_enable_pin, false);
|
|
||||||
gpio_descriptor_set_level(external_5v_bus_enable_pin, true);
|
|
||||||
gpio_descriptor_set_level(lcd_reset_pin, false);
|
|
||||||
gpio_descriptor_set_level(touch_reset_pin, false);
|
|
||||||
gpio_descriptor_set_level(camera_reset_pin, true);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(10));
|
|
||||||
// Enable touch and lcd, but not the camera
|
|
||||||
gpio_descriptor_set_level(lcd_reset_pin, true);
|
|
||||||
gpio_descriptor_set_level(touch_reset_pin, true);
|
|
||||||
|
|
||||||
gpio_descriptor_release(rf_pin);
|
|
||||||
gpio_descriptor_release(speaker_enable_pin);
|
|
||||||
gpio_descriptor_release(external_5v_bus_enable_pin);
|
|
||||||
gpio_descriptor_release(lcd_reset_pin);
|
|
||||||
gpio_descriptor_release(touch_reset_pin);
|
|
||||||
gpio_descriptor_release(camera_reset_pin);
|
|
||||||
gpio_descriptor_release(headphone_detect_pin);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void initExpander1(::Device* io_expander1) {
|
|
||||||
|
|
||||||
auto* c6_wlan_enable_pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_C6_WLAN_ENABLE, GPIO_OWNER_GPIO);
|
|
||||||
check(c6_wlan_enable_pin);
|
|
||||||
auto* usb_a_5v_enable_pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_USB_A_5V_ENABLE, GPIO_OWNER_GPIO);
|
|
||||||
check(usb_a_5v_enable_pin);
|
|
||||||
auto* device_power_pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_DEVICE_POWER, GPIO_OWNER_GPIO);
|
|
||||||
check(device_power_pin);
|
|
||||||
auto* ip2326_ncharge_qc_enable_pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_IP2326_NCHG_QC_EN, GPIO_OWNER_GPIO);
|
|
||||||
check(ip2326_ncharge_qc_enable_pin);
|
|
||||||
auto* ip2326_charge_state_led_pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_IP2326_CHG_STAT_LED, GPIO_OWNER_GPIO);
|
|
||||||
check(ip2326_charge_state_led_pin);
|
|
||||||
auto* ip2326_charge_enable_pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_IP2326_CHG_EN, GPIO_OWNER_GPIO);
|
|
||||||
check(ip2326_charge_enable_pin);
|
|
||||||
|
|
||||||
gpio_descriptor_set_flags(c6_wlan_enable_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
|
||||||
gpio_descriptor_set_flags(usb_a_5v_enable_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
|
||||||
gpio_descriptor_set_flags(device_power_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
|
||||||
gpio_descriptor_set_flags(ip2326_ncharge_qc_enable_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
|
||||||
gpio_descriptor_set_flags(ip2326_charge_state_led_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
|
||||||
gpio_descriptor_set_flags(ip2326_charge_enable_pin, GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_PULL_UP);
|
|
||||||
|
|
||||||
gpio_descriptor_set_level(c6_wlan_enable_pin, true);
|
|
||||||
gpio_descriptor_set_level(usb_a_5v_enable_pin, true);
|
|
||||||
gpio_descriptor_set_level(device_power_pin, false);
|
|
||||||
gpio_descriptor_set_level(ip2326_ncharge_qc_enable_pin, false);
|
|
||||||
gpio_descriptor_set_level(ip2326_charge_state_led_pin, false);
|
|
||||||
|
|
||||||
gpio_descriptor_release(c6_wlan_enable_pin);
|
|
||||||
gpio_descriptor_release(usb_a_5v_enable_pin);
|
|
||||||
gpio_descriptor_release(device_power_pin);
|
|
||||||
gpio_descriptor_release(ip2326_ncharge_qc_enable_pin);
|
|
||||||
gpio_descriptor_release(ip2326_charge_state_led_pin);
|
|
||||||
gpio_descriptor_release(ip2326_charge_enable_pin);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Audio codec register programming is owned by the es8388-module/es7210-module drivers
|
|
||||||
// (registered as AUDIO_CODEC_TYPE devices, see m5stack,tab5.dts). This board still needs
|
|
||||||
// to drive the external speaker amplifier's enable line via io_expander0, which is board
|
|
||||||
// wiring glue rather than codec configuration, so it stays here.
|
|
||||||
static error_t enableSpeakerAmplifier(::Device* io_expander0) {
|
|
||||||
auto* speaker_enable_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_SPEAKER_ENABLE, GPIO_OWNER_GPIO);
|
|
||||||
check(speaker_enable_pin, "Failed to acquire speaker enable pin");
|
|
||||||
error_t error = gpio_descriptor_set_level(speaker_enable_pin, true);
|
|
||||||
gpio_descriptor_release(speaker_enable_pin);
|
|
||||||
if (error != ERROR_NONE) {
|
|
||||||
LOG_E(TAG, "Failed to enable amplifier: %s", error_to_string(error));
|
|
||||||
return ERROR_RESOURCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static esp_clock_output_mapping_handle_t camera_osc_handle = nullptr;
|
|
||||||
|
|
||||||
static void initCameraOsc() {
|
|
||||||
if (camera_osc_handle != nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 24 MHz clock on GPIO 36 for the SC2356 MIPI CSI sensor, required before esp_video_init.
|
|
||||||
// Uses SPLL (480 MHz) via esp_clock_output with divider 20 = 24 MHz exactly.
|
|
||||||
// This avoids any LEDC clock source conflict with the display backlight.
|
|
||||||
if (esp_clock_output_start(CLKOUT_SIG_SPLL, GPIO_NUM_36, &camera_osc_handle) != ESP_OK) {
|
|
||||||
LOG_E(TAG, "Camera OSC clock output start failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (esp_clock_output_set_divider(camera_osc_handle, 20) != ESP_OK) {
|
|
||||||
LOG_E(TAG, "Camera OSC clock divider set failed");
|
|
||||||
esp_clock_output_stop(camera_osc_handle);
|
|
||||||
camera_osc_handle = nullptr;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LOG_I(TAG, "Camera OSC 24MHz started on GPIO 36 (SPLL/20)");
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool initBoot() {
|
|
||||||
auto* io_expander0 = device_find_by_name("io_expander0");
|
|
||||||
check(io_expander0, "io_expander0 not found");
|
|
||||||
auto* io_expander1 = device_find_by_name("io_expander1");
|
|
||||||
check(io_expander1, "io_expander1 not found");
|
|
||||||
|
|
||||||
initCameraOsc();
|
|
||||||
initExpander0(io_expander0);
|
|
||||||
initExpander1(io_expander1);
|
|
||||||
|
|
||||||
error_t error = enableSpeakerAmplifier(io_expander0);
|
|
||||||
if (error != ERROR_NONE) {
|
|
||||||
LOG_E(TAG, "Failed to enable speaker amplifier");
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern const Configuration hardwareConfiguration = {
|
|
||||||
.initBoot = initBoot,
|
|
||||||
.createDevices = createDevices
|
|
||||||
};
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
#include "Detect.h"
|
|
||||||
|
|
||||||
#include <tactility/device.h>
|
|
||||||
#include <tactility/drivers/i2c_controller.h>
|
|
||||||
#include <tactility/log.h>
|
|
||||||
#include <esp_lcd_touch_gt911.h>
|
|
||||||
#include <esp_lcd_touch_st7123.h>
|
|
||||||
#include <freertos/FreeRTOS.h>
|
|
||||||
#include <freertos/task.h>
|
|
||||||
|
|
||||||
constexpr auto* TAG = "Tab5Detect";
|
|
||||||
|
|
||||||
Tab5Variant detectVariant() {
|
|
||||||
// Allow time for touch IC to fully boot after expander reset in initBoot().
|
|
||||||
// 100ms is enough for I2C ACK (probe) but cold power-on needs ~300ms before
|
|
||||||
// register reads (read_fw_info) succeed reliably.
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(300));
|
|
||||||
|
|
||||||
auto* i2c0 = device_find_by_name("i2c0");
|
|
||||||
check(i2c0);
|
|
||||||
|
|
||||||
constexpr auto PROBE_TIMEOUT = pdMS_TO_TICKS(50);
|
|
||||||
|
|
||||||
for (int attempt = 0; attempt < 3; ++attempt) {
|
|
||||||
// GT911 address depends on INT pin state during reset:
|
|
||||||
// GPIO 23 has a pull-up resistor to 3V3, so INT is high at reset → GT911 uses 0x5D (primary)
|
|
||||||
// It may also appear at 0x14 (backup) if the pin happened to be driven low
|
|
||||||
if (i2c_controller_has_device_at_address(i2c0, ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS, PROBE_TIMEOUT) == ERROR_NONE ||
|
|
||||||
i2c_controller_has_device_at_address(i2c0, ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP, PROBE_TIMEOUT) == ERROR_NONE) {
|
|
||||||
LOG_I(TAG, "Detected GT911 touch — using ILI9881C display");
|
|
||||||
return Tab5Variant::Ili9881c_Gt911;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Probe for ST7123 touch (new variant)
|
|
||||||
if (i2c_controller_has_device_at_address(i2c0, ESP_LCD_TOUCH_IO_I2C_ST7123_ADDRESS, PROBE_TIMEOUT) == ERROR_NONE) {
|
|
||||||
LOG_I(TAG, "Detected ST7123 touch — using ST7123 display");
|
|
||||||
return Tab5Variant::St7123;
|
|
||||||
}
|
|
||||||
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(100));
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_W(TAG, "No known touch controller detected, defaulting to ST7123");
|
|
||||||
return Tab5Variant::St7123;
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
enum class Tab5Variant {
|
|
||||||
Ili9881c_Gt911, // Older variant
|
|
||||||
St7123, // Newer variant (default)
|
|
||||||
};
|
|
||||||
|
|
||||||
[[nodiscard]] Tab5Variant detectVariant();
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
#include "Detect.h"
|
|
||||||
#include "Display.h"
|
|
||||||
#include "Ili9881cDisplay.h"
|
|
||||||
#include "St7123Display.h"
|
|
||||||
#include "St7123Touch.h"
|
|
||||||
|
|
||||||
#include <Gt911Touch.h>
|
|
||||||
#include <PwmBacklight.h>
|
|
||||||
#include <Tactility/hal/gpio/Gpio.h>
|
|
||||||
#include <tactility/check.h>
|
|
||||||
#include <tactility/device.h>
|
|
||||||
#include <tactility/log.h>
|
|
||||||
#include <freertos/FreeRTOS.h>
|
|
||||||
#include <freertos/task.h>
|
|
||||||
|
|
||||||
constexpr auto* TAG = "Tab5Display";
|
|
||||||
|
|
||||||
// LCD reset is wired to the PI4IOE5V6408 IO expander (io_expander0, bit 4), pulsed in
|
|
||||||
// Configuration.cpp's initExpander0() before display creation - not a direct SoC GPIO.
|
|
||||||
constexpr auto LCD_PIN_RESET = GPIO_NUM_NC;
|
|
||||||
constexpr auto LCD_PIN_BACKLIGHT = GPIO_NUM_22;
|
|
||||||
|
|
||||||
static std::shared_ptr<tt::hal::touch::TouchDevice> createGt911Touch() {
|
|
||||||
auto* i2c = device_find_by_name("i2c0");
|
|
||||||
check(i2c);
|
|
||||||
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
|
||||||
i2c,
|
|
||||||
720,
|
|
||||||
1280,
|
|
||||||
false, // swapXY
|
|
||||||
false, // mirrorX
|
|
||||||
false, // mirrorY
|
|
||||||
GPIO_NUM_NC, // reset pin
|
|
||||||
GPIO_NUM_NC // "GPIO_NUM_23 cannot be used due to resistor to 3V3"
|
|
||||||
// https://github.com/espressif/esp-bsp/blob/ad668c765cbad177495a122181df0a70ff9f8f61/bsp/m5stack_tab5/src/m5stack_tab5.c#L76234
|
|
||||||
);
|
|
||||||
return std::make_shared<Gt911Touch>(std::move(configuration));
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::shared_ptr<tt::hal::touch::TouchDevice> createSt7123Touch() {
|
|
||||||
auto* i2c = device_find_by_name("i2c0");
|
|
||||||
check(i2c, "i2c0 not found");
|
|
||||||
auto configuration = std::make_unique<St7123Touch::Configuration>(
|
|
||||||
i2c,
|
|
||||||
720,
|
|
||||||
1280,
|
|
||||||
false, // swapXY
|
|
||||||
false, // mirrorX
|
|
||||||
false, // mirrorY
|
|
||||||
GPIO_NUM_23 // interrupt pin
|
|
||||||
);
|
|
||||||
return std::make_shared<St7123Touch>(std::move(configuration));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
|
|
||||||
// Initialize PWM backlight
|
|
||||||
if (!driver::pwmbacklight::init(LCD_PIN_BACKLIGHT, 5000, LEDC_TIMER_1, LEDC_CHANNEL_0)) {
|
|
||||||
LOG_W(TAG, "Failed to initialize backlight");
|
|
||||||
}
|
|
||||||
|
|
||||||
Tab5Variant variant = detectVariant();
|
|
||||||
|
|
||||||
std::shared_ptr<tt::hal::touch::TouchDevice> touch;
|
|
||||||
|
|
||||||
if (variant == Tab5Variant::St7123) {
|
|
||||||
touch = createSt7123Touch();
|
|
||||||
} else {
|
|
||||||
touch = createGt911Touch();
|
|
||||||
|
|
||||||
// Work-around to init GT911 touch: interrupt pin must be set to low
|
|
||||||
// Note: There is a resistor to 3V3 on interrupt pin which is blocking GT911 touch
|
|
||||||
// See https://github.com/espressif/esp-bsp/blob/ad668c765cbad177495a122181df0a70ff9f8f61/bsp/m5stack_tab5/src/m5stack_tab5.c#L777
|
|
||||||
tt::hal::gpio::configure(23, tt::hal::gpio::Mode::Output, true, false);
|
|
||||||
tt::hal::gpio::setLevel(23, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto configuration = std::make_shared<EspLcdConfiguration>(EspLcdConfiguration {
|
|
||||||
.horizontalResolution = 720,
|
|
||||||
.verticalResolution = 1280,
|
|
||||||
.gapX = 0,
|
|
||||||
.gapY = 0,
|
|
||||||
.monochrome = false,
|
|
||||||
.swapXY = false,
|
|
||||||
.mirrorX = false,
|
|
||||||
.mirrorY = false,
|
|
||||||
.invertColor = false,
|
|
||||||
.bufferSize = 0, // 0 = default (1/10 of screen)
|
|
||||||
.swRotate = true,
|
|
||||||
.buffSpiram = true,
|
|
||||||
.touch = touch,
|
|
||||||
.backlightDutyFunction = driver::pwmbacklight::setBacklightDuty,
|
|
||||||
.resetPin = LCD_PIN_RESET,
|
|
||||||
.lvglColorFormat = LV_COLOR_FORMAT_RGB565,
|
|
||||||
.lvglSwapBytes = false,
|
|
||||||
.rgbElementOrder = LCD_RGB_ELEMENT_ORDER_RGB,
|
|
||||||
.bitsPerPixel = 16
|
|
||||||
});
|
|
||||||
|
|
||||||
if (variant == Tab5Variant::St7123) {
|
|
||||||
return std::static_pointer_cast<tt::hal::display::DisplayDevice>(
|
|
||||||
std::make_shared<St7123Display>(configuration)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return std::static_pointer_cast<tt::hal::display::DisplayDevice>(
|
|
||||||
std::make_shared<Ili9881cDisplay>(configuration)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
#include "Ili9881cDisplay.h"
|
|
||||||
#include "ili9881_init_data.h"
|
|
||||||
|
|
||||||
#include <esp_lcd_ili9881c.h>
|
|
||||||
#include <tactility/log.h>
|
|
||||||
|
|
||||||
constexpr auto* TAG = "ILI9881C";
|
|
||||||
|
|
||||||
Ili9881cDisplay::~Ili9881cDisplay() {
|
|
||||||
// TODO: This should happen during ::stop(), but this isn't currently exposed
|
|
||||||
if (mipiDsiBus != nullptr) {
|
|
||||||
esp_lcd_del_dsi_bus(mipiDsiBus);
|
|
||||||
mipiDsiBus = nullptr;
|
|
||||||
}
|
|
||||||
if (ldoChannel != nullptr) {
|
|
||||||
esp_ldo_release_channel(ldoChannel);
|
|
||||||
ldoChannel = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Ili9881cDisplay::createMipiDsiBus() {
|
|
||||||
esp_ldo_channel_config_t ldo_mipi_phy_config = {
|
|
||||||
.chan_id = 3,
|
|
||||||
.voltage_mv = 2500,
|
|
||||||
.flags = {
|
|
||||||
.adjustable = 0,
|
|
||||||
.owned_by_hw = 0,
|
|
||||||
.bypass = 0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldoChannel) != ESP_OK) {
|
|
||||||
LOG_E(TAG, "Failed to acquire LDO channel for MIPI DSI PHY");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_I(TAG, "Powered on");
|
|
||||||
|
|
||||||
// Create bus
|
|
||||||
// TODO: use MIPI_DSI_PHY_CLK_SRC_DEFAULT() in future ESP-IDF 6.0.0 update with esp_lcd_jd9165 library version 2.x
|
|
||||||
const esp_lcd_dsi_bus_config_t bus_config = {
|
|
||||||
.bus_id = 0,
|
|
||||||
.num_data_lanes = 2,
|
|
||||||
.phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT,
|
|
||||||
.lane_bit_rate_mbps = 1000
|
|
||||||
};
|
|
||||||
|
|
||||||
if (esp_lcd_new_dsi_bus(&bus_config, &mipiDsiBus) != ESP_OK) {
|
|
||||||
LOG_E(TAG, "Failed to create bus");
|
|
||||||
esp_ldo_release_channel(ldoChannel);
|
|
||||||
ldoChannel = nullptr;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_I(TAG, "Bus created");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Ili9881cDisplay::createIoHandle(esp_lcd_panel_io_handle_t& ioHandle) {
|
|
||||||
// Initialize MIPI DSI bus if not already done
|
|
||||||
if (mipiDsiBus == nullptr) {
|
|
||||||
if (!createMipiDsiBus()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use DBI interface to send LCD commands and parameters
|
|
||||||
esp_lcd_dbi_io_config_t dbi_config = ILI9881C_PANEL_IO_DBI_CONFIG();
|
|
||||||
|
|
||||||
if (esp_lcd_new_panel_io_dbi(mipiDsiBus, &dbi_config, &ioHandle) != ESP_OK) {
|
|
||||||
LOG_E(TAG, "Failed to create panel IO");
|
|
||||||
esp_lcd_del_dsi_bus(mipiDsiBus);
|
|
||||||
mipiDsiBus = nullptr;
|
|
||||||
esp_ldo_release_channel(ldoChannel);
|
|
||||||
ldoChannel = nullptr;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_lcd_panel_dev_config_t Ili9881cDisplay::createPanelConfig(std::shared_ptr<EspLcdConfiguration> espLcdConfiguration, gpio_num_t resetPin) {
|
|
||||||
return {
|
|
||||||
.reset_gpio_num = resetPin,
|
|
||||||
.rgb_ele_order = espLcdConfiguration->rgbElementOrder,
|
|
||||||
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
|
|
||||||
.bits_per_pixel = static_cast<uint8_t>(espLcdConfiguration->bitsPerPixel),
|
|
||||||
.flags = {
|
|
||||||
.reset_active_high = 0
|
|
||||||
},
|
|
||||||
.vendor_config = nullptr // Will be set in createPanelHandle
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Ili9881cDisplay::createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_panel_dev_config_t& panelConfig, esp_lcd_panel_handle_t& panelHandle) {
|
|
||||||
// Based on BSP: https://github.com/espressif/esp-bsp/blob/master/bsp/m5stack_tab5/README.md
|
|
||||||
// TODO: undo static
|
|
||||||
esp_lcd_dpi_panel_config_t dpi_config = {
|
|
||||||
.virtual_channel = 0,
|
|
||||||
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
|
|
||||||
.dpi_clock_freq_mhz = 60,
|
|
||||||
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
|
|
||||||
.in_color_format = LCD_COLOR_FMT_RGB565,
|
|
||||||
.out_color_format = LCD_COLOR_FMT_RGB565,
|
|
||||||
.num_fbs = 2,
|
|
||||||
.video_timing =
|
|
||||||
{
|
|
||||||
.h_size = 720,
|
|
||||||
.v_size = 1280,
|
|
||||||
.hsync_pulse_width = 40,
|
|
||||||
.hsync_back_porch = 140,
|
|
||||||
.hsync_front_porch = 40,
|
|
||||||
.vsync_pulse_width = 4,
|
|
||||||
.vsync_back_porch = 20,
|
|
||||||
.vsync_front_porch = 20,
|
|
||||||
},
|
|
||||||
.flags = {
|
|
||||||
.use_dma2d = 1, // TODO: true?
|
|
||||||
.disable_lp = 0,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ili9881c_vendor_config_t vendor_config = {
|
|
||||||
.init_cmds = ili9881_init_data,
|
|
||||||
.init_cmds_size = std::size(ili9881_init_data),
|
|
||||||
.mipi_config = {
|
|
||||||
.dsi_bus = mipiDsiBus,
|
|
||||||
.dpi_config = &dpi_config,
|
|
||||||
.lane_num = 2,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create a mutable copy of panelConfig to set vendor_config
|
|
||||||
esp_lcd_panel_dev_config_t mutable_panel_config = panelConfig;
|
|
||||||
mutable_panel_config.vendor_config = &vendor_config;
|
|
||||||
|
|
||||||
if (esp_lcd_new_panel_ili9881c(ioHandle, &mutable_panel_config, &panelHandle) != ESP_OK) {
|
|
||||||
LOG_E(TAG, "Failed to create panel");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_I(TAG, "Panel created successfully");
|
|
||||||
// Defer reset/init to base class applyConfiguration to avoid double initialization
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
lvgl_port_display_dsi_cfg_t Ili9881cDisplay::getLvglPortDisplayDsiConfig(esp_lcd_panel_io_handle_t /*ioHandle*/, esp_lcd_panel_handle_t /*panelHandle*/) {
|
|
||||||
// Disable avoid_tearing to prevent stalls/blank flashes when other tasks (e.g. flash writes) block timing
|
|
||||||
return lvgl_port_display_dsi_cfg_t{
|
|
||||||
.flags = {
|
|
||||||
.avoid_tearing = 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <EspLcdDisplayV2.h>
|
|
||||||
|
|
||||||
#include <esp_lcd_mipi_dsi.h>
|
|
||||||
#include <esp_ldo_regulator.h>
|
|
||||||
|
|
||||||
class Ili9881cDisplay final : public EspLcdDisplayV2 {
|
|
||||||
|
|
||||||
esp_lcd_dsi_bus_handle_t mipiDsiBus = nullptr;
|
|
||||||
esp_ldo_channel_handle_t ldoChannel = nullptr;
|
|
||||||
|
|
||||||
bool createMipiDsiBus();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
bool createIoHandle(esp_lcd_panel_io_handle_t& ioHandle) override;
|
|
||||||
|
|
||||||
esp_lcd_panel_dev_config_t createPanelConfig(std::shared_ptr<EspLcdConfiguration> espLcdConfiguration, gpio_num_t resetPin) override;
|
|
||||||
|
|
||||||
bool createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_panel_dev_config_t& panelConfig, esp_lcd_panel_handle_t& panelHandle) override;
|
|
||||||
|
|
||||||
bool useDsiPanel() const override { return true; }
|
|
||||||
|
|
||||||
lvgl_port_display_dsi_cfg_t getLvglPortDisplayDsiConfig(esp_lcd_panel_io_handle_t /*ioHandle*/, esp_lcd_panel_handle_t /*panelHandle*/) override;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Ili9881cDisplay(
|
|
||||||
const std::shared_ptr<EspLcdConfiguration>& configuration
|
|
||||||
) : EspLcdDisplayV2(configuration) {}
|
|
||||||
|
|
||||||
~Ili9881cDisplay() override;
|
|
||||||
|
|
||||||
std::string getName() const override { return "ILI9881C"; }
|
|
||||||
|
|
||||||
std::string getDescription() const override { return "ILI9881C MIPI-DSI display"; }
|
|
||||||
};
|
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
#include "Power.h"
|
|
||||||
|
|
||||||
#include <Tactility/hal/power/PowerDevice.h>
|
|
||||||
#include <drivers/ina226.h>
|
|
||||||
#include <tactility/device.h>
|
|
||||||
#include <tactility/drivers/gpio_controller.h>
|
|
||||||
#include <tactility/log.h>
|
|
||||||
#include <freertos/FreeRTOS.h>
|
|
||||||
#include <freertos/task.h>
|
|
||||||
|
|
||||||
using namespace tt::hal::power;
|
|
||||||
|
|
||||||
static constexpr auto* TAG = "Tab5Power";
|
|
||||||
|
|
||||||
// NP-F550 is a 2S Li-ion pack; INA226 measures the pack voltage on BAT_IN
|
|
||||||
// before the DC-DC converter. Per-cell range 3.2-4.2V → pack range 6.4-8.4V.
|
|
||||||
static constexpr float MIN_BATTERY_VOLTAGE_MV = 6400.0f;
|
|
||||||
static constexpr float MAX_BATTERY_VOLTAGE_MV = 8400.0f;
|
|
||||||
|
|
||||||
// INA226 convention: negative raw current = charging, positive = discharging.
|
|
||||||
// After negation in getMetric(Current), >50mA means charging into the battery.
|
|
||||||
static constexpr float CHARGING_CURRENT_THRESHOLD_AMPS = 0.05f;
|
|
||||||
|
|
||||||
// GPIO expander 1 (0x44) pin 4: PWROFF_PULSE
|
|
||||||
static constexpr int GPIO_EXP1_PIN_DEVICE_POWER = 4;
|
|
||||||
// GPIO expander 1 (0x44) pin 5: IP2326 nCHG_QC_EN (active-low: LOW = QC enabled)
|
|
||||||
static constexpr int GPIO_EXP1_PIN_IP2326_NCHG_QC_EN = 5;
|
|
||||||
// GPIO expander 1 (0x44) pin 7: IP2326 CHG_EN (HIGH = charging enabled, LOW = disabled)
|
|
||||||
static constexpr int GPIO_EXP1_PIN_IP2326_CHG_EN = 7;
|
|
||||||
|
|
||||||
class Tab5Power final : public PowerDevice {
|
|
||||||
public:
|
|
||||||
Tab5Power(::Device* ina226Device, ::Device* ioExpander1Device)
|
|
||||||
: ina226(ina226Device), ioExpander1(ioExpander1Device) {
|
|
||||||
// Initialize CHG_EN as output HIGH (charging enabled at startup).
|
|
||||||
setAllowedToCharge(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getName() const override { return "M5Stack Tab5 Power"; }
|
|
||||||
std::string getDescription() const override { return "Battery monitoring via INA226 over I2C"; }
|
|
||||||
|
|
||||||
bool supportsMetric(MetricType type) const override {
|
|
||||||
switch (type) {
|
|
||||||
using enum MetricType;
|
|
||||||
case BatteryVoltage:
|
|
||||||
case ChargeLevel:
|
|
||||||
case Current:
|
|
||||||
case IsCharging:
|
|
||||||
return ina226 != nullptr;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getMetric(MetricType type, MetricData& data) override {
|
|
||||||
switch (type) {
|
|
||||||
using enum MetricType;
|
|
||||||
|
|
||||||
case BatteryVoltage: {
|
|
||||||
if (ina226 == nullptr) return false;
|
|
||||||
float volts = 0.0f;
|
|
||||||
if (ina226_read_bus_voltage(ina226, &volts) != ERROR_NONE) return false;
|
|
||||||
data.valueAsUint32 = static_cast<uint32_t>(volts * 1000.0f);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ChargeLevel: {
|
|
||||||
if (ina226 == nullptr) return false;
|
|
||||||
float volts = 0.0f;
|
|
||||||
if (ina226_read_bus_voltage(ina226, &volts) != ERROR_NONE) return false;
|
|
||||||
float voltage_mv = volts * 1000.0f;
|
|
||||||
if (voltage_mv >= MAX_BATTERY_VOLTAGE_MV) {
|
|
||||||
data.valueAsUint8 = 100;
|
|
||||||
} else if (voltage_mv <= MIN_BATTERY_VOLTAGE_MV) {
|
|
||||||
data.valueAsUint8 = 0;
|
|
||||||
} else {
|
|
||||||
float factor = (voltage_mv - MIN_BATTERY_VOLTAGE_MV) / (MAX_BATTERY_VOLTAGE_MV - MIN_BATTERY_VOLTAGE_MV);
|
|
||||||
data.valueAsUint8 = static_cast<uint8_t>(factor * 100.0f);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Current: {
|
|
||||||
if (ina226 == nullptr) return false;
|
|
||||||
float amps = 0.0f;
|
|
||||||
if (ina226_read_shunt_current(ina226, &s) != ERROR_NONE) return false;
|
|
||||||
// INA226 convention: negative = charging, positive = discharging.
|
|
||||||
// Negate so the HAL value is positive when charging, negative when discharging.
|
|
||||||
data.valueAsInt32 = static_cast<int32_t>(-amps * 1000.0f);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case IsCharging: {
|
|
||||||
if (ina226 == nullptr) return false;
|
|
||||||
float amps = 0.0f;
|
|
||||||
if (ina226_read_shunt_current(ina226, &s) != ERROR_NONE) return false;
|
|
||||||
// Raw INA226: negative = charging. Threshold in raw terms = -0.05A.
|
|
||||||
data.valueAsBool = amps < -CHARGING_CURRENT_THRESHOLD_AMPS;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool supportsChargeControl() const override { return ioExpander1 != nullptr; }
|
|
||||||
|
|
||||||
bool isAllowedToCharge() const override { return chargingAllowed; }
|
|
||||||
|
|
||||||
void setAllowedToCharge(bool allowed) override {
|
|
||||||
if (ioExpander1 == nullptr) return;
|
|
||||||
auto* pin = gpio_descriptor_acquire(ioExpander1, GPIO_EXP1_PIN_IP2326_CHG_EN, GPIO_OWNER_GPIO);
|
|
||||||
if (pin == nullptr) {
|
|
||||||
LOG_W(TAG, "Failed to acquire CHG_EN pin");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (gpio_descriptor_set_flags(pin, GPIO_FLAG_DIRECTION_OUTPUT) != ERROR_NONE) {
|
|
||||||
LOG_W(TAG, "Failed to set CHG_EN pin direction");
|
|
||||||
gpio_descriptor_release(pin);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (gpio_descriptor_set_level(pin, allowed) != ERROR_NONE) {
|
|
||||||
LOG_W(TAG, "Failed to set CHG_EN pin level");
|
|
||||||
gpio_descriptor_release(pin);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
gpio_descriptor_release(pin);
|
|
||||||
chargingAllowed = allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool supportsQuickCharge() const override { return ioExpander1 != nullptr; }
|
|
||||||
|
|
||||||
bool isQuickChargeEnabled() const override { return quickChargeEnabled; }
|
|
||||||
|
|
||||||
void setQuickChargeEnabled(bool enabled) override {
|
|
||||||
if (ioExpander1 == nullptr) return;
|
|
||||||
auto* pin = gpio_descriptor_acquire(ioExpander1, GPIO_EXP1_PIN_IP2326_NCHG_QC_EN, GPIO_OWNER_GPIO);
|
|
||||||
if (pin == nullptr) {
|
|
||||||
LOG_W(TAG, "Failed to acquire nCHG_QC_EN pin");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (gpio_descriptor_set_flags(pin, GPIO_FLAG_DIRECTION_OUTPUT) != ERROR_NONE) {
|
|
||||||
LOG_W(TAG, "Failed to set nCHG_QC_EN pin direction");
|
|
||||||
gpio_descriptor_release(pin);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (gpio_descriptor_set_level(pin, !enabled) != ERROR_NONE) {
|
|
||||||
LOG_W(TAG, "Failed to set nCHG_QC_EN pin level");
|
|
||||||
gpio_descriptor_release(pin);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
gpio_descriptor_release(pin);
|
|
||||||
quickChargeEnabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool supportsPowerOff() const override { return ioExpander1 != nullptr; }
|
|
||||||
|
|
||||||
void powerOff() override {
|
|
||||||
if (ioExpander1 == nullptr) return;
|
|
||||||
auto* pin = gpio_descriptor_acquire(ioExpander1, GPIO_EXP1_PIN_DEVICE_POWER, GPIO_OWNER_GPIO);
|
|
||||||
if (pin == nullptr) {
|
|
||||||
LOG_E(TAG, "Failed to acquire DEVICE_POWER pin");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < 3; i++) {
|
|
||||||
gpio_descriptor_set_level(pin, true);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(100));
|
|
||||||
gpio_descriptor_set_level(pin, false);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(100));
|
|
||||||
}
|
|
||||||
gpio_descriptor_release(pin);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
::Device* ina226;
|
|
||||||
::Device* ioExpander1;
|
|
||||||
bool chargingAllowed = true;
|
|
||||||
bool quickChargeEnabled = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::shared_ptr<PowerDevice> createPower() {
|
|
||||||
auto* ina226 = device_find_by_name("ina226");
|
|
||||||
if (ina226 == nullptr) {
|
|
||||||
LOG_E(TAG, "ina226 device not found");
|
|
||||||
}
|
|
||||||
auto* io_expander1 = device_find_by_name("io_expander1");
|
|
||||||
if (io_expander1 == nullptr) {
|
|
||||||
LOG_E(TAG, "io_expander1 not found");
|
|
||||||
}
|
|
||||||
return std::make_shared<Tab5Power>(ina226, io_expander1);
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <Tactility/hal/power/PowerDevice.h>
|
|
||||||
|
|
||||||
std::shared_ptr<tt::hal::power::PowerDevice> createPower();
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
#include "St7123Display.h"
|
|
||||||
#include "st7123_init_data.h"
|
|
||||||
|
|
||||||
#include <esp_lcd_st7123.h>
|
|
||||||
#include <tactility/log.h>
|
|
||||||
|
|
||||||
constexpr auto* TAG = "St7123";
|
|
||||||
|
|
||||||
St7123Display::~St7123Display() {
|
|
||||||
// TODO: This should happen during ::stop(), but this isn't currently exposed
|
|
||||||
if (mipiDsiBus != nullptr) {
|
|
||||||
esp_lcd_del_dsi_bus(mipiDsiBus);
|
|
||||||
mipiDsiBus = nullptr;
|
|
||||||
}
|
|
||||||
if (ldoChannel != nullptr) {
|
|
||||||
esp_ldo_release_channel(ldoChannel);
|
|
||||||
ldoChannel = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool St7123Display::createMipiDsiBus() {
|
|
||||||
esp_ldo_channel_config_t ldo_mipi_phy_config = {
|
|
||||||
.chan_id = 3,
|
|
||||||
.voltage_mv = 2500,
|
|
||||||
.flags = {
|
|
||||||
.adjustable = 0,
|
|
||||||
.owned_by_hw = 0,
|
|
||||||
.bypass = 0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldoChannel) != ESP_OK) {
|
|
||||||
LOG_E(TAG, "Failed to acquire LDO channel for MIPI DSI PHY");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_I(TAG, "Powered on");
|
|
||||||
|
|
||||||
const esp_lcd_dsi_bus_config_t bus_config = {
|
|
||||||
.bus_id = 0,
|
|
||||||
.num_data_lanes = 2,
|
|
||||||
.phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT,
|
|
||||||
.lane_bit_rate_mbps = 965 // ST7123 lane bitrate per M5Stack BSP
|
|
||||||
};
|
|
||||||
|
|
||||||
if (esp_lcd_new_dsi_bus(&bus_config, &mipiDsiBus) != ESP_OK) {
|
|
||||||
LOG_E(TAG, "Failed to create bus");
|
|
||||||
esp_ldo_release_channel(ldoChannel);
|
|
||||||
ldoChannel = nullptr;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_I(TAG, "Bus created");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool St7123Display::createIoHandle(esp_lcd_panel_io_handle_t& ioHandle) {
|
|
||||||
if (mipiDsiBus == nullptr) {
|
|
||||||
if (!createMipiDsiBus()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DBI interface for LCD commands/parameters (8-bit cmd/param per ST7123 spec)
|
|
||||||
esp_lcd_dbi_io_config_t dbi_config = {
|
|
||||||
.virtual_channel = 0,
|
|
||||||
.lcd_cmd_bits = 8,
|
|
||||||
.lcd_param_bits = 8,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (esp_lcd_new_panel_io_dbi(mipiDsiBus, &dbi_config, &ioHandle) != ESP_OK) {
|
|
||||||
LOG_E(TAG, "Failed to create panel IO");
|
|
||||||
esp_lcd_del_dsi_bus(mipiDsiBus);
|
|
||||||
mipiDsiBus = nullptr;
|
|
||||||
esp_ldo_release_channel(ldoChannel);
|
|
||||||
ldoChannel = nullptr;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_lcd_panel_dev_config_t St7123Display::createPanelConfig(std::shared_ptr<EspLcdConfiguration> espLcdConfiguration, gpio_num_t resetPin) {
|
|
||||||
return {
|
|
||||||
.reset_gpio_num = resetPin,
|
|
||||||
.rgb_ele_order = espLcdConfiguration->rgbElementOrder,
|
|
||||||
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
|
|
||||||
.bits_per_pixel = 16,
|
|
||||||
.flags = {
|
|
||||||
.reset_active_high = 0
|
|
||||||
},
|
|
||||||
.vendor_config = nullptr
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool St7123Display::createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_panel_dev_config_t& panelConfig, esp_lcd_panel_handle_t& panelHandle) {
|
|
||||||
esp_lcd_dpi_panel_config_t dpi_config = {
|
|
||||||
.virtual_channel = 0,
|
|
||||||
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
|
|
||||||
.dpi_clock_freq_mhz = 70,
|
|
||||||
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
|
|
||||||
.num_fbs = 2,
|
|
||||||
.video_timing = {
|
|
||||||
.h_size = 720,
|
|
||||||
.v_size = 1280,
|
|
||||||
.hsync_pulse_width = 2,
|
|
||||||
.hsync_back_porch = 40,
|
|
||||||
.hsync_front_porch = 40,
|
|
||||||
.vsync_pulse_width = 2,
|
|
||||||
.vsync_back_porch = 8,
|
|
||||||
.vsync_front_porch = 220,
|
|
||||||
},
|
|
||||||
.flags = {
|
|
||||||
.use_dma2d = 1,
|
|
||||||
.disable_lp = 0,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
st7123_vendor_config_t vendor_config = {
|
|
||||||
.init_cmds = st7123_init_data,
|
|
||||||
.init_cmds_size = std::size(st7123_init_data),
|
|
||||||
.mipi_config = {
|
|
||||||
.dsi_bus = mipiDsiBus,
|
|
||||||
.dpi_config = &dpi_config,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create a mutable copy of panelConfig to set vendor_config
|
|
||||||
esp_lcd_panel_dev_config_t mutable_panel_config = panelConfig;
|
|
||||||
mutable_panel_config.vendor_config = &vendor_config;
|
|
||||||
|
|
||||||
if (esp_lcd_new_panel_st7123(ioHandle, &mutable_panel_config, &panelHandle) != ESP_OK) {
|
|
||||||
LOG_E(TAG, "Failed to create panel");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_I(TAG, "Panel created successfully");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
lvgl_port_display_dsi_cfg_t St7123Display::getLvglPortDisplayDsiConfig(esp_lcd_panel_io_handle_t /*ioHandle*/, esp_lcd_panel_handle_t /*panelHandle*/) {
|
|
||||||
// Disable avoid_tearing to prevent stalls/blank flashes when other tasks (e.g. flash writes) block timing
|
|
||||||
return lvgl_port_display_dsi_cfg_t{
|
|
||||||
.flags = {
|
|
||||||
.avoid_tearing = 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <EspLcdDisplayV2.h>
|
|
||||||
|
|
||||||
#include <esp_lcd_mipi_dsi.h>
|
|
||||||
#include <esp_ldo_regulator.h>
|
|
||||||
|
|
||||||
class St7123Display final : public EspLcdDisplayV2 {
|
|
||||||
|
|
||||||
esp_lcd_dsi_bus_handle_t mipiDsiBus = nullptr;
|
|
||||||
esp_ldo_channel_handle_t ldoChannel = nullptr;
|
|
||||||
|
|
||||||
bool createMipiDsiBus();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
bool createIoHandle(esp_lcd_panel_io_handle_t& ioHandle) override;
|
|
||||||
|
|
||||||
esp_lcd_panel_dev_config_t createPanelConfig(std::shared_ptr<EspLcdConfiguration> espLcdConfiguration, gpio_num_t resetPin) override;
|
|
||||||
|
|
||||||
bool createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_panel_dev_config_t& panelConfig, esp_lcd_panel_handle_t& panelHandle) override;
|
|
||||||
|
|
||||||
bool useDsiPanel() const override { return true; }
|
|
||||||
|
|
||||||
lvgl_port_display_dsi_cfg_t getLvglPortDisplayDsiConfig(esp_lcd_panel_io_handle_t /*ioHandle*/, esp_lcd_panel_handle_t /*panelHandle*/) override;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
St7123Display(
|
|
||||||
const std::shared_ptr<EspLcdConfiguration>& configuration
|
|
||||||
) : EspLcdDisplayV2(configuration) {}
|
|
||||||
|
|
||||||
~St7123Display() override;
|
|
||||||
|
|
||||||
std::string getName() const override { return "St7123"; }
|
|
||||||
|
|
||||||
std::string getDescription() const override { return "St7123 MIPI-DSI display"; }
|
|
||||||
};
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
#include "St7123Touch.h"
|
|
||||||
|
|
||||||
#include <tactility/drivers/esp32_i2c_master.h>
|
|
||||||
#include <tactility/log.h>
|
|
||||||
#include <esp_lcd_touch_st7123.h>
|
|
||||||
#include <esp_err.h>
|
|
||||||
|
|
||||||
constexpr auto* TAG = "ST7123Touch";
|
|
||||||
|
|
||||||
bool St7123Touch::createIoHandle(esp_lcd_panel_io_handle_t& outHandle) {
|
|
||||||
esp_lcd_panel_io_i2c_config_t io_config = ESP_LCD_TOUCH_IO_I2C_ST7123_CONFIG();
|
|
||||||
io_config.scl_speed_hz = esp32_i2c_master_get_clock_frequency(configuration->controller);
|
|
||||||
i2c_master_bus_handle_t bus = esp32_i2c_master_get_bus_handle(configuration->controller);
|
|
||||||
return esp_lcd_new_panel_io_i2c_v2(bus, &io_config, &outHandle) == ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool St7123Touch::createTouchHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_touch_config_t& config, esp_lcd_touch_handle_t& touchHandle) {
|
|
||||||
return esp_lcd_touch_new_i2c_st7123(ioHandle, &config, &touchHandle) == ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_lcd_touch_config_t St7123Touch::createEspLcdTouchConfig() {
|
|
||||||
return {
|
|
||||||
.x_max = configuration->xMax,
|
|
||||||
.y_max = configuration->yMax,
|
|
||||||
.rst_gpio_num = GPIO_NUM_NC,
|
|
||||||
.int_gpio_num = configuration->pinInterrupt,
|
|
||||||
.levels = {
|
|
||||||
.reset = 0,
|
|
||||||
.interrupt = 0,
|
|
||||||
},
|
|
||||||
.flags = {
|
|
||||||
.swap_xy = configuration->swapXy,
|
|
||||||
.mirror_x = configuration->mirrorX,
|
|
||||||
.mirror_y = configuration->mirrorY,
|
|
||||||
},
|
|
||||||
.process_coordinates = nullptr,
|
|
||||||
.interrupt_callback = nullptr,
|
|
||||||
.user_data = nullptr,
|
|
||||||
.driver_data = nullptr
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user