Parallel QuadSPI

cancel
Showing results for 
Search instead for 
Did you mean: 

Parallel QuadSPI

4,655 Views
NXP Employee
NXP Employee

We've been helping one of our alpha customers with using QuadSPI in parallel mode on Vybrid, so I wanted to create a thread about some helpful tips when trying to do the same. There will be a parallel mode booting example in the next release of the sample code.

 

  • Vybrid has two QuadSPI modules: QuadSPI0 and QuadSPI1. QuadSPI0 then has two QuadSPI ports associated with it: QuadSPI0_A and QuadSPI0_B. This lets you use the QuadSPI flashes connected to those ports in parallel. QuadSPI1 only has one port, and thus parallel mode cannot be used with it. So in summary, there are two modules on Vybrid, capable of interfacing with up to 3 flashes in all, but only QuadSPI0 can do parallel mode.

 

  • Parallel mode is enabled by setting QuadSPI_BFGENCR[PAR_EN]=1. When set, the data at offset 0x200 of each QuadSPI would be read at offset 0x400 when combined. This is very important to keep in mind when programming data into each flash.

 

  • Each flash in parallel mode holds a nibble (4 bits) of data from each byte. The way that data is split is a somewhat complicated, and so it's very important to properly split the data that ends up being programmed in each of the two flashes. The sample code contains a function split() which does this a word (2 bytes) at a time. The code is attached. It takes a source memory address, and outputs each half into the two destination memory addresses.

 

  • After programming the flashes, put the QuadSPI into parallel mode, and make sure the data you read back from the memory window matches what you think you should have. This will double check your programming and splitting algorithms.

 

Parallel Booting:

  • The QuadSPI boot header must be programmed into only *one* flash connected to QuadSPI0_A. The BootROM reads this configuration data, and only then puts the QuadSPI in parallel mode. So all other boot data and code after that must be programmed as if being read in parallel mode. What this ends up meaning is that you need three programming passes:
    1. Program the QuadSPI boot header into QuadSPI0_A flash at offset 0x0
    2. Program the split data starting at offset 0x200 (per the sample code) into QuadSPI0_A
    3. Program the split data starting at offset 0x200 (per the sample code) into QuadSPI0_B.

          The sample code will show this being done.

 

  • There are only a few minor changes in the QuadSPI boot header necessary.
    1. Set the "Parallel Port Enable" field
    2. Make sure the "Flash B1 Size" field is properly sized
    3. Make sure the "Port B Enable" field is set

 

  • There should be no other code changes necessary if you already have single QuadSPI flash boot working.

 

     Debugging Tips:

  • Make sure the data read back in parallel mode when you program the flashes match the binary you're trying to boot (except for the boot header section, which will look incorrect when read in parallel mode since it was only programmed into the single QuadSPI0_A flash).
  • Make sure the code works in single flash mode still
  • Make sure your IO Mux config isn't turning off the QuadSPI0_B pins.
  • As with any boot debugging, try turning on an LED as one of the very first instructions. If you reach there, showing you did boot successfully, then keep moving it back through your code until you find the spot it crashes on.

Original Attachment has been moved to: split.c.zip

48 Replies

47 Views
Contributor I

Hi

I am working on PARALLEL QSPI for Vybrid Custom Board and currently unable to boot the board (When image was flashed for non-parallel mode, Boot is successful) Here is my QSPI configuration

