大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是i.MXRT系列ROM中的FlexSPI驱动API实现IAP

  痞子衡的技术交流群里经常有群友提问: i.MXRT中的FlexSPI驱动API到底怎么用啊?这个问题已经出现过好几次了,本来痞子衡不打算专门为这个写文章的,因为这部分内容在芯片手册System Boot章节里的最后一节ROM APIs里其实介绍得非常详细了,但是既然还是有不少朋友在问这个,看起来手册里的内容藏得有点深,这么好的东西被埋没太可惜了,那么今天痞子衡就跟大家再认真聊一聊。

一、ROM API简介

1.1、API产生背景

  i.MXRT系列都是Flashless(没有内置NVM)的芯片,所以BootROM必不可少。BootROM是个很特殊的东西,本质上它是一个完整的C代码写成的系统级App,这个系统级App专门用于从外部存储器中加载用户级App执行。简单地说,BootROM就是PC机里的BIOS。

  BootROM代码是存放在专门的ROM区域的(前面讲i.MXRT系列没有内置NVM,其实不够准确,其实是有内部ROM空间的,只不过这个ROM区域用户无法下载程序使用,因此等效于没有NVM),ROM顾名思义Readonly,所以BootROM代码只能随着芯片一起Tapeout,代码无法更改(其实也有ROM patch机制,以后再介绍)。

  ROM空间其实挺大的,从64KB到512KB不等,因芯片启动功能复杂程度而异。下图是i.MXRT1050系列的BootROM所占空间,ROM起始地址是0x200000(起始地址在i.MXRT上都一样),ROM大小为96KB(这是标准启动功能所要的代码长度。在i.MXRT1010上是64KB - 精简启动功能,在i.MXRT1170上是256KB - 复杂启动功能)。

  BootROM代码其实并没有占满全部ROM空间,总有些剩余空间(因为工艺原因,ROM空间都是8/16KB倍数),这部分空间浪费了着实可惜。如果我们能把SDK里的一些常用模块驱动(比如WDOG)顺便放进去供用户调用,既充分利用ROM空间,也为用户节省Flash空间,岂不是一举两得。此外,BootROM功能代码中也有一些现成模块驱动(比如各种启动设备存储器驱动接口)可以一并导出,这便是API由来。

1.2、API设计实现

  有了API想法,现在就是设计实现了。其实i.MXRT ROM API设计并不是重头开始的,在这个MCU系列被主推之前,Kinetis系列也曾当红过,Kinetis中也内置了ROM,并且提供了ROM API,痞子衡之前为此写过一篇文章 《飞思卡尔Kinetis系列MCU启动那些事(11)- KBOOT特性(ROM API)》。 i.MXRT ROM API设计思路完全复用了Kinetis ROM API的设计。

  API说到底就是一个个功能函数的结合,我们知道工程代码都是由链接器自动分配的,因此每个函数实际链接地址是无法预期的(在链接文件里给每个函数分配固定地址链接这种方法不在考虑范畴,当函数数量众多时,这种方法太麻烦),业界上一个比较通用的做法是定义成员是函数指针的结构体,i.MXRT ROM API就是采用的业界通用方式,下面bootloader_api_entry_t便是i.MXRT1060中API原型,g_bootloaderTree就是实例:

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 = {
.copyright = "Copyright 2018 NXP",
.version = MAKE_VERSION(1, 0, 0),
.runBootloader = run_bootloader,
.habDriver = &hab_rvt, .flexSpiNorDriver = &g_flexspiNorDriverInterface, .nandEccDriver = &g_nandEccDriverInterface,
.clockDriver = &g_clockDriverInterface,
.rtwdogDriver = &g_rtwdogDriverInterface,
.wdogDriver = &g_wdogDriverInterface,
.stdlibDriver = &g_stdlibDriverInterface,
};

  从上面代码我们可以看出,bootloader_api_entry_t成员好像并不是函数指针,是的,为了分组方便,bootloader_api_entry_t成员还是一个个结构体,它的这些结构体成员(比如flexspi_nor_driver_interface_t)才是真正包含一个个函数指针的结构体。API从功能来分一共提供了7类:HAB、FlexSPI NOR、NAND ECC、Clock、RT-WDOG、WDOG、stdlib。

  设计到这里,我们通过g_bootloaderTree结构体常量就可以调用所有的API函数了,最后剩下的问题就是如何在ROM里找一个确定的地方保存随机链接的g_bootloaderTree地址(只要4字节即可)。是的,还是Kinetis ROM API用的那个巧妙的方法,下面是BootROM工程的startup文件(Keil版),BootROM将g_bootloaderTree的地址放到了中断向量表第8个向量的位置处(该向量为ARM Cortex-M未定义的系统向量),因此0x20001c处开始的4bytes便固定是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
