From bb992c5b6c58b23b333616781ecd85d9fcbaadb3 Mon Sep 17 00:00:00 2001 From: luoweiyuan Date: Thu, 20 Aug 2026 14:00:24 +0800 Subject: [PATCH] Add M5Tab5X board support Tab5X upgrades the ESP32-P4 silicon revision used by Tab5. Tab5X EXT interface power is controllable. --- src/M5Unified.cpp | 21 ++++++++++++++++++--- src/M5Unified.hpp | 6 +++++- src/utility/Power_Class.cpp | 29 ++++++++++++++++++++++++++++- src/utility/Power_Class.hpp | 1 + src/utility/RTC_Class.cpp | 1 + 5 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/M5Unified.cpp b/src/M5Unified.cpp index eda7f43..05b10c9 100644 --- a/src/M5Unified.cpp +++ b/src/M5Unified.cpp @@ -449,6 +449,10 @@ static constexpr const uint8_t _pin_table_mbus[][31] = { void M5Unified::_setup_pinmap(board_t id) { + if (id == board_t::board_M5Tab5X) { + id = board_t::board_M5Tab5; + } + constexpr const std::pair tbl[] = { { _pin_table_i2c_ex_in, sizeof(_pin_table_i2c_ex_in[0]) }, { _pin_table_port_bc, sizeof(_pin_table_port_bc[0]) }, @@ -1892,8 +1896,14 @@ static constexpr const uint8_t _pin_table_mbus[][31] = { { m5gfx::pinMode(GPIO_NUM_32, m5gfx::pin_mode_t::input_pulldown); m5gfx::pinMode(GPIO_NUM_0, m5gfx::pin_mode_t::input_pulldown); - if (m5gfx::gpio_in(GPIO_NUM_32)) // M5Tab5 G32 always High - board = board_t::board_M5Tab5; + if (m5gfx::gpio_in(GPIO_NUM_32)) // M5Tab5 and M5Tab5X G32 always High + { + esp_chip_info_t chip_info; + esp_chip_info(&chip_info); + board = chip_info.revision >= 300 + ? board_t::board_M5Tab5X + : board_t::board_M5Tab5; + } else if(m5gfx::gpio_in(GPIO_NUM_0)) // M5UnitPoEP4 G0 always High board = board_t::board_M5UnitPoEP4; else @@ -1962,6 +1972,7 @@ static constexpr const uint8_t _pin_table_mbus[][31] = { switch (board) { #if defined (CONFIG_IDF_TARGET_ESP32P4) case board_t::board_M5Tab5: + case board_t::board_M5Tab5X: for (int i = 0; i < 2; ++i) { auto ioexp = new PI4IOE5V6408_Class(0x43 + i); @@ -2370,6 +2381,7 @@ static constexpr const uint8_t _pin_table_mbus[][31] = { #if defined (M5UNIFIED_PC_BUILD) #elif defined (CONFIG_IDF_TARGET_ESP32P4) case board_t::board_M5Tab5: + case board_t::board_M5Tab5X: if (cfg.internal_mic) { mic_cfg.pin_mck = GPIO_NUM_30; @@ -2576,6 +2588,7 @@ static constexpr const uint8_t _pin_table_mbus[][31] = { #elif defined (CONFIG_IDF_TARGET_ESP32P4) case board_t::board_M5Tab5: + case board_t::board_M5Tab5X: if (cfg.internal_spk) { spk_cfg.pin_mck = GPIO_NUM_30; @@ -2977,7 +2990,7 @@ static constexpr const uint8_t _pin_table_mbus[][31] = { #if defined (M5UNIFIED_PC_BUILD) #elif defined ( CONFIG_IDF_TARGET_ESP32P4 ) #define ENABLE_M5MODULE - if (_board == board_t::board_M5Tab5) + if (_board == board_t::board_M5Tab5 || _board == board_t::board_M5Tab5X) #elif defined ( CONFIG_IDF_TARGET_ESP32S3 ) #define ENABLE_M5MODULE if (_board == board_t::board_M5StackCoreS3 @@ -3162,6 +3175,7 @@ static constexpr const uint8_t _pin_table_mbus[][31] = { tb_k = 364; // (65536*3/540) break; case board_t::board_M5Tab5: + case board_t::board_M5Tab5X: tb_y = 1280; tb_k = 273; // (65536*3/540) break; @@ -3517,6 +3531,7 @@ static constexpr const uint8_t _pin_table_mbus[][31] = { height = 960; break; case board_t::board_M5Tab5: + case board_t::board_M5Tab5X: height = 1280; break; default: diff --git a/src/M5Unified.hpp b/src/M5Unified.hpp index 53ebda9..89ba77c 100644 --- a/src/M5Unified.hpp +++ b/src/M5Unified.hpp @@ -166,7 +166,11 @@ namespace m5 #elif defined (CONFIG_IDF_TARGET_ESP32C3) = board_t::board_M5StampC3; #elif defined (CONFIG_IDF_TARGET_ESP32P4) +#if defined (BOARD_ID) && BOARD_ID == 35 + = board_t::board_M5Tab5X; +#else = board_t::board_M5Tab5; +#endif #elif defined (CONFIG_IDF_TARGET_ESP32C5) = board_t::board_M5StampC5; #elif defined (CONFIG_IDF_TARGET_ESP32) || !defined (CONFIG_IDF_TARGET) @@ -406,7 +410,7 @@ namespace m5 #if defined ( __M5GFX_M5MODULEDISPLAY__ ) if (cfg.external_display.module_display) { #if defined (CONFIG_IDF_TARGET_ESP32P4) - if (_board == board_t::board_M5Tab5) + if (_board == board_t::board_M5Tab5 || _board == board_t::board_M5Tab5X) #elif defined (CONFIG_IDF_TARGET_ESP32S3) if (_board == board_t::board_M5StackCoreS3 || _board == board_t::board_M5StackCoreS3SE || _board == board_t::board_M5StackChan) diff --git a/src/utility/Power_Class.cpp b/src/utility/Power_Class.cpp index 13b6f67..cbbf986 100644 --- a/src/utility/Power_Class.cpp +++ b/src/utility/Power_Class.cpp @@ -119,6 +119,7 @@ namespace m5 break; case board_t::board_M5Tab5: + case board_t::board_M5Tab5X: { static constexpr std::uint8_t reg_array_0x43[] = { /// +--------- HP_DET : Headphone detect @@ -154,6 +155,13 @@ namespace m5 }; M5.getIOExpander(0).writeRegister8Array(reg_array_0x43, sizeof(reg_array_0x43)); M5.getIOExpander(1).writeRegister8Array(reg_array_0x44, sizeof(reg_array_0x44)); + if (M5.getBoard() == board_t::board_M5Tab5X) + { + auto& ioe = M5.getIOExpander(0); // PI4IOE 0x43, ADDR grounded, bottom Hat power + ioe.setHighImpedance(3, false); + ioe.setDirection(3, true); + ioe.digitalWrite(3, true); + } Ina226.begin(); INA226_Class::config_t cfg; cfg.sampling_rate = INA226_Class::Sampling::Rate16; @@ -893,12 +901,21 @@ namespace m5 { #if defined (CONFIG_IDF_TARGET_ESP32P4) case board_t::board_M5Tab5: + case board_t::board_M5Tab5X: if (port_mask & ext_port_mask_t::ext_PA) { auto& ioe = M5.getIOExpander(0); ioe.setPullMode(2, enable ? IOExpander_Base::pull_up : IOExpander_Base::pull_down); ioe.digitalWrite(2, enable); } + if (M5.getBoard() == board_t::board_M5Tab5X + && (port_mask & ext_port_mask_t::ext_EXT)) + { + auto& ioe = M5.getIOExpander(0); + ioe.setHighImpedance(3, false); + ioe.setDirection(3, true); + ioe.digitalWrite(3, enable); + } if (port_mask & ext_port_mask_t::ext_USB) { auto& ioe = M5.getIOExpander(1); @@ -1061,6 +1078,8 @@ namespace m5 #elif defined (CONFIG_IDF_TARGET_ESP32P4) case board_t::board_M5Tab5: return M5.getIOExpander(0).getWriteValue(2); + case board_t::board_M5Tab5X: + return M5.getIOExpander(0).getWriteValue(3); #elif defined (CONFIG_IDF_TARGET_ESP32C6) case board_t::board_ArduinoNessoN1: @@ -1442,6 +1461,7 @@ namespace m5 default: break; #if defined (CONFIG_IDF_TARGET_ESP32P4) case board_t::board_M5Tab5: + case board_t::board_M5Tab5X: for (int i = 0; i < 10; ++i) { M5.getIOExpander(1).digitalWrite(4, i & 1); // io1.gpio4 == PWROFF_PLUSE @@ -2148,6 +2168,7 @@ namespace m5 switch (M5.getBoard()) { #if defined (CONFIG_IDF_TARGET_ESP32P4) case board_t::board_M5Tab5: + case board_t::board_M5Tab5X: return Ina226.getBusVoltage() * 1000; #endif @@ -2232,6 +2253,7 @@ namespace m5 switch (M5.getBoard()) { #if defined (CONFIG_IDF_TARGET_ESP32P4) case board_t::board_M5Tab5: + case board_t::board_M5Tab5X: // 2S Li-Po ( * 1000 / 2 == * 500) mv = Ina226.getBusVoltage() * 500; break; @@ -2321,6 +2343,7 @@ namespace m5 switch (M5.getBoard()) { #if defined (CONFIG_IDF_TARGET_ESP32P4) case board_t::board_M5Tab5: + case board_t::board_M5Tab5X: M5.getIOExpander(1).digitalWrite(7, enable); break; #endif @@ -2398,7 +2421,8 @@ namespace m5 default: #if defined (CONFIG_IDF_TARGET_ESP32P4) switch (M5.getBoard()) { - case board_t::board_M5Tab5: { + case board_t::board_M5Tab5: + case board_t::board_M5Tab5X: { switch (max_mA) { case 0: // charge disable @@ -2474,6 +2498,7 @@ namespace m5 switch (M5.getBoard()) { #if defined (CONFIG_IDF_TARGET_ESP32P4) case board_t::board_M5Tab5: + case board_t::board_M5Tab5X: // The shunt is wired so that charge current reads negative; invert to // match the documented convention (+ = charge / - = discharge). return -1000.0f * Ina226.getShuntCurrent(); @@ -2523,6 +2548,7 @@ namespace m5 switch (M5.getBoard()) { #if defined (CONFIG_IDF_TARGET_ESP32P4) case board_t::board_M5Tab5: + case board_t::board_M5Tab5X: // TODO:implement #endif default: @@ -2638,6 +2664,7 @@ namespace m5 #endif #if defined (CONFIG_IDF_TARGET_ESP32P4) case board_t::board_M5Tab5: + case board_t::board_M5Tab5X: return M5.getIOExpander(1).digitalRead(6) // io1.gpio6 == CHG_STAT ? is_charging_t::is_charging : is_charging_t::is_discharging; #endif diff --git a/src/utility/Power_Class.hpp b/src/utility/Power_Class.hpp index 294294c..3249c9a 100644 --- a/src/utility/Power_Class.hpp +++ b/src/utility/Power_Class.hpp @@ -46,6 +46,7 @@ namespace m5 , ext_USB = 1 << 5 // M5Station external USB. ※ Not for CoreS3 main USB. , ext_PWR485 = 1 << 6 // M5PowerHub external RS485. , ext_PWRCAN = 1 << 7 // M5PowerHub external CAN. + , ext_EXT = 1 << 8 // M5Tab5X bottom Hat power. , ext_MAIN = 1 << 15 }; diff --git a/src/utility/RTC_Class.cpp b/src/utility/RTC_Class.cpp index e52694c..a50faf2 100644 --- a/src/utility/RTC_Class.cpp +++ b/src/utility/RTC_Class.cpp @@ -45,6 +45,7 @@ namespace m5 { #if defined (CONFIG_IDF_TARGET_ESP32P4) case board_t::board_M5Tab5: + case board_t::board_M5Tab5X: instance.reset(new RX8130_Class(RX8130_Class::DEFAULT_ADDRESS, 400000, i2c)); break; #endif