const SFLASH_CONFIGURATION_PARAM quadspi_conf __attribute__ ((section ("conf")))= {

  0,                      /* Reserved 0 */

  0,                      /* Hold Delay for QSPI[0,1] A/B */

  0,                      /* Select sampling at non-inverted clock */

  0,                      /* One Clock cycle delay */

  0,                      /* Reserved 1 */

  {0,                     /* Reserved 2 */

  0,                      /* Reserved 3 */

  0},                     /* Reserved 4 */

  0,                      /* cs_hold_time */

  0,                      /* cs_setup_time */

  0x1000000,              /* A1 flash size - 16MB (This is not a dual die flash) */

  0,                      /* A2 flash size (This is not a dual die flash) */

  0x1000000,              /* B1 flash size - 16MB` (This is not a dual die flash) */

  0,                      /* B2 flash size (This is not a dual die flash) */

  3,                      /* SCLK Frequency (0-18MHz, 1-60MHz, 2-74MHz, 3-104 MHz (SDR Mode) ) */

  0,                      /* Reserved 5*/

  4,                      /* Quad Mode Flash (4-bit) */

  1,                      /* Port A is always available. This field informs the device ROM the availability of Port B. 0 - Port B is not used. 1 - Port B is used */

  0,                      /* Dual Data Rate (DDR) Mode Disable */

  0,                      /* Data Strobe signal (DQS) Disable */

  1,                      /* Parallel Mode Disable (This field enables the device ROM to configure the QSPI interface

                             in parallel mode. Data will be read from serial Flash in parallel mode. ) */

  0,                      /* Disable Port A CS1 */

  0,                      /* Disable Port B CS1 */

  0,                      /* FS Phase (Select sampling at non-inverted clock) */

  0,                      /* FS Delay (One clock cycle delay) */

  0,                      /* DDR Sampling (Select the sampling point for incoming data when serial flash is in DDR mode) */

  /* LUT Programming */

  /* Quad read*/

  {0x04EB,   /* Instruction - (CMD-1)       || 1 - Pads || QIOR - Quad IO Read (3 or 4-byte address) */

   0x0A18,   /* Instruction - (ADDR-2)      || 4 - Pads || 24 bit address */

   0x12A5,   /* Instruction - (MODE-4)      || 4 - Pads || Remain in QIOR */

   0x0E04,   /* Instruction - (DUMMY-3)     || 4 - Pads || 4 Dummy Cycles */

   0x1E80,   /* Instruction - (READ-7)      || 4 - Pads || 128 Bytes */

   0x2401}   /* Instruction - (JMP_ON_CS-9) || 1 - Pads || to 1 */

};

Is these settings correct?

In my programme of flashing the binary image, I have adapted the following scheme.

#define  HEADER_SIZE 2048 // Also checked for 512

1. Split the original image (total_image_size-HEADER_SIZE) into "d1" and "d2" arrays

2. Copy Boot Configuration Header of "HEADER_SIZE" Bytes [1024 + 32 + 16 + 976 i.e. conf + IVT + boot_data_qspi + DCD] into "h_d" array from original image

3. Copy the "d1" array into "h_d" (after header). Now "h_d" contains Boot Configuration Header of "HEADER_SIZE" Bytes and then "d1" array

4. Flash "h_d" into Flash A

5. Flash "d2" into Flash B (start at HEADER_SIZE of Flash i.e. 0x21000800)

6. Set the Quad Bit to 1 in Flash Configuration Register 1 which is non-volatile bit.

7. Invalidate the TX and RX buffers (bits 10 and 11)

8. Set Parallel mode bit (Bit 16 of BFGENCR register)

where

I am using split.c file.  "h_d", "d1", "d2" arrays are of type (unsigned int *)

Is code provided in split.c considering quad mode bit settings?

Note:

1. The chip in use is Spansion FL128SAIF00 (SDR not DDR)

2. In Freescale "Document Number: TWRVF65GS10UG Rev. 1.2, 08/2014 Section 2.8", It is written that "QuadSPI interface supports Parallel QuadSPI operation in DDR mode." My chip is SDR so can I claim that "QuadSPI interface does not supports Parallel QuadSPI operation in SDR mode."

Regards

0 Kudos

47 Views
Contributor III

My question to the forum folks: has anyone succeeded in running MQX XIP  from QuadSPI in parallel mode?

Nancy

0 Kudos

47 Views
Contributor III

Here is my problem summary analysis:

1. Vybrid A5 CPU execution chokes on the first instruction in PSP routine boot.s: " mrc p15, 0, r0, c1, c0, 0       /* Read CP15 System Control register */"

2. The bare metal project does not execute a mrc (move from ARM to co-processor) instruction.

2. This problem only occurs when QuadSPI is flashed for parallel mode operation; single mode works without exception.

3. If the the Vybrid A5 CPU is running from RAM and you attach the debugger to the running target, you can perform a reset and the CPU will execute the MQX image from QuadSPI without exception.

I don't know if this is a MQX or ARM issue, or is still some arcane cockpit error.

Nancy

0 Kudos

55 Views
Contributor III

I am having trouble creating a bootable MQX QSPI image in parallel mode.

I have two test images: hello_world from the Vybrid sample code and hello2 from MQX examples. I am using the Vybrid Tower platform, IAR 7.2 Embedded Workbench, and j-trace debugger pod.

I modified the Vybrid sample code program quadspi_load to support flashing an image in parallel mode using split.c, modified quadspi_load.c, and related QuadSPI configuration parameters as noted in earlier thread entries.

I can reliably flash hello_world and boot in parallel mode; no problems at all.

I can build, flash and boot hello2 in QSPI single mode but the image will not boot in parallel mode.

I have discovered that after exiting quadspi_load debug, and without changing the board jumpers or cycling power, I can connect the debugger to the target using the hello2 QSPI debug configuration. Then I can reset the debugger and execution starts at __boot at 0x20000800. Thereupon the MQX image will run in parallel mode without problem.

I verified that hello_world and hello2 use identical QuadSPI configuration parameters and IVT. The QuadSPI configuration parameters are programmed in single mode and the reset of the image is programmed in parallel mode.


Is there some other configuration required for MQX that I have overlooked that would allow the single mode image to boot and derail the parallel mode boot?

0 Kudos

55 Views
Senior Contributor IV

Nancy,

I guess you are booting MQX code, which executes from QSPI? If so, then perhaps MQX initializes QSPI and at some point CPU is unable to read some instructions. You could try disabling QSPI, rebuilding MQX and see if it helps. QSPI still can be reinitialized while executing from QSPI, but it should be done executing from RAM or DDR or some other unaffected memory. If there are some interrupt handlers in QSPI memory, then QSPI reinitialization should be done with interrupts disabled.

Also you may try debugging MQX from start point. Don't know about IAR, but DS-5 has hardware breakpoints, which can be set in QSPI and load_debugger_symbols without loading code. After QSPI programming one needs to reset from debugger, so that PC points to 0, set HW breakpoint at MQX entry point and hit run. Debugger should stop where it is asked for.

0 Kudos

55 Views
Contributor III

Hi Edward,

My executable image using MQX is built for QSPI XIP and the Vybrid boot ROM handles the QSPI device initialization using the QuadSPI configuration values.

I build the MQX image for single mode and Vybrid boots XIP without issue. I can connect the debugger and step/run without exception.

I build the MQX image for parallel mode and Vybrid goes off into the weeds. Nothing gets initialized and the debugger cannot connect.

The only difference between an MQX image that works and fails is building the image for QuadSPI parallel mode.


I have verified that QuadSPI configuration values and the IVT are valid because I use the same values to run the non-MQX hello_world image.

I am at a loss to explain why my MQX image built for QuadSPI parallel mode fails to boot XIP.

Nancy


0 Kudos

55 Views
Senior Contributor IV

Hi Nancy,

I guess you have MQX configured to enable / initialize QSPI at reset. I guess it MQX is configured to initialize QSPI for non-parallel mode. That's one possible problem. Even if MQX was configuring QSPI for parallel mode, the same like it is specified in QPSI boot config tables, reinitialization of QSPI still may make your code jumping into the weeds. It is the same like destroying a bridge, on which you are at the moment. Will it hang or not depends on many factors. So I'm asking (again), did you try to disable QSPI in MQX BSP? I'd try it.

     > I build the MQX image for parallel mode and Vybrid goes off into the weeds. Nothing gets initialized and the debugger cannot connect.

