From 1bf561e0415ff28b91d0fe82240c0e46aa58e28f Mon Sep 17 00:00:00 2001 From: ainyan03 <205502311+ainyan03@users.noreply.github.com> Date: Wed, 26 Aug 2026 07:35:07 +0000 Subject: [PATCH 1/2] Probe with the software I2C port in every autodetect block until the board is confirmed Several blocks still opened a hardware I2C port to identify the board and handed it over only when a board matched. When none did, the ESP32 AXP probe left I2C_NUM_1 open on G21/G22: with the ESP-IDF i2c_master driver the pins stay reserved, so M5Unified opening the same pins on I2C_NUM_0 for a Core BASIC logged "i2c.common: GPIO 21/22 is not usable, maybe conflict with others", and I2C_NUM_1 was left unusable for the application. The other blocks released the port on a miss but still touched the peripheral and pins of a board that was not there. Every block now probes on the software port and opens the hardware port right after the board is confirmed (the backlight and touch use it), matching what the newer chips already did. probe_i2c_t bundles the sequence so all eleven blocks follow it, including the pre-existing soft probe blocks (Tab5, NessoN1, ToughC5, CoreMatrix): - The software port routes SDA/SCL to plain GPIO output while probing. When the hardware port was already opened by the application (shared bus), init() leaves the pins as the owner configured them, so the GPIO routing left behind by the probe would cut the port off from its pads and every later transfer from the backlight and touch drivers would fail. The probe backs up both pads before it starts and restores them right after it is released, on the handover and on the miss path alike. - PaperS3, StickS3 and NessoN1 test the pull-ups on SDA/SCL with gpio::command before probing, which already routes the pads to GPIO, so those blocks hand the backup they took before the test to the probe. - The UnitC6L block opens its port only once the panel matched. --- src/M5GFX.cpp | 181 +++++++++++++++++++++++++++++++------------------- 1 file changed, 113 insertions(+), 68 deletions(-) diff --git a/src/M5GFX.cpp b/src/M5GFX.cpp index a64627e..d627eb2 100644 --- a/src/M5GFX.cpp +++ b/src/M5GFX.cpp @@ -96,6 +96,40 @@ namespace m5gfx __attribute__ ((unused)) static constexpr int_fast16_t probe_i2c_port = -1; + // ボード未確定段階の探索をソフト I2C で行い、確定時に常用のハードウェアポートへ引き継ぐ。 + // probe が変えたパッドの配線 (pinMode による GPIO 出力への付け替え) は引き継ぎ前に戻す: + // アプリが先に同じポートを開いていた共有バスでは init() がピンに触らないため、 + // 戻さないと以後の HW I2C が通らない。 + struct __attribute__ ((unused)) probe_i2c_t + { + probe_i2c_t(int sda, int scl) : _pins { sda, scl }, _sda { sda }, _scl { scl } + { + lgfx::i2c::init(probe_i2c_port, _sda, _scl); + } + // パッドが probe の前に既に触られている (プルアップ試験など) ブロックでは、 + // その前に取ったバックアップを渡して復元先にする + probe_i2c_t(const gpio::pin_backup_t& sda_backup, const gpio::pin_backup_t& scl_backup) + : _pins { sda_backup, scl_backup }, _sda { sda_backup.getPin() }, _scl { scl_backup.getPin() } + { + lgfx::i2c::init(probe_i2c_port, _sda, _scl); + } + // ボードが確定した: probe を閉じ、パッドを戻してから常用ポートを開く + void handover(int hw_port) + { + release(); + lgfx::i2c::init(hw_port, _sda, _scl); + } + // ボードが一致しなかった: probe を閉じ、パッドを探索前の状態に戻す + void release(void) + { + lgfx::i2c::release(probe_i2c_port); + for (auto &pin : _pins) { pin.restore(); } + } + private: + gpio::pin_backup_t _pins[2]; + int _sda, _scl; + }; + // I2Cデバイスの存在をチェックする。 // SDA,SCLのプルアップが確認できない場合は0を返す。 // プルアップが確認できた場合は ~0u を返すが、存在しないデバイスに対応するビットは 0 となる。 @@ -1350,11 +1384,10 @@ namespace m5gfx || board == board_t::board_M5StackCore2 || board == board_t::board_M5Tough) { - gpio::pin_backup_t backup_pins[] = { axp_i2c_sda, axp_i2c_scl }; // I2C addr 0x34 = AXP192 - lgfx::i2c::init(axp_i2c_port, axp_i2c_sda, axp_i2c_scl); + probe_i2c_t probe(axp_i2c_sda, axp_i2c_scl); - auto chk_axp = lgfx::i2c::readRegister8(axp_i2c_port, axp_i2c_addr, 0x03, 400000); + auto chk_axp = lgfx::i2c::readRegister8(probe_i2c_port, axp_i2c_addr, 0x03, 400000); if (chk_axp.has_value()) { uint_fast16_t axp_exists = 0; @@ -1384,6 +1417,8 @@ namespace m5gfx { // check panel (ST7789) ESP_LOGI(LIBRARY_NAME, "[Autodetect] M5Station"); board = board_t::board_M5Station; + // ボードが確定したので常用するハードウェアポートへ引き継ぐ (バックライトが使う) + probe.handover(axp_i2c_port); bus_spi->release(); bus_cfg.spi_host = SPI2_HOST; @@ -1461,12 +1496,12 @@ namespace m5gfx bool isAxp192 = axp_exists == 192; - i2c_write_register8_array(axp_i2c_port, axp_i2c_addr, isAxp192 ? reg_data_axp192_first : reg_data_axp2101_first, axp_i2c_freq); + i2c_write_register8_array(probe_i2c_port, axp_i2c_addr, isAxp192 ? reg_data_axp192_first : reg_data_axp2101_first, axp_i2c_freq); if (use_reset) { - i2c_write_register8_array(axp_i2c_port, axp_i2c_addr, isAxp192 ? reg_data_axp192_reset : reg_data_axp2101_reset, axp_i2c_freq); + i2c_write_register8_array(probe_i2c_port, axp_i2c_addr, isAxp192 ? reg_data_axp192_reset : reg_data_axp2101_reset, axp_i2c_freq); lgfx::delay(1); } - i2c_write_register8_array(axp_i2c_port, axp_i2c_addr, isAxp192 ? reg_data_axp192_second : reg_data_axp2101_second, axp_i2c_freq); + i2c_write_register8_array(probe_i2c_port, axp_i2c_addr, isAxp192 ? reg_data_axp192_second : reg_data_axp2101_second, axp_i2c_freq); lgfx::delay(1); { @@ -1497,7 +1532,7 @@ namespace m5gfx // ・Core2のTPがスリープしている場合は反応が得られない; // ・ToughにGoPlus2を組み合わせると0x38に反応がある; // 上記のことから、ここではToughのTP(0x2E)の有無によって判定する; - if ( ! lgfx::i2c::readRegister8(axp_i2c_port, 0x2E, 0, 400000).has_value()) // 0x2E:M5Tough TOUCH + if ( ! lgfx::i2c::readRegister8(probe_i2c_port, 0x2E, 0, 400000).has_value()) // 0x2E:M5Tough TOUCH { ESP_LOGI(LIBRARY_NAME, "[Autodetect] M5StackCore2"); board = board_t::board_M5StackCore2; @@ -1554,6 +1589,8 @@ namespace m5gfx p->touch(t); } + // ボードが確定したので常用するハードウェアポートへ引き継ぐ (バックライトとタッチが使う) + probe.handover(axp_i2c_port); goto init_clear; } bus_spi->release(); @@ -1561,7 +1598,7 @@ namespace m5gfx } } } - for (auto pin: backup_pins) { pin.restore(); } + probe.release(); } if (board == 0 || board == board_t::board_M5Stack) @@ -1726,8 +1763,8 @@ namespace m5gfx uint32_t i2c_result = _detect_i2c_device(i2c_sda, i2c_scl, i2c_addr_list); if (i2c_result == ~0u) { - lgfx::i2c::init(i2c_port, i2c_sda, i2c_scl); - auto chk_aw = lgfx::i2c::readRegister8(i2c_port, aw9523_i2c_addr, 0x10, i2c_freq); + probe_i2c_t probe(i2c_sda, i2c_scl); + auto chk_aw = lgfx::i2c::readRegister8(probe_i2c_port, aw9523_i2c_addr, 0x10, i2c_freq); if (chk_aw .has_value() && chk_aw .value() == 0x23) { auto result = lgfx::gpio::command( @@ -1745,16 +1782,16 @@ namespace m5gfx /// (USBホストモジュール等、5Vが出ていないと信号線の電気を吸い込む組合せがあるため) uint8_t reg0x02 = (result == 0) ? 0b00000111 : 0b00000101; uint8_t reg0x03 = (result == 0) ? 0b10000011 : 0b00000011; - m5gfx::i2c::bitOn(i2c_port, aw9523_i2c_addr, 0x02, reg0x02); //port0 output ctrl - m5gfx::i2c::bitOn(i2c_port, aw9523_i2c_addr, 0x03, reg0x03); //port1 output ctrl - m5gfx::i2c::writeRegister8(i2c_port, aw9523_i2c_addr, 0x04, 0b00011000); // CONFIG_P0 - m5gfx::i2c::writeRegister8(i2c_port, aw9523_i2c_addr, 0x05, 0b00001100); // CONFIG_P1 - m5gfx::i2c::writeRegister8(i2c_port, aw9523_i2c_addr, 0x11, 0b00010000); // GCR P0 port is Push-Pull mode. - m5gfx::i2c::writeRegister8(i2c_port, aw9523_i2c_addr, 0x12, 0b11111111); // LEDMODE_P0 - m5gfx::i2c::writeRegister8(i2c_port, aw9523_i2c_addr, 0x13, 0b11111111); // LEDMODE_P1 - m5gfx::i2c::writeRegister8(i2c_port, axp_i2c_addr, 0x90, 0xBF); // LDOS ON/OFF control 0 - m5gfx::i2c::writeRegister8(i2c_port, axp_i2c_addr, 0x94, 33 - 5); // ALDO3 set to 3.3v // for GC0308 Camera - m5gfx::i2c::writeRegister8(i2c_port, axp_i2c_addr, 0x95, 33 - 5); // ALDO4 set to 3.3v // for TF card slot + m5gfx::i2c::bitOn(probe_i2c_port, aw9523_i2c_addr, 0x02, reg0x02); //port0 output ctrl + m5gfx::i2c::bitOn(probe_i2c_port, aw9523_i2c_addr, 0x03, reg0x03); //port1 output ctrl + m5gfx::i2c::writeRegister8(probe_i2c_port, aw9523_i2c_addr, 0x04, 0b00011000); // CONFIG_P0 + m5gfx::i2c::writeRegister8(probe_i2c_port, aw9523_i2c_addr, 0x05, 0b00001100); // CONFIG_P1 + m5gfx::i2c::writeRegister8(probe_i2c_port, aw9523_i2c_addr, 0x11, 0b00010000); // GCR P0 port is Push-Pull mode. + m5gfx::i2c::writeRegister8(probe_i2c_port, aw9523_i2c_addr, 0x12, 0b11111111); // LEDMODE_P0 + m5gfx::i2c::writeRegister8(probe_i2c_port, aw9523_i2c_addr, 0x13, 0b11111111); // LEDMODE_P1 + m5gfx::i2c::writeRegister8(probe_i2c_port, axp_i2c_addr, 0x90, 0xBF); // LDOS ON/OFF control 0 + m5gfx::i2c::writeRegister8(probe_i2c_port, axp_i2c_addr, 0x94, 33 - 5); // ALDO3 set to 3.3v // for GC0308 Camera + m5gfx::i2c::writeRegister8(probe_i2c_port, axp_i2c_addr, 0x95, 33 - 5); // ALDO4 set to 3.3v // for TF card slot bus_cfg.pin_mosi = GPIO_NUM_37; bus_cfg.pin_miso = GPIO_NUM_35; @@ -1771,6 +1808,8 @@ namespace m5gfx if ((id & 0xFF) == 0xE3) { // check panel (ILI9342) board = board_t::board_M5StackCoreS3; + // ボードが確定したので常用するハードウェアポートへ引き継ぐ (バックライトとタッチが使う) + probe.handover(i2c_port); // Camera GC0308 check (not found == M5StackCoreS3SE) auto chk_gc = lgfx::i2c::readRegister8(i2c_port, gc0308_i2c_addr, 0x00, i2c_freq); if (chk_gc.has_value() && chk_gc.value() == 0x9b) { @@ -1808,8 +1847,8 @@ namespace m5gfx lgfx::pinMode(GPIO_NUM_4, lgfx::pin_mode_t::input); // TF card CS lgfx::pinMode(GPIO_NUM_3, lgfx::pin_mode_t::input); // LCD CS } + probe.release(); } - lgfx::i2c::release(i2c_port); } if (board == 0 || board == board_t::board_M5Dial) @@ -1899,8 +1938,10 @@ namespace m5gfx const bool is_papermono = (i2c_result & ~1u) == ~0b0011u; // no CST820, with NFC == PaperMono,PaperMono Pro if (is_stopwatch || is_papermono) { gpio::pin_backup_t backup_pins[] = { GPIO_NUM_47, GPIO_NUM_48 }; - lgfx::i2c::init(i2c_port, stopwatch_i2c_sda, stopwatch_i2c_scl); - if (_check_m5pm1(i2c_port) && _check_m5ioe1(i2c_port)) { + probe_i2c_t probe(stopwatch_i2c_sda, stopwatch_i2c_scl); + if (_check_m5pm1(probe_i2c_port) && _check_m5ioe1(probe_i2c_port)) { + // ボードが確定したので常用するハードウェアポートへ引き継ぐ + probe.handover(i2c_port); // reg: 0x09(I2C_CFG) - Set to 0x00 to disable I2C idle sleep mode. // PMIC is always-on powered, and with battery power, shutdown doesn't reset the chip. // This register may have been modified elsewhere, causing PMIC communication issues. @@ -2113,7 +2154,7 @@ namespace m5gfx #endif } } - lgfx::i2c::release(i2c_port); + probe.release(); bus_spi->release(); for (auto pin: backup_pins) { pin.restore(); } } @@ -2132,10 +2173,12 @@ namespace m5gfx if (i2c_result == ~0u) { gpio::pin_backup_t backup_pins[] = { GPIO_NUM_2, GPIO_NUM_3, GPIO_NUM_15, GPIO_NUM_16, GPIO_NUM_45, GPIO_NUM_46 }; - lgfx::i2c::init(i2c_port, chain_captain_i2c_sda, chain_captain_i2c_scl); - if (_check_m5pm1(i2c_port) && _check_m5ioe1(i2c_port)) { + probe_i2c_t probe(chain_captain_i2c_sda, chain_captain_i2c_scl); + if (_check_m5pm1(probe_i2c_port) && _check_m5ioe1(probe_i2c_port)) { board = board_t::board_M5ChainCaptain; ESP_LOGI(LIBRARY_NAME, "[Autodetect] board_M5ChainCaptain"); + // ボードが確定したので常用するハードウェアポートへ引き継ぐ + probe.handover(i2c_port); #if !(defined(CONFIG_ESP32S3_SPIRAM_SUPPORT)) ESP_LOGE(LIBRARY_NAME, "M5ChainCaptain needs OPI-PSRAM enabled"); @@ -2202,7 +2245,7 @@ namespace m5gfx goto init_clear; #endif } - lgfx::i2c::release(i2c_port); + probe.release(); bus_spi->release(); for (auto pin: backup_pins) { pin.restore(); } } @@ -2221,10 +2264,12 @@ namespace m5gfx if (i2c_result == ~0u) { gpio::pin_backup_t backup_pins[] = { GPIO_NUM_2, GPIO_NUM_3, GPIO_NUM_11, GPIO_NUM_12, GPIO_NUM_13, GPIO_NUM_14, GPIO_NUM_15, GPIO_NUM_43, GPIO_NUM_44, GPIO_NUM_47 }; - lgfx::i2c::init(i2c_port, papercolor_i2c_sda, papercolor_i2c_scl); - if (_check_m5pm1(i2c_port)) { + probe_i2c_t probe(papercolor_i2c_sda, papercolor_i2c_scl); + if (_check_m5pm1(probe_i2c_port)) { board = board_t::board_M5PaperColor; ESP_LOGI(LIBRARY_NAME, "[Autodetect] board_M5PaperColor"); + // ボードが確定したので常用するハードウェアポートへ引き継ぐ + probe.handover(i2c_port); #if !(defined(CONFIG_ESP32S3_SPIRAM_SUPPORT)) ESP_LOGE(LIBRARY_NAME, "M5PaperColor need OPI-PSRAM enabled"); @@ -2291,7 +2336,7 @@ namespace m5gfx goto init_clear; #endif } - lgfx::i2c::release(i2c_port); + probe.release(); bus_spi->release(); for (auto pin: backup_pins) { pin.restore(); } } @@ -2321,16 +2366,16 @@ namespace m5gfx ); // Check G41,G42 HIGH if (result == 0x03) { - lgfx::i2c::init(i2c_port, paper_i2c_sda, paper_i2c_scl); + probe_i2c_t probe(backup_pins[0], backup_pins[1]); // SDA, SCL の復元先はプルアップ試験の前 bool paperdiy_found = false; bool gt911_found = false; if (board != board_t::board_M5PaperS3) { - paperdiy_found = _check_m5pm1(i2c_port); + paperdiy_found = _check_m5pm1(probe_i2c_port); } if (!paperdiy_found && board != board_t::board_M5PaperDIY) { for (auto addr: gt911_i2c_addr) { - if (lgfx::i2c::beginTransaction(i2c_port, addr, 400000).has_value()) { - gt911_found = lgfx::i2c::endTransaction(i2c_port).has_value(); + if (lgfx::i2c::beginTransaction(probe_i2c_port, addr, 400000).has_value()) { + gt911_found = lgfx::i2c::endTransaction(probe_i2c_port).has_value(); if (gt911_found) { break; } @@ -2343,12 +2388,12 @@ namespace m5gfx ESP_LOGI(LIBRARY_NAME, "[Autodetect] board_M5PaperDIY"); // M5PM1 GPIO2 drives EPD_PWR on PaperDIY. - lgfx::i2c::writeRegister8(i2c_port, m5pm1_i2c_addr, 0x09, 0x00, 0, m5pm1_i2c_freq); - lgfx::i2c::writeRegister8(i2c_port, m5pm1_i2c_addr, 0x0A, 0x00, 0, m5pm1_i2c_freq); - lgfx::i2c::bitOff(i2c_port, m5pm1_i2c_addr, 0x16, 0b11 << (2 * 2), m5pm1_i2c_freq); - lgfx::i2c::bitOn (i2c_port, m5pm1_i2c_addr, 0x10, 1 << 2, m5pm1_i2c_freq); - lgfx::i2c::bitOff(i2c_port, m5pm1_i2c_addr, 0x13, 1 << 2, m5pm1_i2c_freq); - lgfx::i2c::bitOn (i2c_port, m5pm1_i2c_addr, 0x11, 1 << 2, m5pm1_i2c_freq); + lgfx::i2c::writeRegister8(probe_i2c_port, m5pm1_i2c_addr, 0x09, 0x00, 0, m5pm1_i2c_freq); + lgfx::i2c::writeRegister8(probe_i2c_port, m5pm1_i2c_addr, 0x0A, 0x00, 0, m5pm1_i2c_freq); + lgfx::i2c::bitOff(probe_i2c_port, m5pm1_i2c_addr, 0x16, 0b11 << (2 * 2), m5pm1_i2c_freq); + lgfx::i2c::bitOn (probe_i2c_port, m5pm1_i2c_addr, 0x10, 1 << 2, m5pm1_i2c_freq); + lgfx::i2c::bitOff(probe_i2c_port, m5pm1_i2c_addr, 0x13, 1 << 2, m5pm1_i2c_freq); + lgfx::i2c::bitOn (probe_i2c_port, m5pm1_i2c_addr, 0x11, 1 << 2, m5pm1_i2c_freq); lgfx::delay(10); } else { board = board_t::board_M5PaperS3; @@ -2357,6 +2402,12 @@ namespace m5gfx lgfx::pinMode(GPIO_NUM_44, lgfx::pin_mode_t::output); lgfx::gpio_lo(GPIO_NUM_44); } + if (gt911_found) { + // ボードが確定したので常用するハードウェアポートへ引き継ぐ (タッチが使う。PaperDIY には無い) + probe.handover(i2c_port); + } else { + probe.release(); + } #if !(defined(CONFIG_ESP32S3_SPIRAM_SUPPORT)) ESP_LOGE(LIBRARY_NAME, "%s need OPI-PSRAM enabled", board == board_t::board_M5PaperDIY ? "M5PaperDIY" : "M5PaperS3"); @@ -2433,13 +2484,10 @@ namespace m5gfx _panel_last->touch(t); p->touch(t); } - if (board == board_t::board_M5PaperDIY) { - lgfx::i2c::release(i2c_port); - } goto init_clear; #endif } - lgfx::i2c::release(i2c_port); + probe.release(); } for (auto &bup : backup_pins) { bup.restore(); } } @@ -2876,11 +2924,13 @@ The usage of each pin is as follows. } ); if (result == 0x03) { // scl & sda pull-up - lgfx::i2c::init(I2C_NUM_1, GPIO_NUM_47, GPIO_NUM_48); // SDA, SCL - auto chk_pm1 = lgfx::i2c::readRegister8(I2C_NUM_1, m5pm1_i2c_addr, 0x00, m5pm1_i2c_freq); // Try to read M5PM1 device id + probe_i2c_t probe(backup_pins[5], backup_pins[6]); // SDA=G47, SCL=G48。復元先はプルアップ試験の前 + auto chk_pm1 = lgfx::i2c::readRegister8(probe_i2c_port, m5pm1_i2c_addr, 0x00, m5pm1_i2c_freq); // Try to read M5PM1 device id if (chk_pm1.has_value()) { ESP_LOGI(LIBRARY_NAME, "[Autodetect] board_M5StickS3"); - board = board_t::board_M5StickS3; + board = board_t::board_M5StickS3; + // ボードが確定したので常用するハードウェアポートへ引き継ぐ + probe.handover(I2C_NUM_1); // PM1_G2 -- L3B Enable, LCD Power On (M5Stack PM1 G2) lgfx::i2c::bitOff(I2C_NUM_1, m5pm1_i2c_addr, 0x16, 1 << 2, m5pm1_i2c_freq); // Set pin gpio2 as gpio function @@ -2931,7 +2981,7 @@ The usage of each pin is as follows. _set_pwm_backlight(GPIO_NUM_38, 7, 256, false, 16); goto init_clear; } - lgfx::i2c::release(I2C_NUM_1); + probe.release(); } for (auto pin: backup_pins) { pin.restore(); } } @@ -3069,7 +3119,7 @@ The usage of each pin is as follows. lgfx::pinMode(GPIO_NUM_23, lgfx::pin_mode_t::output); // TP INT lgfx::gpio_hi(GPIO_NUM_23); // select I2C Addr (high=0x14 / low=0x5D) // ボード確定まではソフトウェア I2C で通信し、ハードウェアポートを温存する - lgfx::i2c::init(probe_i2c_port, GPIO_NUM_31, GPIO_NUM_32); + probe_i2c_t probe(GPIO_NUM_31, GPIO_NUM_32); id = lgfx::i2c::readRegister8(probe_i2c_port, pi4io1_i2c_addr, 0x01).has_value() && lgfx::i2c::readRegister8(probe_i2c_port, pi4io2_i2c_addr, 0x01).has_value(); @@ -3171,8 +3221,7 @@ The usage of each pin is as follows. // ボードが確定し I2C の用は済んだので、常用するハードウェアポートへ // バスを引き継ぐ (タッチがこのポートを使う) - lgfx::i2c::release(probe_i2c_port); - lgfx::i2c::init(in_i2c_port, GPIO_NUM_31, GPIO_NUM_32); + probe.handover(in_i2c_port); auto bus_dsi = new Bus_DSI(); _bus_last.reset(bus_dsi); @@ -3299,7 +3348,7 @@ The usage of each pin is as follows. goto init_clear; } // ボード不成立時のみここへ来る。プローブに使ったソフトウェアポートを返す - lgfx::i2c::release(probe_i2c_port); + probe.release(); } } @@ -3355,8 +3404,6 @@ The usage of each pin is as follows. // ESP_LOGE("debug", "\n\nN1/C6L detect %02x\n\n\n", (int)result); if (result == 0x07) { // UnitC6L ? - lgfx::i2c::init(i2c_port, GPIO_NUM_10, GPIO_NUM_8); - _pin_reset(GPIO_NUM_6, use_reset); // LCD RST bus_cfg.pin_mosi = GPIO_NUM_21; bus_cfg.pin_miso = GPIO_NUM_22; // NC @@ -3372,6 +3419,7 @@ The usage of each pin is as follows. { board = board_t::board_M5UnitC6L; ESP_LOGI(LIBRARY_NAME, "[Autodetect] board_M5UnitC6L"); + lgfx::i2c::init(i2c_port, GPIO_NUM_10, GPIO_NUM_8); bus_spi->release(); bus_cfg.freq_write = 40000000; @@ -3402,7 +3450,7 @@ The usage of each pin is as follows. if (result == 0x03) { // NessoN1 ? // パネル ID で確定するまではソフトウェア I2C で通信する - lgfx::i2c::init(probe_i2c_port, GPIO_NUM_10, GPIO_NUM_8); + probe_i2c_t probe(backup_pins[1], backup_pins[0]); // SDA=G10, SCL=G8。復元先はプルアップ試験の前 // PI4IO E0 // P0 BTN1 // P1 BTN2 @@ -3459,8 +3507,7 @@ The usage of each pin is as follows. // ボードが確定したので、常用するハードウェアポートへバスを引き継ぐ // (バックライトとタッチがこのポートを使う) - lgfx::i2c::release(probe_i2c_port); - lgfx::i2c::init(i2c_port, GPIO_NUM_10, GPIO_NUM_8); + probe.handover(i2c_port); bus_spi->release(); bus_cfg.freq_write = 40000000; @@ -3515,10 +3562,9 @@ The usage of each pin is as follows. goto init_clear; } bus_spi->release(); + // ボード不成立時のみここへ来る (成立時は goto で抜けている) + probe.release(); } - // ボード不成立時のみここへ来る (成立時は goto で抜けている)。 - // プローブに使ったソフトウェアポートを返し、ピンを元へ戻す - lgfx::i2c::release(probe_i2c_port); for (auto &bup : backup_pins) { bup.restore(); } } } @@ -3559,7 +3605,7 @@ The usage of each pin is as follows. }; // ボード確定まではソフトウェア I2C で通信し、ハードウェアポートを温存する - lgfx::i2c::init(probe_i2c_port, toughc5_i2c_sda, toughc5_i2c_scl); + probe_i2c_t probe(toughc5_i2c_sda, toughc5_i2c_scl); if (_check_m5pm1(probe_i2c_port) && _check_m5ioe1(probe_i2c_port)) { // ボード確定 (パネル ID 確認) 前の書き込みは、ID 読みに必要な最小限 @@ -3643,8 +3689,7 @@ The usage of each pin is as follows. // ボードが確定したので、常用するハードウェアポートへバスを引き継ぐ // (バックライトとタッチがこのポートを使う) - lgfx::i2c::release(probe_i2c_port); - lgfx::i2c::init(i2c_port, toughc5_i2c_sda, toughc5_i2c_scl); + probe.handover(i2c_port); bus_spi->release(); bus_cfg.freq_write = 40000000; @@ -3701,7 +3746,7 @@ The usage of each pin is as follows. } // ここへ来るのはボード不成立の場合のみ。デバイスへ書いた分は復元済みで、 // ソフトウェア I2C と ESP 側のピン状態を返す - lgfx::i2c::release(probe_i2c_port); + probe.release(); for (auto &bup : backup_pins) { bup.restore(); } } @@ -3719,7 +3764,7 @@ The usage of each pin is as follows. }; // Probe over software I2C; the hardware port is left untouched until the board is confirmed - lgfx::i2c::init(probe_i2c_port, corematrix_i2c_sda, corematrix_i2c_scl); + probe_i2c_t probe(corematrix_i2c_sda, corematrix_i2c_scl); if (_check_m5pm1(probe_i2c_port) && _check_m5ioe1(probe_i2c_port)) { lgfx::i2c::writeRegister8(probe_i2c_port, m5pm1_i2c_addr, 0x09, 0x00, 0, m5pm1_i2c_freq); // I2C sleep disable @@ -3741,8 +3786,8 @@ The usage of each pin is as follows. board = board_t::board_M5CoreMatrix; ESP_LOGI(LIBRARY_NAME, "[Autodetect] board_M5CoreMatrix"); - // Board confirmed: hand the bus over to the hardware I2C port - lgfx::i2c::release(probe_i2c_port); + // Board confirmed: the Bus_I2C below opens the hardware port + probe.release(); auto bus_i2c = new Bus_I2C(); { @@ -3776,7 +3821,7 @@ The usage of each pin is as follows. lgfx::i2c::bitOff(probe_i2c_port, m5ioe1_i2c_addr, 0x05, 1 << 3, m5ioe1_i2c_freq); } // Reached only when no board was detected; only the software port was touched - lgfx::i2c::release(probe_i2c_port); + probe.release(); for (auto &bup : backup_pins) { bup.restore(); } } From 2260e3c213c8483372ebef0f0e9b61c131951d21 Mon Sep 17 00:00:00 2001 From: ainyan03 <205502311+ainyan03@users.noreply.github.com> Date: Wed, 26 Aug 2026 07:35:15 +0000 Subject: [PATCH 2/2] Warn when the hardware I2C port cannot be opened after the board was confirmed Probing on the software port means a board can now be identified even when the hardware port fails to open (a slave driver holding it, for one). The identification is kept, since dropping it would lose the display as well, but the users of that port would fail silently, so leave a warning that names the port and pins. --- src/M5GFX.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/M5GFX.cpp b/src/M5GFX.cpp index d627eb2..359da14 100644 --- a/src/M5GFX.cpp +++ b/src/M5GFX.cpp @@ -113,11 +113,16 @@ namespace m5gfx { lgfx::i2c::init(probe_i2c_port, _sda, _scl); } - // ボードが確定した: probe を閉じ、パッドを戻してから常用ポートを開く + // ボードが確定した: probe を閉じ、パッドを戻してから常用ポートを開く。 + // 開けなくてもボードの判定は取り消さない (表示まで失うため)。バックライトやタッチなど + // このポートの利用者が通信できなくなるので、原因が追えるよう警告だけ残す void handover(int hw_port) { release(); - lgfx::i2c::init(hw_port, _sda, _scl); + if (!lgfx::i2c::init(hw_port, _sda, _scl).has_value()) + { + ESP_LOGW(LIBRARY_NAME, "[Autodetect] I2C port %d could not be opened for SDA=%d SCL=%d", hw_port, _sda, _scl); + } } // ボードが一致しなかった: probe を閉じ、パッドを探索前の状態に戻す void release(void) @@ -132,6 +137,8 @@ namespace m5gfx // I2Cデバイスの存在をチェックする。 // SDA,SCLのプルアップが確認できない場合は0を返す。 + // 内部でパッドを backup/restore するので、呼び出し側はこの後に probe_i2c_t を作れば + // 探索前の状態を復元先にできる (プルアップ試験を自前で行うブロックは試験前の backup を渡す)。 // プルアップが確認できた場合は ~0u を返すが、存在しないデバイスに対応するビットは 0 となる。 // つまり、引数のアドレスリストにある全てのデバイスが存在する場合は ~0u となる。 __attribute__ ((unused))