Embedded system: IAP can be easily realized by using flexspi driver API provided by i.mxrt1xxx series ROM

Time:2020-10-6

Hello, everyone. I’m a ruffian. I’m a real technical ruffian. What ruffian Heng introduced to you today isi. Implementation of IAP with flexspi driver API in mxrt series ROM

In the technical exchange group of ruffian Heng, some friends often ask: how to use flexspi driver API in I. mxrt? This problem has appeared several times. Originally, ruffian Heng did not intend to write a special article for this, because this part is in the last ROM of the system boot chapter of the chip manual In fact, the introduction in Apis is very detailed, but since there are still many friends asking about this, it seems that the content in the manual is a little deep. It’s a pity that such a good thing is buried. So today, ruffian Heng will have a serious talk with you.

1、 Introduction to ROM API

1.1 background of API

i. Mxrt series are flash less chips (without built-in NVM), 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 specially used to load user level app execution from external memory. Simply put, bootrom is the BIOS of PC.

Bootrom code is stored in a special ROM area (i.mxrt series does not have built-in NVM, which is not accurate enough. In fact, there is internal ROM space, but users in this ROM area cannot download programs for use, so it is equivalent to no NVM). As the name implies, the bootrom code can only be tapeout along with the chip, and the code cannot be changed (there is also ROM in fact) Patch mechanism, which will be introduced later).

ROM space is actually quite large, ranging from 64KB to 512KB, depending on the complexity of the chip boot function. The following figure shows the space occupied by the bootrom of i.mxrt1050 series. The ROM start address is 0x200000 (the starting address is the same on i.mxrt), and the ROM size is 96kb (this is the code length required by the standard boot function). On i.mxrt1010, it is 64KB – thin boot function, and on i.mxrt1170, it is 256Kb – complex boot function).

In fact, bootrom code does not take up all ROM space. There is always some space left (ROM space is 8 / 16kb multiple for process reasons). It is a pity that this part of space is wasted. If we can put some common module drivers (such as wdog) in the SDK for users to call, it will not kill two birds with one stone if we can make full use of ROM space and save flash space for users. In addition, there are some ready-made module drivers (such as various boot device memory driver interfaces) in the bootrom function code that can be exported together. This is the origin of API.

1.2. API design and Implementation

With the API idea, it’s time to design and implement. In fact, i.mxrt ROM API design is not a new start. Before this MCU series was launched, kinetis series was also popular. Kinetis also had built-in ROM and provided ROM API. Ruffian Heng wrote an article “Freescale kinetis Series MCU startup things (11) – kboot features (ROM API)”. i. The design idea of mxrt ROM API completely reuses the design of kinetis ROM API.

In the final analysis, API is a combination of function functions. We know that the engineering code is automatically assigned by the linker, so the actual link address of each function can not be expected (this method of assigning fixed address links to each function in the link file is not considered. When the number of functions is large, this method is too cumbersome). It is a common practice in the industry The i.mxrt ROM API is a common method used in the industry. The following bootloader_ api_ entry_ T is the API prototype in i.mxrt1060_ 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,
};

From the above code, we can see that bootloader_ api_ entry_ It seems that the T member is not a function pointer. Yes, for the convenience of grouping, bootloader_ api_ entry_ The T member is also a structure, and its structural members (such as flexspi)_ nor_ driver_ interface_ t) It is the structure that contains function pointers. API provides 7 categories in terms of function: HAB, flexspi nor, NAND ECC, clock, rt-wdog, wdog and stdlib.

So far as the design is concerned, we use G_ Bootloadertree structure constant can call all API functions. The last remaining problem is how to find a certain place in ROM to save the random linked G_ Bootloadertree address (only 4 bytes). Yes, or the ingenious method used by kinetis ROM API. The following is the startup file (keil version) of the bootrom project. Bootrom will_ The address of bootloadertree is placed at the position of the eighth vector in the interrupt vector table (this vector is the system vector not defined by arm cortex-m7), so the starting 4 bytes at 0x20001c is fixed as G_ Bootloadertree address.

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
		        ;; ...

1.3 API call method

After understanding the background and design of ROM API described above, its calling method is very simple. Taking wdog API call as an example, only three simple codes are needed as follows:

//Find the API root structure

1.4. I.mxrt model supporting API

Up to now, there are seven models of i.mxrt1xxx series, but not every model has open ROM API. The three earliest models (105x, 1021, 1015) have no open API (not no API, but no strict testing), and the rest of the models support API.