Perhaps you can't debug using Keil, but it is possible to debug using DS-5. Hit reset button in debugger, which is set up to not start and go until main() or other function, set HARDWARE breakpoint, hit run.

Regards

Edward

0 Kudos

55 Views
Contributor III

Hi Edward,

I verified that the MQX QuadSPI and QuadSPI FlashX drivers are disabled in user_config.h and the BSP has been built with this setting.

I didn't think the MQX BSP would be an issue because the debugger stops at the first instruction in the image prior to starting MQX.


I set up my j-Trace with hardware breakpoints but the debugger reports failure to temporarily halting the CPU for reading CP15 register when I try to connect to the target. If I continue rather than abort the debugger I cannot perform any operations.

It seems to me that if the QuadSPI configuration parameters and IVT are valid then the ROM boot code would proceed with a viable QuadSPI boot. I can observe this behavior with my non-MQX image built for parallel mode and with my MQX image built for single mode.

I appreciate your suggestions and insight into how I can proceed.

Nancy

0 Kudos

55 Views
Senior Contributor IV

Hi Nancy

How do you program image to flash? Are you using quadspi_load? I'm not sure, but I think I saw bug in quadspi.c quadspi_program() function. I think it didn't program last sector of image, in case it wasn't complete and not sector address aligned. I'm not sure about it, but you should check if whole image is programmed properly. There should be no difference between MQX program and bare metal program, both should run well in parallel mode.

     I didn't think the MQX BSP would be an issue because the debugger stops at the first instruction in the image prior to starting MQX.

After code runs away, debugger may point to any location.

     I set up my j-Trace with hardware breakpoints but the debugger reports failure to temporarily halting the CPU for reading CP15 register when I try to connect to the target. If I continue rather than abort the debugger I cannot perform any operations.

You should not worry about connection problems here. Debugger still should allow you to reset target so that PC register points to 0x0 address. Then you should set HW breakpoint to entry point and hit Run. Target CPU should execute boot ROM code, and if QSPI config is OK, debugger should stop at entry point, of course if boot ROM reads QSPI config and all tables properly and makes a jump to proper address.

Does your project include some IP? If not, perhaps I could try compiling it and see what's wrong.

Edward

0 Kudos

55 Views
Contributor III

Hi Edward,

I use quadspi_load to flash QuadSPI. My version of quadspi_load defines size at 0x40000, which is much larger than the MQX image size of 0xed3c. Next time I run quadspi_load I will observe quadspi_program() to see how it handles the size.

The test images do not have any IP issues. They are example code that I was using to test my modifications of quadspi_load to handle parallel QuadSPI.

Nancy

0 Kudos

55 Views
Contributor III

For some reason I cannot post my original response; the website keeps reporting an error and will not save my reply. I am using Chrome but the same error happens using IE.

Nancy

0 Kudos

55 Views
Contributor III

One curious observation: When I exit quadspi_load after flashing my MQX image to QuadSPI, and without altering the boot configuration or resetting the target, I can connect back to the target using the MQX hello2 XIP image. Then I can pause the processor and observe it running the endless loop from quadspi_load. When I issue a reset command then execution stops at 0x20000800. From that point I can step through the MQX image and the MQX image executes without issue. The trouble begins when I set the boot configuration for QuadSPI and power cycle the target. The image fails to boot and I cannot connect the debugger.

0 Kudos

47 Views
Contributor III

I have not succeeded in setting up j-Link or j-Trace to issue a hardware reset. I have tried the available reset strategies (Software, Hardware halt using DBGRQ, and Hardware halt at 0) and none drive the reset line. I have an oscilloscope attached and only see activity at power up or when pressing the reset pushbutton.

Nancy

0 Kudos

47 Views
Contributor III

