How to READ/WRITE SPI based Serial EEPROM using Arduino Uno (e.g. winbond W25X80A)

How to READ/WRITE SPI based Serial EEPROM using Arduino Uno (e.g. winbond W25X80A)

Hello everyone,

In this post, you will find how to READ/WRITE SPI based serial EEPROM chips like winbond W25X10A / W25X20A / W25X40A / W25X80A, Atmel AT25HP256 / AT25HP512, etc. using Arduino Uno. Same can be done with other Arduino boards also.

I was little “Bit” off and I saw a dead desktop motherboard (ASUS P5KPL-AM/PS) lying around and covered by heavy dust underneath my sofa. Instantly, playing with these little bits instead – came to my mind. It has a winbond W25X80A EEPROM BIOS chip. I was working with Arduino and decided to play with the EEPROM chip. Long before this, I already have faced the problem that when one need to read/write a BIOS chip but do not have any external EEPROM programmer. May be you are one of them as well. If you are one of them or you want to learn how to read/write a serial EEPROM chip just by using any Arduino development board, keep reading.

By reading this article, you’ll learn the following things:

  1. About EEPROM chips and how they work
  2. SPI Protocol
  3. Serial communication between Arduino and computer using python pyserial

Winbond W25X80A is a 8mbit or 1MB EEPROM chip and it is very common to find. It has 8 pins like below and many EEPROM chips has exactly same pin configuration.

winbond EEPROM - W25X10A, W25X20A, W25X40A, W25X80A2 pin configuration
winbond EEPROM – W25X10A, W25X20A, W25X40A, W25X80A2 pin configuration

IN NO.PIN NAMEI/OFUNCTION
1/CSIChip Select Input
2DOOData Output
3/WPIWrite Protect Input
4GNDGround
5DIOI/OData Input / Output
6CLKISerial Clock Input
7/HOLDIHold Input
8VCCPower Supply

Note: This chip is operated on 3.3V. Don’t apply 5V on it or it will just get fried up.

Pins and their functions

Chip Select (/CS)

The SPI Chip Select (/CS) pin enables and disables device operation.
The /CS input must track the VCC supply level at power-up. If needed a 10kΩ pull-up resister on /CS can be used to accomplish this.

Serial Data Output (DO)

The SPI Serial Data Output (DO) pin provides a means for data and status to be serially read from (shifted out of) the device. Data is shifted out on the falling edge of the Serial Clock (CLK) input pin.

Write Protect (/WP)

The Write Protect (/WP) pin can be used to prevent the Status Register from being written.

HOLD (/HOLD)

The Hold (/HOLD) pin allows the device to be paused while it is actively selected.

Serial Clock (CLK)

The SPI Serial Clock Input (CLK) pin provides the timing for serial input and output operations.

Serial Data Input / Output (DIO)

The SPI Serial Data Input/Output (DIO) pin provides a means for instructions, addresses and data to be serially written to (shifted into) the device. Data is latched on the rising edge of the Serial Clock (CLK) input pin.

What is SPI (Serial Peripheral Interface)

SPI or Serial Peripheral Interface is a synchronous serial data transfer protocol used by microcontrollers for communicating with one or more peripheral devices. Two or more microcontrollers can communicate with one another with SPI also. Each SPI devices has three common lines and one device specific line as following:

  • MISO (Master In Slave Out) – The Slave line for sending data to the master. In our case its DIO or Data Input Output.
  • MOSI (Master Out Slave In) – The Master line for sending data to the peripherals. In our case its DO or Data Output.
  • SCK (Serial Clock) – The clock pulses which synchronize data transmission generated by the master. In our case its CLK.
  • SS (Slave Select) – the pin on each device that the master can use to enable and disable specific devices. In our case it is /CS or Chip Select Bar (active low).

When a device’s Slave Select pin is low, it communicates with the master. When it’s high, it ignores the master. This allows you to have multiple SPI devices sharing the same MISO, MOSI, and CLK lines.

Modes of operation

SPI has four modes of operation, combine polarity and phase according to this table:

ModeClock Polarity
(CPOL)
Clock Phase
(CPHA)
Output EdgeData Capture
SPI_MODE000FallingRising
SPI_MODE101RisingFalling
SPI_MODE210RisingFalling
SPI_MODE311FallingRising

As per datasheet, our winbond W25X80A EEPROM chip works with both SPI_MODE0 and SPI_MODE3 i.e. raising edge of the clock.

More details on Arduino SPI operations can be found here: https://www.arduino.cc/en/Reference/SPI

Logic level conversion (5V to 3.3V)

As we are using Arduino Uno R3, by default we have 5V logic along with one 3.3V output power line. We must convert Arduino’s 5V logic outputs to 3.3V otherwise the EEPROM chip will be fried in very short time. As this is just for sending binary logic signals i.e. 1 (true) or 0 (false), not for powering up a device – few milliampere of current will be absolutely fine. Hence, a simple voltage divider will do the job done. In a 0-5V logic system, below 2.5V means 0 and above 2.5V means 1. For the EEPROM’s output pins – they are already 3.3V i.e. much higher than 2.5V of threshold. So, there will be no problem detecting 3.3V as 1 (true) and 0V as 0 (false) in the Arduino. If you use a Arduino board that operate on 3.3V, just ignore all these precautions.

