I2C Repeated Starts: Preserve the Combined Transaction a Register Read Requires
A register read that requires a repeated START must remain one combined I2C transaction. Write the register selector, issue the repeated START without an intervening STOP, then address the device for reading. Two independently successful API calls do not prove that the controller generated this sequence.
Applicability: the concrete device is Bosch Sensortec BMI270 using its primary I2C interface, datasheet BST-BMI270-DS000-08, section 6.5.2. The host example uses Linux i2c-dev. This is a transaction-framing diagnostic, not an instruction to probe unknown devices or bypass a bound kernel driver.

1. Start with a device requirement, not an I2C habit
The BMI270 datasheet specifies that its register-read write phase and read phase must be separated by a repeated START. The write phase sends the register address; the read phase returns the selected data. The controller finishes by not acknowledging the final byte and issuing STOP.
That requirement is device-specific. Some other components permit a STOP after updating a persistent address pointer. Others interpret STOP as command completion or abandon a pending operation. A successful split read on one sensor is therefore not evidence that another sensor accepts the same framing. Record the target document and exact operation beside the transaction design.
Also distinguish a register selector from a device address. The device address chooses the target on the bus; the subsequent payload selects a register inside that target. Confusing those fields can produce a correctly framed transaction to the wrong location. Keep the seven-bit address separate from the read/write bit used on the wire.
2. Build a phase worksheet before changing code
For the selected read, list the initial START, write-address header, selector bytes, repeated START, read-address header, data bytes, final NACK, and STOP. Assign ownership of every ACK/NACK. The target acknowledges write-side fields; the controller acknowledges received data except the final byte.
Use a documented read-only, side-effect-free register as the initial oracle. A data FIFO or clear-on-read status register can change as it is observed, making two captures difficult to compare. Confirm that startup has completed and that the selected interface is active before treating a mismatched value as a transaction error.
For a hypothetical BMI270 bench test, read one approved identification register repeatedly, then extend to a documented consecutive register range. Keep the expected values or validation rules with the fixture. Do not infer acceleration correctness merely because a register transaction returns the expected device identity.
3. Check the host’s combined-transfer capability
The Linux userspace I2C documentation defines I2C_FUNCS for querying adapter functionality and I2C_RDWR for combined transfers without a STOP between their messages. That operation requires I2C_FUNC_I2C. For the ordinary register-read pattern, supply a write message followed by a read message in the same request.
Each message describes its own target address, flags, buffer, and length. The register selector belongs in the write buffer, not in the message address. Mark only the read message with the read flag. A library convenience function is acceptable only when its documented transaction matches the target’s required phases.
Do not assume that an SMBus-named helper and a raw I2C transfer are interchangeable. Compare the actual command, length, and response semantics, plus the adapter capability needed by that helper. If the adapter cannot express the operation, select a supported host interface or driver path. Adding sleeps between separate write and read calls cannot synthesize a missing repeated START.
4. Preserve transaction ownership through the complete request
A local application mutex can stop two application threads from changing a device pointer at once. It does not convert separate adapter transfers into one bus transaction, and it cannot prevent an external controller from using a bus released by STOP. Treat local serialization and on-wire continuity as separate requirements.
Review wrapper code for a hidden split. A function may accept a register and result buffer while internally calling a standalone write followed by a standalone read. Instrument the request boundary and inspect the adapter submission, especially when moving from a microcontroller SDK to Linux or from one USB-I2C bridge to another.
Use the existing kernel driver when it owns the device. Raw userspace transactions competing with that driver can change its register pointer or consume data unexpectedly. Perform alternative framing experiments only on an isolated test setup with an explicitly controlled owner and a known recovery path.
5. Compare the capture with the worksheet
Capture SDA and SCL at the target-side segment. The NXP I2C specification, revision 7.0 defines START and STOP by SDA transitions while SCL is high. Inspect those physical transitions around the selector/read boundary; do not rely solely on an analyzer summary saying “read register.”
- Confirm the intended target acknowledges the write-address header.
- Confirm the correct selector bytes arrive and are acknowledged.
- Locate a repeated START with no preceding STOP.
- Confirm the read-address header names the same intended target.
- Check the requested byte count, controller ACKs, final NACK, and final STOP.
Save the raw waveform and decoded view together with adapter identity, firmware/driver revision, request lengths, and API result. If the controller reports success but the capture shows STOP in the middle, the software path has not met the target contract. If the capture is correct but the data is wrong, investigate register selection, target readiness, and electrical timing separately.
6. Use a capability and negative-test matrix
For each supported adapter, test the normal combined read, an unsupported-capability path, a target NACK, and a short or failed completion. Require the application to reject incomplete results. Repeat under ordinary concurrent bus traffic to confirm that other requests do not split the logical operation.
A deliberately split STOP-separated request is useful as a negative framing fixture on a disposable setup. Its expected test result is “does not satisfy the required waveform,” not a universally prescribed returned value. A device may appear to tolerate it in one state; that observation does not override the documented interface requirement.
The handoff should include a phase worksheet, supported-adapter inventory, matched request/capture pairs, and explicit failure handling. No I2C transactions or sensor measurements were run for this article. The procedure establishes a proposed framing qualification method; actual adapter quirks, power sequencing, and measurement behavior remain target-specific validation work.