Skip to content

Fix CardputerADV being misdetected as plain Cardputer - #233

Merged
lovyan03 merged 1 commit into
m5stack:developfrom
ainyan03:fix-cardputeradv-detect
Jul 28, 2026
Merged

Fix CardputerADV being misdetected as plain Cardputer#233
lovyan03 merged 1 commit into
m5stack:developfrom
ainyan03:fix-cardputeradv-detect

Conversation

@ainyan03

Copy link
Copy Markdown
Contributor

Summary

  • fix CardputerADV being misdetected as board_M5Cardputer whenever an I2C Cap/Unit is attached
  • keep the VAMeter I2C probe result out of result, so the G8/G9 bits of the GPIO read survive for the CardputerADV check

Problem

With any I2C Cap/Unit attached, M5.getBoard() returns board_M5Cardputer (14) instead of
board_M5CardputerADV (24). Plain Cardputer has no internal I2C, so M5Unified's pin table selects
in_i2c = 255, 255 and M5.In_I2C comes up unusable:

[I][adapter_i2c.cpp:697] I2CClassImpl(): I2C_Class SDA:-1, SCL:-1
[E][M5UnitComponent.cpp:300] readRegister(): Failed to write
[E][unit_bmi270.cpp:108] begin(): Not BMI270 00

Every access to a built-in device on the internal bus then fails. It flips reliably with the Cap on
and off (reported with the M5Unit-NFC Cap on M5GFX 0.2.26 via M5Unified 0.2.19).

Root cause

In src/M5GFX.cpp the variable result is used for two different things and gets overwritten:

auto result = lgfx::gpio::command(/* pulldown + read G9, G8, G6, G5 */);
if ((result & 3) == 3) {                     // G5+G6 high -> VAMeter candidate
    result = (transactionWrite(1, 0x40, ...).has_value()
           && transactionWrite(1, 0x41, ...).has_value());   // <-- overwritten with a bool
    if (result) { board = board_t::board_M5VAMeter; }
}
if (board == board_t::board_M5Cardputer) {
    if ((result & 0x0C) == 0x0C) {           // <-- a bool is 0 or 1, so never true
        board = board_t::board_M5CardputerADV;
    }
}

Once the (result & 3) == 3 branch is taken, result holds a bool, so (result & 0x0C) == 0x0C
can never be satisfied and CardputerADV becomes undetectable. This holds regardless of how the read
bits are packed.

For reference, lgfx::gpio::command packs MSB first (result = (result << 1) + res in
src/lgfx/v1/platforms/esp32/common.cpp), reading G9, G8, G6, G5 in that order, giving bit0=G5,
bit1=G6, bit2=G8, bit3=G9. So (result & 3) tests G5/G6 (VAMeter's SYS I2C) and (result & 0x0C)
tests G8/G9 (CardputerADV's SYS I2C) — both conditions match the pin table in the comment above
them. Only the reuse of result is wrong.

Why a Cap triggers it

On CardputerADV, G5/G6 are the external (Cap/GROVE) pins. A Cap's I2C pull-ups hold them high, so
(result & 3) == 3 becomes true, the VAMeter probe runs, finds nothing, and leaves result == 0.
Without a Cap those pins read low, the branch is skipped, and the CardputerADV check works on the
preserved GPIO value — which is why the bug only appears with something attached.

Why not reorder the checks

Evaluating the CardputerADV test first would also fix the symptom, but it introduces the opposite
misdetection: on VAMeter, G8/G9 are the external pins, so a VAMeter with an I2C Unit attached would
be detected as CardputerADV. The existing order (VAMeter first, CardputerADV behind the
board == board_M5Cardputer guard) is correct as designed, so this PR only separates the variables
and leaves the detection order untouched.

Known remaining case (not addressed here)

With a Cap attached to a CardputerADV, G5/G6/G8/G9 are all high and the VAMeter probe still runs on
G5/G6. A Cap that answers at both 0x40 and 0x41 would be detected as VAMeter. Closing that would
require probing a built-in device on the CardputerADV internal bus as well, which changes the
detection design rather than fixing the defect, so it is left out of this PR.

Validation

  • Builds clean (ESP32-S3, Arduino framework); no new warnings.
  • Hardware validation is still pending — the reproduction was reported by a user and we do not
    currently have an I2C Cap on hand to confirm the fix on a CardputerADV. Happy to hold this PR
    until that is confirmed if you prefer.

The GPIO read used for the VAMeter / Cardputer / CardputerADV split was
overwritten by the VAMeter I2C probe result, so the subsequent
(result & 0x0C) == 0x0C test saw a bool and could never select
CardputerADV.

This surfaces whenever an I2C Cap or Unit is attached: on CardputerADV
G5/G6 are the external pins, so the Cap pull-ups make (result & 3) == 3
true, the VAMeter probe runs, finds nothing and leaves result at 0.
M5Unified then picks the plain Cardputer pin table, whose in_i2c entry is
255/255, and every access to a built-in device on the internal bus fails.

Keep the probe result in its own variable so the G8/G9 bits survive.
@lovyan03
lovyan03 merged commit 701a8b4 into m5stack:develop Jul 28, 2026
33 of 35 checks passed
@ainyan03
ainyan03 deleted the fix-cardputeradv-detect branch July 28, 2026 12:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants