AT25SF081 Tutorial 03: Reading Memory Page


Now that we know how to read a single byte of data, let’s work on pulling back whole pages of data.


  1. Understand how to build a buffer to hold returned data.
  2. Learn how to craft a function to work with arrays.

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.

Reading AT25SF081 Memory Pages

Knowing how to pull a single byte of data is great, but since this thing can hold about a million bytes, chances are you’ll want to be able to work with larger quantities of data.

There is no great mystery on how to accomplish this. The AT25SF081 will send you one byte of data at a time, and do so sequentially as long as you keep sending it clock cycles. So if you’re reading the data back from byte 0x000003, you’ll get byte 4, then 5, then 6, etc. in turn as long as you keep sending junk data out on MOSI.

To accomplish this, we’ll need to make three structural changes to our code.

  1. We’ll need an array of bytes to hold the large chunk of bytes being returned from Flash.
  2. In order to keep things clean, we’d like to take all the commands necessary to read the data back and place them in their own function. This will also make reusing code much easier for later modules.
  3. Some method of displaying the returned values will be necessary too, so we’ll need a function to perform that as well.

Building a Buffer

Since we program the memory array in “pages” comprised of 256 bytes each, that seems like a reasonable size to make our buffer, and creating it is simple enough, byte pageData[256];. We now have an array of 256 bytes, ready to receive a full page of data.

You don’t pass the values of arrays back and forth between functions like you do with regular variables, you pass pointers to the array back and forth. That means our the functions that will receive the data and cram it into pageData and the one that will then spit that data out to the serial monitor will have to be coded specifically to accommodate that.

Building Functions

The functions that we need to make I’m going to call readPage and outputData. Nothing too inventive there.


For the readPage function, we’ll need to send it the starting memory array address to read from, and the pointer to the array we want it to load the data into. The address is called some24bitLocation and the array we declared above, pageData. When the function gets hold of it, the function will reference those as readAddress and memoryData.

When looking at how we create the function, pay attention to the fact that we’re saying it’s not going to return anything, that’s what the “void” means at the start. We’re passing the pointer to the pageData array and inside the function, we’ll be directly manipulating the values in that array, so there’s nothing to return.

We will still need a junk data byte to use, and the way we send the memory address is exactly the same as in the previous module.

What we need to change is very simple, instead of just reading back the single byte into a variable as we did before, we’re doing to read back single bytes, but do it 256 times in a row, relying on the fact that sending that junk byte over and over again to the AT25SF081 will cause it to read back the next byte, and then the next byte, and then the next byte, etc.

And, of course, all of that has to get wrapped with bringing chip select low and high. The final form of this function then looks like this.


Our output function is really just a bunch of formatted serial commands. We’ll pass it the pointer to the array just like we did for the readPage function.

The if statements at the top just say that if we’re reading back the first 100 bytes of data, add some extra whitespace to the output to the columns nice and clean. When you look at the code and see the output at the same time, it’ll make total sense.

Full Sketch

Here’s the sketch in full…

After uploading that, open up serial monitor to see the output. Remember since all the function calls are occurring in Setup, they’ll only be executed once.

Read Memory Page Output
Read Memory Page Output