I2C ignoring 7th address bit?

Hi,

I’m trying to communicate with an EEPROM (AT24 compatible, address: 0x50) using PAC5527. When trying a write operation (or read, doesn’t matter), I do the following:

// START

  • I2C.CONSET.STA = 1
  • Wait until I2C.STAT == 0x08
  • I2C.CONCLR.SIC = 1

// SLA+W

  • I2C.DAT = 0xA0 (0x50 << 1 | 0)
  • Wait until I2C.STAT == 0x18 (ACK) or 0x20 (NACK)

PCLK = 150MHz, M=5, N=4, fSCL~=93.75KHz

Apparently the 7th bit in the DAT register is ignored, as you can see in the captures:

So instead of transmitting 0b10100000, 0b00100000 is transmitted.

Is there anything I’m missing?

Thanks

So I think I have discovered the issue after observing that it is only present in debug builds (so much slower, not optimized).

Apparently, after sending the start bit, you need to write the address to the DAT register pretty fast; otherwise it seems to miss the 7th bit. If I write the data before sending the START, it seems to work fine regardless of optimization level, see:

The issue can easily be reproduced in optimized builds by inserting a small delay after clearing the interrupt, and before writing the address. I guess this should be documented somewhere?

Thanks

Here’s the final sequence I’ve used to overcome the observed hardware limitations/bugs. Section 29.4.3 of the datasheet should be updated.

READ

  • Load address: I2C.DAT = (address << 1) | 1
  • Send START: I2C.CONSET.STA = 1
  • Wait until I2C.STAT == 0x08 (START sent)
  • Clear IRQ: I2C.CONCLR.SIC = 1
  • Wait until I2C.STAT == 0x40 (Addr ACK), handling 0x48 (Addr NACK)
  • Clear IRQ: I2C.CONCLR.SIC = 1
  • For each byte to read:
    • If not last: ACK I2C.CONSET.AA = 1, wait until I2C.STAT == 0x50 (Data ACK), read data from I2C.DAT, Clear IRQ I2C.CONCLR.SIC = 1
    • If last: NACK I2C.CONSET.AAC = 1, wait until I2C.STAT == 0x58 (Data NACK), read data from I2C.DAT, Clear IRQ I2C.CONCLR.SIC = 1
  • Send STOP: I2C.CONSET.STO = 1

WRITE

  • Load address: I2C.DAT = (address << 1)
  • Send START: I2C.CONSET.STA = 1
  • Wait until I2C.STAT == 0x08 (START sent)
  • Clear IRQ: I2C.CONCLR.SIC = 1
  • Wait until I2C.STAT == 0x40 (Addr ACK), handling 0x48 (Addr NACK)
  • For each byte to write:
    • Write byte to I2C.DAT, Clear IRQ I2C.CONCLR.SIC = 1, wait until I2C.STAT == 0x28 (Data ACK) or handle 0x30 (Data NACK)
  • Clear IRQ I2C.CONCLR.SIC = 1
  • Send STOP: I2C.CONSET.STO = 1

WRITE+READ

  • Load address: I2C.DAT = (address << 1)
  • Send START: I2C.CONSET.STA = 1
  • Wait until I2C.STAT == 0x08 (START sent)
  • Clear IRQ: I2C.CONCLR.SIC = 1
  • Wait until I2C.STAT == 0x40 (Addr ACK), handling 0x48 (Addr NACK)
  • For each byte to write:
    • Write byte to I2C.DAT, Clear IRQ I2C.CONCLR.SIC = 1, wait until I2C.STAT == 0x28 (Data ACK) or handle 0x30 (Data NACK)
  • Load address: I2C.DAT = (address << 1) | 1
  • Send repeated START: I2C.CONSET.STA = 1
  • Clear IRQ: I2C.CONCLR.SIC = 1
  • Wait until I2C.STAT == 0x10 (repeated START sent)
  • Clear IRQ: I2C.CONCLR.SIC = 1
  • Wait until I2C.STAT == 0x40 (Addr ACK), handling 0x48 (Addr NACK)
  • Clear IRQ: I2C.CONCLR.SIC = 1
  • For each byte to read:
    • If not last: ACK I2C.CONSET.AA = 1, wait until I2C.STAT == 0x50 (Data ACK), read data from I2C.DAT, Clear IRQ I2C.CONCLR.SIC = 1
    • If last: NACK I2C.CONSET.AAC = 1, wait until I2C.STAT == 0x58 (Data NACK), read data from I2C.DAT, Clear IRQ I2C.CONCLR.SIC = 1
  • Send STOP: I2C.CONSET.STO = 1