AT25SF081 Tutorial 05: Erasing Memory


We can Read and we can Write, so now let’s Reset…


  1. Understand what a block is.
  2. Understand what block sizes can be erased.
  3. Determine which opcodes are used to erase various block sizes.

AT25SF081 Tutorial 02: Reading Memory Byte
SPI Signals
Adesto AT25SF081 Datasheet

Education Shield – AT25SF081 Flash Memory Subsystem

For this module, you’ll need the following equipment:

1. Mate the Education Shield with your Arduino UNO R3. If you’re using the AT25SF081 Flash Memory Breakout Board, connect 5V to 5V, 3V3 to 3.3V, GND to GND, HOLD to Digital09,CS to Digital10, MOSI to Digital11, MISO to Digital12, and CLK to Digital13. That’s a lot of pins!

2. Connect your Arduino to your USB cable, and use the Arduino IDE to upload the “Bare Minimum” sketch from the Basics section of the Examples.

Working with the HOLD pin is not necessary for any of the tutorials, it is only included on the breakout board for completeness. In the sketch it will always be set as an output in a high state, and on the I2C and SPI Education Shield, the pin is tied directly to the 3V3 rail on the PCB.

Memory Array Blocks

Similar to how the bytes of your memory array are arranged in pages when you program the AT25SF081, the erase commands deal with arrangements of bytes called blocks. The block sizes comprise 4K bytes, 32K bytes or 64K bytes in size, and each block size has an associated erase opcode associated with it. If you’re feeling really frisky, you can erase the entire chip at once as well using that dedicated opcode.

  • 4K Erase: 0x20
  • 32K Erase: 0x52
  • 64K Erase: 0xD8
  • Chip Erase: 0x60 or 0xC7

Arranging the bytes into blocks allows for faster erase times and simplifies the internal structures of the chip. If you think back to what it takes to make a crude single bit register using discrete logic, imagine that on a scale of millions and you’ll swiftly see the amount of stuff that would have to be crammed into a chip that small in order to allow erasing each byte of memory individually.

AT25SF081 Organization By Block
AT25SF081 Organization By Block

Since erase operations occur exclusively on a block level, that means choosing to erase a single byte, regardless of where it appears within that block, will cause the entire block to be erased with it. Just like you need to be cognizant of how much data you want to program to the byte and where you’re starting to write it to with a mind to avoiding problems with overwriting data within a page, you have to be aware of what other data is vulnerable within a block of memory when you apply one of the erase opcodes on it.

Just like the read, and program commands, the erase commands necessarily requires you to supply a starting address for the operation. However, unlike the others which start at the specified byte, the erase opcodes will interpret any of the least significant bits that correspond to some address in the middle of the block, as zero. This forces the command to always be executed at the starting threshold of the block.

In the example below, you can see that a starting address of 0x0E8FE1 was used for the 4K erase command, but the chip does the equivalent of logically anding that address with 0xFFF000 to only keep the parts of the address that indicate the start of that block.

AT25SF081 Block Erase Logic
AT25SF081 Block Erase Logic

For a 32K erase, the internal logical and mask would be 0xFF8000.
For a 64K erase, the internal logical and mask would be 0xFF0000.

AT25SF081 Internal Block Address Mask
AT25SF081 Internal Block Address Mask

Writing an Erase Function

The code to erase blocks of the chip is very nearly the same as that used to program the chip. You first set the WEL bit, then send the erase opcode for the size you want to zap, and then the starting block address. That’s all. As soon as you bring the chip select pin high after sending the block address, the chip will begin the erase cycle.

All you have to do is shoehorn that function into the code from the program tutorial (in this case I have replaced the program code with the erase code) and the sketch is ready to go.

Upload up the sketch, open the serial monitor and press the latch button to see the before and after execute just as it did with the program command.

Final Note on Timing

In the previous sketch, we create the checkStatus function, which determined the state of the RDY/BSY bit in the first status register byte. The time it takes to write a single byte of data, though, is a mere 5µs, which is shorter than it takes for us to actually execute a digitalWrite command.

The time it takes to execute a block erase though, is much longer…

CommandOpcodeTypical TimeMax TimeUnit
4K Erase0x2030300ms
32K Erase0x523001300ms
64K Erase0xD85003000ms
Full Chip Erase0x601220seconds
Full Chip Erase0xC71220seconds

The time scale ramps up quickly into the range of multiple seconds, which is an eternity in microcontroller timescales. If you had eliminated the checkStatus function in your byte program sketch, you would most likely never notice it, but if you do that with this sketch, you’ll get some unpredictable results. It’s worth a try to comment out the checkStatus function call in the button press routine just to see what happens.

As you begin to erase larger portions of memory, or write more data as the case may be, that checkStatus function becomes ever more important, and needs to grow a bit in sophistication to handle the delays intelligently.