I2C Interface to EPROM 256K

Hello,

I've have been playing around trying to write data to the EEROM, http://learning.media.mit.edu/projects/gogo/parts_pdf/EEPROM%20-%2024LC256.pdf, using the wire class. With the help of this tutorial, Arduino + EEPROM i2c, I was sucessful. However, I have read the data sheet and I can't understand why in this tutorial he used 0x50 as the hex address to the eeprom. The data sheet says the address is 1010 000 0. Where the first byte is specific for the EEROM and the last byte is set by pins and the read or write operation. 1010 is A in hex so why does he use 0x50 and not, 0xA0. I can't grasp why, but the code does work. But, I'd really want to know why. Thank you

It can be a bit confusing. First there is only one byte, the address byte, not two in your statement. The I2C standard allows for up to 128 device address to be used (0-127, but 0 is a general call address) so that only requires 7 bits of a byte. The I2C standard adds the low bit to signify if the command is going to be a read or write command to the slave. To make it tricky some manufactures show their device address as a 8 bit value and some a 7 bit address. The arduino wire library only wants to have the 7 bit address sent to it as it will append the read/write bit to the end for it's internal operations.

So the 7 bit addess for that device is 1010000 (note the bottom 3 bits are changable by pin wiring, but we will assume 000) which equates to a hex 0x50, but if shown as a full 8 bit number which includes the R/W low order bit it would be a binary 10100000 or hex 0xA0. So they really are the same I2C address one with and one without the R/W bit stuck on the end. Again the wire library only wants to except the 7 bit version of the address. Again manufactures don't agree on how to define their devices I2C addresses, as a 7 or 8 bit address, so you will see it in both forms for different devices. If you see a 8 bit version just shift the byte right one bit and that is the address to use with the wire library.

By the way here is a great little I2C scanning sketch to run if you are not sure what address a device is assigned. Just wire up the device and run the sketch and it tries all 128 valid address and tells you were it got a hit. A Arduino member posted it, and it's a great little test tool to have around.

/**
 * I2CScanner.pde -- I2C bus scanner for Arduino
 *
 * 2009, Tod E. Kurt, http://todbot.com/blog/
 *
 */

#include "Wire.h"
extern "C" { 
#include "utility/twi.h"  // from Wire library, so we can do bus scanning
}

// Scan the I2C bus between addresses from_addr and to_addr.
// On each address, call the callback function with the address and result.
// If result==0, address was found, otherwise, address wasn't found
// (can use result to potentially get other status on the I2C bus, see twi.c)
// Assumes Wire.begin() has already been called
void scanI2CBus(byte from_addr, byte to_addr, 
                void(*callback)(byte address, byte result) ) 
{
  byte rc;
  byte data = 0; // not used, just an address to feed to twi_writeTo()
  for( byte addr = from_addr; addr <= to_addr; addr++ ) {
    rc = twi_writeTo(addr, &data, 0, 1);
    callback( addr, rc );
  }
}

// Called when address is found in scanI2CBus()
// Feel free to change this as needed
// (like adding I2C comm code to figure out what kind of I2C device is there)
void scanFunc( byte addr, byte result ) {
  Serial.print("addr: ");
  Serial.print(addr,HEX);
  Serial.print( (result==0) ? " found!":"       ");
  Serial.print( (addr%4) ? "\t":"\n");
}


byte start_address = 1;
byte end_address = 127;

// standard Arduino setup()
void setup()
{
    delay(2000);
    Wire.begin();
    Serial.begin(38400);
    Serial.println("\nI2CScanner ready!");

    Serial.print("starting scanning of I2C bus from ");
    Serial.print(start_address,HEX);
    Serial.print(" to ");
    Serial.print(end_address,HEX);
    Serial.println("...Hex");

    // start the scan, will call "scanFunc()" on result from each address
    scanI2CBus( start_address, end_address, scanFunc );

    Serial.println("\ndone");
}

// standard Arduino loop()
void loop() 
{
    // Nothing to do here, so we'll just blink the built-in LED
    digitalWrite(13,HIGH);
    delay(300);
    digitalWrite(13,LOW);
    delay(300);
}

Lefty

So the 7 bit addess for that device is 1010000 (note the bottom 3 bits are changeable by pin wiring, but we will assume 000) which equates to a hex 0x50, but if shown as a full 8 bit number which includes the R/W low order bit it would be a binary 10100000 or hex 0xA0. So they really are the same I2C address one with and one without the R/W bit stuck on the end. Again the wire library only wants to except the 7 bit version of the address. Again manufactures don't agree on how to define their devices I2C addresses, as a 7 or 8 bit address, so you will see it in both forms for different devices. If you see a 8 bit version just shift the byte right one bit and that is the address to use with the wire library.

I would word this a little differently although the end result is the same.

The 'address' for an I2C device is a 7-bit number and in many cases some of the lower bits are changeable. For this device the address is 1010xxx and with the assumption of zeroes for the changeable bits we get 1010000. If this address were to be written as a 8-bit binary number it would be padded with a '0' at the left to become binary 01010000 or 0x50.

In communicating with an I2C device the 7-bit address is not padded but instead an extra read/write bit is tacked on at the end. The data is sent out most significant bit first which means that when the resulting information is looked at as a byte it appears as if the address was shifted to the left and the r/w bit was inserted as the least significant bit of this byte. This means that the information sent to the I2C device, when looked at as a byte of data, will be 10100000 (0xA0) or 10100001 (0xA1) depending on if you are going to write to the device or read from the device. This byte is technically not the address, it is part of the 'address packet' (which also includes an acknowledge bit). Atmel designates the 8 bits as SLA-W or SLA-R implying slave address write and slave address read.

From the Philips I2C Bus Specification:

After the START condition (S), a slave address is sent. This address is 7 bits long followed by an eighth bit which is a data direction bit (R/W) - a ‘zero’ indicates a transmission (WRITE), a ‘one’ indicates a request for data (READ).

Of course some manufacturers do things differently and state that their devices have two 8-bit 'addresses', one for writing and one for reading. These are actually the shifted 7-bit base addresses along with the r/w bit as mentioned above.

Don