Can't read or write to external EEPROM

SUMMARY: I'm having difficult reading and writing to an external EEPROM. An i2c scanner I found on the arduino website recognizes it on the bus. When I read the data from the EEPROM and print it to the serial monitor, all the addresses come back as "FF". If I try to write to the same address before reading the address it still comes back as "FF".

INTRO AND CODE:
I'm making a project where an arduino nano will read an ADC pin and write the measured value to an external EEPROM. I want to sample at about 2samp/sec for several hours. I'm using the 24FC1025 by Microchip. This is its datasheet. In order to make sure I correctly connected the EEPROM chip to the nano, I used the an I2C device scanner found on the arduino website. It is posted here. The serial monitor output found two devices. One at address 0x50 and one at 0x54. These addresses correspond to the chip's two blocks of memory. It seems that the I2C bus is wired up correctly. I found a library written for this chip. It is on github here. The first thing I tried was running the example code for reading the EEPROM. During compilation, it through one warning but it still compiled and ran.

sketch\EEPROM24.cpp: In constructor 'EEPROM24::EEPROM24()':
sketch\EEPROM24.cpp:23:42: warning: cannot call constructor 'EEPROM24::EEPROM24' directly [-fpermissive]
   EEPROM24::EEPROM24(EEPROM24_ADDR, false);
                                          ^
sketch\EEPROM24.cpp:23:42: note: for a function-style cast, remove the redundant '::EEPROM24'

I not very comfortable working with constructors so I decided to ignore this.

This is the example code

#include <Wire.h>     
#include "EEPROM24.h"

// init eeprom with default address
EEPROM24 eeprom;

// example: bytes to be read with a single loop
#define READ_BYTES 32

// example: using one chip max address is 2^17 => 1024K
#define ADDR_BOUNDARY 131072

// variables
int i = 0;
unsigned int curr_addr = 0;

void setup() {
  // initialize serial communications at 9600 bps
  Serial.begin(9600);
  
  // init TWI pins
  pinMode(SDA, INPUT);
  pinMode(SCL, INPUT);

  // enable pull-ups on SDA & SCL pins
  digitalWrite(SDA, HIGH);
  digitalWrite(SCL, HIGH);
  
  // display welcome
  Serial.println("Arduino Nano Board");
}

void loop() {
  Serial.print("eeprom[");
  Serial.print(curr_addr, HEX);
  Serial.println("]:");
  
  // eeprom read loop
  for(i = 0; i < READ_BYTES; i++) {

    byte re = (byte) eeprom.read(curr_addr);
    
    Serial.print(re, HEX);
    Serial.print(' ');
    
    curr_addr += 1;

    if(curr_addr > ADDR_BOUNDARY)
    	curr_addr = 0;
  }
  Serial.println(' ');
 

  // wait before the next loop
  delay(2000);
}

This is the .cpp

/*
  EEPROM_24X1025.cpp - Library for interfacing 24XX1025 EEPROM chips.
  Created by Valerio De Carolis, January, 2013.
  Licensed under MIT license, see LICENSE.md
 */

#include "Arduino.h"
#include "EEPROM24.h"
#include <Wire.h>

// TWI clock frequency (400 kHz)
#define TWI_FREQ_FAST 400000L

// default config (address & speed)
#define EEPROM24_ADDR B10100000
#define EEPROM24_FAST false

/**
 * Default constructor (using default address and low speed)
 */
EEPROM24::EEPROM24() 
{
  EEPROM24::EEPROM24(EEPROM24_ADDR, false);
}

/**
 * Standard constructor using address and fast flag.
 * It initializes the Wire library.
 */
EEPROM24::EEPROM24(byte address, bool fast)
{
  _address = address;
  _fast = fast;

  // init Wire library
  Wire.begin();

  // change TWI base clock
  if(fast) {
    TWBR = ((F_CPU / TWI_FREQ_FAST) - 16) / 2;
  }
}

/**
 * [EEPROM24::read description]
 * @param  eeprom_addr [description]
 * @return             [description]
 */
int EEPROM24::read(unsigned int eeprom_addr)
{
  byte i2c_status = 0;
  int i2c_addr = (int) _address;
  int ee_out = 0;
  
  // swap chip (for daisy-chained eeproms)
  if( eeprom_addr > 65535 )
    i2c_addr = i2c_addr | B00001000;    
 
  // seven-bit address
  i2c_addr = i2c_addr >> 1;
  
  // i2c commands
  Wire.beginTransmission(i2c_addr);
  Wire.write( (byte) eeprom_addr >> 8 );
  Wire.write( (byte) (eeprom_addr && 0x00FF) );
  
  // check status
  i2c_status = Wire.endTransmission();
  
  if( i2c_status == 0 ) {  
    Wire.requestFrom(i2c_addr, 1);

    while( Wire.available() )
      ee_out = Wire.read();    

    return ee_out;
  } else {  
    return -1;
  } 
}

