How to i.MXRT1051 QSPI Boot w/o XIP (Reside in Flash, Run from TCM)

cancel
Showing results for 
Search instead for 
Did you mean: 

How to i.MXRT1051 QSPI Boot w/o XIP (Reside in Flash, Run from TCM)

Jump to solution
3,534 Views
scott_thompson
Contributor II

I'm using MCUXpresso IDE to create a sample Hello World (VCP) application.  I can run it from MCUXpresso fine and debug in RAM and have verified the application runs okay.  I even can run it from Hyperflash and have it persistent, but our project will be using QSPI NOR flash and I'm trying to configure for this mode (which I know I have to use the Kinetis flashloader and NOT MCUXpresso).

I have set my project to start at 0x60002000 per the linker configuration for the application start point and got the MfgTool to successfully program a resulting boot_image.sd into the FlexSPI on the modified i.MXRT1052-EVKB board.  However, my application didn't run, and subsequent attempts to program the QSPI with the MfgTool fails.

My end goal is currently NOT to run using XIP.  Due to hardware issues on the first revision, our dead-bugged NOR flash device is a x1 configuration and will not be able to do XIP, so I want to use the ROM bootloader to load the image to RAM (our product will have SDRAM as well but running from TCM is preferred).  However, whenever I try to configure an image to run from RAM (anything but 0x60002000 for an address) the 'elftosb' tool crashes.

The project settings that I had when I got the MfgTool to work were:

XIP_EXTERNAL_FLASH=0

XIP_BOOT_HEADER_ENABLE=1

XIP_BOOT_HEADER_DCD_ENABLE=0

Under Project Settings -> Memory, I have:

BOARD_FLASH   0x60002000 with a size of 0x3FFE000 and a driver of MIMXRT1050-EVK_IS25WP064A.cfx

SRAM_DTC         0x20000000 with a size of 0x20000

SRAM_ITC            0x0 with a size of 0x2000

SRAM_OC            0x20200000 with a size of 0x40000

BOARD_SDRAM   0x80000000 with a size of 0x2000000

Again, since I'm trying to mimic what our final product will be to have our application image in FlexSPI NOR (x1) (but using the EVKB's QSPI device), I'm trying to flash and load a program that resides in QSPI but will ultimately execute from RAM.  

However, after the first successful programming (but failure to launch the code--maybe I used the padded version instead of the non-padded .bin file by mistake) I can no longer get ANY image to load on FlexSPI using the serial bootloader and MfgTool. 

Also, every time I try and specify to NOT use XIP (various means, most are likely wrong--I'm trying to figure this out), the 'elftosb' tool, when creating the first .bin iMX boot image .bin file, always crashes.

Any thoughts on getting a FlexSPI NOR flash to work with MfgTool, built from MCUXpresso, without using XIP?

Thanks for any insight.  I've been drilling through the rest of the community comments and code and haven't found exactly what I'm looking for yet...

Cheers,

Scott Thompson, TC Helicon

Tags (1)
1 Solution
1,230 Views
weidong_sun
NXP TechSupport
NXP TechSupport

Hello Scott,

    if you are using I.MXRT1050 SDK 2.3.1 or above version, you don't need to convert .bin file to be .sb file.  please write .bin file to QSPI NOR FLASH by MFG tools.

     Then configure board boots from port connected to QSPI NOR Flsh, and power it on!

Try it , please!

Have a nice day!

Best Regards,

Weidong

View solution in original post

8 Replies
1,230 Views
venugopal_v
Contributor III

hello, i had requirement to store data as well program in same QSPI flash with  imx rt 1050 i followed above process with different method that is through linker scrips to relocate  all flexspi code to ITC ram . hope this would help

Dropbox - BEL2_flexspi_nor_polling_transfer.7z - Simplify your life 

0 Kudos
1,230 Views
jay_heng
NXP Employee
NXP Employee

You can also try this tool, with this tool, You can flash bare image into various boot devices easily and don't need to care about headers (ivt, boot data...)

GitHub - JayHeng/nxp-sec-boot-ui: A one-stop GUI tool to work with NXP MCU (Kinetis, i.MXRT, LPC) RO... 

0 Kudos
1,230 Views
scott_thompson
Contributor II

It's working!  Sort-of.

The trick was to ensure the code was copied to 0x2000 in ITC, since the ROM image starts at 0x60002000.  Specifying OCRAM as a destination always fails.  I have to modify the boot configuration as given above, but the SRAM_OC_BASE is 0x0 and the size is 0x20000.

I'm able to get non-XiP working in QSPI x1 mode and x4 mode.  I'm posting the configuration code here for anyone who needs it.

#define QSPI_USE_1PAD 0
/*******************************************************************************
 * Code
 ******************************************************************************/
#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
#if defined(__CC_ARM) || defined(__GNUC__)
__attribute__((section(".boot_hdr.conf")))
#elif defined(__ICCARM__)
#pragma location = ".boot_hdr.conf"
#endif
const flexspi_nor_config_t flexspi_config = {
    .memConfig =
        {
            .tag = FLEXSPI_CFG_BLK_TAG,
            .version = FLEXSPI_CFG_BLK_VERSION,
            .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackInternally,
            .csHoldTime = 3u,
            .csSetupTime = 3u,
            .columnAddressWidth = 0,
   .deviceModeCfgEnable = 0,
   .waitTimeCfgCommands = 0,
            // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
            .controllerMiscOption = 0u,
   .deviceType = kFlexSpiDeviceType_SerialNOR,
#if defined(QSPI_USE_1PAD) && (QSPI_USE_1PAD == 1)
            .sflashPadType = kSerialFlash_1Pad,
#else
            .sflashPadType = kSerialFlash_4Pads,
#endif
            .serialClkFreq = kFlexSpiSerialClk_50MHz,
   .lutCustomSeqEnable = 0,
            .sflashA1Size = 8u * 1024u * 1024u,
            .dataValidTime = {16u, 16u},
   .busyOffset = 0,
   .busyBitPolarity = 0,
            .lookupTable =
    {
#if defined(QSPI_USE_1PAD) && (QSPI_USE_1PAD == 1)
     [4 * NOR_CMD_LUT_SEQ_IDX_READ] =    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x03, RADDR_SDR, FLEXSPI_1PAD, 0x18),
     [4 * NOR_CMD_LUT_SEQ_IDX_READ+1] =    FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x04, STOP, FLEXSPI_1PAD, 0x00),
#else
     [4 * NOR_CMD_LUT_SEQ_IDX_READ] =    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18),
     [4 * NOR_CMD_LUT_SEQ_IDX_READ+1] =    FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04),
#endif
     [4 * NOR_CMD_LUT_SEQ_IDX_READSTATUS] =   FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
     [4 * NOR_CMD_LUT_SEQ_IDX_WRITEENABLE] =  FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0x00),
     [4 * NOR_CMD_LUT_SEQ_IDX_ERASESECTOR] =  FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xD7, RADDR_SDR, FLEXSPI_1PAD, 0x18),
#if defined(QSPI_USE_1PAD) && (QSPI_USE_1PAD == 1)
     [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM] =  FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 0x18),
     [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM+1] = FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0x04, STOP, FLEXSPI_1PAD, 0x00),
#else
     [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM] =  FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18),
     [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM+1] = FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0x00),
#endif
     [4 * NOR_CMD_LUT_SEQ_IDX_CHIPERASE] =   FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xC7, STOP, FLEXSPI_1PAD, 0x00),
     [4 * NOR_CMD_LUT_SEQ_IDX_EXIT_NOCMD] =   FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_1PAD, 0x08, STOP, FLEXSPI_1PAD, 0x00),
    },
        },
    .pageSize = 256U,
    .sectorSize = 4096u,
 .ipcmdSerialClkFreq = 0,
 .isUniformBlockSize = 0,
 .serialNorType = 0,
 .blockSize = 32768u
};
I was clever enough to include the led_blinky code that blinks the user LED using SysTick 1000ms on, 1000ms off in the background.  That way, I was able to check if the code was working if USB didn't fire up.  Interestingly, whenever I run in XiP mode, I'm able to get the USB virtual COM port to work, but when I am in non-XiP mode, the virtual COM port reports from windows as my device has failed.  Any ideas?
0 Kudos
1,230 Views
anjalikkrishna
Contributor III

Hi Scott,

        Did you manage to flash XIP code to qspi using MFGTOOL. Even I am using MCUXpresso. My task is to work with emWin GUI which should have the xip driver included . I am using i.MXRT1050 EVKB board.

Thanks & Regards,

Anjali 

0 Kudos
1,230 Views
scott_thompson
Contributor II

Hello Anjali,

Yes, I was able to be successful in both flashing and booting XiP code as well as non-XiP code using MfgTool.  In fact, I cannot use the USB debug interface to load code using MCUXpresso even though I have updated the firmware for QSPI in it.

Using the MfgTool required modification of a couple of the .xml files so that it could properly load the code to the right memory location (0x60000000 instead of 0x60020000 IIRC).  Plus I had to add a command to the section that I was duplicating to actually erase the flash, which is why it always failed on subsequent tries when using the instructions given by the application notes, etc.

Also, as noted above, in order to properly achieve non-XiP code execution, I had to modify the image vector table (IVT) to have the pointers remapped to ITCM.

Remember, I'm not able to use MCUXpresso to load QSPI code nor debug from QSPI.  I have to load to RAM and run from there when using MCUXpresso.  The MfgTool is what I use to create a permanent image to the QSPI flash using the IVT builder code in MCUXpresso.

Good luck!

--Scott

0 Kudos
1,230 Views
scott_thompson
Contributor II

Well, can get the SPI to get flashed but still cannot get non-XiP code to run.

Here's what I've done so far:

I modified the fsl_flexspi_nor_boot.c file to be more inline with non-XiP configuration as given in the i.MXRT1051 datasheet (see below).  The reason I'm putting into SRAM_OC is from the datasheet it shows that the ROM loader puts the non-XiP code to this region.

#define BOOT_FLASH   (0x60000000)
#define SRAM_OC_BASE (0x20200000)
#define SRAM_OC_SIZE (0x40000)
#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
#if defined(__CC_ARM) || defined(__GNUC__)
    __attribute__((section(".boot_hdr.ivt")))
#elif defined(__ICCARM__)
#pragma location=".boot_hdr.ivt"
#endif
/*************************************
 *  IVT Data
 *************************************/
const ivt image_vector_table = {
  IVT_HEADER,                         /* IVT Header */
  IMAGE_ENTRY_ADDRESS,                /* Image Entry Function (SRAM_OC @ 0x20201400)*/
  IVT_RSVD,                           /* Reserved = 0 */
  0,              /* Address where DCD information is stored */
  (uint32_t)BOOT_DATA_ADDRESS - BOOT_FLASH + SRAM_OC_BASE,        /* Address where BOOT Data Structure is stored */
  (uint32_t)((uint32_t)&image_vector_table - BOOT_FLASH + SRAM_OC_BASE),      /* Pointer to IVT Self (absolute address */
  0,              /* Address where CSF file is stored */
  IVT_RSVD                            /* Reserved = 0 */
};
#if defined(__CC_ARM) || defined(__GNUC__)
    __attribute__((section(".boot_hdr.boot_data")))
#elif defined(__ICCARM__)
#pragma location=".boot_hdr.boot_data"
#endif
/*************************************
 *  Boot Data
 *************************************/
