Piziheng Embedded: IAP can be easily IAP by using FlexSPI driver API provided by i.MXRT1xxx series ROM

Piziheng Embedded: IAP can be easily IAP by using FlexSPI driver API provided by i.MXRT1xxx series ROM


Hello, everyone, I am the ruffian, a serious ruffian who engages in technology. Today Pi Ziheng introduced to you the FlexSPI driver API in the i.MXRT series ROM to implement IAP .

In Pi Ziheng's technical exchange group, friends often ask questions: How to use the FlexSPI driver API in i.MXRT? This problem has appeared several times. Originally, Pi Ziheng didn't plan to write an article specifically for this, because this part of the content is actually introduced in great detail in the last section of the ROM APIs in the System Boot chapter of the chip manual, but since there are Many friends are asking this. It seems that the content in the manual is a little bit deep. It's a pity that such a good thing is buried, so today Pi Ziheng will have a serious talk with everyone.

1. Introduction to ROM API

1.1. API background

The i.MXRT series are all Flashless (no built-in NVM) chips, so BootROM is essential. BootROM is a very special thing. In essence, it is a system-level App written in complete C code. This system-level App is specifically used to load user-level App from external memory for execution. Simply put, BootROM is the BIOS in the PC.

The BootROM code is stored in a special ROM area (I said that the i.MXRT series does not have a built-in NVM, but it is not accurate enough. In fact, there is internal ROM space, but users of this ROM area cannot download programs and use it, so it is equivalent to no NVM. ), ROM, as the name implies, Readonly, so the BootROM code can only be tapeout with the chip, and the code cannot be changed (in fact, there is also a ROM patch mechanism, which will be introduced later).

The ROM space is actually quite large, ranging from 64KB to 512KB, depending on the complexity of the chip's startup function. The following figure shows the space occupied by the BootROM of the i.MXRT1050 series. The ROM starting address is 0x200000 (the starting address is the same on i.MXRT), and the ROM size is 96KB (this is the code length required for the standard boot function. In i. On MXRT1010 it is 64KB-simplified boot function, on i.MXRT1170 it is 256KB-complex boot function).

The BootROM code does not actually occupy all the ROM space, and there is always some remaining space (due to process reasons, the ROM space is a multiple of 8/16KB), it is a pity that this part of space is wasted. If we can put some commonly used module drivers in the SDK (such as WDOG) in the way for users to call, it will not only make full use of ROM space, but also save Flash space for users, wouldn't it kill two birds with one stone. In addition, there are some ready-made module drivers in the BootROM function code (such as various boot device memory driver interfaces) that can be exported together, which is the origin of the API.

1.2, API design and implementation

With the API idea, it is now the design and implementation. In fact, the design of i.MXRT ROM API did not start from the beginning. Before this MCU series was promoted, the Kinetis series was also popular. Kinetis also built-in ROM and provided ROM API. Pi Ziheng wrote an article about this before. The article "Those things started with Freescale Kinetis series MCUs (11)-KBOOT features (ROM API)" . The design idea of i.MXRT ROM API completely reuses the design of Kinetis ROM API.

After all, API is a combination of functions. We know that the engineering code is automatically allocated by the linker. Therefore, the actual link address of each function is unpredictable (assigning a fixed address link to each function in the link file) The method is not considered in the category. When the number of functions is large, this method is too troublesome). A more common method in the industry is to define the structure of the member as a function pointer. The i.MXRT ROM API is the industry common method. The following bootloader_api_entry_t is It is the API prototype in i.MXRT1060, g_bootloaderTree is an example:

typedef struct { const uint32_t version; const char *copyright; void (*runBootloader)( void *arg); const hab_rvt_t *habDriver; //!< FlexSPI NOR Flash API const flexspi_nor_driver_interface_t *flexSpiNorDriver; const nand_ecc_driver_interface_t *nandEccDriver; const clock_driver_interface_t *clockDriver; const rtwdog_driver_interface_t *rtwdogDriver; const wdog_driver_interface_t *wdogDriver; const stdlib_driver_interface_t *stdlibDriver; } bootloader_api_entry_t ; //Bootloader API Tree const bootloader_api_entry_t g_bootloaderTree = { .version = MAKE_VERSION( 1 , 0 , 0 ), .copyright = "Copyright 2018 NXP" , .runBootloader = run_bootloader, .habDriver = &hab_rvt, .flexSpiNorDriver = &g_flexspiNorDriverInterface, .nandEccDriver = &g_nandEccDriverInterface, .clockDriver = &g_clockDriverInterface, .rtwdogDriver = &g_rtwdogDriverInterface, .wdogDriver = &g_wdogDriverInterface, .stdlibDriver = &g_stdlibDriverInterface, }; Copy code

From the above code, we can see that the bootloader_api_entry_t member does not seem to be a function pointer. Yes, for the convenience of grouping, the bootloader_api_entry_t member is still a structure, and its structure members (such as flexspi_nor_driver_interface_t) really contain function pointers. Structure. API provides a total of 7 categories in terms of functions: HAB, FlexSPI NOR, NAND ECC, Clock, RT-WDOG, WDOG, stdlib.

At this point of design, we can call all API functions through the g_bootloaderTree structure constant. The last remaining problem is how to find a certain place in the ROM to save the randomly linked g_bootloaderTree address (as long as 4 bytes are enough). Yes, it is the clever method used by the Kinetis ROM API. The following is the startup file of the BootROM project (Keil version). BootROM puts the address of g_bootloaderTree in the position of the eighth vector of the interrupt vector table (the vector is ARM Cortex- M7 undefined system vector), so the 4bytes starting at 0x20001c is always the address of g_bootloaderTree.

PRESERVE8 THUMB ; Vector Table Mapped to Address 0 at Reset AREA RESET, DATA, READONLY EXPORT __Vectors EXPORT __Vectors_End EXPORT __Vectors_Size IMPORT |Image$$ARM_LIB_STACK$$ZI$$Limit| IMPORT g_bootloaderTree __Vectors DCD |Image$$ARM_LIB_STACK$$ZI$$Limit| DCD Reset_Handler DCD DefaultISR DCD HardFault_Handler DCD DefaultISR DCD DefaultISR DCD DefaultISR DCD g_bootloaderTree DCD 0 DCD 0 DCD 0 DCD SVC_Handler DCD DefaultISR DCD 0 DCD DefaultISR DCD DefaultISR ;; ... Copy code

1.3, API call method

After understanding the background and design implementation of the ROM API introduced earlier, its calling method is very simple. Taking the WDOG API call as an example, only the following three simple codes are needed:

//Find the API root structure # define g_bootloaderTree (*(bootloader_api_entry_t **)0x0020001c) //Define the WDOG module configuration variable wdog_config_t config; //Call WDOG_Init() in the API g_bootloaderTree->wdogDriver->WDOG_Init(WDOG1, config); Copy code

1.4, i.MXRT models that support API

Up to now, there are 7 models in the i.MXRT1xxx series, but not every model has open ROM API. The first three models (105x, 1021, 1015) do not have open API (not without API, but No rigorous testing), the rest of the models all support API.

RT chip modelWhether to support ROM APIWhether full-featured API
i.MXRT117xstand byYes
i.MXRT1064stand byYes
i.MXRT106xstand byYes
i.MXRT105xNot openN/A
i.MXRT1021Not openN/A
i.MXRT1015Not openN/A
i.MXRT1011stand byno

2. FlexSPI driver of API

I have laid too many ROM API design details in the front, and it is considered to be the topic here. In fact, this article is mainly to talk to you about how to use the FlexSPI NOR driver in the API to implement IAP. The reason why Pi Ziheng has laid so much in front is actually to tell everyone that every driver in the API has been thoroughly tested, especially this FlexSPI NOR driver, which has been tempered, whether it is ease of use and stable operation. Both sex and Flash model support are second to none.

For the serial SPI interface Flash driver under the JESD216 standard, everyone knows that it may be the open source SFUD project of the RT-Thread technical director Zhu Tianlong , but Pi Ziheng tells you that the serial Flash driver in the i.MXRT ROM API It's not inferior (it has been maintained and optimized for nearly 6 years, and has gone through a variety of MCU ROMs, which is a real product level), but it is not as well-known as open source projects, but its source code is also open source in the SDK (\SDK/middleware\mcu-boot\src\drivers\flexspi_nor), BSD-3-Clause license.

2.1 FlexSPI driver prototype

flexspi_nor_driver_interface_t is the prototype of the FlexSPI NOR driver. The ordinary read-write function is naturally not a problem. In addition, there is a very powerful xfer() function in the API, which can be used to implement other customized Flash operation functions , Friends who are interested can study further.

typedef struct { uint32_t Version; status_t (* the init) ( uint32_t instance, flexspi_nor_config_t * config); status_t (* Program) ( uint32_t instance, flexspi_nor_config_t * config, uint32_t dst_addr The, const uint32_t * the src); status_t (* erase_all) ( uint32_t instance , flexspi_nor_config_t *config); status_t (*erase)( uint32_t instance, flexspi_nor_config_t *config, uint32_t start,uint32_t lengthInBytes); status_t (* Read) ( uint32_t instance, flexspi_nor_config_t * config, uint32_t * DST, uint32_t addr, uint32_t lengthInBytes); void (* clear_cache) ( uint32_t instance); status_t (* XFER) ( uint32_t instance, flexspi_xfer_t * XFER ); status_t (*update_lut)( uint32_t instance, uint32_t seqIndex, const uint32_t *lutBase, uint32_t seqNumber); status_t(*get_config)( *option); uint32_tinstance, flexspi_nor_config_t *config, serial_nor_config_option_t } flexspi_nor_driver_interface_t ; //FlexSPI NOR Driver API const flexspi_nor_driver_interface_t g_flexspiNorDriverInterface = { .version = MAKE_VERSION( 1 , 5 , 0 ), .init = flexspi_nor_flash_init, .program = flexspi_nor_flash_page_program, .erase_all = flexspi_nor_flash_erase_all, .erase = flexspi_nor_flash_erase, .read = flexspi_nor_flash_read, .clear_cache = flexspi_clear_cache, .xfer = flexspi_command_xfer, .update_lut = flexspi_update_lut, .get_config = flexspi_nor_get_config, }; Copy code

2.2 FlexSPI driver usage example

The FlexSPI driver uses a basic three-step process. First call get_config() to obtain the complete FlexSPI module configuration, then call the init() function to initialize FlexSPI and access Flash to obtain SFDP table information, and finally call the Flash operation function (such as erase()).

//Find the API root structure # define g_bootloaderTree (*(bootloader_api_entry_t **)0x0020001c) //Define FlexSPI, Flash configuration variable flexspi_nor_config_t config; serial_nor_config_option_t option; option.option0.U = 0xC0000008 ; //QuadSPI NOR, Frequency: 133MHz uint32_t instance = 0 ; //Call the get_config() function in the API g_bootloaderTree->flexSpiNorDriver->get_config(instance, &config, &option); //Call the init() function in the API g_bootloaderTree->flexSpiNorDriver->init(instance, &config); //call the API erase () function g_bootloaderTree-> flexSpiNorDriver-> ERASE (instance, & config, 0x40000 , 0x1000 ); duplicated code

2.3 FlexSPI driver characteristics

Because the FlexSPI NOR driver API comes from BootROM, there are some small restrictions in its use, which can be regarded as its characteristics. The Pinmux configuration for Flash connection is not provided in the FlexSPI driver API. The Pinmux configuration has been written to death in the init() function, which is the pins on the FlexSPI PORTA that the ROM supports to start (the chip selection is SS0).

In the example code above, you will see the option.option0.U = 0xC0000008 code. This is the biggest feature of the FlexSPI driver. This is a simplified option configuration word (the prototype can be found in the chip manual). This simplified option can be easily configured by users to access Flash from different manufacturers. The following are commonly used Flash mode configuration values.

QuadSPI NOR-Quad SDR Read: option0 = 0xc0000008 (133MHz) QuadSPI NOR-Quad DDR Read: option0 = 0xc0100003 (60MHz) HyperFLASH 1V8: option0 = 0xc0233009 (166MHz) HyperFLASH 3V0: option0 = 0xc0333006 (100MHz) MXIC OPI DDR (OPI DDR enabled by default): option=0xc0433008(133MHz) Micron Octal DDR: option0=0xc0600006 (100MHz) Micron OPI DDR: option0=0xc0603008 (133MHz), SPI->OPI DDR Micron OPI DDR (DDR read enabled by default): option0 = 0xc0633008 (133MHz) Adesto OPI DDR: option0=0xc0803008(133MHz) Copy code

2.4 FlexSPI driver used as IAP

IAP is actually the realization of Flash erasing in the App, which is not a difficult thing purely technically. But many times on i.MXRT App code itself is also executed in the same piece of Flash (also called XIP), and many Flashes on the market do not support RWW (Read-While-Write), which leads to a problem when you When the Flash operation function is called to erase and write Flash, the CPU needs to continue to Flash to obtain instructions, which violates the RWW. Therefore, you can only put all Flash related operation functions in RAM to execute (this involves scatter loading, for primary embedded It's a little bit difficult for users).

Now that we have the ROM API, the FlexSPI driver code body is all in the ROM space and does not occupy Flash space. Therefore, there is no RWW problem. It is really natural for IAP, and there is no need to worry about scattered loading. .

2.5. About non-full-featured API

As mentioned in the previous section 1.4, i.MXRT1010 does not have a full-featured API, mainly because its BootROM space is small and cannot store redundant API codes. The following is an example of the API in i.MXRT1010. You can see that there are very few FlexSPI driver functions provided. , And its usage will be introduced separately later.

//Bootloader API Tree const bootloader_api_entry_t g_bootloaderTree = { .version = MAKE_VERSION( 1 , 0 , 0 ), .copyright = "Copyright 2019 NXP" , .runBootloader = run_bootloader, .habDriver = &hab_rvt, .flexSpiNorDriver = &g_flexspiNorDriverInterface, }; //FlexSPI NOR Driver API const flexspi_nor_driver_interface_t g_flexspiNorDriverInterface = { .version = MAKE_VERSION( 1 , 5 , 0 ), .init = flexspi_nor_flash_init, .clear_cache = flexspi_clear_cache, .xfer = flexspi_command_xfer, .update_lut = flexspi_update_lut, }; Copy code

3. FlexSPI API industry application

Finally, I will introduce the application of i.MXRT FlexSPI API in the industry. This API is not a niche. It has been used as the i.MXRT Flash download algorithm by mainstream IDEs and debugging tools.

3.1 Download algorithm for IAR

If your IAR version is new enough to support i.MXRT1060 and other models, just open an i.MXRT1060 SDK project, find the Debugger in the project Option, and then enter the Flashloader configuration, you will see a column of Extra parameters in the page. The following explanation has an example of this parameter, which is the option0 introduced in the previous section 2.3. With the Flash download algorithm designed in this way, you no longer have to manually update the download algorithm file to support different Flash, just change the parameters.

3.2 Used for J-Link download algorithm

At present, the download algorithm in the latest Jlink driver is also based on the ROM API. Pi Ziheng has an open source project that collects download algorithm source code projects for all models of i.MXRT. The jlink algorithm is the most complete, and other IDE algorithms are still being developed. Improving.

github.com/JayHeng/imx...

So far, the FlexSPI driver API in the i.MXRT series ROM to realize IAP Piziheng has been introduced. Where is the applause~~~