Understanding the 24C64 EEPROM I2C Communication Issue

Understanding the 24C64 EEPROM I2C Communication Issue

Introduction

When working with I2C EEPROM devices like the 24C64, proper communication requires understanding the specific protocol requirements of the device. In this article, we'll analyze an issue encountered when trying to read from a 24C64 EEPROM I2C adapter, where the Linux driver implementation fails while the Windows implementation works correctly.

The Problem

The issue manifests as follows:

  • Using i2cget command fails with FAIL: 0xFF
  • Using i2ctransfer with a specific sequence works: i2ctransfer -y 15 w2@0x50 0x00 0x00 r1

This discrepancy suggests a fundamental difference in how the commands construct the I2C transaction.

Root Cause Analysis

1. 24C64 EEPROM Addressing Requirements

The 24C64 is a 64Kbit (8K x 8) EEPROM that requires a two-byte address for accessing its memory locations. This is clearly shown in the datasheet diagrams:

Article content

  • For random read operations, the protocol requires:

- START condition

- Device address with Write bit (0x50 << 1)

- First address byte (high bits)

- Second address byte (low bits)

- Repeated START

- Device address with Read bit ((0x50 << 1) | 1)

- Read data byte(s)

- STOP condition

  • For byte write operations, a similar two-byte address is required:

- START condition

- Device address with Write bit

- First address byte

- Second address byte

- Data byte

- STOP condition

2. I2C Command Behavior

Looking at the I2C bus captures:

  • i2cget command (failing):

- Sends device address (0x50) with write bit

- Sends ONE address bytes (0x00)

- Performs repeated start

- Sends device address (0x50) with read bit

- EEPROM doesn't know which memory location to read, returns NAK (0xFF)

  • i2ctransfer command (working):

- Sends device address (0x50) with write bit

- Sends two address bytes (0x00, 0x00)

- Performs repeated start

- Sends device address (0x50) with read bit

- Successfully reads the byte (0xCC)

Evidence from Bus Captures

The I2C bus captures clearly show:

  • Failed transaction:

- Write [0x50] + ACK

- 0x00 + ACK

- Read [0x50] + ACK

- 0xFF + NAK (device doesn't recognize the command sequence)

  • Successful transaction:

- Write [0x50] + ACK

- 0x00 + ACK

- 0x00 + ACK

- Read [0x50] + ACK

- 0xCC + NAK (successful read)

Why Clock Stretching Doesn't Help

Clock stretching allows the slave device to hold the clock line low to request more time for processing. While enabling clock stretching can help with timing-sensitive I2C devices, it doesn't solve the fundamental protocol issue here.

The problem isn't that the EEPROM needs more time; it's that the command sequence is incorrect. The EEPROM expects a two-byte address before it can perform a read operation, and no amount of waiting will change this protocol requirement.

Solution Approaches

  • Use i2ctransfer instead of i2cget:

- The i2ctransfer command allows specifying the complete transaction sequence

- Example: i2ctransfer -y 15 w2@0x50 0x00 0x00 r1

  • Use an EEPROM-specific driver:

- The Linux kernel has an at24 driver specifically for EEPROMs

- This driver understands the two-byte addressing requirement

Conclusion

The issue with reading from the 24C64 EEPROM stems from its requirement for a two-byte address before any read operation. The i2cget command doesn't provide this address, while i2ctransfer does. Understanding device-specific protocol requirements is crucial when working with I2C devices.

For users encountering this issue, the simplest solution is to use i2ctransfer with the proper sequence of write address bytes followed by read operations, rather than trying to use i2cget directly.


To view or add a comment, sign in

Others also viewed

Explore topics