I edited boot.s and put a branch to self at __boot. I successfully connected the debugger after configuring the boot configuration for XIP and power cycling the target. I paused execution and set the next statement to the branch to reset. The debugger immediately choked on the first instruction:

ASM_LABEL(reset)

                /* disable caches, MMU - this is not required from a cold reset */

                mrc p15, 0, r0, c1, c0, 0       /* Read CP15 System Control register */

I am investigating this further.

Nancy

0 Kudos

47 Views
Senior Contributor IV

I just tried to parallel-quadspiboot image, that executes the same MRC instruction. No problems at all.

It is not very clear what happens when debugger chokes. It should be either JTAG access problem duo some HW problem, or some CPU access error. Second can be further investigates setting HW breakpoint at exception handler and stepping over MRC.

     > When I issue a reset command then execution stops at 0x20000800.

Then your debugger is not very good, either on reset it sets PC to entry point of your program, or resets and runs until entry point. This is not useful to debug problems like this. System reset debuggers button should make CPU PC pointing to 0 address, like it is when using DS-5 with TWR boards CMSIS-DAP.

Regards

Edward

0 Kudos

47 Views
Contributor III

Hi Edward,

I agree that my Segger j-link and j-trace debug environment in IAR has capability gaps. I have never been able to step through boot ROM. The capability might be there but I have not discovered how to enable it.

This morning I tried an i-jet debug pod with worse results; IAR hangs after stepping and the only way to recover is to kill IAR.

If I upload my image, hello2.bin, would you be able to flash the image and let me know what you find?

What do you use to connect to the target hardware when using DS-5 with CMSIS-DAP? IAR supports CMSIS-DAP but I have not been able to access the capability.

Nancy

0 Kudos

47 Views
Senior Contributor IV

Hi Nancy,

with Vybrid's program-once fuses, it is bit risky to flash unknown binary... Can you promise it won't try to program fuses? Also it would be nice if image wasn't accessing NAND memory.

Is it supposed to run on Tower board? Yes, I can try, but having no symbols and code I doubt about meaningful results. It would be better if you tried to reproduce problem with sensitive IP removed, much better to have sources.

I'm using CMSIS-DAP JTAG-USB, which is on Vybrid Tower card. Perhaps it is just a difference between IAR and DS-5 debuggers.

Edward

0 Kudos

47 Views
Contributor III

Hi Edward,

I understand your concerns flashing an arbitrary image and let's not go that way. The image I am trying to test is from the MQX example code; hello2 built for QuadSPI parallel mode.

Is the CMSIS-DAP JTAG-USB accessed through USB connector J3 on the Tower board?

Nancy

0 Kudos

47 Views
Senior Contributor IV

Hi Nancy,

If it's MQX hello2, then why not clean, zip and share it? Original hello2 has build configs for Int RAM and DDR. Linker script and boot config tables are missing, unless you have more fresh copy of MQX and they changed something. I checked hello2 from MQX 4.1

Yes, it's CMSIS is on J3 connector on Tower board.

Edward

0 Kudos

47 Views
Contributor III

Hi Edward,

Not sure how to share the project. In IAR I created a QSPI build using customized quadspi_boot.h, quadspi_boot.c, and quadspi_xip.icf. In the IAR/Freescale project scheme these files are in various folders that encompass a lot of other irrelevant files. In the DS-5 world things may be more ordered. In any case I don't see any edit buttons that allow me to attach anything to this post except for pictures or videos.

When I selected CMSIS-DAP in the IAR debugger it complained that it could not find a pod. I have read through the IAR documentation but don't see anything that would tell me how to use CMSIS-DAP with IAR and the Tower board. An internet search An internet search "Use CMSIS-DAP with IAR" leads to an IAR page saying I need to install some patches. The release notes do not say they support the Vybrid Tower board.

I apologize for being so ineffective to your suggestions. It's not clear to me how to proceed.

Nancy

0 Kudos