const BOOT_DATA_T boot_data = {
FLASH_BASE - BOOT_FLASH + SRAM_OC_BASE,                 /* boot start location */
FLASH_SIZE - FLASH_SIZE + SRAM_OC_SIZE,                 /* size */
  PLUGIN_FLAG,                /* Plugin flag*/
  0xFFFFFFFF        /* empty - extra data word */
};
This is done due to the IVT from the datasheet showing non-XiP linkage to absolute memory and the IMAGE_ENTRY_ADDRESS is where the vector table resides and is actually offset by the mandatory 0x1000 IVT offset, plus a little headroom for the copy of the IVT and DCD area, etc.
So, the 0x60000000 region contains the NOR SPI flash configuration block and the IVT starts at 0x60001000 which is 32 bytes long, then comes the Boot Data block.  As shown, it appears that a portion of the Boot Device Memory is copied into Dest. Memory, so for non-XiP I needed to adjust the IVT vectors to not point to 0x6000000 region but instead the 0x20200000 region (SRAM_OC).  
From MCUXpresso, the IMAGE_ENTRY_ADDRESS is governed by the memory region in the project settings and is 0x20201400, so that the "Application" region points past the IVT offset in RAM, plus the actual IVT and DCD regions.  However, the other fields are simply offsets so I subtract 0x6000000 for boot_data start, etc. as shown in the code changes above to generate a non-XiP IVT.
In addition to this change, I updated the old Hyperflash FlexSPI NOR configuration block to reflect the QSPI device (and attempted to operate in x1 mode) according to the IS25WP064A datasheet.
#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
#if defined(__CC_ARM) || defined(__GNUC__)
__attribute__((section(".boot_hdr.conf")))
#elif defined(__ICCARM__)
#pragma location = ".boot_hdr.conf"
#endif
const flexspi_nor_config_t flexspi_config = {
    .memConfig =
        {
            .tag = FLEXSPI_CFG_BLK_TAG,
            .version = FLEXSPI_CFG_BLK_VERSION,
            .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackInternally,
            .csHoldTime = 3u,
            .csSetupTime = 3u,
            .columnAddressWidth = 0,
   .deviceModeCfgEnable = 0,
   .waitTimeCfgCommands = 0,
            // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock
            .controllerMiscOption = 0u,
   .deviceType = kFlexSpiDeviceType_SerialNOR,
            .sflashPadType = kSerialFlash_4Pads,
            .serialClkFreq = kFlexSpiSerialClk_50MHz,
   .lutCustomSeqEnable = 0,
            .sflashA1Size = 8u * 1024u * 1024u,
            .dataValidTime = {16u, 16u},
   .busyOffset = 1,
   .busyBitPolarity = 0,
            .lookupTable =
    {
     [4 * NOR_CMD_LUT_SEQ_IDX_READ] =    FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x03, RADDR_SDR, FLEXSPI_1PAD, 0x18),
     [4 * NOR_CMD_LUT_SEQ_IDX_READ+1] =    FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x01, STOP, FLEXSPI_1PAD, 0x04),
     [4 * NOR_CMD_LUT_SEQ_IDX_READSTATUS] =   FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01),
     [4 * NOR_CMD_LUT_SEQ_IDX_WRITEENABLE] =  FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0x00),
     [4 * NOR_CMD_LUT_SEQ_IDX_ERASESECTOR] =  FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xD7, RADDR_SDR, FLEXSPI_1PAD, 0x18),
     [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM] =  FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 0x18),
     [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM+1] = FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0x04, STOP, FLEXSPI_1PAD, 0x00),
     [4 * NOR_CMD_LUT_SEQ_IDX_CHIPERASE] =   FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xC7, STOP, FLEXSPI_1PAD, 0x00),
     [4 * NOR_CMD_LUT_SEQ_IDX_EXIT_NOCMD] =   FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_1PAD, 0x08, STOP, FLEXSPI_1PAD, 0x00),
    },
        },
    .pageSize = 256U,
    .sectorSize = 4096u,
 .blockSize = 32768u,
 .ipcmdSerialClkFreq = 0
};
I went ahead and filled-in as much of the LUT as I could in anticipation that we may require FlexSPI to access/program non-code portions of the QSPI Flash.  In hindsight I see that I forgot to change the '.sflashPadType' from 4 pads and the .ipcmdSerialClkFreq might be better off as 1 or 2 (not sure about this parameter).
Unfortunately, I am still unable to get ANY code to run from QSPI flash (modified EVKB board).  GUI programming from MCUXpresso has been able to program and verify this device as well, but lately I have problems with the DAP accessors so have to revisit that.
For completeness, the MfgTool .xml file relevant programming code is shown below.
<LIST name="MXRT105x-DevBootFlexSPI_noXiP" desc="Manufacturing with Flashloader">
<!-- Stage 1, load and execute Flashloader -->   
    <CMD state="BootStrap" type="boot" body="BootStrap" file="ivt_flashloader.bin" > Loading Flashloader. </CMD>
    <CMD state="BootStrap" type="jump"  onError = "ignore"> Jumping to Flashloader. </CMD>
