The pseudo-code or my code above is not always able to unlock a hung I2C bus, nor my sample code.
This is the case if something goes wrong when reading some data from a slave : if for any reason some SCL clock periods are lost by the slave, it keeps on driving some data on SDA when the master terminates with a STOP. If the data driven by the slave at this time is 0, the STOP is not detected and the bus is hung.
Any attemp to disable/reenable the I2C module on MCF52259 does not help (my code fails).
Also trying to send some data, a START or a STOP fails because as the bus is found busy the MCF52259 immediately lose arbitration and does nothing on the bus (so pseudo code in doc fails)
The only workaround I found is :
- disable the I2C module (IEN bit = 0)
- switch I2C pins to GPIO mode
- set the pins at inputs (to have them high-Z)
- make 9 clock pulses on SDA by doing the following sequence 8 times :
- set SCL GPIO to output @ 0
- wait 1mS (example)
- set SCL GPIO to input (high-Z)
- wait 1mS
this sequence makes the slave shift-out its data until the ACK bit where the master is expected to drive SDA; but as SDA is high-Z, the slave sees a NOACK and stops transmitting even if some extra clock pulses are done.
- then do a START + STOP (not sure really required) :
- set SDA GPIO to output @ 0 (does a START)
- wait 1mS
- set SDA GPIO to input (high-Z, does a STOP)
- wait 1mS
- set pins back to I2C mode (primary or secondary function depending on the port used)
- reenable the I2C module (IEN bit = 1)
The first access after that sometimes fails, but the bus is no more hung and retrying the access is OK.
.