Using a SPI DataFlash

Memory chips used to be a pain with all their address and data lines, but no more. Today I hooked up the 32 Mbit DataFlash (an Atmel AT25DF321A in case you skipped my previous post) to the Bus Pirate and I can barely believe how easy it was. Here’s a shot of the entire setup:

All you need to do it hook up the SPI lines and apply 3,3V power. As a first test requesting it’s manufacturer and device ID seemed logical:

SPI>[0x9f r:4]
/CS ENABLED
WRITE: 0x9F
READ: 0x1F 0x47 0x01 0x00
/CS DISABLED

Only 4 bytes are returned, but it indicates the chip is working as it should be. The first byte (0x1F) means Atmel is the manufacturer. The 2nd and 3rd byte hold device information and exactly match the datasheet (AT25DF series with 32-Mbit density). The last byte is optional according the JEDEC standard and appears to be unused. Well this confirmed things were working, so next would be reading and writing data.

Well…. easier said than done. Eagerly I went right to the writing part, but that didn’t work as the device is protected by default. Individual sectors can be protected, but there’s also a global protection which is enabled by default. To see what the status of this protection is, issue a read status register command:

SPI>[0x05 r:2]
/CS ENABLED
WRITE: 0x05
READ: 0x1C 0x00
/CS DISABLED

Bits 3:2 indicates global protect is enabled, so we need to disable it. Some bit in the status register can be written to and to disable global protect 0×00 must be written. However it can’t be done right away. All writes to the devices are ignored unless writing is enabled first. So before each write cycle the write enable command must be issued:

SPI>[0x06]
/CS ENABLED
WRITE: 0x06
/CS DISABLED

The WEL bit in the status register changes accordingly (note that the WEL bit is cleared after each write attempt (successful or failed)):

SPI>[0x05 r:2]
/CS ENABLED
WRITE: 0x05
READ: 0x1E 0x00
/CS DISABLED

Now perform a global unprotect:

SPI>[0x01 0x00]
/CS ENABLED
WRITE: 0x01
WRITE: 0x00
/CS DISABLED

Check the status register to be sure it worked (should be 0×10 0×00). Keep in mind that global protecting is restored after a power cycle.
Next I wanted to do a full erase to make sure no garbage data would screw up testing. Fully erasing the chip is as easy as sending a enable writing, send the chip erase command (0×60 or 0xC7) and wait till the busy bit clears:

SPI>[0x06]
/CS ENABLED
WRITE: 0x06
/CS DISABLED
SPI>[0xC7]
/CS ENABLED
WRITE: 0xC7
/CS DISABLED

I’ve specifically used 0xC7 and not 0×60 to make it easier to differentiate between erasing and enabling writing (e.g. 0×60 and 0×06 typos are easy to overlook). Erasure will take a couple of seconds, so be sure to check the busy flag by reading the status register. It takes long enough for me to manually enter the command while getting a busy in return (also note the WEL bit is still set):

SPI>[0x05 r:2]
/CS ENABLED
WRITE: 0x05
READ: 0x13 0x00
/CS DISABLED

Once the erase chip command has finished the status register returns to its idle state:

SPI>[0x05 r:2]
/CS ENABLED
WRITE: 0x05
READ: 0x10 0x00
/CS DISABLED

At this point the chip is fully erased (filled with 0xFF) and ready to be used for data storage. To test this just write some data to it. First enable writing again by setting the WEL bit:

SPI>[0x06]
/CS ENABLED
WRITE: 0x06
/CS DISABLED

Optionally you could check the status register:

SPI>[0x05 r:2]
/CS ENABLED
WRITE: 0x05
READ: 0x12 0x00
/CS DISABLED

Now do the actual writing:

SPI>[0x02 0x00 0x00 0x00 0x73 0x63 0x68 0x69 0x6A 0x66 0x2E 0x6F 0x72 0x67]
/CS ENABLED
WRITE: 0x02
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0x73
WRITE: 0x63
WRITE: 0x68
WRITE: 0x69
WRITE: 0x6A
WRITE: 0x66
WRITE: 0x2E
WRITE: 0x6F
WRITE: 0x72
WRITE: 0x67
/CS DISABLED

Optionally you can read the status register to see if anything went wrong. Bit 5 indicates an erase or program error.

SPI>[0x05 r:2]
/CS ENABLED
WRITE: 0x05
READ: 0x10 0x00
/CS DISABLED

In this case no errors occurred. Now read back what was just written (the status register will not change):

SPI>[0x03 0x00 0x00 0x00 r:10]
/CS ENABLED
WRITE: 0x03
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
READ: 0x73 0x63 0x68 0x69 0x6A 0x66 0x2E 0x6F 0x72 0x67
/CS DISABLED

That’s it for now, till next time.

Comments are closed.