K64 I2C Dead Lock handling with KDS 2.0

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

K64 I2C Dead Lock handling with KDS 2.0

2,972 次查看
peterprocek
Contributor I

Hi all,

Currently I am running a FreeRTOS environment on the K64 in which I have a task setup to communicate with various I2C peripherals once a second. However, I've been noticing while debugging that when ever I do a software reset or re-flash my code, the I2C interface will more often than not return that it is busy on the very first instance of an I2C transaction after a reset. I feel like this is likely related to the possibility that the interface was reset before any stop or acknowledge conditions were met and the slave devices are in a dead-lock keeping the interface busy.

How do I handle the case of an I2C Dead lock scenario? I found the following application note regarding the topic:

https://www.nxp.com/docs/en/application-note/AN4803.pdf 

Its a little dated, but it has software functions for I2C Recovery. It does not seem like the fsl_i2c.c driver handles recovery. There are flags that are set for a timeout but it does not seem to be used for anything.

I assume the approach would be that in all of my software which attempts an I2C transaction, I would need to poll if the interface is busy and do a manual count at which point a 'timeout' event would happen and the I2C interface would have to be reset by sending a couple of clock pulses followed by a stop signal.

Has anyone already encountered something similar to this/implemented this solution?

Thank you!

标签 (1)
0 项奖励
5 回复数

1,447 次查看
trailman
Contributor V

Hi,

I think sending clock pulses until SDA is back high, as proposed by Mark, is better than always sending 9 clock pulses.

A slave hangs the SDA line low in the following cases :

- when it sends an ACK bit to acknowledge a byte that has been written to it by the master (address byte or data byte). In this case only one clock pulse is needed to make the slave release SDA. Doing 9 clock pulses would write an extra byte to the device with value 0xFF (undriven SDA) and would stop at the next ACK with the slave driving SDA low again. This may be dangerous !

- when it sends a data bit at 0 because a byte is read from it by the master. In this case, the number of clock pulses depends on the data; as many as required to reach the next data bit at 1, or the ACK bit where the slave releases SDA (the ACK is done by the master during a read).

So as Mark, I prefer doing only the required number of clock pulses to get SDA high. At this point both SDA and SCL should be high, so the next start done on the bus by the master will be detected by the slaves that will abort any pending transfer and answer as expected.

0 项奖励

1,448 次查看
donelmore
Contributor I

Interesting! I agree with your analysis. I wonder why the folks that wrote the I2C spec suggest the 9 pulses route. I am going to change my app per your suggestion.

0 项奖励

1,448 次查看
donelmore
Contributor I

From the I2C spec:

UM10204
I2C-bus specification and user manual
Rev. 6 — 4 April 2014

3.1.16 Bus clear
In the unlikely event where the clock (SCL) is stuck LOW, the preferential procedure is to
reset the bus using the HW reset signal if your I2C devices have HW reset inputs. If the
I2C devices do not have HW reset inputs, cycle power to the devices to activate the
mandatory internal Power-On Reset (POR) circuit.

If the data line (SDA) is stuck LOW, the master should send nine clock pulses. The device
that held the bus LOW should release it sometime within those nine clocks. If not, then
use the HW reset or cycle power to clear the bus.

My comments:

This same condition can arise from a variety of sources.  In one of my applications, various conditions can reset the CPU--the problem is that if the CPU is reset mid-transaction, the I2C bus will be left in an undefined state.  Sending the 9 pulses as described forces the slave device that was in use to release the bus.

Cheers.

0 项奖励

1,448 次查看
danielcaetano
Contributor III

Hello Peter,

In my k64f baremetal project I have found 2 issues with the i2c communication.

Issue 1) is the same as yours. Sometimes after flashing and initiating a debug session i2c will be stuck. I've never seen it happening with the release build, so I don't worry too much about it. I just power cycle the board and most times it will debug just fine.

Issue 2) is that sometimes the i2c communication will stop due to not receiving a stop signal from the slave device, locking the i2c in a busy state. As a workaround I set up a pseudo-watchdog to check if the busy flag is on and restart the i2c driver. So far, seems to fix the lockup issue.

Below is an example of my pseudo-watchdog ISR:

void FAKEDOG_ISR(void)
{
   /* Clear interrupt flag.*/
   PIT_ClearStatusFlags(PIT, kPIT_Chnl_2, PIT_TFLG_TIF_MASK);
   PIT_StopTimer(PIT, kPIT_Chnl_2);

   /*deal with I2C*/
   if(I2C0->S & kI2C_BusBusyFlag)
   {
      i2c_master_transfer_t tmpXfer;
      //preserve transfer status
      memcpy(&tmpXfer,&masterXfer,sizeof(i2c_master_transfer_t));

      //reset drivers
      DMAMGR_Deinit();
      I2C_MasterDeinit(I2C_MASTER_BASEADDR);

      DMAMGR_Init();
      i2c_init();

      //restore transfer status
      memcpy(&masterXfer,&tmpXfer,sizeof(i2c_master_transfer_t));
   }

   PIT_StartTimer(PIT, kPIT_Chnl_2);

}

Although not an exact answer to your question, I hope this information is useful to you.

Best regards,

Daniel Caetano

0 项奖励

1,448 次查看
mjbcswitzerland
Specialist V

Hi

I use this for start-time deadlock recovery - https://community.nxp.com/message/398627 

Regards

Mark

0 项奖励