Hi,
I am implementing an interrupt driven I2C slave driver on an C6746 (bare-metal application) and I am having difficulty understanding the behavour of the I2C peripheral. Lets say my processor has to act like an I2C eeprom (24Cxx) where a master reads a number of bytes from the slave. This is done with two transactions: a slave-receiver transaction where the master sets the address to read from, and a slave-transmitter transaction where the data is read. My driver handles the first correctly, but I have problems implemeting the second (salve-transmitter). Here is how my driver works in this case:
1. AAS, RRDY and SCD interrupts are initially enabled.
2. I get an AAS interrupt on the reception of the slave address. The SDIR bit is set indicating that this is a slave-transmitter transaction (I2C-RD)
3. I write the first data byte to ICDXR and enable the XRDY interrupts as well.
4. Due to the double buffering of the transmit path (transmit data register and transmit shift register), I get another XRDY interrupt alsmot immediately.
5. I keep on getting XRDY interrupts and writing data to the ICDXR as bytes are read by the master until I get a stop condition interrupt SCD. I disable XRDY interrupts again.
This all seems fine so far. The problem, however, is that because of the double buffering, I have already written byte N+1 to the transmit buffer by the time that the stop condition arrives. This byte remains there until the next transaction and it is then shifted out first, before the first byte of the new transaction. The slave does not know how many bytes the master is going to read, and the NACK produced by the master at the end of the last byte is reading, is received after the XRDY interrupt that writes byte N+1. I have drawn up a diagram showing the sequence of interrupts and the actions I take at each interrupt (attached). The end result is that after the first read, all subsequent reads have their data shifted by one byte since byte N+1 of the previous read is always the first byte to be returned to the master.
e.g. (assume 4 bytes are read) first read returns 00 01 02 03, all subsequent reads return 04 00 01 02
Is there some way to fix this? I either need to get an XRDY interrupt when the shift register is already empty (no double buffering) or I need to get rid of the extra byte. I have toggled IRS after receiving the SCD interrupt, and it seems to work, but is it safe to reset the I2C peripheral after each transaction?
Also, I have not been able to detect the NACK returned by the master. The NACK bit in the ICSTR register seems to only function in master mode (master-transmitter). I have enabled the NACK interrupt but it is never triggered. So even if I could get a transmit ready interrupt when the shift register is truly empty, I still cannot detect when the master has signalled a NACK (i.e. the last byte in the transfer).
Any suggestions welcome!
Thanks!
N