From 7ec5b828ae7cd6297f06e0554ac46a70b069fd82 Mon Sep 17 00:00:00 2001 From: ainyan03 <205502311+ainyan03@users.noreply.github.com> Date: Fri, 9 Oct 2026 05:26:23 +0000 Subject: [PATCH 1/3] Apply BOARD_ID before detector candidates on ESP32-P4 BOARD_ID 31 (CoreP4X) and 35 (Tab5X), set by board-specific firmware builds, now apply after cfg.fallback_board and before the detector's candidate. M5GFX reports a StampP4 candidate for any P4 board it cannot confirm, which would otherwise hide the build selection. --- src/M5Unified.hpp | 8 ++++++++ src/M5Unified.inl | 6 ------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/M5Unified.hpp b/src/M5Unified.hpp index b34241b..c90f4cd 100644 --- a/src/M5Unified.hpp +++ b/src/M5Unified.hpp @@ -364,6 +364,14 @@ namespace m5 if (!board_detected) { board = cfg.fallback_board; + // UIFlow selects board-specific firmware with BOARD_ID and M5GFX_BOARD. +#if defined (CONFIG_IDF_TARGET_ESP32P4) && defined (BOARD_ID) +#if BOARD_ID == 31 + if (board == board_t::board_unknown) { board = board_t::board_M5CoreP4X; } +#elif BOARD_ID == 35 + if (board == board_t::board_unknown) { board = board_t::board_M5Tab5X; } +#endif +#endif if (board == board_t::board_unknown) { board = Display.getBoardCandidate(); } if (board == board_t::board_unknown) { board = _check_boardtype(board); } if (board == board_t::board_unknown) { board = _default_fallback_board(); } diff --git a/src/M5Unified.inl b/src/M5Unified.inl index 5564845..501fbcf 100644 --- a/src/M5Unified.inl +++ b/src/M5Unified.inl @@ -1626,12 +1626,6 @@ static constexpr const uint8_t _pin_table_mbus[][31] = { #if defined (CONFIG_IDF_TARGET_ESP32P4) if (board == board_t::board_unknown) { - // Preserve legacy build-time selection before GPIO observations. -#if defined (BOARD_ID) && BOARD_ID == 31 - return board_t::board_M5CoreP4X; -#elif defined (BOARD_ID) && BOARD_ID == 35 - return board_t::board_M5Tab5X; -#endif // GPIO observations remain here until the P4 family moves into the detector. m5gfx::pinMode(GPIO_NUM_32, m5gfx::pin_mode_t::input_pulldown); m5gfx::pinMode(GPIO_NUM_0, m5gfx::pin_mode_t::input_pulldown); From 2329c2331c828bf0b1c23eb8973cf17e16ce8eb5 Mon Sep 17 00:00:00 2001 From: ainyan03 <205502311+ainyan03@users.noreply.github.com> Date: Fri, 9 Oct 2026 05:26:23 +0000 Subject: [PATCH 2/3] Use the board detector for ESP32-P4 boards Remove the P4 GPIO checks from _check_boardtype() (G32 high: Tab5, G0 high: UnitPoEP4, otherwise StampP4). Both pins can be changed by user wiring; M5GFX now confirms UnitPoEP4 by its Ethernet PHY and reports Tab5 and StampP4 candidates. The P4 package default becomes StampP4 / StampP4X (by chip revision) instead of Tab5. --- src/M5Unified.inl | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/src/M5Unified.inl b/src/M5Unified.inl index 501fbcf..dc3c987 100644 --- a/src/M5Unified.inl +++ b/src/M5Unified.inl @@ -1623,32 +1623,6 @@ static constexpr const uint8_t _pin_table_mbus[][31] = { board_t M5Unified::_check_boardtype(board_t board) { -#if defined (CONFIG_IDF_TARGET_ESP32P4) - if (board == board_t::board_unknown) - { - // GPIO observations remain here until the P4 family moves into the detector. - 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)) - { - 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)) - { - board = board_t::board_M5UnitPoEP4; - } - else - { - esp_chip_info_t chip_info; - esp_chip_info(&chip_info); - board = chip_info.revision >= 300 - ? board_t::board_M5StampP4X : board_t::board_M5StampP4; - } - } -#endif return board; } @@ -1706,7 +1680,10 @@ static constexpr const uint8_t _pin_table_mbus[][31] = { #elif defined (CONFIG_IDF_TARGET_ESP32C5) return board_t::board_M5StampC5; #elif defined (CONFIG_IDF_TARGET_ESP32P4) - return board_t::board_M5Tab5; + // Unidentified P4 modules have no display or board-specific power contract. + esp_chip_info_t info; + esp_chip_info(&info); + return info.revision >= 300 ? board_t::board_M5StampP4X : board_t::board_M5StampP4; #else return board_t::board_unknown; #endif From 7d73b4b5f0a7375902e1ad4d8ea7b8d787fbde3b Mon Sep 17 00:00:00 2001 From: ainyan03 <205502311+ainyan03@users.noreply.github.com> Date: Fri, 9 Oct 2026 05:26:23 +0000 Subject: [PATCH 3/3] Rename the PoE-P4 display output settings to Display Out cfg.unit_poep4_display_out and cfg.external_display.unit_poep4_display_out replace the unit_poep4_hdmi names, which remain as deprecated members. - The two settings structures are separate members. If the deprecated one differs from its defaults it is used, with a warning. - Bit 9 of external_display_value is now unit_poep4_display_out; the deprecated flag moves to bit 10. Clearing either flag disables Display Out. A sketch that zeroes external_display_value and then sets only the deprecated flag no longer enables it. --- examples/Basic/Displays/Displays.ino | 26 +++++----- examples/Basic/HowToUse/HowToUse.ino | 22 ++++----- src/M5Unified.hpp | 73 ++++++++++++++++++++++++---- 3 files changed, 87 insertions(+), 34 deletions(-) diff --git a/examples/Basic/Displays/Displays.ino b/examples/Basic/Displays/Displays.ino index da40830..6445d92 100644 --- a/examples/Basic/Displays/Displays.ino +++ b/examples/Basic/Displays/Displays.ino @@ -43,7 +43,7 @@ #include // If you use AddOn Display Out For PoE-P4, write this. -#include +#include // * The display header must be included before the M5Unified library. @@ -67,7 +67,7 @@ void setup(void) cfg.external_display.unit_lcd = false; // default=true. use UnitLCD cfg.external_display.unit_rca = false; // default=true. use UnitRCA VideoOutput cfg.external_display.module_rca = false; // default=true. use ModuleRCA VideoOutput - cfg.external_display.unit_poep4_hdmi = false; // default=true. use AddOn Display Out For PoE-P4 + cfg.external_display.unit_poep4_display_out = false; // default=true. use AddOn Display Out For PoE-P4 /* ※ Unit OLED, Unit Mini OLED, Unit GLASS2 cannot be distinguished at runtime and may be misidentified as each other. @@ -167,15 +167,15 @@ void setup(void) // cfg.unit_lcd.i2c_freq = 400000; // cfg.unit_lcd.i2c_port = I2C_NUM_0; #endif -#if defined ( __M5GFX_M5UNITPOEP4HDMI__ ) // setting for AddOn Display Out For PoE-P4. +#if defined ( __M5GFX_M5UNITPOEP4DISPLAYOUT__ ) // setting for AddOn Display Out For PoE-P4. // Supported timings only. Choose one of the following two modes: -cfg.unit_poep4_hdmi.width = 1280; -cfg.unit_poep4_hdmi.height = 720; -cfg.unit_poep4_hdmi.refresh_rate = 60; +cfg.unit_poep4_display_out.width = 1280; +cfg.unit_poep4_display_out.height = 720; +cfg.unit_poep4_display_out.refresh_rate = 60; -// cfg.unit_poep4_hdmi.width = 1920; -// cfg.unit_poep4_hdmi.height = 1080; -// cfg.unit_poep4_hdmi.refresh_rate = 30; +// cfg.unit_poep4_display_out.width = 1920; +// cfg.unit_poep4_display_out.height = 1080; +// cfg.unit_poep4_display_out.refresh_rate = 30; #endif @@ -207,7 +207,7 @@ cfg.unit_poep4_hdmi.refresh_rate = 60; // m5::board_t::board_M5UnitOLED, // m5::board_t::board_M5UnitLCD, // m5::board_t::board_M5UnitRCA, -// m5::board_t::board_M5UnitPoEP4HDMI +// m5::board_t::board_M5UnitPoEP4DisplayOut } ); @@ -225,7 +225,7 @@ cfg.unit_poep4_hdmi.refresh_rate = 60; int index_unit_mini_oled = M5.getDisplayIndex(m5::board_t::board_M5UnitMiniOLED); int index_unit_lcd = M5.getDisplayIndex(m5::board_t::board_M5UnitLCD); int index_unit_rca = M5.getDisplayIndex(m5::board_t::board_M5UnitRCA); - int index_unit_poep4_hdmi = M5.getDisplayIndex(m5::board_t::board_M5UnitPoEP4HDMI); + int index_unit_poep4_display_out = M5.getDisplayIndex(m5::board_t::board_M5UnitPoEP4DisplayOut); if (index_module_display >= 0) { M5.Displays(index_module_display).print("This is Module Display\n"); } @@ -253,8 +253,8 @@ cfg.unit_poep4_hdmi.refresh_rate = 60; if (index_unit_rca >= 0) { M5.Displays(index_unit_rca).print("This is Unit RCA\n"); } - if (index_unit_poep4_hdmi >= 0) { - M5.Displays(index_unit_poep4_hdmi).print("This is Unit PoE-P4 HDMI\n"); + if (index_unit_poep4_display_out >= 0) { + M5.Displays(index_unit_poep4_display_out).print("This is Unit PoE-P4 Display Out\n"); } M5.delay(5000); } diff --git a/examples/Basic/HowToUse/HowToUse.ino b/examples/Basic/HowToUse/HowToUse.ino index 40fa1f7..e460f0f 100644 --- a/examples/Basic/HowToUse/HowToUse.ino +++ b/examples/Basic/HowToUse/HowToUse.ino @@ -50,7 +50,7 @@ #include // If you use AddOn Display Out For PoE-P4, write this. -#include +#include // * The display header must be included before the M5Unified library. @@ -104,7 +104,7 @@ void setup(void) cfg.external_display.unit_lcd = false; // default=true. use UnitLCD cfg.external_display.unit_rca = false; // default=true. use UnitRCA VideoOutput cfg.external_display.module_rca = false; // default=true. use ModuleRCA VideoOutput - cfg.external_display.unit_poep4_hdmi = false; // default=true. use AddOn Display Out For PoE-P4 + cfg.external_display.unit_poep4_display_out = false; // default=true. use AddOn Display Out For PoE-P4 /* ※ Unit OLED, Unit Mini OLED, Unit GLASS2 cannot be distinguished at runtime and may be misidentified as each other. @@ -116,7 +116,7 @@ void setup(void) - unit_oled - unit_mini_oled - unit_lcd - - unit_poep4_hdmi + - unit_poep4_display_out ※ Displays that cannot be auto-detected - module_rca @@ -186,15 +186,15 @@ void setup(void) // cfg.unit_lcd.i2c_freq = 400000; // cfg.unit_lcd.i2c_port = I2C_NUM_0; #endif -#if defined ( __M5GFX_M5UNITPOEP4HDMI__ ) // setting for AddOn Display Out For PoE-P4. +#if defined ( __M5GFX_M5UNITPOEP4DISPLAYOUT__ ) // setting for AddOn Display Out For PoE-P4. // Supported timings only. Choose one of the following two modes: -// cfg.unit_poep4_hdmi.width = 1280; -// cfg.unit_poep4_hdmi.height = 720; -// cfg.unit_poep4_hdmi.refresh_rate = 60; +// cfg.unit_poep4_display_out.width = 1280; +// cfg.unit_poep4_display_out.height = 720; +// cfg.unit_poep4_display_out.refresh_rate = 60; -// cfg.unit_poep4_hdmi.width = 1920; -// cfg.unit_poep4_hdmi.height = 1080; -// cfg.unit_poep4_hdmi.refresh_rate = 30; +// cfg.unit_poep4_display_out.width = 1920; +// cfg.unit_poep4_display_out.height = 1080; +// cfg.unit_poep4_display_out.refresh_rate = 30; #endif // begin M5Unified. @@ -212,7 +212,7 @@ void setup(void) // m5::board_t::board_M5UnitOLED, // m5::board_t::board_M5UnitLCD, // m5::board_t::board_M5UnitRCA, -// m5::board_t::board_M5UnitPoEP4HDMI, +// m5::board_t::board_M5UnitPoEP4DisplayOut, } ); if (M5.Speaker.isEnabled()) diff --git a/src/M5Unified.hpp b/src/M5Unified.hpp index c90f4cd..5c272cf 100644 --- a/src/M5Unified.hpp +++ b/src/M5Unified.hpp @@ -82,6 +82,10 @@ namespace m5 class M5Unified { public: + // Suppress deprecated-member initialization in the implicit constructor; + // sketch accesses outside this definition still receive warnings. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" struct config_t { #if defined ( ARDUINO ) @@ -120,8 +124,9 @@ namespace m5 uint16_t unit_glass2 : 1; uint16_t unit_rca : 1; uint16_t module_rca : 1; - uint16_t unit_poep4_hdmi : 1; - uint16_t reserve : 6; + uint16_t unit_poep4_display_out : 1; + uint16_t unit_poep4_hdmi : 1 __attribute__((deprecated("Use unit_poep4_display_out; after clearing external_display_value, the legacy bit alone cannot enable Display Out"))); + uint16_t reserve : 5; } external_display; uint16_t external_display_value = 0xFFFF; }; @@ -200,13 +205,15 @@ namespace m5 #if defined ( __M5GFX_M5UNITLCD__ ) M5UnitLCD::config_t unit_lcd; #endif -#if defined ( __M5GFX_M5UNITPOEP4HDMI__ ) - M5UnitPoEP4HDMI::config_t unit_poep4_hdmi; +#if defined ( __M5GFX_M5UNITPOEP4DISPLAYOUT__ ) + M5UnitPoEP4DisplayOut::config_t unit_poep4_display_out; + M5UnitPoEP4DisplayOut::config_t unit_poep4_hdmi __attribute__((deprecated("Use unit_poep4_display_out"))); #endif #if defined ( __M5GFX_M5UNITRCA__ ) M5UnitRCA::config_t unit_rca; #endif }; +#pragma GCC diagnostic pop M5GFX Display; // setPrimaryされたディスプレイのインスタンス M5GFX &Lcd = Display; @@ -437,20 +444,27 @@ namespace m5 _begin(cfg); - // Unit PoEP4 has no built-in LCD; attach its LT8912B HDMI output as a board display. -#if defined ( __M5GFX_M5UNITPOEP4HDMI__ ) - if (cfg.external_display.unit_poep4_hdmi && _board == board_t::board_M5UnitPoEP4 && getDisplayCount() == 0) + // Unit PoEP4 has no built-in LCD; attach its LT8912B Display Out as a board display. +#if defined ( __M5GFX_M5UNITPOEP4DISPLAYOUT__ ) + // Either spelling can disable the addon; bit 9 keeps its raw-mask meaning. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + const bool use_poep4_display_out = cfg.external_display.unit_poep4_hdmi + && cfg.external_display.unit_poep4_display_out; +#pragma GCC diagnostic pop + if (use_poep4_display_out && _board == board_t::board_M5UnitPoEP4 && getDisplayCount() == 0) { + auto& display_out_cfg = _select_poep4_display_out_config(cfg); // The bridge sits on the internal bus: unless the sketch chose a bus itself, share // In_I2C's port and pins (lgfx::i2c underneath both). A partly filled config is // completed from In_I2C too, with a warning, so nothing is mixed silently. { - auto& h = cfg.unit_poep4_hdmi; + auto& h = display_out_cfg; const bool none = (h.i2c_port < 0 && h.pin_sda < 0 && h.pin_scl < 0); const bool all = (h.i2c_port >= 0 && h.pin_sda >= 0 && h.pin_scl >= 0); #if defined (ESP_LOGW) if (!none && !all) { - ESP_LOGW("M5Unified", "unit_poep4_hdmi: i2c_port/pin_sda/pin_scl partly set (%d/%d/%d); the rest is taken from In_I2C", h.i2c_port, h.pin_sda, h.pin_scl); + ESP_LOGW("M5Unified", "unit_poep4_display_out: i2c_port/pin_sda/pin_scl partly set (%d/%d/%d); the rest is taken from In_I2C", h.i2c_port, h.pin_sda, h.pin_scl); } #else (void)none; (void)all; @@ -459,7 +473,7 @@ namespace m5 if (h.pin_sda < 0) { h.pin_sda = In_I2C.getSDA(); } if (h.pin_scl < 0) { h.pin_scl = In_I2C.getSCL(); } } - M5UnitPoEP4HDMI dsp(cfg.unit_poep4_hdmi); + M5UnitPoEP4DisplayOut dsp(display_out_cfg); if (cfg.clear_display ? dsp.init() : dsp.init_without_reset(false)) { addDisplay(dsp); } @@ -700,6 +714,45 @@ namespace m5 IOExpander_Base& getIOExpander(size_t idx) { return *_io_expander[idx & 1]; }; private: + +#if defined ( __M5GFX_M5UNITPOEP4DISPLAYOUT__ ) + static bool _poep4_display_out_config_changed(const M5UnitPoEP4DisplayOut::config_t& cfg) + { + const M5UnitPoEP4DisplayOut::config_t defaults{}; + return cfg.width != defaults.width + || cfg.height != defaults.height + || cfg.refresh_rate != defaults.refresh_rate + || cfg.fb_num != defaults.fb_num + || cfg.dsi_bus_id != defaults.dsi_bus_id + || cfg.dsi_lane_num != defaults.dsi_lane_num + || cfg.dsi_lane_mbps != defaults.dsi_lane_mbps + || cfg.dsi_ldo_chan_id != defaults.dsi_ldo_chan_id + || cfg.dsi_ldo_voltage_mv != defaults.dsi_ldo_voltage_mv + || cfg.i2c_freq != defaults.i2c_freq + || cfg.output_depth != defaults.output_depth + || cfg.i2c_port != defaults.i2c_port + || cfg.pin_sda != defaults.pin_sda + || cfg.pin_scl != defaults.pin_scl + || cfg.i2c_master_bus != defaults.i2c_master_bus; + } + + static M5UnitPoEP4DisplayOut::config_t& _select_poep4_display_out_config(config_t& cfg) + { + // Separate live objects avoid inactive-union-member access. Changed legacy + // settings take precedence, including when both spellings were configured. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + if (_poep4_display_out_config_changed(cfg.unit_poep4_hdmi)) + { +#if defined (ESP_LOGW) + ESP_LOGW("M5Unified", "Deprecated unit_poep4_hdmi settings override unit_poep4_display_out"); +#endif + return cfg.unit_poep4_hdmi; + } +#pragma GCC diagnostic pop + return cfg.unit_poep4_display_out; + } +#endif /// Power_Class needs to release the interrupt path of the wakeup pin before sleeping, /// which requires knowledge of how the board is wired. That knowledge lives here. friend class Power_Class;