<!-- Stage 2, Program boot image into external memory using Flashloader -->  
    <CMD state="Blhost" type="blhost" body="get-property 1" > Get Property 1. </CMD> <!--Used to test if flashloader runs successfully-->
    <CMD state="Blhost" type="blhost" body="fill-memory 0x2000 4 0xc0000002"> Prepare FlexSPI Flash Configuration option </CMD>
    <CMD state="Blhost" type="blhost" body="configure-memory 0x9 0x2000"> Configure QuadSPI NOR Flash </CMD>
    <!-- This erase size need to be updated based on the actual boot image size-->
    <CMD state="Blhost" type="blhost" timeout="30000" body="flash-erase-region 0x60000000 0x100000" > Erase 1MBytes </CMD> 
    <CMD state="Blhost" type="blhost" timeout="15000" body="write-memory 0x60000000 \"Profiles\\MXRT105x\\OS Firmware\\boot_image.bin\"" > Program Boot Image. </CMD>
    <CMD state="Blhost" type="blhost" body="Update Completed!">Done</CMD>
</LIST>
Finally, please note that I HAD to change the BOARD_FLASH region back to 0x6000000 (from 0x60002000 when using the DAP programming) because it turns out the linker configuration template has a check for the region start to be 0x60000000 or else the boot configuration block was never being kept in the linker image--that took a little sleuthing!  Not sure how the DAP programmer worked (maybe it generated its own boot_config block?) but I believe I am forced to use the MfgTool at this point, even though I have programmed the DAP firmware with the QSPI variant.
<#-- Only insert header if Flash region starts at true base address -->
<#if (MemUtils.location(CODE) == Utils.strToInt("0x60000000")) >
    /* Image Vector Table and Boot Data for booting from external flash */
    .boot_hdr : ALIGN(${text_align})
    {
        FILL(0xff)
        __boot_hdr_start__ = ABSOLUTE(.) ;
        KEEP(*(.boot_hdr.conf))
        . = 0x1000 ;
        KEEP(*(.boot_hdr.ivt))
        . = 0x1020 ;
        KEEP(*(.boot_hdr.boot_data))
        . = 0x1030 ;
        KEEP(*(.boot_hdr.dcd_data))
        __boot_hdr_end__ = ABSOLUTE(.) ;
        . = 0x2000 ;
    } >${CODE}
 </#if>
I'm starting to sigh a lot from frustration as there's no telling where in this chain things are broken; if anyone has insight into NON-XIP mode, I'm listening. 
Thanks for any input,
Scott Thompson, TC Helicon
0 Kudos
1,231 Views
weidong_sun
NXP TechSupport
NXP TechSupport

Hello Scott,

    if you are using I.MXRT1050 SDK 2.3.1 or above version, you don't need to convert .bin file to be .sb file.  please write .bin file to QSPI NOR FLASH by MFG tools.

     Then configure board boots from port connected to QSPI NOR Flsh, and power it on!

Try it , please!

Have a nice day!

Best Regards,

Weidong

View solution in original post

1,230 Views
scott_thompson
Contributor II

Thank you! 

The problem with subsequent flashing is that I was using the profile identified in the App Note to load the boot_image.sb and that XML entry doesn't erase the flash--that's why all subsequent attempts to program the device have failed.

I created a new entry for FlexSPI_noXIP and see where the similarities in configuring using this tool and the accompanying .bd file are, so was able to configure for FlexSPI (x1) configuration at 50 MHz.  Am now able to erase the chip, etc.

I still have to troubleshoot why my image doesn't boot, but I may need to rework the memory a bit, but you have got me on the right track.

Thank you for pointing me in the right direction; and I'm very happy to not have to fuss with the 'elftosb' tool and can certainly leverage the MfgTool to program the device when not pushing directly to RAM from MCUXpresso.

Really appreciate you taking the time to answer my question.

Cheers,

Scott Thompson, TC Helicon

0 Kudos