How to Use Serial EEPROM for Storing Data
2019-06-19 | By Maker.io Staff
In a previous How-To, we looked at how an Arduino Mega 2560 can be used to interface with a Parallel EEPROM memory chip. In this How-To, we will look at how an Arduino can use an I2C serial EEPROM for storing and retrieving data.
BOM
- 1 x Arduino Uno – 1050-1040-ND
- 1 x 24LC01B - 24LC01B-I/P-ND
- 2 x 1K Resistor - CF14JT1K00CT-ND
- 1 x Wire - 1471-1232-ND
- 1 x Breadboard - BKGS-400-ND
Scheme-It
Serial Memory
The previous How-To looked at parallel memory, which accesses data one byte at a time. Serial memory, however, accesses that same byte one bit at a time, potentially making serial memory slower than parallel memory (this, however, depends on many factors, including maximum clock speeds, trace routing, etc.).
While most parallel memories are accessed in a near-identical method (with the use of WE, CS, and OE pins), serial memories are not as uniform and come in many different styles. For example, the access protocol for a memory device may differ between manufacturers (I2C, SPI, etc.), or serial memory chips may have different pin arrangements. In this How-To, we will look at the 24LC01B, which is an I2C-accessed serial EEPROM.
I2C Memory Pins
I2C memory is often found in 8-pin packages with the following pins:
- VCC / VSS – Power-providing pins
- Ax – Device selection pins
- SCL – Serial Clock
- SDA – Serial Data
- WP – Write Protect
It might seem like the device selection pins (A0, A1, and A2) are address pins like those found in parallel memories, but these are, in fact, device selection pins. The majority of I2C devices have unique address identifiers that allow them to all be connected to the same data bus and keep the number of wire connections as low as possible. However, it is very plausible for a device to incorporate more than one of the same I2C devices (such as memory chips that require more storage space). Since identical devices have the same I2C IDs, we can’t select individual devices.
I2C devices have address pins, however, that allow them to have a “sub ID” whose value is equal to the state of the address pins. For example, if all the address pins are connected to ground, then the I2C device will have a sub ID of 0; if all the address pins are connected to power, then the device will have a sub ID of 7. Many designs will only have one I2C memory device, so all the address pins can be connected to grounds, but if more than one is needed, each I2C device requires a unique address configuration.
The SCL pin is used to connect to the Master Serial Clock, which is produced by the microcontroller (in our case the Arduino Uno (Leonardo)), while the SDA pin is used for bi-directional data between the memory chip and the microcontroller. Both of these lines require a pull-up resistor: in our circuit, we use 1K resistors.
The WP pin is used to protect the memory chip from accidental writes, which may be useful if the chip stores vital information such as user ID, usernames, passwords, etc. When this pin is connected to ground, the chip can be written to, but when it is connected to VCC, it cannot.
I2C Memory Protocol
Control Byte
Any transaction with a serial memory requires a control byte, which is made up of 8 bits.
- The first four bits are 1010 for I2C serial EEPROM memories produced by Microchip
- The next three bits are the value of the address pins
- The last bit is the read / write bit (0 = write 1 = read)
Write Byte
Writing bytes to a serial EEPROM is very simple and only requires three bytes; the write control byte, the address to write to, and the data byte.
Read byte
Reading a byte from a serial EEPROM is more complex than writing a byte as the address to read from needs to be first written. The first byte is a write control byte, which is then followed by the address that will be read from. However, a repeated start condition is sent, and then a read control byte is sent. The next byte after this control byte is the data found at that location.
Arduino Example
#include <Wire.h> byte dataByte = 0x5A; void setup() { Wire.begin(); // join i2c bus (address optional for master) } void loop() { // ************************************************************** // EEPROM WRITE // ************************************************************** Wire.beginTransmission(B10100000); // Send command to write to device id 0 Wire.write(0x00); // Set address pointer to address 0x00 Wire.write(dataByte); // Save this data byte to address 0x00 Wire.endTransmission(); // We have now written the byte // ************************************************************** // EEPROM READ // ************************************************************** Wire.beginTransmission(B10100000); // Send command to write to device id 0 Wire.write(0x00); // Set address pointer to 0x00 Wire.requestFrom(B1010000, 1); // Send a read command dataByte = Wire.read(); // Store received byte into dataByte variable Wire.endTransmission(); // End transmission }
Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.
Visit TechForum