I2C EEPROM 24c04 problems

Hello everyone,

I'm trying to get a 24C04 EEPROM to work with my Arduino, but ran into Problems instead. I never used the Wire.h aka I2C before, so I think the problem lies somewhere in the code, but let me explain my setup first:

1/PRE = Gnd
2/E1, 3/E2 = Gnd
4/VSS = Gnd
5/SDA = Analog 4 + 0.1uF (-> Gnd) + 12k? (-> VCC)
6/SDC = Analog 5 + 0.1uF (-> GND) + 12k? (-> VCC)
7/MODE = GND
8/VCC = VCC (5V);

The memories carry a built-in 4 bit, unique device identification code (1010) corresponding to the I2C bus definition. This is used together with 2 chip enable inputs (E2, E1) so that up to 4 x 4K devices may be attached to the I2C bus and selected individually.

While E1 and E2 are pulled to GND, the address should be 101000 or 0x28 in HEX.

The MODE input is available on pin 7 and may be driven dynamically. It must be at VIL or VIH for the Byte Write mode, VIH for Multibyte Write mode or VIL for Page Write mode. When unconnected, the MODE input is internally read as VIH (Multibyte Write mode).

That means, 7/MODE could be either LOW or HIGH for bytewise write mode. Mine is LOW.

Serial Clock (SCL).

The SCL input pin is used to synchronize all data in and out of the memory. A resistor can be connected from the SCL line to VCC to act as a pull up.

Serial Data (SDA).

The SDA pin is bi-directional and is used to transfer data in or out of the memory. It is an open drain output that may be wire-OR’ed with other open drain or open collector signals on the bus. A resistor must be connected from the SDA bus line to VCC to act as pull up.

Ok, I've added some Caps (0.1uF=100pF) and Pullups(12k?) as shown here:

I'm kind of sure, the Setup should be right so far. Here is a simple example Code to test. It should first write and then read one single byte:

#include <Wire.h>

const int EEPROMID = 0x28;
int byte_address=1;
byte exampleByte =0x10;

void setup(){
  Serial.begin(9600);
  Wire.begin();
  Serial.println("writing 1 byte..");
  eepWrite(byte_address, exampleByte);
  Serial.println("writing finished");
  Serial.println("Reading 1 byte..");
  byte b = eepRead(byte_address);
  Serial.print("read: ");
  Serial.println(b);  
}

void loop(){};

byte eepRead(int address){
  byte data;
  Wire.beginTransmission(EEPROMID);
  Wire.write(address);
  Wire.endTransmission();
  Wire.requestFrom(EEPROMID, 1);
  do {
    data=Wire.read();
  } while(Wire.available()==0);
  return data;
  //if(Wire.available())data=Wire.read();
  //return data;
}

void eepWrite(int address, byte data){
  Wire.beginTransmission(EEPROMID);
  Wire.write(address);
  Wire.write(data);
  Wire.endTransmission();
  delay(15);
}

The Problem is, I dont know if it writes a byte, but this code gets stuck with my setup when trying to read. Serial output:

writing 1 byte..
writing finished
Reading 1 byte..

and there it stucks, so I think somethings wrong with eepRead() Method. Any suggestions?

Thanks in advance,
harald

EDIT: I forgot to add the Datasheet: 24C04 pdf, 24C04 Description, 24C04 Datasheet, 24C04 view ::: ALLDATASHEET :::

Ok, I've added some Caps (0.1uF=100pF) and Pullups(12k?) as shown here:

Actually 0.1uF = 100nF = 100000pF.

You never want to add capacitance to the I2C bus, what that graph is showing you is how to calculate the resistance of a pull up resistor to place on the bus to overcome the effects of the capacitance on the bus (from the layout, wiring, devices, etc...). In short, you want to reduce the capacitance on the bus so remove them from your circuit and see if it works.

5/SDA = Analog 4 + 0.1uF (-> Gnd) + 12k? (-> VCC)
6/SDC = Analog 5 + 0.1uF (-> GND) + 12k? (-> VCC)

As stated remove the caps, but also try 4k7 on the lines instead of 12K.

You can put capacitors on I2C lines to act as a noise filter along with something like a series 300R resistor, but these should be in the order of a nF or so not 0.1uF. Most of the time this is not needed.

While E1 and E2 are pulled to GND, the address should be 101000 or 0x28 in HEX.

that may not be the correct address either...looks like you're missing a bit (1010000) so try 0x50 instead.

Thank you all for you response. Unfortunately I've already tried anything you recommended.
@wayneft: I've tried that before reading the first quote I made in the first post but I dont't think so. 0x50 is used for Chips that have 3 address-Pins, usually A0, A1, A2.
Thanks for explain me how I missed both the chart and the conversion. If I remove the caps, the serial output stucks while writing, if any kind of resistor is used.

writing 1 byte..

@Grumpy_Mike: I tried any kind of resistor between 2k2 and 22k with and without caps (I've also tried with 100 pF instead of the wrong calculated 0.1uF yet), but havn't got any luck either.

@wayneft: I've tried that before reading the first quote I made in the first post but I dont't think so. 0x50 is used for Chips that have 3 address-Pins, usually A0, A1, A2.

Not according to the link you posted. The I2C address consists of 8 bits, the lsb (b0) is the R/W bit and is controlled by the Wire library so you only need to use 7 bits (b7 - b1). The address you're using only contains six bits, so you're missing a bit. The datasheet shows the 4 msb as 1010 (b7 - b4), so by only sending 6 bits you've changed the address from 1010xxxx to 01010xxx. Download the I2C scanner sketch here at the bottom of the page (Gammon Forum : Electronics : Microprocessors : I2C - Two-Wire Peripheral Interface - for Arduino) and it will scan the bus and tell you what the device address is.

0x50 is used for Chips that have 3 address-Pins, usually A0, A1, A2.

No and even if it was if all three were tied to ground it would make no difference.
The correct address to use is 0x50, I have just used the chips this week to make something, my hardware looked like this:-

Thank you both so much, I finally got it work!

Both the datasheet for the "2gb 2" and the usable I2C Scanner Sketch prove that 50 is the right address, so I start playing with the code again. Changing

  do {
    data=Wire.read();
  } while(Wire.available()==0);

to

  while(Wire.available()==0);
  data=Wire.read();
  return data;

javascript:void(0);

solved it. Now that I know it looks pretty logic to me - if there's no data to read, no data can be read for sure :~ So the loop I've seen in many sketches and libraries is just to wait until the wire is available.

I'm so happy now - thank you very much for quick help and patience!

Please allow me one more question: the I2C Scanner says there are 2 devices found: 0x50 and 0x51. The Code now works with both of them. Why?

the I2C Scanner says there are 2 devices found: 0x50 and 0x51.

This is because there is 128K of memory in those chips this takes 17 bits to define. So to keep the address value down to two bytes, and so keep the access time shorter, the most significant bit of the address appears in the device's address. So 0x50 will access the first 64K of memory and 0x51 will access the second.

The external address pins then map onto the next most significant bits in the address, so in my example where I had two devices, these actually looked like 4 devices as far as I2C addresses were concerned and went from 0x50 to 0x53. This is so the large address space can look contagious.