LPC55S69: I2C4 (Flexcomm 4) master never physically drives SDA/SCL despite fully correct register configuration - I2C_MasterStart() hangs permanently in I2C_MasterCheckStartResponse()
Summary
On an LPC55S69-EVK, I2C_MasterTransferBlocking() hangs permanently (no timeout, confirmed via SDK source inspection) on the very first transaction attempted after I2C_MasterInit(). Every peripheral configuration register I can inspect - CFG, PSELID, CLKDIV, MSTTIME, IOCON pin function, and the Secure AHB Controller's peripheral access rules - reads back as correctly configured. However, a direct multimeter measurement of the physical SDA/SCL lines, taken while execution is frozen mid-hang inside the driver, shows both lines sitting at a clean, unchanged idle ~3.3V - meaning the I2C master's internal state machine never actually asserts a START condition onto the physical bus at all, despite software believing it did.
Environment
- Board: LPCXpresso55S69-EVK, LPC55S69JBD100
- IDE: MCUXpresso IDE v25.6 [Build 136]
- I2C peripheral: I2C4 (Flexcomm 4), pins P1_20 (SCL) / P1_21 (SDA)
- This is Core 1 (non-secure, no TrustZone - confirmed this chip's Core 1 has no TrustZone capability at all per AN12278) of a dual-core project. Core 1 is confirmed booting and executing correctly (proven via a working LED heartbeat and independent shared-memory diagnostics) - this report is specifically about the I2C peripheral, not the multicore boot sequence.
- Sensor: Adafruit BME688 (STEMMA QT, onboard pull-ups), address 0x77, connected via genuine Adafruit STEMMA QT-to-header cable
The core evidence
1. The hang location, confirmed via SDK source inspection
Reading fsl_i2c.c directly: I2C_MasterTransferBlocking() calls I2C_MasterStart() then I2C_MasterCheckStartResponse(). The latter calls I2C_PendingStatusWait(), which polls kI2C_MasterPendingFlag in a loop with no timeout at all when I2C_RETRY_TIMES is 0/undefined (confirmed this is the active code path in this project - the #else branch with an unconditional while(...) and no exit condition). Execution never returns from this call, confirmed by a shared-memory diagnostic checkpoint written immediately before the call, which is reached, and one written immediately after, which is never reached, even after 5+ seconds of continuous execution.
2. Register state at the moment of the hang (read live via debugger, not assumed)
Register Address Value Meaning
| I2C4->STAT | 0x5008A000 | 0x00000000 | Idle. MSTPENDING=0, MSTSTATE=0, no error flags |
| I2C4->CFG | 0x5008A800 | 0x00000001 | MSTEN=1 - master mode enabled |
| FLEXCOMM4->PSELID | 0x5008AFF8 | 0x1020F3 | PERSEL=3 (I2C personality genuinely selected), I2CPRESENT=1 |
| I2C4->CLKDIV | 0x5008A814 | 74 | Non-zero, plausible divider |
| I2C4->MSTTIME | 0x5008A824 | 102 | Non-zero, plausible SCL timing |
| IOCON->PIO[1][20] (P1_20/SCL) | 0x500010D0 | 0x323 | FUNC=3 (Flexcomm alt-function), pull-up + open-drain enabled |
| IOCON->PIO[1][21] (P1_21/SDA) | 0x500010D4 | 0x323 | Same - correctly configured |
| AHB_SECURE_CTRL FLEXCOMM4_RULE | 0x500AC124 | 0 | 0b00 = "Non-secure and Non-privilege user access allowed" (most permissive) |
| AHB_SECURE_CTRL IOCON_RULE | 0x500AC130 | 0 | Same - fully open, non-secure access unrestricted |
Every one of these is exactly what a correctly-configured, unrestricted, ready-to-transact I2C master should show.
3. Physical measurement (the decisive evidence)
With execution frozen mid-hang (confirmed via the checkpoint diagnostic, STAT still reading 0x00000000 at this exact moment):
- SDA to GND: 3.299 V
- SCL to GND: 3.299 V
Both lines are indistinguishable from a fully idle, untouched bus. The physical pins never moved at all, despite I2C_MasterStart() having already executed (it's called before I2C_MasterCheckStartResponse(), where we're actually hung) and despite every register above showing a fully configured, unrestricted master.
What has been ruled out
- Sensor/cable/breadboard fault - wiring continuity confirmed with a multimeter across multiple different physical wire positions (5+ attempts); genuine Adafruit STEMMA QT cable; sensor address pad confirmed consistent with the documented 0x77 default; identical result reproduces regardless of which physical header pins are used
- Clock source/frequency - explicitly re-asserted CLOCK_SetupFROClocking(12000000U) immediately before attaching Flexcomm4's clock; no change
- Baud rate/timing miscalculation - reduced from 100 kHz to 10 kHz (10x); identical hang; CLKDIV/MSTTIME both confirmed non-zero and plausible
- Pin mux - confirmed via IOCON_FUNC3 write and independently re-verified via direct register read at the exact moment of the hang
- I2C personality selection - confirmed via PSELID
- Sensor driver library - bypassed bme68x.c entirely; a raw, minimal zero-length address probe built directly with the SDK's i2c_master_transfer_t struct produces the identical hang
- MasterEnable off/on toggle workaround (from a similar-sounding NXP community report for a different part) - no effect
- TrustZone/Secure AHB Controller peripheral access restriction - confirmed both IOCON and FLEXCOMM4 are set to the most permissive non-secure access rule
Question
Given every software-visible register indicates a correctly configured, unrestricted I2C master, but the physical SDA/SCL pins provably never move (confirmed by direct voltage measurement while frozen inside the driver call), what remaining hardware-level step is required to get the I2C4 peripheral to actually drive its pads on this part?
Specifically:
- Is there a known LPC55S69 errata affecting Flexcomm I2C pad drive that isn't captured by the CFG/PSELID/IOCON registers I've checked?
- Is there an additional power-domain, pad-supply, or analog block that needs to be explicitly enabled for Flexcomm I2C physical output (something outside the digital peripheral configuration registers) that I may have missed?
- Given this is Core 1 (bare-metal, no RTOS, no TrustZone) in a dual-core multicore project where Core 0 runs FreeRTOS - is there any known interaction between Core 0's own boot-time configuration and Core 1's ability to drive Flexcomm4's physical pads, beyond what a register-level snapshot would reveal (e.g., something in SYSCON clock-gating for the pad IO cell itself, distinct from CLOCK_AttachClk's peripheral function clock)?
Happy to provide the full project, a logic analyzer capture, or any additional register dump on request.