Skip to content

xiao_nrf52: move Wire to NFC pins to unblock BLE pairing#2499

Open
Strykar wants to merge 1 commit intomeshcore-dev:devfrom
Strykar:fix/xiao-nrf52-wire-pins
Open

xiao_nrf52: move Wire to NFC pins to unblock BLE pairing#2499
Strykar wants to merge 1 commit intomeshcore-dev:devfrom
Strykar:fix/xiao-nrf52-wire-pins

Conversation

@Strykar
Copy link
Copy Markdown

@Strykar Strykar commented May 7, 2026

Problem

On Xiao_nrf52* envs, PIN_WIRE_SDA=D7 / PIN_WIRE_SCL=D6 collide with PIN_SERIAL1_RX/TX defined in variants/xiao_nrf52/variant.h:

#define PIN_SERIAL1_RX  (7)
#define PIN_SERIAL1_TX  (6)

With Wire muxed onto the same pads, the BLE companion advertises briefly after boot and then stops. The MeshCore Android app intermittently fails to pair, and Serial output is unreliable.

Fix

Move Wire to the NFC pads (P0.30 NFC1, P0.31 NFC2). The Adafruit BSP exposes them as Arduino pins 30/31 and they aren't claimed by another peripheral on this board. Same approach Meshtastic uses for the same baseboard (their seeed_xiao_nrf52840_kit/variant.h).

Diff

+5/-2 in variants/xiao_nrf52/platformio.ini. No code changes.

Tested

  • Hardware: XIAO nRF52840 Sense + Wio-SX1262 for XIAO Kit
  • Confirmed: BLE advertises stably, MeshCore Android app pairs and stays connected
  • Tested on dev (current meshcore-dev/Adafruit_nRF52_Arduino fork) and on main with the stock framework-arduinoadafruitnrf52@1.10700.0 — both work

PIN_WIRE_SDA=D7/PIN_WIRE_SCL=D6 collide with PIN_SERIAL1_RX/TX defined
in variant.h. Muxing Wire on those pads lets the BLE companion advertise
briefly then go silent on the Wio-SX1262 for XIAO baseboard.

Move Wire to the NFC pads (P0.30/P0.31, Arduino pins 30/31), matching
what Meshtastic does for the same baseboard.

Co-Authored-By: Claude Opus <noreply@anthropic.com>
@446564
Copy link
Copy Markdown
Contributor

446564 commented May 7, 2026

I can't reproduce this on a xiao nrf w/ wio. I think it's a red herring the AI dreamed up

@Strykar
Copy link
Copy Markdown
Author

Strykar commented May 9, 2026

The Serial1 framing in the PR is wrong. Serial1.begin is never called in the BLE companion build, so the symbolic overlap with PIN_SERIAL1_RX/TX in variant.h has no runtime effect.

The actual symptom on this unit: SCL on the original D6 (P1.11) is held low. Internal pull-up (~13kΩ) loses to it; the chip's S0S1 drive overpowers it cleanly, so it's a moderate ~1–5kΩ external pull, not a hard short. With SCL low, TwoWire::endTransmission in the Adafruit nRF52 BSP spins forever at while(!_p_twim->EVENTS_TXSTARTED && !_p_twim->EVENTS_ERROR); (no timeout). The first I2C probe is in AutoDiscoverRTCClock::begin(Wire) inside radio_init(), before BLE init runs, so advertising never starts.

Both the Wio-SX1262 for XIAO carrier (V1.0) and the Seeed XIAO nRF52840 Sense schematics show nothing on P1.11. Multimeter check still to do, but the most likely cause is a unit-specific defect on this Sense board (a P1.10/P1.11 solder bridge is the leading candidate; P1.10 is MIC_PWR on the adjacent QFN ball). That's consistent with your "can't reproduce".

If it holds up as a unit-specific issue, the PR shouldn't apply to everyone on Xiao_nrf52*. Happy to withdraw. The more generally-useful change is adding TWIM stuck-bus recovery before Wire.begin() so a held-low line doesn't silently kill BLE init regardless of cause. Would you prefer that as a separate PR?

@recrof
Copy link
Copy Markdown
Member

recrof commented May 9, 2026

correct fix here would be to remove PIN_SERIAL1_RX/PIN_SERIAL1_TX, not remapping SDA/SCL which people use for sensors.

@Strykar
Copy link
Copy Markdown
Author

Strykar commented May 9, 2026

Removing PIN_SERIAL1_RX/PIN_SERIAL1_TX won't change the runtime behaviour. cores/nRF5/Uart.cpp instantiates Uart Serial1(...) at static init unconditionally, and that constructor only stores pin numbers in member fields — PSEL.TXD/RXD aren't written until Serial1.begin() is called, which never happens in the BLE companion build (grep -rn Serial1 examples/companion_radio/ variants/xiao_nrf52/ is empty). So the defines aren't claiming the pins. They'd also need to stay defined for the BSP to compile.

Empirically on this unit: with all UARTE/TWIM/SPIM PSELs cleared and NRF_P1->PIN_CNF[11] reset to default, D6 at INPUT_PULLUP still reads LOW. D6 driven HIGH at standard CMOS drive reads HIGH cleanly. That's a moderate ~kΩ external pull-down on P1.11. Hardware, not software. With SCL held low, TwoWire::endTransmission spins forever in while(!EVENTS_TXSTARTED && !EVENTS_ERROR); on the first probe inside AutoDiscoverRTCClock::begin(Wire), before BLE ever starts.

Agree the PR shouldn't move Wire pins for everyone given the sensor users on D6/D7. Closing it. The defensive change worth doing separately: detect a stuck bus before Wire.begin() (read SDA/SCL with INPUT_PULLUP for a few ms, abort I2C init and skip RTC probing if either is low). That converts a held line into "no I2C" instead of an infinite hang, regardless of cause. Want me to put that up as a separate PR?

@recrof
Copy link
Copy Markdown
Member

recrof commented May 9, 2026

would probably test if -D PIN_SERIAL1_RX=-1 and PIN_SERIAL1_TX=-1 would work..

@Strykar
Copy link
Copy Markdown
Author

Strykar commented May 9, 2026

Tested. Build compiles fine — the -1 truncates to 255 as the uint8_t arg, and the Uart Serial1(...) constructor at static init does uc_pinRX = g_ADigitalPinMap[_pinRX], which reads out of bounds (UB) but only stores the resulting garbage in a member field. Nothing crashes because that field is never read until Serial1.begin() is called, which doesn't happen in this build.

Behaviour on hardware: identical to without the defines. BLE doesn't advertise; Android scan doesn't see the device. The first I2C probe in AutoDiscoverRTCClock::begin(Wire) still hangs in TwoWire::endTransmission's no-timeout busy-wait, because PSEL.SCL ends up pointing to P1.11 via Wire.setPins/Wire.begin, and P1.11 is held LOW off-chip on this unit (proven independently with the drive-strength test).

So PIN_SERIAL1_RX/TX value is genuinely inert in this build path, regardless of what we set it to. The hang is electrical, not symbolic. Closing this PR; will post the stuck-bus detect/skip patch separately.

@446564
Copy link
Copy Markdown
Contributor

446564 commented May 9, 2026

if this is only with the sense, and reproducible, then it would be best to create a new variant for it as existing xiao nrf work fine and do not suffer this issue.

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.

3 participants