RT chip model Is ROM API supported Is it a fully functional API
i.MXRT117x support yes
i.MXRT1064 support yes
i.MXRT106x support yes
i.MXRT105x Not open N/A
i.MXRT1021 Not open N/A
i.MXRT1015 Not open N/A
i.MXRT1011 support no

2、 Flexspi driver of API

There are too many ROM API design details in front of us, so we can enter into the topic here. In fact, this paper mainly talks about how to use flexspi nor driver in API to realize IAP. In fact, the reason why ruffian Heng paved the way in front of us is to tell you that every driver in the API has been well tested, especially the flexspi nor driver, which is second to none in terms of ease of use, running stability and support of flash models.

As for the serial spi flash driver under the jesd216 standard, we all know that it may be the open source sfud project of Zhu Tianlong Dashen, technical director of RT thread. But ruffian Heng tells you, i.mxrt ROM The serial flash driver in the API is not inferior (it has been maintained and optimized for nearly six years, and it is a real product level after several MCU ROMs), but it is not as well-known as the open source project. However, 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 driven prototype

flexspi_ nor_ driver_ interface_ T is the prototype of flexspi nor driver, and the common read-write function is not uncommon. In addition, there is a very powerful xfer() function in the API, which can be used to implement other customized flash operation functions. Interested friends can further study it.

typedef struct
{
    uint32_t version;
    status_t (*init)(uint32_t instance, flexspi_nor_config_t *config);
    status_t (*program)(uint32_t instance, flexspi_nor_config_t *config, uint32_t dst_addr, const uint32_t *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)(uint32_t instance, flexspi_nor_config_t *config, serial_nor_config_option_t *option);
} 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,
};

2.2 examples of flexspi driver

Flexspi driver uses the basic three-step method, calling get first_ Config () gets the complete FlexSPI module configuration, then calls the init () function to initialize FlexSPI and access Flash to get the SFDP table information. Finally, it calls the Flash operation function (erase ()).

//Find the API root structure

2.3 flexspi drive features

Because the flexspi nor driver API comes from bootrom, it has some small limitations in use, which is its characteristics. The pinmux configuration for flash connection is not provided in the flexspi driver API. The pinmux configuration has been written in the init() function, that is, the pins on the flexspi porta that ROM supports booting (the selection is SS0).

In the example code above, you can see that option.option0 . u = 0xc0000008 code, which is the biggest feature of flexspi driver. This is a simplified option configuration word (its prototype can be found in the chip manual). Through this simplified option, users can easily configure to access flash from different manufacturers. The following are the 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)

2.4 flexspi driver as IAP

IAP is actually to achieve flash rewriting in the app, which is not a very difficult thing from the technical point of view. However, on i.mxrt, most of the app code itself is executed in the same flash (also known as XIP), and many flash in the market does not support RWW (read while write), which leads to a problem. When you call the flash operation function to erase flash, the CPU needs to continue to get instructions from flash, which violates RWW. Therefore, you can only put all flash related operation functions in RAM Execution (this involves distributed loading, which is a little bit difficult for a beginner embedded user).

Now that we have the ROM API, the flexspi driver code body is all in ROM space, and does not occupy flash space. Therefore, there is no RWW problem. It is born naturally for IAP, and we don’t have to worry about such troublesome things as distributed loading.

2.5. About non full function API

As mentioned in section 1.4, there is no full-featured API in i.mxrt1010, mainly because its bootrom space is too small to store redundant api code. The following is an API instance in i.mxrt1010. You can see that there are very few flexspi driver functions provided. We will introduce its usage 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,
 };

3、 Flexspi API industry application

Finally, I will introduce the application of i.mxrt flexspi API in the industry. This API is not a minority, and has been used as i.mxrt flash download algorithm by mainstream IDE and debugging tools.

3.1 for IAR download algorithm

If your IAR version is new enough to support i.mxrt1060 and other models, open an i.mxrt1060 SDK project, find the debugger in the project option, and then enter the flashloader configuration. You will see the extra parameters column in the page. An example of this parameter is shown in the following explanation. It is the option0 described in Section 2.3 above. With the flash download algorithm designed in this way, you no longer need to manually update the download algorithm file to support different flash, just change the parameters.

3.2 for j-link download algorithm

At present, the download algorithm in the latest JLINK driver is also based on ROM API. PI Ziheng has an open source project, which collects all the download algorithm source code projects of i.mxrt. Among them, the JLINK algorithm is the most complete, and other ide algorithms are still being improved.

https://github.com/JayHeng/imxrt-tool-flash-algo

So far, i.mxrt series ROM flexspi driver API implementation IAP ruffian balance will be introduced, where is the applause~~~