How to use the RT1064 on-chip flash as NVM

cancel
Showing results for 
Search instead for 
Did you mean: 

How to use the RT1064 on-chip flash as NVM

How to use the RT1064 on-chip flash as NVM

Introduction

The RT1064 is the only Crossover MCU from the RT family that comes with an on-chip flash, it has a 4MB Winbond W25Q32JV memory. It's important to remark that it's not an internal memory but an on-chip flash connected to the RT1064 through the FlexSPI2 interface. Having this flash eliminates the need of an external memory.

Although the intended use of the on-chip flash is to store your application and do XiP, there might be cases where you would like to use some space of this memory as NVM. This document will explain how to modify one of the SDK example projects to achieve this. 

Prerequisites

  • RT1064-EVK 
  • The latest SDK which you can download from the following link: Welcome | MCUXpresso SDK Builder.
  • In this document, I will use MCUXpresso IDE but you can use the IDE of your preference. The modifications that you need to make are the same despite the IDE that you are using. 

Importing the SDK example 

The RT1064-EVK comes with two external flash memories, 512 Mb Hyper Flash and 64 Mb QSPI Flash. The RT1064-SDK includes two example projects that demonstrate how to use any of these two external flash memories as NVM. In this document, we will take as a base one of these examples to modify it to use the on-chip flash as NVM.

Once you downloaded and imported the SDK into MCUXpresso IDE, you will need to import the example flexspi_nor_polling_transfer into your workspace. 

pastedImage_17.png

 

Modifying the SDK example

The external NOR Flash memory of the EVK is connected to the RT1064 through the FlexSPI1 interface. Due to this, the example project that we just imported initializes the FlexSPI1 interface pins. In our case, we want to use the on-chip flash that is connected through the FlexSPI2 instance, since we will boot from this memory, the ROM bootloader will configure the pins of this FlexSPI interface. So, in the function BOARD_InitPins we can delete all the pins that were related to the FlexSPI1 interface. At the end your function should look like the following: 

void BOARD_InitPins(void) {
 CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */

 IOMUXC_SetPinMux(
 IOMUXC_GPIO_AD_B0_12_LPUART1_TX, /* GPIO_AD_B0_12 is configured as LPUART1_TX */
 0U); /* Software Input On Field: Input Path is determined by functionality */
 IOMUXC_SetPinMux(
 IOMUXC_GPIO_AD_B0_13_LPUART1_RX, /* GPIO_AD_B0_13 is configured as LPUART1_RX */
 0U); /* Software Input On Field: Input Path is determined by functionality */
 /* Software Input On Field: Force input path of pad GPIO_SD_B1_11 */
 IOMUXC_SetPinConfig(
 IOMUXC_GPIO_AD_B0_12_LPUART1_TX, /* GPIO_AD_B0_12 PAD functional properties : */
 0x10B0u); /* Slew Rate Field: Slow Slew Rate
 Drive Strength Field: R0/6
 Speed Field: medium(100MHz)
 Open Drain Enable Field: Open Drain Disabled
 Pull / Keep Enable Field: Pull/Keeper Enabled
 Pull / Keep Select Field: Keeper
 Pull Up / Down Config. Field: 100K Ohm Pull Down
 Hyst. Enable Field: Hysteresis Disabled */
 IOMUXC_SetPinConfig(
 IOMUXC_GPIO_AD_B0_13_LPUART1_RX, /* GPIO_AD_B0_13 PAD functional properties : */
 0x10B0u); /* Slew Rate Field: Slow Slew Rate
 Drive Strength Field: R0/6
 Speed Field: medium(100MHz)
 Open Drain Enable Field: Open Drain Disabled
 Pull / Keep Enable Field: Pull/Keeper Enabled
 Pull / Keep Select Field: Keeper
 Pull Up / Down Config. Field: 100K Ohm Pull Down
 Hyst. Enable Field: Hysteresis Disabled */
}
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Function flexspi_nor_flash_init initializes the FlexSPI interface but in our case, the ROM bootloader already did this for us. So we need to make some modifications to this function as well. The only things that we will need from this function are to update the LUT and to do a software reset of the FlexSPI2 interface. At the end your function should look like the following: 

void flexspi_nor_flash_init(FLEXSPI_Type *base)
{
 /* Update LUT table. */
 FLEXSPI_UpdateLUT(base, 0, customLUT, CUSTOM_LUT_LENGTH);

 /* Do software reset. */
 FLEXSPI_SoftwareReset(base);
}
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Inside the file app.h, we need to change some macros since now we will use a different memory and a different FlexSPI interface. The following macros are the ones that you need to modify: 

MacroBeforeAfterObservations
EXAMPLE_FLEXPIFLEXSPIFLEXSPI2On-chip flash is connected through FlexSPI2 interface 
FLASH_SIZE0x20000x200The size of the on-chip flash is different from the external NOR flash 
EXAMPLE_FLEXSPI_AMBA_BASEFlexSPI_AMBA_BASEFlexSPI2_AMBA_BASEOn-chip flash is connected through FlexSPI2 interface 
EXAMPLE_SECTOR4100The size of the on-chip flash is less than the external NOR flash, hence we will decrease the sector size to avoid erasing our application 

Everything else in this file remains the same. 

Finally, there are two changes that we need to make in the customLUT. To understand these changes you need to analyze the datasheets of the memories. But in the end, the two modifications are the followings: 

  1. Erase sector command of the on-chip flash is 0x20 instead of 0xD7. 
  2. Exchange the FLEXSPI command index for NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD and NOR_CMD_LUT_SEQ_IDX_READ_NORMAL to align with XIP settings.

At the end your customLUT should look like the following: 

const uint32_t customLUT[CUSTOM_LUT_LENGTH] = {
 /* Fast read quad mode - SDR */
 [4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD] =
 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x6B, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
 [4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD + 1] = FLEXSPI_LUT_SEQ(
 kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_4PAD, 0x08, kFLEXSPI_Command_READ_SDR, kFLEXSPI_4PAD, 0x04),

 /* Fast read mode - SDR */
 [4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST] =
 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x0B, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
 [4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST + 1] = FLEXSPI_LUT_SEQ(
 kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_1PAD, 0x08, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),

 /* Normal read mode -SDR */
 [4 * NOR_CMD_LUT_SEQ_IDX_READ_NORMAL] =
 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x03, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
 [4 * NOR_CMD_LUT_SEQ_IDX_READ_NORMAL + 1] =
 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),

 /* Read extend parameters */
 [4 * NOR_CMD_LUT_SEQ_IDX_READSTATUS] =
 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x81, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),

 /* Write Enable */
 [4 * NOR_CMD_LUT_SEQ_IDX_WRITEENABLE] =
 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x06, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),

 /* Erase Sector */
 [4 * NOR_CMD_LUT_SEQ_IDX_ERASESECTOR] =
 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x20, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),

 /* Page Program - single mode */
 [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE] =
 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x02, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
 [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE + 1] =
 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),

 /* Page Program - quad mode */
 [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD] =
 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x32, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
 [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD + 1] =
 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_4PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),

 /* Read ID */
 [4 * NOR_CMD_LUT_SEQ_IDX_READID] =
 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x9F, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),

 /* Enable Quad mode */
 [4 * NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG] =
 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x01, kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04),

 /* Enter QPI mode */
 [4 * NOR_CMD_LUT_SEQ_IDX_ENTERQPI] =
 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x35, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),

 /* Exit QPI mode */
 [4 * NOR_CMD_LUT_SEQ_IDX_EXITQPI] =
 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_4PAD, 0xF5, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),

 /* Read status register */
 [4 * NOR_CMD_LUT_SEQ_IDX_READSTATUSREG] =
 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x05, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),

 /* Erase whole chip */
 [4 * NOR_CMD_LUT_SEQ_IDX_ERASECHIP] =
 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xC7, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
};

‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

These are all the changes that you need to make to the flexspi_nor_polling_transfer to use the on-chip flash as NVM instead of the external NOR flash. 

Important notes

It's important to mention that you cannot write, erase or read the on-chip flash while making XiP from this memory. So, you need to reallocate all the instructions that read, write and erase the flash to the internal FlexRAM. Fortunately, the example that we use as a base (flexspi_nor_polling_transfer) already does this. This is accomplished thanks to the files located in the linkscritps folder. To learn more about how this works, please refer to section 17.15 of the MCUXpresso IDE User Guide. 

Additional resources

Datasheet of the on-chip memory (Winbond W25Q32JV). 

MCUXpresso IDE User Guide. 

I hope that you find this document useful! 

Regards, 

Victor 

Labels (1)
Comments

Hi

Note also that the uTasker i.MX RT project has inherent file system (uFileSystem or FAT) and parameter storage (uParameterSystem) support for the internal QSPI flash in the 1064, as well as for all external QSPI and Hyper flash parts of other i.MX RT parts. The project also emulates the FlexSPI interface and the flash parts operation so that all driver and application code can be tested and debugged in Visual Studio, which makes such work and general product development easier and increases product development efficiency.

Regards

Mark

[uTasker project developer for Kinetis and i.MX RT]

Version history
Revision #:
2 of 2
Last update:
‎09-10-2020 02:58 AM
Updated by:
 
Contributors