;; ...

1.3、API调用方法

  了解了前面介绍的ROM API产生背景与设计实现,它的调用方法就非常简单了,以WDOG API调用为例,只需要如下简单3句代码:

// 找到API根结构体
#define g_bootloaderTree (*(bootloader_api_entry_t **)0x0020001c)
// 定义WDOG模块配置变量
wdog_config_t config;
// 调用API中WDOG_Init()
g_bootloaderTree->wdogDriver->WDOG_Init(WDOG1, config);

1.4、支持API的i.MXRT型号

  截止目前,i.MXRT1xxx系列一共出了7款型号,但并不是每个型号都开放了ROM API,最早诞生的三款型号(105x、1021、1015)就并没有开放API(不是没有API,而是没有严格测试),其余型号都支持API。

RT芯片型号 是否支持ROM API
i.MXRT117x 支持
i.MXRT1064 支持
i.MXRT106x 支持
i.MXRT105x 未开放
i.MXRT1021 未开放
i.MXRT1015 未开放
i.MXRT1011 支持

二、API之FlexSPI驱动

  前面铺垫了太多ROM API设计细节,到这里才算进入正题,本文其实主要是要跟大家聊如何利用API里的FlexSPI NOR驱动实现IAP。痞子衡在前面铺垫那么多的原因其实主要是想告诉大家,API里的每个驱动都是经过完善测试的,尤其是这个FlexSPI NOR驱动,更是经过了千锤百炼,无论是易用性、运行稳定性还是Flash型号的支持度上都是首屈一指的。

  对于JESD216标准下的串行SPI接口Flash驱动,大家知道更多的可能是RT-Thread技术总监朱天龙大神的开源 SFUD 项目,但痞子衡告诉你,i.MXRT ROM API里的这个串行Flash驱动也毫不逊色(持续维护与优化了近6年,历经多款MCU的ROM,是真正的产品级),只是不如开源项目那么知名,不过它的源代码也是开源在SDK里的(\SDK\middleware\mcu-boot\src\drivers\flexspi_nor),BSD-3-Clause许可证。

2.1 FlexSPI驱动原型

  flexspi_nor_driver_interface_t便是FlexSPI NOR驱动的原型,寻常的读写擦功能自然不在话下,除此以外,API里面还有一个非常厉害的xfer()函数,这个函数可以用来实现其他定制化的Flash操作函数,有兴趣的朋友可以进一步去研究。

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;

2.2 FlexSPI驱动使用示例

  FlexSPI驱动使用基本三步走,先调用get_config()获取完整FlexSPI模块配置,然后调用init()函数去初始化FlexSPI以及访问Flash获取SFDP表信息,最后就是调用Flash操作函数(比如erase())。

// 找到API根结构体
#define g_bootloaderTree (*(bootloader_api_entry_t **)0x0020001c) // 定义FlexSPI, Flash配置变量
flexspi_nor_config_t config;
serial_nor_config_option_t option;
option.option0.U = 0xC0000008; // QuadSPI NOR, Frequency: 133MHz
uint32_t instance = 0; // 调用API中get_config()函数
g_bootloaderTree->flexSpiNorDriver->get_config(instance, &config, &option);
// 调用API中init()函数
g_bootloaderTree->flexSpiNorDriver->init(instance, &config);
// 调用API中erase()函数
g_bootloaderTree->flexSpiNorDriver->erase(instance, &config, 0x40000, 0x1000);

