03-20-2014 11:56 AM
I've just been through hell trying to get an FPGA to be able to write new configuration data to its SPI FLASH PROM, and I want to save people some of the pain I went through by sharing a couple of the tricks it took me longest to figure out.
I'm using a Spartan 6 FPGA with a Numonyx SPI FLASH (M25PX16). In my application, we want to update the firmware over Ethernet. The FPGA gets an .mcs file over Ethernet and writes it to the FLASH using SPI, then resets to load the new firmware.
One thing that isn't mentioned in the FLASH documentation is that you can only change 1's to 0's when writing data. You have to perform an erase, which sets all the bits in the targeted area to 1's, before writing data using a Page Program or Dual Input Fast Program instruction. Keep in mind that any instruction that changes FLASH data requires a Write Enable instruction first.
I encountered some really odd behavior where the FLASH would overwrite the first page of data with mostly zeroes when I power cycled it. This only happened when I had written the data to the FLASH using the FPGA - if I used Impact to program the FLASH, it worked just fine when I power cycled. I read back the data in the FLASH after programming with Impact, and it seemed to be identical to the data I wrote in with the FPGA. I checked the Block Protect (TB, BP2, BP1, and BP0 in the Status Register) and it was zeroed out - Impact hadn't locked down the data that way. I eventually set the Block Protect to lock down the data in the area of the FLASH I was using after I'd written to it, and that kept the FLASH from overwriting the first page after power cycling. I still have no idea what caused it to happen in the first place, or what I was doing differently from Impact, but using Block Protect seems to have fixed it. If anyone knows more about this one, I'd love to hear about it.
If you want to write an .mcs file directly to FLASH as opposed to a data-only format like .bin, you'll need to strip out the metadata. .mcs files have a short line at the beginning and end that will need to be stripped out. There is a short line every 4097 lines that will also need to be stripped out. The first 9 and last 2 characters of each line also need to be removed.
It's probably worth a quick summary of the write protection on this thing, since it's complicated and not well laid out in the documentation. There are three ways to lock down data - Block Protect, Lock Registers, and Hardware Protect.
Locks down a large section of the memory. This is non-volatile and will continue to keep data locked after a power cycle. Block Protect is defined by the Top/Bottom bit and BP2, BP1, and BP0 bits in the Status Register. Table 3 in the M25PX16 datasheet shows how they are used to protect different parts of the memory. Note that you can only protect a single contiguous area of the memory that is either at the beginning or end of the memory using Block Protect.
Block Protect is sometimes referred to as Software Protected Mode 2 (SPM2) in the datasheet.
Each sector has a lock register that prevents modification to that sector. The lock registers are volatile and are reset to an unlocked state on powerup. Each lock register contains a Sector Lock Down bit (b1) which prevents modification of the sector when set to 1. It can only be reset to 0 by a powerup.
Each Lock Register contains a Write Lock bit (b0) in addition to the Sector Lock Down bit. When set to 1, the Write Lock bit prevents the Sector Lock Down bit from being set. The Write Lock bit can be cleared by a Write to Lock Register (WRLR) instruction, which will allow you to set the Sector Lock Down bit with a second WRLR instruction.
The Lock Registers are sometimes referred to as Software Protected Mode 1 (SPM1) in the datasheet.
Hardware Protect mode is enabled when the W/Vpp pin on the FLASH is driven to 0, and the Status Register Write Disable (SRWD) bit in the Status Register is set to 1. When it is enabled, the contents of the FLASH cannot be modified and the Status Register cannot be modified. Note that the SRWD bit in the Status Register does nothing without the W/Vpp pin driven low.
There is also the Write Enable (WREN) instruction. Any instruction that modifies the contents of the FLASH memory or its registers must be preceeded by a Write Enable. The Write Enable instruction sets the Write Enable Latch (WEL) bit of the Status Register to 1. The WEL bit is cleared by any instruction that requires it, so you need to set it again with another WREN instruction before doing another instruction that needs a Write Enable.
If I remember anything else I had a particularly tough time finding a simple answer to, I'll post it. Good luck!
03-21-2014 02:39 PM
Some time ago I worked with a Spartan 3A DSP design that updated firmware over a serial port. The FPGA-based writes to the flash always locked the flash when they were finished. Then if I wanted to program using Impact I found that programming always failed because Impact never bothered to unlock the flash. I eventually added a command to the serial interface to just unlock the flash. Has Impact become smarter since then or have you found another way to deal with locked flash memory?
03-24-2014 07:22 AM
Impact 14.6 seems to be smarter. It can successfully program the FLASH when it is locked. When it finishes, it re-locks the FLASH if it was locked before, but doesn't lock the FLASH if it wasn't locked when it started.
I'm mostly doing FPGA-based memory writes anyway though, so I unlock it over SPI every time I write to memory.