Table of Content
ToggleOverview
During development of a removable-battery charger for a German medical-device company, we encountered an intermittent locked I2C bus condition during battery insertion or removal. When the fault occurred, every device on the affected bus became unreachable. Normal communication retries could not restore operation, and the charger required a power cycle.
Logic-analyzer captures showed SDA remaining low while SCL was released, preventing the controller from generating a new START or STOP condition. The behavior was consistent with a connected device waiting for additional clock pulses after a disturbance on the bus.
To recover from this condition, we implemented a firmware routine that temporarily controls the I2C lines as GPIO. It applies recovery clock pulses, generates a STOP condition, and reinitializes the I2C peripheral. When the bus can be released, communication resumes without power-cycling the charger.
System Context
The charger is controlled by a TI MSPM0 microcontroller and supports two lithium battery packs. Each battery position has a dedicated I2C bus operating at 60 kHz. The firmware communicates with each BMS over SMBus to read pack voltage, current, temperature, state of charge, and protection flags. The same buses also connect permanently mounted devices, including the charge controller, board-temperature sensor, LED driver, and light sensor.
The BMS is different from the other devices because it is connected through the removable battery interface. Since users can replace the battery, the connector may be connected or disconnected while the charger and the rest of the system are still powered.

Figure: Dual I2C buses connecting removable battery BMS devices and onboard components
Problem Observed
The issue occurred intermittently when the battery was inserted or removed. When it happened, all devices on the affected bus became unreachable. Communication timed out, and the charger required a power cycle to recover.
This affected more than battery telemetry. The firmware could no longer read protection information, command the charge controller, read the local temperature sensor, or confirm whether the battery was present.
Diagnosis with a Logic Analyzer
We connected a logic analyzer to SCL and SDA and repeated the battery insertion and removal sequence. During the failure, the capture showed SDA remaining low after the transaction stopped progressing, while SCL was no longer being driven low. This is a common signature of a target waiting for additional clock edges and holding the bus in a busy state.
The capture also distinguished the problem from a simple missing-device response. With a missing or unpowered target, the bus normally returns to its idle state with both lines high. In this case, the persistent low level on SDA prevented the controller from forming a new START condition.
Likely Root Cause
I2C is a shared, open-drain bus. All devices use the same SCL and SDA lines, and any device may pull either line low. When the battery connector mates, the BMS and its input capacitance are introduced onto a live bus. Contact order, contact bounce, and the charging of that capacitance can create short glitches on the bus lines, which devices may interpret as real signals.
A disturbance becomes serious when the controller and a target interpret it differently. Their input filters and thresholds may differ, so one device may detect an edge that another device ignores. This can leave their protocol states out of sync. The target may continue holding SDA low while waiting for another clock, while the controller believes the transfer has already ended. The bus then remains locked instead of recovering on its own.
Removal can produce a related disturbance if the battery begins to disconnect partway through a transaction. Contact bounce or a brief partial connection may interrupt the transfer before the BMS is fully disconnected. In either case, the key design constraint is that a removable device directly shares a live bus with devices that the firmware must continue to access.

Figure: A disturbed clock edge can leave the target holding SDA low
Why Resetting the I2C Peripheral Was Not Enough
Resetting the MCU I2C peripheral clears the controller state machine, buffers, and registers. It does not reset the external device that is physically holding SDA low. After reinitialization, the controller still sees a busy bus and cannot generate a valid START condition.
The recovery, therefore, has to act on the bus lines themselves. The controller must temporarily stop using the I2C peripheral and provide the missing clock edges manually.
Firmware Recovery Sequence
Disable the I2C peripheral: The firmware first prevents other tasks or interrupts from starting a transaction. The controller is then stopped and reset so it does not drive the pins while recovery is in progress.
Claim the pins as GPIO: SDA and SCL are reassigned from the peripheral to GPIO and controlled in an open-drain manner, allowing each line to be driven low or released to the pull-up resistor.
Check the bus lines before clocking: If both SDA and SCL are high, the bus is idle and no clock-recovery sequence is required. If SCL remains low, the routine reports a separate bus fault because recovery pulses cannot be generated safely.
Pulse SCL while SDA is low: The firmware produces clock pulses and checks SDA after each pulse. A waiting target advances through its remaining bit state and can release SDA. The implementation permits up to sixteen pulses and stops as soon as SDA rises.
Generate a STOP condition: The firmware first drives SCL low and then drives SDA low. It releases SCL and verifies that the line has risen high before releasing SDA. SDA rising while SCL is high forms a STOP condition. If SCL remains low, the routine reports that recovery has failed.
Verify the line state: Before restoring normal communication, the firmware confirms that both SDA and SCL are high. If either line remains low, the routine reports that recovery failed instead of assuming the bus is usable.
Restore normal operation: The pins are returned to the I2C peripheral, which is then initialized from a known configuration before communication resumes.

Figure: Conceptual bus-recovery sequence using SCL pulses followed by a STOP condition
Detecting When Recovery Is Needed
The firmware identifies a possible stuck-bus condition using the following indicators:
- A read fails repeatedly from a permanently connected device that should always be present and powered.
- A transaction times out, and SDA remains low after the controller is reset.
Recovery Limits and Design Lessons
- The firmware routine is a recovery mechanism; it does not prevent the connector disturbance from occurring.
- Clocking SCL can release a target holding SDA low, but it cannot recover a bus if SCL itself is held low by a device or by an electrical fault.
- Failure after the configured pulse limit is reported so that a different hardware or device fault is not mistaken for a successful recovery.
- Hot-plug behavior should be evaluated during both hardware and firmware design whenever a removable device shares a live communication bus.
- A future hardware revision could isolate the removable segment with a hot-swap I2C buffer that supports stuck-bus recovery. Firmware recovery should still remain as a secondary robustness measure.
Result
The firmware recovery routine changed how the charger responds to a stuck bus, as summarized below:
|
Before recovery logic |
After recovery logic |
| A connector disturbance could leave SDA low indefinitely. All devices on the affected bus remained unreachable, transfers repeatedly timed out, and normal operation required a charger power cycle. | The firmware recognizes the line-state signature, attempts to release the waiting target with controlled clock pulses, issues a STOP, and reinitializes the controller. If the line remains low, the failure is reported rather than hidden. |
In around 100 battery insertion and removal tests, the lockup occurred in roughly 10% of cases. With the recovery logic in place, the firmware released the bus and resumed communication without a power cycle, typically in under 1 ms and within about 2 ms in the worst case.
If you are working on a medical device or any product with removable batteries and running into I2C communication issues, we are happy to help. Feel free to Contact Us for firmware development, hardware design, and debugging support.