Clock-synchronous operation (three-wire) of the serial peripheral interface (RSPI) and a single port are used for control. The quad serial peripheral interface (QSPI) which is set to clock-synchronous operation and a single port are used for control. RL78 Family, 78K Family Data can be read, written, and erased simply by calling user API functions. Accessing Serial Flash Memory Using SPI Interface 4 spiflashread This function reads the content from the serial flash. The data is read from the memory location specified by the first parameter. This address ranges from 0 to SPI flash size and is not the processor’s absolute range.
This is a small ATtiny84 based device to program I2C and SPI EEPROM chips over a serial port. As usual all code and schematics are available in GitHub.
Background
The TGL-6502 project uses an SPI EEPROM (the Microchip 25AA1024) to simulate the ROM exposed to the 6502 processor. To get the content into the ROM I added a simple serial protocol to the TGL-6502 firmware but as the firmware grew this functionality had to be dropped to free up some of the limited flash memory so I had to find an alternative method.
I considered using a generic tool such as the Bus Pirate to program the EEPROMS or even investing in a generic programmer (there are a wide range available on eBay that support various MCU chips as well as EEPROMs). In the end I decided to build my own - the EEPROM programming protocol is very straight forward and I would be needing it for future projects as well.
As well as supporting SPI devices I wanted to be able to program I2C EEPROMs as well (the Raspberry Pi HAT specification uses an I2C EEPROM to provide information about the expansion board) - at this stage the hardware for I2C support is in place but there is no firmware support for that protocol yet, I will add it as I need it.
Hardware Design
I am using an ATtiny84 in 14 pin DIP format as the main CPU for the project. This chip has enough IO lines to do everything needed, more than enough flash to allow for more complex firmware and is small enough to keep the board fairly compact. The circuit could easily be modified to use an ATmega though if that is what you have available.
The circuit is very simple, apart from the CPU the only other electrical components are three resistors and a diode. The first two resistors pull the I2C lines (SDA and SCL) high and the third pulls the ATtiny84 RESET line high. Rather than use a serial bootloader I added a 10 pin AVR ISP header on the board for programming the firmware, the diode is used to isolate the VCC lines from the ISP header and the FTDI connector.
The rest of the components are connectors, the 10 pin ISP header I mentioned, a 6 pin FTDI connector and an 18 pin ZIF (Zero Insertion Force) socket for mounting the target EEPROM in. Using the ZIF socket reduces the risk of damaging the pins on the EEPROM - I had an 18 pin socket in my parts collection already, you can swap it out for two 8 pin DIP sockets if you want.
The serial connection and power come from a 6 pin FTDI Friend connector. The ones I use are switchable between 3.3V and 5.0V so when programming 3.3V EEPROM chips I just ensure that I have the FTDI adapter switched to the correct voltage level.
Firmware Design
To make development a bit easier I am using an Arduino core for the ATtiny84 and the firmware is implemented as an Arduino sketch. There were a few hardware limitations of the ATtiny that needed to be worked around in software though.
The ATtiny doesn't have a UART so there is no hardware serial port support - the serial port needs to be implemented in software by driving the IO pins directly at the right time. I didn't have a lot of luck with the Arduino SoftwareSerial library, I could not get reliable serial communications working at any speed. I wound up migrating the serial implementation from my tinytemplate library for the ATtiny85 and using that instead which gives me reliable communications at 57600 baud.
The USI (Universal Serial Interface) module on the ATtiny is used to implement both I2C and SPI but you can only use one protocol at a time. This in itself is not a problem (you will only be programming an I2C or an SPI EEPROM, not both simultaneously) but some of the pins overlap (SCL and SCK for example) which would complicate the circuit and routing. Because SPI is a lot easier to simulate in software (using the shiftIn() and shiftOut() functions in the Arduino library) I reserve the USI module for I2C and selected the SPI interface pins based on how easy they were to route.
One problem I did have in this project is the timer interrupts - the Arduino library uses an interrupt triggered by TIMER0 for timing functions (delay(), millis() and the like). This interrupt seemed to be causing issues with the SPI communications so I disabled it in the init() function:
In this case I'm not using any of the timer functions so it doesn't effect the rest of the code.
The remainder of the firmware deals with memory buffer management and protocol handling. The current implementation takes up a little over 4K, around half of the available space, which leaves a lot of room for enhancements.
Control Protocol
The programmer is controled over a serial port (57600 8/N/1) using an ASCII ping/pong protocol. You send a command terminated by a line feed character and wait for a response terminated by a line feed character. The response must be received before the next command can be sent. There are 5 available commands, outlined below:
With the exception of RESET the first character of the response will indicate success ('+') or failure ('-') and there may be additional information between the result character and the end of the line. For the read command this is hex data, for other commands any additional characters can be treated as an informational message.
The details of each command are described below, you can use a serial terminal to talk directly to the programmer but don't include the '<' and '>' characters shown in the examples - they are used to indicate the direction of the data.
RESET
This should be the first command sent to the device - it will set the device into an idle state and ensure the power to the EEPROM slots is turned off. Unlike the other commands this one does not respond with a +/- success or failure indication - instead it reports the programmer identification string and the firmware version.
After receiving the reset command (and responding with the identity string) the programmer will go into IDLE mode.
INIT
This command is used to tell the programmer the type and specifications of the EEPROM it is dealing with. For each EEPROM we need to know a number of parameters:
- The EEPROM protocol - SPI or I2C.
- The size of the EEPROM. I use the number of bits in the address to determine this.
- The size of the EEPROM write page. This is the smallest amount of memory that can be written at once, once again I use the number of bits to determine the size (eg: a 32 byte page is 6 bits, 256 bytes is 8).
- The number of bytes of address to send on the SPI bus.
This information is encoded in a 16 bit integer as shown below.
The 16 bit value is sent as hex with the INIT command and the programmer will respond with success if the configuration is acceptable.
The following table shows the ID codes for some of the Microchip EEPROMs I have been using:
Part | Size | Page Size | Address Bytes | ID Code |
---|---|---|---|---|
25AA1024 | 1Mbit (128K x 8) | 256 bytes | 24 bit | 0x7830 |
25LC1024 | 1Mbit (128K x 8) | 256 bytes | 24 bit | 0x7830 |
25AA640 | 64Kbit (8K x 8) | 32 bytes | 16 bit | 0x4620 |
READ
Use this command to read data from the EEPROM. The command character is followed by a 3 byte address in hexadecimal and a successful response is the 3 byte address, a sequence of data bytes and a 2 byte checksum.
The checksum is simply a sum of all bytes in the response (excluding the checksum itself) and the lowest 16 bits of the value is used as the checksum. The code to do this looks like the following:
WRITE
This command is used to begin or continue a write sequence. Once the first write command has been accepted you can continue writing to sequential addresses or send a DONE command (described below) to finish the sequence and return to READY mode.
The format of the WRITE command is similar to the response from the READ command - a 3 byte address, a sequence of data bytes and a 2 byte checksum. The checksum is calculated in the same way as for READ - simply sum the byte values in the line into a 16 bit integer ignoring overflow.
Note that the write command will buffer data into RAM until it has a full page to write to the EEPROM - you must use the DONE command to terminate a write sequence to ensure all data has actually been written. If the buffer only contains a partial page the rest of the contents will be filled with whatever is already in the EEPROM allowing you to do partial page writes to patch the data in the EEPROM rather than doing a complete rewrite.
DONE
All write sequences must be terminated with this command. If there is a partial page still in the RAM buffer it will be filled with the current contents of the EEPROM and written. The command then returns to READY mode allowing you to issue READ commands or start another WRITE sequence.
The EEPROG Utility
The repository includes a simple Windows GUI utility to control the programmer in the software/eeprog directory.
You can compile this utility with the Visual Studio Community Edition - it's a simple Windows Forms application written in C#. The utility doesn't make use of all the functionality of the programmer - it simply allows you to burn an arbitrary binary file to the target EEPROM or read the contents of the EEPROM to a binary file. In most cases this will be all that you need.
Next Steps
The tool currently provides all the functionality I need to work on the TGL-6502 but there are obviously a few enhancements that can be made. So far I have only tested the device with Microchip SPI EEPROM devices which all have the same command set - supporting other manufacturers devices may require providing additional information in the EEPROM identity word to select alternative command sets.
Support for I2C devices is built in to the hardware but not yet implemented in the firmware. I intend to use the Arduino Wire library to communicate with these chips.
The programming utility for Windows could be extended to support Intel HEX format files as well as raw binary which would be useful for dealing with output from linkers. The ability to set the start address for programming would also come in handy rather than having to prepare a complete EEPROM image for every burn. More importantly a command line utility that could be incorporated into make files is a must.
All of these enhancements are relatively simple to implement and I will modify the code to support them as the need arises. If you make the changes yourself (or add interesting new functionality) please send me a pull request and I'll add them to the main repository.
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:
- About EEPROM chips and how they work
- SPI Protocol
- 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.
IN NO. | PIN NAME | I/O | FUNCTION |
1 | /CS | I | Chip Select Input |
2 | DO | O | Data Output |
3 | /WP | I | Write Protect Input |
4 | GND | – | Ground |
5 | DIO | I/O | Data Input / Output |
6 | CLK | I | Serial Clock Input |
7 | /HOLD | I | Hold Input |
8 | VCC | – | Power Supply |
Note: This chip is operated on 3.3V. Don’t apply 5V on it or it will just get fried up.
Spi Programmer Software
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:
Mode | Clock Polarity (CPOL) | Clock Phase (CPHA) | Output Edge | Data Capture |
SPI_MODE0 | 0 | 0 | Falling | Rising |
SPI_MODE1 | 0 | 1 | Rising | Falling |
SPI_MODE2 | 1 | 0 | Rising | Falling |
SPI_MODE3 | 1 | 1 | Falling | Rising |
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)
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:
How to read a single byte data from EEPROM
Function prototype
Usage example
Output
How to read a block data from EEPROM
Function prototype
Usage example
Output
How to download the entire EEPROM
Steps to download the content of EEPROM into a file:
- First, make download_rom() function only active and flash the sketch into your arduino.
- Configure serial port and baud rate in download_rom.py according to your arduino sketch.
- Press reset button in your arduino.
- Run download_rom.py by entering ‘python2.7 download_rom.py‘ in your terminal/cmd window.
- Now press ‘d‘ and hit enter in the prompt in your terminal/cmd window and wait for finish.
Function prototype
Usage example
Output
How to erase a 4KB block from given address in EEPROM
Spi Flash Memory Programmer
Function prototype
Usage example
Output
How to erase a 64KB block from given address in EEPROM
Function prototype
Usage example
Output
How to erase the entire EEPROM at once
Function prototype
Usage example
Output
How to write data to EEPROM
Function prototype
Usage example
Output
How to upload a ROM file to the EEPROM
Steps to upload a file from computer to the EEPROM:
- First, make upload_rom() function only active and flash the sketch into your arduino.
- Configure serial port and baud rate in upload_rom.py according to your arduino sketch.
- Run upload_rom.py by entering ‘python2.7 upload_rom.py‘ in your terminal/cmd window.
- Press reset button in your arduino.
- Enter the file path i.e. ‘/path/to/the/file.rom‘ and hit enter and wait for finish.
Function prototype
Usage example
Output
How to read manufacturer ID and device ID from EEPROM
Function prototype
Usage example
Output
According 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
8051 Spi Programmer
- https://media.digikey.com/pdf/Data%20Sheets/Winbond%20PDFs/W25X10A,20A,40A,80A.pdf – winbond W25X80A datasheet.
Have anything in your mind? Just comment below.
Hope you learn something!
Ch341a Spi Flash Programmer Software
Thank you.