AnsweredAssumed Answered

K22 I2C Arbitration Lost

Question asked by Mike Litster on Feb 22, 2016
Latest reply on Jan 7, 2019 by Andrew Darrow

Problem: I am using the K22, a MK22FN512VLH12 processor with KSDK 1.3. I found that after leaving the code running for 15 minutes or so, frequently polling an accelerometer on the I2C bus, the code fails the assert at the beginning of the I2C_HAL_SendStop function. Further investigation led me to see that in I2C_DRV_MasterIRQHandler, we are taking the "if (wasArbLost)" condition, indicating that I2C bus arbitration was lost.


The K22 is releasing the lines before the stop, as shown in the bottom trace in the picture. The top trace is a correct transfer.


I2c trace.png

I also found that if I continuously call I2C_DRV_MasterReceiveDataBlocking, it will produce this same failure within 2-3 minutes.


Isolate the problem: The K22 is the only master on the bus, so I isolated the bus so that only the K22 and the accelerometer were on the line. The problem continued. I removed the accelerometer and replaced it with a geomagnetic sensor and had the same result. This effectively indicated that the K22 is the cause of the problem.


Putting a 25us delay after every call to I2C_DRV_MasterReceiveDataBlocking causes it to no longer fail the assert in the I2C_HAL_SendStop function. It will then return "kStatus_I2C_AribtrationLost" the first time through. On subsequent calls, it will then fail the "if (!master->i2cIdle)" condition in I2C_DRV_MasterReceive and return "kStatus_I2C_Busy" everytime it is called, effectively disabling the I2C bus.


Reading the values of the I2C Status Register (I2Cx_S) during the I2C_DRV_MasterIRQHandler function indicates that the BUSY bit is set and doesn't clear.


When arbitration is lost, what is the proper way to reset the BUSY bit? According to the K22's reference manual, the BUSY bit of the I2C Status Register (I2Cx_S) is cleared when a STOP signal is detected. If I call I2C_HAL_SendStop when it returns from I2C_DRV_MasterReceiveDataBlocking it will fail the assert. The only effective workaround I have found is to call I2C_DRV_MasterDeinit followed by I2C_DRV_MasterInit whenever I2C_DRV_MasterReceiveDataBlocking returns "kStatus_I2C_AribtrationLost." Not a very elegant solution.