I2C SDA Lockup after arbitration loss

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

I2C SDA Lockup after arbitration loss

2,175 Views
quevedo
Contributor V

Hello,

After solving another problem on arbitration loss detection for Kinetis I2C modules, I am stuck with a very serious problem.

I am writing an I2C low level driver for multimaster operation in a FRDM-K64F board, and to test it I am emulating data collisions using another K64 board, through "bit-bang" approach. The emulation board works nice, it tests all conditions I want to test.

First, I keep flooding the bus with repeated start data until I press a button to release the bus, forcing my driver to wait for the bus release to send its data. This is working fine.

Then, it waits for my driver to issue a START and then sends data to the same ID (and EEPROM sharing the same bus), but the first data byte of my emulating board has higher priority, and so my driver has to detect arbitration loss and let the emulator finish its transfer. It also works fine.

The final test is the problem: the emulator waits for the START again, and then sends the slave ID of my driver (0x20), which has higher priority than the ID that the driver is sending (0x50 for the EEPROM). Thus, the driver should recognize bôth arbitration loss and slave ID match. Both conditions are recognized at the respective flags in the Status register, but when I try to clear the TX bit at the Control 1 register (I2C1_C1) to put the module in receive state, it locks the SDA line to Low. I should not happen, I would understand that it could lock if I was changing from RX to TX, but not the opposite way.

I don't know what wrong I am doing. Any clues?

Thanks in advance,

Antonio

Labels (1)
0 Kudos
3 Replies

1,319 Views
quevedo
Contributor V

Hello again,

This problem was becoming a kind of obssession for me. After my last post, I kept testing, now breaking the flow inside my ISR and going step by step, and then I stumbled upon something very interesting:

I have added the code to transfer data from my emulator to my test board, using the board's slave ID, just like in the lock-up situation, but without waiting for the START signal from my test board. As I had a breakpoint at the very beginning of the ISR, and when I sent data with my test board's ID, the board halted at the beginning of the ISR... and SDA stayed Low!

Strangely, when I ran the code without breakpoints, it received nicely. I thought... every time the I2C module has a slave ID match, it puts SDA Low, which is obvious, since it has to ACK the ID. The problem is, if I do something that locks SCL Low, the 9th clock cycle will never occur, and SDA will not be released.

So I had to figure what difference there was between receiving the ID with and without arbitration loss. Thus, I got back at my flowchart, and then it was clear: the code went through testing slave mode, then arbitration loss. Then, it tested for slave ID match, but both branches after this text were missing a dummy read to the Data Register!

After I added the dummy read, I ran the code again, and... surprise! Now I had my I2C transfer cycle working nicely!

Conclusion: slave ID matches force SDA to Low for the ACK bit. For some reason, when I switch to SLAVE RX, SCL also goes Low, and only after a dummy read at the Data Register both lines will be released!

I hope it helps someone in the future.

Thanks Jorge for your feedback.

Cheers,

Antonio

0 Kudos

1,319 Views
Jorge_Gonzalez
NXP Employee
NXP Employee

Hello Antonio:

There is a published errata concerning I2C arbitration in K64 (mask 1N83J):

pastedImage_0.png

From a previous post I think you are using Processor Expert, right?

If so, then this might explain that behavior. Try with the workaround of clearing the MST bit before clearing th e ARB bit.

Regards!

Jorge Gonzalez

1,319 Views
quevedo
Contributor V

Hello Jorge,

I tried switching to SLAVE RX mode before changing anything on the I2Cx_S register, but SDA still locks up on Low. Here is the piece of code at the very beginning of the IIC ISR:

byte is;

byte ic;

is = I2C1_S;

ic = I2C1_C1;

if(is & 0x10) { // ARBL

    arbl = TRUE;

    I2C1_C1 &= 0xCF; // Switch to RX SLAVE before cleaning ARBL (errata e6749)

    I2C1_S |= 0x10; // Clear ARBL

}

I2C1_S |= 0x02; // Clear IICIF

First, I save copies of I2C_C1 and I2C_S registers, and then I test for ARBL. If an arbitration loss has just occurred, I clear MST and TX bits on I2C_C1. Only after this, I clear the IICIF flag.

Unfortunately, it did not work. After receiving the slave ID, my boars puts SDA and SCL in Low, as it can be seen at my logic analyzer:

screenshot1.png

After receiving the whole ID, both SDA and SCL go to low. My emulator board keeps transmitting the rest of the message, but it does not show up because of the lock. Channel 2 has a sync signal that is asserted right after my board starts transmitting. The other 4 channels have the bits of a state indicator that helps me running through the flowchart. According to it, after the code above it tests if the module is in MASTER mode (if(ic & 0x20)), and the answer is still yes, even after cleaning up MST bit. Then, it checks if it has received ACK, and the answer is yes. Finally, it supposedly send the next byte.

It is funny that if the ID sent by the emulator does not match my board ID, my board releases the bus, even with the same tests going through (same program flow):

screenshot1.png

Here my board releases the bus after the first data byte transfer (0x11). Notice the Sync signal that goes low after the transfer is complete or the cycle is aborted.

Any ideas?

EDITED:

As I was using the copy of I2C_C1 to test Master mode (if(ic & 0x20)), the module was going through the Master mode branch of teh flowchart. I have corrected that, and now it follows the Slave mode branch, but the SDA and SCL lines still behave the same way.

I have changed my code to work on polling mode, as the frequency is low (approx. 5kHz), and now I can go step by step through the ISR. I noticed that the SDA line goes low even before the first test (line 7 of my code sample above). After I execute line 9 (switch ro Slave RX), it also drives SCL line to Low. And all of this problem only happens when I have a Slave ID match.

0 Kudos