Schematic (pin connections)

 

 

SPI Based EEPROM Reader Writer for winbond EEPROMs – W25X10A, W25X20A, W25X40A, W25X80A2 Schematic

Link to the schematic: https://easyeda.com/arp14/spi-based-eeprom-reader-writer

List of components needed

  • Arduino Uno
  • winbond W25X10A/W25X20A/W25X40A/W25X80A EEPROM
  • 100 Ω resistor x3
  • 220 Ω resistor x1
  • 1k Ω resistor x1
  • Jumper wires
  • Breadboard

Pin map from EEPROM chip to Arduino

  • Arduino 3.3V to EEPROM pin 8 (VCC)
  • Arduino 3.3V to EEPROM pin 3
  • Arduino 3.3V to EEPROM pin 7
  • Arduino GND to EEPROM pin 4 (GND)
  • Arduino pin 10 to EEPROM pin 1
  • Arduino pin 11 to EEPROM pin 2
  • Arduino pin 12 to EEPROM pin 5
  • Arduino pin 13 to EEPROM pin 6

Note: Don’t forget to convert logic level 5V to 3.3V.

Various functions to read/write to/from EEPROM

Full source code can be found on my GitHub page:

https://github.com/Cyberster/Arduino-SPI-EEPROM-Reader-Writer

How to read a single byte data from EEPROM

Function prototype

byte read_eeprom(long EEPROM_address);

Usage example

byte data = read_eeprom(0x0000FF); // 0x000000 to 0x100000
Serial.println(data, HEX);

Output

Read EEPROM

How to read a block data from EEPROM

Function prototype

void read_block(long starting_address, int block_size, int block_count, boolean fastread);

Usage example

// read data, block_size columns (bytes) in a row, block_count rows
read_block(0x000000, 16, 10, true);

Output

Read an entire block

How to download the entire EEPROM

Steps to download the content of EEPROM into a file:

  1. First, make download_rom() function only active and flash the sketch into your arduino.
  2. Configure serial port and baud rate in download_rom.py according to your arduino sketch.
  3. Press reset button in your arduino.
  4. Run download_rom.py by entering ‘python2.7 download_rom.py‘ in your terminal/cmd window.
  5. Now press ‘d‘ and hit enter in the prompt in your terminal/cmd window and wait for finish.

Function prototype

void download_rom(boolean fastread);

Usage example

download_rom(true);

Output

ROM download result
How to erase a 4KB block from given address in EEPROM

Function prototype

void sector_erase(long address);

Usage example

// erase 4kB from given address
sector_erase(0x000000); 

Output

Sector erase

How to erase a 64KB block from given address in EEPROM

Function prototype

void block_erase(long address);

Usage example

// erase 64kB from given address
block_erase(0x000000);

Output

Block erase

How to erase the entire EEPROM at once

Function prototype

void chip_erase();

Usage example

// erase the entire EEPROM chip
chip_erase();

Output

Chip erase

How to write data to EEPROM

Function prototype

void write_eeprom(long address, byte data[], int data_size);

Usage example

// write data to the EEPROM
byte buffer[256];
for (int i = 0; i < 256; i++) {
  buffer[i] = i; // filling buffer with 0-255
}
// buffer size must be 1 to 256
// EEPROM can only be written if empty i.e. filled with 1's
// use appropriate erase function before writing anything
write_eeprom(0x000000, buffer, 256);

Output

Write eeprom

How to upload a ROM file to the EEPROM

Steps to upload a file from computer to the EEPROM:

  1. First, make upload_rom() function only active and flash the sketch into your arduino.
  2. Configure serial port and baud rate in upload_rom.py according to your arduino sketch.
  3. Run upload_rom.py by entering ‘python2.7 upload_rom.py‘ in your terminal/cmd window.
  4. Press reset button in your arduino.
  5. Enter the file path i.e. ‘/path/to/the/file.rom‘ and hit enter and wait for finish.

Function prototype

void upload_rom();

Usage example

// upload data from file to the EEPROM
upload_rom();

Output

Upload rom

How to read manufacturer ID and device ID from EEPROM

Function prototype

void get_device_info(byte &manufacturer_id, byte &device_id);

Usage example

// read manufacturer id and device id
byte manufacturer_id;
byte device_id;
get_device_info(manufacturer_id, device_id);
Serial.println(manufacturer_id, HEX);
Serial.println(device_id, HEX);

Output

Get device informationAccording to the Manufacturer and Device Identification table in the winbond W25X80A datasheet, EF is “Winbond Serial Flash” and 13 is “W25X80A“.

Conclusion

Yes, we can flash a standard BIOS chip with Arduino. It was fun to play with bits, specially – seeing first byte fetched from the EEPROM was just amazing. From now, I am a worry-free person from a bad BIOS flash 🙂

Motivation

References

Have anything in your mind? Just comment below.

Hope you learn something!

Thank you.

Leave a Reply

Note: Your email address will not be published. Required fields are marked *