2.3 FlexSPI驱动特点

  因为FlexSPI NOR驱动API来自于BootROM,因此其在使用上有一些小小的限制,也算是其特点吧。FlexSPI驱动API里并没有提供Flash连接的Pinmux配置,其Pinmux配置已经写死在init()函数中,就是ROM支持启动的FlexSPI PORTA上的那些pin(片选是SS0)。

  在上面的使用示例代码中,你会看到option.option0.U = 0xC0000008代码,这算是FlexSPI驱动最大的特点了,这是一个简化的option配置word(其原型可在芯片手册里找到),通过这个简化的option,用户可以轻松配置来访问不同厂商的Flash,下面是常用的Flash模式配置值。

• 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驱动用作IAP

  IAP其实就是在App中实现Flash擦写,单纯从技术上来说并不是一个很难的东西。但i.MXRT上很多时候App代码本身也在同一片Flash里执行(也叫XIP),而市面上很多Flash都是不支持RWW(Read-While-Write)的,这就导致一个问题,当你调用Flash操作函数去擦写Flash时,CPU又需要继续去Flash获取指令,违反了RWW,因此你只能把Flash相关操作函数全部放在RAM中去执行(这涉及分散加载了,对于初级嵌入式用户来说稍微有点难)。

  现在我们有了ROM API,FlexSPI驱动代码体全部都在ROM空间里,并不占用Flash空间,因此不存在RWW问题,真是天然为IAP而生,再也不用再管什么分散加载这么麻烦的事了。

三、FlexSPI API业界应用

  最后再介绍一下i.MXRT FlexSPI API在业界的应用,这个API其实并不小众,目前已被主流IDE和调试工具用作i.MXRT Flash下载算法。

3.1 用于IAR下载算法

  如果你的IAR版本够新,能够支持i.MXRT1060等型号,随便打开一个i.MXRT1060 SDK工程,在工程Option里找到Debugger,然后进入Flashloader配置,你会看到页面里有Extra parameters一栏,在下面的解释里有这个参数的示例,它就是前面2.3节里介绍的option0。有了这种方式设计的Flash下载算法,你再也不用手动更新下载算法文件去支持不同的Flash了,改参数就行了。

3.2 用于J-Link下载算法

  目前最新的Jlink驱动里的下载算法也是基于ROM API的,痞子衡有一个开源项目,收集了i.MXRT所有型号的下载算法源代码工程,其中jlink算法是最全的,其他IDE算法还在陆续完善中。

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

  至此,i.MXRT系列ROM中的FlexSPI驱动API实现IAP痞子衡便介绍完毕了,掌声在哪里~~~

欢迎订阅

文章会同时发布到我的 博客园主页CSDN主页微信公众号 平台上。

微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。

痞子衡嵌入式:利用i.MXRT1xxx系列ROM提供的FlexSPI driver API可轻松IAP的更多相关文章

  1. 痞子衡嵌入式:其实i.MXRT1050,1020,1015系列ROM也提供了FlexSPI driver API

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1050/1020/1015系列ROM中的FlexSPI驱动API使用. 今天痞子衡去4S店给爱车做保养了,保养一次要等两小 ...

  2. 痞子衡嵌入式:恩智浦LPC系列MCU开发那些事 - 索引

    大家好,我是痞子衡,是正经搞技术的痞子.本系列痞子衡给大家介绍的是恩智浦LPC系列微控制器相关知识. 恩智浦半导体最早于2003年便开始推出LPC系列MCU,但早期的产品LPC2000/3000系列属 ...

  3. 痞子衡嵌入式:了解i.MXRTxxx系列ROM API及其与i.MXRT1xxx系列的差异

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRTxxx系列ROM API设计细节. 痞子衡之前写过两篇文章 <利用i.MXRT1xxx系列ROM提供的FlexSPI ...

  4. 痞子衡嵌入式:自识别特性(Auto Probe)可以让i.MXRT1060无需FDCB也能从NOR Flash启动

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是自识别特性(Auto Probe)可以让i.MXRT1060无需FDCB也能从NOR Flash启动. 接着上篇文章 <了解i.M ...

  5. 痞子衡嵌入式:轻松为i.MXRT设计更新Segger J-Link Flash下载算法文件

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是为i.MXRT设计更新Segger J-Link Flash下载算法文件. 想要在Flash中调试,基本是离不开Flash下载算法的,毕 ...

  6. 痞子衡嵌入式:超级下载算法(RT-UFL)开发笔记(3) - 统一FlexSPI驱动访问

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是超级下载算法开发笔记(3)之统一FlexSPI驱动访问. 文接上篇 <超级下载算法(RT-UFL)开发笔记(2) - 识别当前i. ...

  7. 痞子衡嵌入式:利用i.MXRT1xxx系列内部DCP引擎计算Hash值时需特别处理L1 D-Cache

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是利用i.MXRT1xxx系列内部DCP引擎计算Hash值时需特别处理L1 D-Cache. 关于i.MXRT1xxx系列内部通用数据协处 ...

  8. 痞子衡嵌入式:了解i.MXRTxxx系列ROM中灵活的串行NOR Flash启动硬复位引脚选择

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRTxxx系列ROM中灵活的串行NOR Flash启动硬复位引脚选择. 关于 i.MXRT 系列 BootROM 中串行 NOR ...

  9. 痞子衡嵌入式:深扒i.MXRTxxx系列ROM中集成的串行NOR Flash启动SW Reset功能及其应用场合

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRTxxx系列ROM中集成的串行NOR Flash启动SW Reset功能及其应用场合. 在串行 NOR Flash 热启动过程 ...

