大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是 IAR 开发环境下 i.MXRT 的串行 NOR Flash 下载算法设计。

 

在 i.MXRT 硬件那些事系列之《在串行 NOR Flash XIP 调试原理》一文中,痞子衡简单提了一下串行 NOR Flash 下载算法的概念,并没有介绍具体设计细节,关于 NOR Flash 下载算法每个 IDE 都有自己的一套设计,虽然基本设计理念是一样的,但是细节方面还是有区别。在前面的文章里,痞子衡分别介绍过《J-Link 下算法设计》、《Keil MDK 下算法设计》,今天痞子衡就来细聊 IAR 下的 NOR Flash 下载算法:

 

一、IAR 各版本对 i.MXRT 的支持

IAR 跟 Keil 一样都是非常经典的 MCU 开发 IDE,可以说是难分伯仲,痞子衡求学期间就用 IAR 开发过 MSP430 单片机,但是只是浅尝辄止,因为搞 ARM Cortex-M 就切换到更熟悉的 Keil 下了,直到毕业后加入恩智浦才一直在用 IAR。这么多年过去了,IAR 还是当初那个独立小公司,没有被收购,而且依然保持竞争力,这一波 RISC-V 浪潮估计会让它超越被 ARM 束缚的 Keil。

 

从 IAR 官网上看,目前最新的 IAR EWARM 版本是 v8.50.6,其能够支持目前所有已量产的 i.MXRT 系列。如果你安装的不是最新版本,比如安装了 v8.40,从 IAR 历史各版本 Release Note 上看,v8.40 版本不支持 RT500 和 RT600,那么如果想要支持新芯片(比如 RT600),是不是一定要重新安装最新 IAR 呢?其实未必!

 

IAR 对新 MCU 型号的支持并不是与自身版本严格绑定的,其增加新芯片的方式很灵活,只需要按要求打上相应芯片的 patch 包即可。

 

二、为当前 IAR 增加新 i.MXRT 型号支持

在 IAR 历史各版本 Release Note 页面点击 8.50 进入这个版本的专属页面,往下翻你会找到专门的 i.MXRT600 patch 包,直接下载这个包(ewarm850-nxp-imxrt5xx-6xx-patch4.zip 文件)。

 

有了 patch 包之后,打 patch 就相当简单了,直接将 ewarm850-nxp-imxrt5xx-6xx-patch4.zip 包解压放到 IAR 安装目录下即可,patch 包的文件目录结构与 IAR 下安装目录结构是一样的。

 

patch 包里的文件很多,其中跟下载算法相关的一共如下四个文件:.board 和 .flash 是 xml 文件,其功能类似 JLink 下的 JLinkDevices.xml 文件。.mac 是预加载文件,功能类似 JLink 下的 .JLinkScript 文件,.out 文件就是真正的下载算法可执行文件。

 

\arm\config\flashloader\NXP\FlashIMXRT600_EVK_FLEXSPI.board

\arm\config\flashloader\NXP\FlashIMXRT600_EVK_FLEXSPI.flash

\arm\config\flashloader\NXP\FlashIMXRT600_EVK_FLEXSPI.mac

\arm\config\flashloader\NXP\FlashIMXRT600_EVK_FLEXSPI.out

 

两个 xml 文件里的代码含义在 \IAR Systems\Embedded Workbench 8.50.6\arm\doc\FlashLoaderGuide.ENU.pdf 文档的 The flash memory configuration file 和 The flash memory system configuration file 两小节里有详细解释。

 

2.1 .board 文件代码分析

.board 顾名思义就是板级描述文件,每个 .board 文件可以指向多个 .flash 文件(如果这块板子存在多块 flash)。让我们试着分析 FlashIMXRT600_EVK_FLEXSPI.board 文件中那些模板代码的含义:.board 文件里可以有多个块,每个 pass 对应一种 flash 类型。在每个里最多有如下 6 个参数(其中 loader 参数是必须的,其他是可选):

 

loader     -- 指示 .flash 文件路径。

range      -- Flash 在芯片内存中的映射空间范围。

abs_offset -- 当被下载的 app 链接地址与往 Flash 中下载的映射地址不同时,指示 Flash 下载地址。

rel_offset -- 作用与 abs_offset 类似,但是指示链接地址与下载地址间的偏移,可正可负。

flash_base -- Flash 在芯片内存中的映射基地址,会覆盖 .flash 文件中同名参数。

args       -- 传入下载算法 FlashInit()函数,类 argc/argv 格式。

 

2.2 .flash 文件代码分析

.flash 就是 flash 描述文件了,这些信息最终会提供给调试器。让我们继续分析 FlashIMXRT600_EVK_FLEXSPI.flash 文件中那些模板代码的含义:.flash 文件里最多有如下 12 个参数(其中前四个参数是必须的,其他是可选):

 

exe        -- 指示下载算法文件(.out)路径。

flash_base -- Flash 在芯片内存中的映射基地址。

page       -- Flash 的页大小。

block      -- Flash 的块数量及大小。

gap        -- 标示 Flash 中块的无效区间,C-SPY 会检查并返回错误。

macro      -- 指示预加载文件(.mac)路径。

online     -- 指示下载算法是否支持 Flash 断点。

filler     -- 下载时的 padding 内容,默认 255(0xFF).

checks     -- 设为 0 则强制检查下载算法中函数(比如 FlashWrite)的返回值,不启用这些检查能提升下载性能。

aggregate  -- 如果 Flash 块大小明显小于 RAM 缓冲区,该参数设为 1,可指示 C-SPY 高效使用 RAM 缓冲区去下载(比如将多个 block 数据放到 RAM 缓冲区)。

