I2C hardware sending an extra 8 clocks (byte?) at end of READ.

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

I2C hardware sending an extra 8 clocks (byte?) at end of READ.

1,214 Views
rickstuart
Contributor V

We have noticed that our KL03 is sending an extra 8 clocks (one byte?) at the end of our I2C reads.  We expected to see a START, EEPROM-ADDRESS-WRITE, EEPROM-REGISTER-ADDRESS, RE-START, EEPROM-ADDRESS-READ, DATA-NAK & STOP.  But what we actually see is an extra 8 clocks after the DATA-NAK.  I think the EEPROM is fine with this as it always sends 0xff because it recognized the NAK given out by the KL03 after the previous DATA given out by the EEPROM.  But we would like to keep all our I2C transactions as short as possible.  Our code looks like this:

I2C0_C1 |= I2C_C1_TX_MASK;
IIC_Start();
IIC_CycleWrite((SlaveAddress | (0x03 & (Reg >> 8))) * 2);
IIC_CycleWrite((uint8_t)(0x00ff & Reg));
IIC_RepeatStart();
IIC_CycleWrite(((SlaveAddress | (0x03 & (Reg >> 8))) * 2 ) + 1);
IIC_CycleRead(0,&res); // Dummy read
IIC_CycleRead(1,&res);
IIC_Stop();

Where passing 0 as the 1st parameter to IIC_CycleRead causes an ACK and passing a 1 causes a NAK.  The 1st res is written over as it is a dummy read.

Now, if we move the call to stop to before the call to read we see on the scope that the 8 extra clocks are gone!  This does not sound correct.  To send a STOP before the final byte is READ:

I2C0_C1 |= I2C_C1_TX_MASK;
IIC_Start();
IIC_CycleWrite((SlaveAddress | (0x03 & (Reg >> 8))) * 2);
IIC_CycleWrite((uint8_t)(0x00ff & Reg));
IIC_RepeatStart();
IIC_CycleWrite(((SlaveAddress | (0x03 & (Reg >> 8))) * 2 ) + 1);
IIC_CycleRead(0,&res); // Dummy read
IIC_Stop();

IIC_CycleRead(1,&res);

Is this actually the correct way to handle I2C?

-thanks

Tags (2)
0 Kudos
5 Replies

910 Views
kerryzhou
NXP TechSupport
NXP TechSupport

Hi rick stuart,

    Please also refer to this post, item 2:

KL25的I2C模块调试的两个注意事项(Two tips in the debugging of KL25's I2C) 

Wish it helps you!


Have a great day,
Kerry

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

910 Views
rickstuart
Contributor V

I thought the KL25 did not have double buffering.  And the KL03 did.  This, I had thought, makes any suggestions with respect to the KL25's I2C hardware almost useless when applied to the double buffered KL03 I2C hardware.

0 Kudos

910 Views
mjbcswitzerland
Specialist V

Rick

KL25 and KL03 have different I2C IPs and so the KL25 code won't help.

Apart from the fact that the code is blocking while sending there shouldn't be any difference in its behavior, whether you are spinning on flags or handling them in interrupts.

In fact NXP recommends using DMA due to the fact that the implementation doesn't wait as it should for slave responses but again, if you are just spinning on flags, you shouldn't have any issues with being fast enough.

The diagrams in the doc show all flags involved and the ordering of flag changes is always the same so (at the moment) I know of no other indications to be used. You can download the OpenSource uTasker project which includes the double-buffered I2C driver for comparison if you like. You can also run its I2C emulation in VS in case that may help.

In case the operation is not already adequate and you would like me to debug the issue please contact me through http://www.utasker.com/support.html

Regards

Mark

0 Kudos

910 Views
mjbcswitzerland
Specialist V

Hi

As mentioned before the double-buffered I2C implementation has various errata and especially has problems when using repeated starts.
See the final page of
http://www.utasker.com/docs/uTasker/uTasker_I2C.pdf
and ensure that you monitor the repeated start condition as being completed before starting the read.

You can put random delays in the code (as NXP does) to possibly get around some effects (if you are feeling lucky) but if you follow the diagram there you should be able to get something reliable. The method has been proven in various industrial products which intensively use I2C on various double-buffered design parts for >18 months and is considered fully reliable now.
You may also consider interrupt driven operation to improve overall code efficiency.

Regards

Mark

0 Kudos

910 Views
rickstuart
Contributor V

For reasons I do not want to go into, I2C interrupts are off the table.  That said, I have, none the less, been trying to use I2C interrupts as "flags" to indicate when I may set / send various I2C signals to the slave.  I have been able to get rid of the extra 8 bits (thank you).  But have been unable to remove a hard coded delay after the RESTART but before the 2nd time I send the slave address during an I2C read.  I have crafted some code which waits for the the START/STOP I2C interrupt.  And it appears to work as a while() loop consistently iterates 11 times after the RESTART is sent.  However this does not appear to be long enough as I get back all 1's from the EEPROM as if I didn't wait at all.  Are there other indications offered up by the KL03 I2C registers that can be interrogated to determine when it is safe to sent anything after a RESTART?

0 Kudos