随机推荐

  1. 跨域解决方案 - 跨域资源共享cors

    目录 1. cors 介绍 2. 原理 3. cors 解决跨域 4. 自定义HTTP 头部字段解决跨域 5. 代码演示 5. 参考链接 1. cors 介绍 cors 说的是一个机制,其实相当于一个 ...

  2. Window10:不能建立到远程计算机的连接,你可能需要更改此连接的网络设置。

    一,右键我的电脑点击管理. 二,在系统工具中找到设备管理,在设备管理中找到网络适配器. 三,在网络适配器中找到WAN Miniport(IP) 四,找到WAN Miniport(IP)右键放心卸载,作 ...

  3. Java实现 LeetCode 724 寻找数组的中心索引(暴力)

    724. 寻找数组的中心索引 给定一个整数类型的数组 nums,请编写一个能够返回数组"中心索引"的方法. 我们是这样定义数组中心索引的:数组中心索引的左侧所有元素相加的和等于右侧 ...

  4. Java实现 LeetCode 565 数组嵌套(没有重复值的数组)

    565. 数组嵌套 索引从0开始长度为N的数组A,包含0到N - 1的所有整数.找到并返回最大的集合S,S[i] = {A[i], A[A[i]], A[A[A[i]]], - }且遵守以下的规则. ...

  5. Java实现 蓝桥杯VIP 算法提高 前10名

    算法提高 前10名 时间限制:1.0s 内存限制:256.0MB 问题描述 数据很多,但我们经常只取前几名,比如奥运只取前3名.现在我们有n个数据,请按从大到小的顺序,输出前10个名数据. 输入格式 ...

  6. Java实现 LeetCode 40 组合总和 II(二)

    40. 组合总和 II 给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的每个数字在 ...

  7. Java实现 蓝桥杯 算法训练 景点游览

    试题 算法训练 景点游览 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 小明来到一个景区游玩,但是他的时间有限,没办法逛遍所有的景点,所以他从网上下载了每个景点的评分,他希望能够使 ...

  8. Java实现蓝桥杯调和级数

    1/1 + 1/2 + 1/3 + 1/4 + - 在数学上称为调和级数. 它是发散的,也就是说,只要加上足够多的项,就可以得到任意大的数字. 但是,它发散的很慢: 前1项和达到 1.0 前4项和才超 ...

  9. java实现棋盘上的麦子

    ** 棋盘上的麦子** 你一定听说过这个故事.国王对发明国际象棋的大臣很佩服,问他要什么报酬,大臣说:请在第1个棋盘格放1粒麦子,在第2个棋盘格放2粒麦子,在第3个棋盘格放4粒麦子,在第4个棋盘格放8 ...

  10. Markdown编辑器说明

    标题: Markdown编辑器说明 作者: 梦幻之心星 347369787@QQ.com 标签: [Markdown, 编辑器] 目录: [软件] 日期: 2020-6-4 前提说明 在使用Markd ...