args       -- 传入下载算法 FlashInit()函数,类 argc/argv 格式。

args_doc   -- args 参数的描述字段(IDE 里会显示)。

 

2.3 使用下载算法

随便打开一个 i.MXRT600 SDK 工程,在工程 Option 里找到 Debugger,然后进入 Flashloader 配置,在界面里你可以看到前面介绍的 .board 和 .flash 文件,以及可以直接设置这些 xml 文件里的部分参数。如果安装的 Flash 下载算法文件不适用你的板子,那么你需要自己提供合适的算法文件(.out),并修改 .flash 文件里相应路径以及参数即可。

 

三、NOR Flash 下载算法设计

IAR 下 Flash 下载算法是开源的,\IAR Systems\Embedded Workbench 8.50.6\arm\doc\FlashLoaderGuide.ENU.pdf 文档有非常详细的介绍,篇幅不长,只有 47 页,建议全部读一遍。

 

3.1 下载算法模板工程

IAR 提供了一个 Flash 下载算法的基础模板,可从官网下载,也可以在 IAR 安装目录下找到,这个模板只是通用的算法源文件,没有相应模板工程,并且源文件只是算法框架,没有具体芯片相关的 Flash 驱动实现。

 

  • 模板官网下载:/zixunimg/eefocusimg/files.iar.com/public/cmsis/IAR_flashloader_framework_200.zipIAR 下模板路径:\IAR Systems\Embedded Workbench 8.50.6\arm\src\flashloader\framework2

 

该算法基础模板包含四个文件,我们需要根据模板源文件创建具体目标芯片的算法工程,然后将 flash_loader.h 里声明的算法 API 函数根据芯片去具体实现。

 

\IAR\arm\src\flashloader\framework2\flash_loader.c

\IAR\arm\src\flashloader\framework2\flash_loader.h

\IAR\arm\src\flashloader\framework2\flash_loader_asm.s

\IAR\arm\src\flashloader\framework2\flash_loader_extra.h

 

算法总共定义了如下 5 个 API 函数,其中关于初始化以及擦写的 API 函数(FlashInit、FlashWrite、FlashErase)是必须要实现的,另外两个是可选的。

 

其实在 IAR 安装目录下也提供了生成最终算法文件的 IAR 工程,我们可以直接在这个工程基础上修改生成新算法文件。i.MXRT 系列有四个算法源工程。

 

3.2 下载算法结构设计

算法本身结构相比 MDK 下算法设计相对来说稍微复杂一点,仅以 FlashInit 相关的代码来介绍。flash_loader_asm.s 文件中定义了 FlashInitEntry()入口,这个入口是直接由调试器来调用的。

 

;---------------------------------

; FlashInitEntry()

;---------------------------------

        SECTION .text:CODE:ROOT(2)

        THUMB



FlashInitEntry:

        BL       Fl2FlashInitEntry

        BL       FlashBreak

 

FlashInitEntry()函数功能非常简单,主要就是跳转到 Fl2FlashInitEntry()函数中,这个 Fl2FlashInitEntry()函数原型在 flash_loader.c 文件中。Fl2FlashInitEntry()还是只是个架子,其主要是将 theFlashParams 全局变量的一些 Flash 属性相关内容传入最关键的也是由用户来实现的 FlashInit()函数。theFlashParams 内容由调试器根据 xml 文件中设置来初始化。

 

FlashInit()函数有两个版本,__argc 和 __argv 参数可带也可不带,实际上这个可选参数就是为 i.MXRT 系列单独加的,主要用于传递外接 Flash 的信息(比如 2.3 节图片里的 --MxicOct )。其余两个重要函数 FlashWrite、FlashErase 与 FlashInit 代码结构类似,不予赘述。

 

// parameter passing structure

typedef struct {

  uint32_t base_ptr;

  uint32_t count;

  uint32_t offset_into_block;

  void *buffer;

  uint32_t block_size;

} FlashParamsHolder;



__root __no_init FlashParamsHolder  theFlashParams;



__no_init int __argc;

__no_init char __argvbuf[MAX_ARG_SIZE];

#pragma required=__argvbuf

__no_init const char* __argv[MAX_ARGS];



void Fl2FlashInitEntry()

{

#if USE_ARGC_ARGV

  theFlashParams.count = FlashInit((CODE_REF)theFlashParams.base_ptr,

                                   theFlashParams.block_size,       // Image size

                                   theFlashParams.offset_into_block,// link adr

                                   theFlashParams.count,            // flags

                                   __argc,

                                   __argv);

#else

  theFlashParams.count = FlashInit((CODE_REF)theFlashParams.base_ptr,

                                   theFlashParams.block_size,       // Image size

                                   theFlashParams.offset_into_block,// link adr

                                   theFlashParams.count);           // flags

#endif

}

 

让我们再打开 FlashIMXRT1060_FlexSPI 示例算法工程,可以看到这个工程既包含了算法基础模板源文件,也包含了用户实现的 i.MXRT1060 的 FlexSPI 驱动。关于这个工程,有一个跟 MDK 下算法工程比较大的区别就是,IAR 算法工程并没有启用位置无关的编译,它更接近标准的嵌入式应用程序工程。


3.3 下载算法 API 调用流程

\IAR Systems\Embedded Workbench 8.50.6\arm\doc\FlashLoaderGuide.ENU.pdf 文档的 The IAR Flash Loader process 小节里对于下载算法调用过程有详细解释。痞子衡将其简要整理在了下面这张图里: