SPIFI Command Mode to Memory Mode

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

SPIFI Command Mode to Memory Mode

959 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by ArriaLive on Wed Aug 27 01:06:38 MST 2014
I discovered last week that when I ran XIP code over SPIFI during a debug session, I could pretty much get full quad mode at 104MHz.  But outside of the debugger, SPIFI was running far slower--in SDR mode, and 50MHz was the max I could squeeze out of it.  Performance dropped from 52MB/s to 6MB/s.

I discovered that this was because the debugger puts the flash in quad mode, but without the debugger, my code was not putting it in quad high-performance mode.  Makes sense.

So, I've spent the last week trying to get the flash into high performance mode, but I continue to fail at that effort.  The problem is that when I put the SPIFI interface into memory mode, the memory essentially disappears.  Here's an example of a simple routine:

Memory at 0x14000000 at start of routine:

0x14000000 - 10020000 140004FD 1400018D 14000191 14000195 14000199 1400019D 00000000 00000000 00000000 
0x14000028 - 00000000 140001A1 140001A5 00000000 140001A9 14009C25 140001B1 140001B1 10000079 00000000 
0x14000050 - 140001B1 1000011D 140001B1 140001B1 140001B1 140001B1 140001B1 140001B1 140001B1 140001B1 
0x14000078 - 140001B1 140001B1 140001B1 140001B1 140001B1 140001B1 140001B1 140001B1 140001B1 140001B1

clearly showing what appears to be a vector table.  Then I execute the following sequence simply going from memory mode to command mode and back again:

------------------
__disable_irq(); // Disable IRQs

    SCnSCB->ACTLR &= ~2; // disable Cortex write buffer to avoid exceptions when switching back to SPIFI for execution

tempmemcmd = LPC_SPIFI->MEMCMD;

    /* check for memory mode.  If not there, reset */
    if (LPC_SPIFI->STAT & SPIFI_STAT_MCINIT) { // In memory mode? MCINIT bit is bit 0

    LPC_SPIFI->STAT = SPIFI_STAT_RESET; // Go to command mode
        while(LPC_SPIFI->STAT & SPIFI_STAT_RESET); // wait for reset to complete
    }

LPC_SPIFI->MEMCMD = tempmemcmd;
-------------------

At the end, all 8 SPIFI registers look EXACTLY as they did at the beginning.  After the reset, the MCINIT bit is 0 as expected.  After the MEMCMD, the MCINIT bit goes to 1 as expected.  All the registers look right, but the memory itself does not.  Here's what that same segment of flash memory looks like at the end of that short sequence:

0x14000000 - 00000000 00000000 CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC 
0x14000028 - CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC
0x14000050 - CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC
0x14000078 - CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC

Obviously something is wrong.  All the flash data is essentially gone.  Any attempt to XIP anywhere in flash after this, of course, creates a hard-fault exception.

I must be missing something somewhere.  Why is the flash going away?  Am I missing a register setting or some other requirement?  I've scoured the documentation for both the processor and flash.  I've searched the forums and googled everything I could think of.  But I have not found an answer.

Anyone have any ideas?  Thank you in advance for the guidance!

Processor: LPC4330
Flash:  Spansion S25FL256S

EdA
Labels (1)
0 Kudos
1 Reply

656 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by ArriaLive on Fri Aug 29 13:02:16 MST 2014
So, I will answer my own question.  I kept working at this until I figured out what was going on.

The flash memory was not disappearing, it was just having access trouble.  It turns out that you can't simply "put the system back in memory mode" setting the registers as they were--at least not if you're using "no opcode" high-performance mode.  For high-performance mode, here are the steps I used (this example uses a Spansion part).  Note that this is different than the examples in the SPIFI library!:

1. Set the intermediate code to 0xA5.  During the actual memory read command (coming up next), this intermediate code tells the flash memory that the *next* request will not be sending an opcode, just the address.

2. Send one "real" memory request using the CMD register, with the desired opcode.  The frameform must use the opcode-with-address (either 3 or 4 byte) option, and the ADDR register needs to be set to something.  Zero is fine.  DATALEN should also be 0.  This CMD makes the initial memory request using the opcode, then sends the intermediate code telling the flash memory what to expect with the *next* request.  This is the key--get that intermediate code registered with the flash so that subsequent requests are address-only (saving 8 clock cycles per request).  Also, make sure to monitor the STAT register to make sure this CMD has completed prior to going on to the next step.

3. Send the MEMCMD the actual code you want the memory to use in memory mode.  The opcode should be the same as you sent in #2 above, but the frameform must be the no-opcode-with-address flag (either 3 or 4 byte addressing).  The intermediate data should always remain 0xA5 to tell the flash memory (again) that the next request will not use an opcode again.  This MEMCMD puts the SPIFI in memory mode.

When doing this (and getting the CTRL register set up correctly), I have successfully gotten back in to high-performance memory mode with all addresses in memory looking correct, with XIP working as well.  Note that I used the Spansion "EC" opcode for 4-byte addressing and quad-speed addressing, intermediate, and data communications.

I hope this helps others to understand some of the complexity of SPIFI setup.

EdA
0 Kudos