/**
 * [EEPROM24::write description]
 * @param  eeprom_addr [description]
 * @param  data        [description]
 * @return             [description]
 */
int EEPROM24::write(unsigned int eeprom_addr, byte data)
{
  int i2c_addr = (int) _address;
  
  if( eeprom_addr > 65535 )
    i2c_addr = i2c_addr | B00001000;    
 
  // seven-bit address
  i2c_addr = i2c_addr >> 1;
  
  // i2c commands
  Wire.beginTransmission(i2c_addr);
  Wire.write( (byte) eeprom_addr >> 8 );
  Wire.write( (byte) (eeprom_addr && 0x00FF) );
  Wire.write( data );
  
  return Wire.endTransmission();  
}

This is the .h

/*
  EEPROM_24X1025.h - Library for interfacing 24XX1025 EEPROM chips.
  Created by Valerio De Carolis, January, 2013.
  Licensed under MIT license, see LICENSE.md
 */

#ifndef EEPROM24_h
#define EEPROM24_h
#include "Arduino.h"

class EEPROM24
{
  public:
    EEPROM24();
    EEPROM24(byte address, bool fast);
    int read(unsigned int eeprom_addr);
    int write(unsigned int eeprom_addr, byte data);
    int read_page();
    int write_page();
  private:
    byte _address;
    bool _fast;
};

#endif

// see: http://arduino.cc/forum/index.php/topic,54345.0.html

FIRST ATTEMPT:
I'm going to describe how I think the code works. First, a class is created that calls the default constructor. The default constructor give the class the a predefined address for the EEPROM. This address matches the way I connected chips elect pins to ground and VCC. The constructor also accepts a clock speed as a parameter, but I don't see where this is utilized in the class's methods. The void loop has a nested loop that read 32bytes of data from the the EEPROM. Each iteration of the loop is a new address to be read. The data read from the EEPROM is then printed to the serial monitor which looks like this

Arduino Nano Board
eeprom[0]:
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF

As you can see, there are 32 bytes of data printed here. What I don't know is if they are actually all "FF" Maybe they come preprogrammed from the factory like this. I don't know. So I added a line of code so that current the loop iteration number is written to the eeprom right before it is read back. That makes the void loop look like this

void loop() {
  Serial.print("eeprom[");
  Serial.print(curr_addr, HEX);
  Serial.println("]:");
  
  // eeprom read loop
  for(i = 0; i < READ_BYTES; i++) {
    
    eeprom.write(curr_addr, i);
    
    byte re = (byte) eeprom.read(curr_addr);
    
    Serial.print(re, HEX);
    Serial.print(' ');
    
    curr_addr += 1;

    if(curr_addr > ADDR_BOUNDARY)
    	curr_addr = 0;
  }
  Serial.println(' ');
 
  // wait before the next loop
  delay(2000);
}

This had no affect on the output of the serial monitor though. It still looks like every address location is read back as "FF".
Troubleshooting:
I found something else in the library that looks strange. The EEPROM's address is stored as a byte. And then shifted by one bit to the right before being fed into the Wire.beginTransmission() function. The address of the EEPROM is 7 bits so I see the logic in right shifting the byte. However, according the the data sheet of the chip the control byte, the first byte sent from the master which contains the slave address, also needs to have a read/write bit as the LSB. I've attached a screen shot of the a figure that shows the control byte format. I don't see anywhere in this library where the read/write bit is given to the EEPROM. Instead of passing off the right shifted i2c address variable to the Wire.beginTransmission(i2c_addr); within the .ccp, I replaced the variable with a hard coded B10100001 for the read method's wire.beginTransmission() and B10100000 for the write method's wire.beginTransmission(). This had no affect on the ouput of the serial monitor. I'm stuck at this point and am not sure what to do from here.

controlbyte.png

controlbyte.png

You have tied the eeprom pins A0 and A1 low and pin A2 high according to the data sheet ?
A factory new chip has all bits set to 1 so your read attempts will show bytes with value 0xFF.
External pull-up resistors (say 4.7k) on SDA and SCL would be a good idea also.

The sample sketch you have posted does not appear to set any bytes so it is behaving correctly. If you have written code to test a write operation to the chip, you should post that also (complete sketch).

Also make sure the WP (write protect) pin is connected to Vcc to enable write.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.