痞子衡嵌入式:超级下载算法(RT-UFL)开发笔记(3) - 统一FlexSPI驱动访问
大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是超级下载算法开发笔记(3)之统一FlexSPI驱动访问。
文接上篇 《超级下载算法(RT-UFL)开发笔记(2) - 识别当前i.MXRT型号》,现在超级算法已经能够识别到当前i.MXRT型号了,下一步就是找到一套统一的底层Flash驱动函数来实现外接串行NOR Flash的基本擦写操作,这套统一的底层Flash驱动至少要在API层面做到与i.MXRT型号无关,并且调用方式统一,这样就相当方便后续的上层算法层面的逻辑设计了。
本篇是开发笔记第三篇,咱们就重点聊聊如何为超级下载算法设计一套统一的FlexSPI驱动接口及其访问方式。
一、找到统一的FlexSPI驱动
我们知道i.MXRT系列内部用于连接NOR Flash的外设名字叫FlexSPI,这个外设在不同i.MXRT型号上差异很小,这对于设计通用Flash驱动函数来说方便了很多,这也是痞子衡做i.MXRT超级算法的最初动机。
说到FlexSPI这个外设,其实就是Kinetis系列的QuadSPI外设的升级,在恩智浦MCUX SDK包里提供了一套标准的FlexSPI驱动,这个驱动写得还挺完善的,但是痞子衡并没有选择SDK标准驱动作为超级下载算法的底层Flash驱动。
\SDK_2.x.x\devices\MIMXRTxxxx\drivers\fsl_flexspi.c
\SDK_2.x.x\devices\MIMXRTxxxx\drivers\fsl_flexspi.h
\SDK_2.x.x\components\flash\nor\flexspi\fsl_flexspi_nor_flash.c
\SDK_2.x.x\components\flash\nor\flexspi\fsl_flexspi_nor_flash.h
我们知道i.MXRT系列都是包含BootROM的,BootROM都支持从外部串行NOR Flash启动,这意味着BootROM中也是集成了FlexSPI驱动的(驱动源码也开源在SDK里了),BootROM里这套驱动与MCUX SDK里的驱动大体上差不多,但是细节上有差异,痞子衡最终选择了BootROM里的FlexSPI驱动作为超级算法的底层Flash驱动,原因下一节会讲。
\SDK_2.x.x\middleware\mcu-boot\src\drivers\flexspi\bl_flexspi.c
\SDK_2.x.x\middleware\mcu-boot\src\drivers\flexspi\bl_flexspi.h
\SDK_2.x.x\middleware\mcu-boot\src\drivers\flexspi_nor\flexspi_nor_flash.c
\SDK_2.x.x\middleware\mcu-boot\src\drivers\flexspi_nor\flexspi_nor_flash.h
二、统一FlexSPI驱动访问方式
现在我们虽然找到了一套看似统一的FlexSPI驱动,但事情远不是这么简单。BootROM版本的FlexSPI驱动从API接口本身而言是几乎一致的,痞子衡之前也为此写过文章 《利用i.MXRT系列ROM提供的FlexSPI driver API可轻松IAP》,但是在不同i.MXRT型号上调用方式不统一(在开放API的i.MXRT型号上API函数地址不一,在不开放API的i.MXRT型号上需要手动移植mcu-boot里的源代码),因此我们需要对所有i.MXRT型号下的BootROM FlexSPI驱动调用方式做一个统一。
2.1 ROM API接口方式
首先讲开放ROM API的几款i.MXRT型号(RT500/RT600/RT1060/RT1064/RT1170),这里顺便先解释一下上一节的遗留问题,为何选择BootROM版本FlexSPI驱动而不是SDK标准驱动?当然是因为有这个ROM API的存在,毕竟超级下载算法最终可执行文件越小越好,能调用ROM API可以极大地减小超级下载算法的最终代码长度。
关于ROM API的细节,痞子衡不予赘述,我们按照如下格式准备好全部的g_bootloaderTree_imxrt宏待用(代码仅示例了i.MXRT1060)
#define RT106X_ROM_API_TREE_ADDR (0x0020001cu)
typedef struct _bootloader_tree_imxrt106x
{
const uint32_t version;
const char *copyright;
void (*runBootloader)(void *arg);
const uint32_t reserved0;
const flexspi_nor_flash_driver_imxrt106x_t *flexspiNorDriver;
} bootloader_tree_imxrt106x_t;
#define g_bootloaderTree_imxrt106x (*(bootloader_tree_imxrt106x_t **)(RT106X_ROM_API_TREE_ADDR))
2.2 源代码(库)接口方式
对于没有开放ROM API的几款i.MXRT型号(RT1010/1015/1020/1024/1050),咱们就必须一一移植mcu-boot里的FlexSPI相关代码了,需移植的代码包含两部分:FlexSPI外设本身驱动,FlexSPI BSP驱动。前者移植起来倒是比较简单(直接找一个最完善的版本即可),但是后者涉及到了clock和pinmux配置,因i.MXRT型号而异,这部分代码差异较大,移植起来比较麻烦。
FlexSPI外设本身驱动就是最终提供如下几个通用的函数即可,这部分是共用的源代码:
status_t flexspi_nor_drv_flash_init(uint32_t instance, flexspi_nor_config_t *config);
status_t flexspi_nor_drv_flash_page_program(uint32_t instance,
flexspi_nor_config_t *config,
uint32_t dstAddr,
const uint32_t *src);
status_t flexspi_nor_drv_flash_erase_all(uint32_t instance, flexspi_nor_config_t *config);
status_t flexspi_nor_drv_flash_erase(uint32_t instance, flexspi_nor_config_t *config, uint32_t start, uint32_t length);
status_t flexspi_nor_drv_flash_read(
uint32_t instance, flexspi_nor_config_t *config, uint32_t *dst, uint32_t start, uint32_t bytes);
status_t flexspi_nor_drv_get_config(uint32_t instance, flexspi_nor_config_t *config, serial_nor_config_option_t *option);
在移植FlexSPI BSP驱动过程中遇到了一个最头疼的事情,就是clock和pinmux代码需使用SDK里的基础驱动,而SDK驱动依赖i.MXRT芯片头文件,但是最终超级下载算法只有一个工程,这个工程几乎无法同时包含多个i.MXRT头文件。如果不用i.MXRT头文件,clock和pinmux代码全部改为裸写寄存器地址,工作量又太大,也不利于后期维护,最终想到的解决方案就是为每个i.MXRT型号的FlexSPI BSP驱动制作一个库工程,在库工程里各自使用自己的头文件,然后生成一个库文件作为超级下载算法工程的源文件。
下面是示例的i.MXRT1050库文件里需提供的BSP函数列表,这也是综合多个型号SDK包里mcu-boot代码后提炼出来的:
void flexspi_iomux_config_rt1050(uint32_t instance, flexspi_mem_config_t *config);
void flexspi_update_padsetting_rt1050(flexspi_mem_config_t *config, uint32_t driveStrength);
void flexspi_clock_config_rt1050(uint32_t instance, uint32_t freq, uint32_t sampleClkMode);
status_t flexspi_set_failsafe_setting_rt1050(flexspi_mem_config_t *config);
status_t flexspi_get_max_supported_freq_rt1050(uint32_t instance, uint32_t *freq, uint32_t clkMode);
uint32_t CLOCK_GetCPUFreq_RT1050(void);
status_t flexspi_get_clock_rt1050(uint32_t instance, flexspi_clock_type_t type, uint32_t *freq);
void flexspi_clock_gate_enable_rt1050(uint32_t instance);
void flexspi_clock_gate_disable_rt1050(uint32_t instance);
status_t flexspi_nor_write_persistent_rt1050(const uint32_t data);
status_t flexspi_nor_read_persistent_rt1050(uint32_t *data);
2.3 两种不同方式的驱动统一
现在无论是ROM API接口方式,还是源代码(库)接口方式,所有的i.MXRT型号下基础FlexSPI驱动已经准备完毕了,到了最关键的统一阶段了,我们首先可以定义一个如下ufl_target_desc_t结构体及其全局变量g_uflTargetDesc,这个结构体由FlexSPI擦写API函数指针(flexspi_nor_flash_driver_t)以及BSP函数指针(flexspi_bsp_driver_t)组成:
typedef struct _target_desc
{
uint32_t imxrtChipId;
flexspi_nor_flash_driver_t flashDriver;
flexspi_bsp_driver_t flexspiBsp;
} ufl_target_desc_t;
ufl_target_desc_t g_uflTargetDesc;
然后我们定义一个ufl_fill_flash_api()函数,该函数的功能就是根据识别出来的i.MXRT型号来具体填充ufl_target_desc_t型全局结构体变量里的成员值。如果是源代码接口方式,则填入对应函数名;如果是ROM API接口方式,则根据g_bootloaderTree_imxrt宏找到对应函数地址,最终我们在g_uflTargetDesc全局变量里统一了FlexSPI驱动访问方式(下述代码仅示例了RT1050和RT1060)。
static void ufl_fill_flash_api(void)
{
rt_chip_id_t chipId = (rt_chip_id_t)g_uflTargetDesc.imxrtChipId;
ufl_target_desc_t *uflTargetDesc = (ufl_target_desc_t *)&g_uflTargetDesc;
switch (chipId)
{
case kChipId_RT105x:
uflTargetDesc->flashDriver.init = flexspi_nor_drv_flash_init;
uflTargetDesc->flashDriver.page_program = flexspi_nor_drv_flash_page_program;
uflTargetDesc->flashDriver.erase_all = flexspi_nor_drv_flash_erase_all;
uflTargetDesc->flashDriver.erase = flexspi_nor_drv_flash_erase;
uflTargetDesc->flashDriver.read = flexspi_nor_drv_flash_read;
uflTargetDesc->flashDriver.set_clock_source = NULL;
uflTargetDesc->flashDriver.get_config = flexspi_nor_drv_get_config;
uflTargetDesc->flexspiBsp.flexspi_iomux_config = flexspi_iomux_config_rt1050;
uflTargetDesc->flexspiBsp.flexspi_update_padsetting = flexspi_update_padsetting_rt1050;
uflTargetDesc->flexspiBsp.flexspi_clock_config = flexspi_clock_config_rt1050;
uflTargetDesc->flexspiBsp.flexspi_set_failsafe_setting = flexspi_set_failsafe_setting_rt1050;
uflTargetDesc->flexspiBsp.CLOCK_GetCPUFreq = CLOCK_GetCPUFreq_RT1050;
uflTargetDesc->flexspiBsp.flexspi_get_max_supported_freq = flexspi_get_max_supported_freq_rt1050;
uflTargetDesc->flexspiBsp.flexspi_clock_gate_enable = flexspi_clock_gate_enable_rt1050;
uflTargetDesc->flexspiBsp.flexspi_clock_gate_disable = flexspi_clock_gate_disable_rt1050;
uflTargetDesc->flexspiBsp.flexspi_nor_write_persistent = flexspi_nor_write_persistent_rt1050;
uflTargetDesc->flexspiBsp.flexspi_get_clock = flexspi_get_clock_rt1050;
uflTargetDesc->flexspiBsp.flexspi_nor_read_persistent = flexspi_nor_read_persistent_rt1050;
break;
case kChipId_RT106x:
uflTargetDesc->flashDriver.init = g_bootloaderTree_imxrt106x->flexspiNorDriver->init;
uflTargetDesc->flashDriver.page_program = g_bootloaderTree_imxrt106x->flexspiNorDriver->program;
uflTargetDesc->flashDriver.erase_all = g_bootloaderTree_imxrt106x->flexspiNorDriver->erase_all;
uflTargetDesc->flashDriver.erase = g_bootloaderTree_imxrt106x->flexspiNorDriver->erase;
uflTargetDesc->flashDriver.read = g_bootloaderTree_imxrt106x->flexspiNorDriver->read;
uflTargetDesc->flashDriver.set_clock_source = NULL;
uflTargetDesc->flashDriver.get_config = g_bootloaderTree_imxrt106x->flexspiNorDriver->get_config;
break;
case kChipId_Invalid:
default:
break;
}
}
有了g_uflTargetDesc全局变量,此时再包一层API驱动给最终下载算法上层逻辑调用就非常简单了。
status_t flexspi_nor_flash_init(uint32_t instance, flexspi_nor_config_t *config)
{
return g_uflTargetDesc.flashDriver.init(instance, config);
}
void flexspi_iomux_config(uint32_t instance, flexspi_mem_config_t *config)
{
g_uflTargetDesc.flexspiBsp.flexspi_iomux_config(instance, config);
}
至此,超级下载算法开发笔记(3)之统一FlexSPI驱动访问痞子衡便介绍完毕了,掌声在哪里~~~
欢迎订阅
文章会同时发布到我的 博客园主页、CSDN主页、知乎主页、微信公众号 平台上。
微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。

痞子衡嵌入式:超级下载算法(RT-UFL)开发笔记(3) - 统一FlexSPI驱动访问的更多相关文章
- 痞子衡嵌入式:借助Serial Plot软件测量i.MXRT系列FlexSPI驱动Flash页编程执行时间
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT系列FlexSPI驱动Flash页编程执行时间. 痞子衡之前写过一篇文章 <串行NOR Flash的页编程模式对于量产 ...
- 痞子衡嵌入式:ARM Cortex-M内核MCU开发那些事 - 索引
大家好,我是痞子衡,是正经搞技术的痞子.本系列痞子衡给大家介绍的是ARM Cortex-M内核微控制器相关知识. ARM公司从2004年开始推出Cortex-M系列内核,迄今Cortex-M家族已经包 ...
- 痞子衡嵌入式:恩智浦LPC系列MCU开发那些事 - 索引
大家好,我是痞子衡,是正经搞技术的痞子.本系列痞子衡给大家介绍的是恩智浦LPC系列微控制器相关知识. 恩智浦半导体最早于2003年便开始推出LPC系列MCU,但早期的产品LPC2000/3000系列属 ...
- 痞子衡嵌入式:超级下载算法RT-UFL v1.0发布,附J-Link下安装教程
痞子衡主导的"学术"项目 <RT-UFL - 一个适用全平台i.MXRT的超级下载算法设计> 历时 8 个月终于迎来了 v1.0 版发布,因为是第一个正式版,为了保证质 ...
- 痞子衡嵌入式:超级下载算法(RT-UFL)开发笔记(4) - 轮询Flash配置参数
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是超级下载算法开发笔记(4)之轮询Flash配置参数. 文接上篇 <超级下载算法(RT-UFL)开发笔记(3) - 统一FlexSP ...
- 痞子衡嵌入式:恩智浦i.MX RT1xxx系列MCU硬件那些事(2.3)- 串行NOR Flash下载算法(J-Link工具篇)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是J-Link工具下i.MXRT的串行NOR Flash下载算法设计. 在i.MXRT硬件那些事系列之<在串行NOR Flash X ...
- 痞子衡嵌入式:RT-UFL - 一个适用全平台i.MXRT的超级下载算法设计
大家好,我是痞子衡,是正经搞技术的痞子.今天给大家带来的是痞子衡的开源项目 RT-UFL. 痞子衡在近两年多的i.MXRT客户项目支持过程中,遇到的一个相当高频的问题就是制作i.MXRT下载算法.我们 ...
- 痞子衡嵌入式:超级下载算法(RT-UFL)开发笔记(1) - 执行在不同CM内核下
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是超级下载算法开发笔记(1)之执行在不同CM内核下. 文接上篇 <RT-UFL - 一个适用全平台i.MXRT的超级下载算法设计&g ...
- 痞子衡嵌入式:超级下载算法(RT-UFL)开发笔记(2) - 识别当前i.MXRT型号
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是超级下载算法开发笔记(2)之识别当前i.MXRT型号. 文接上篇 <超级下载算法(RT-UFL)开发笔记(1) - 执行在不同CM ...
随机推荐
- 干电池升压3.3V的电源芯片
PW5100适用于一节干电池升压到3.3V,两节干电池升压3.3V的升压电路,PW5100干电池升压IC. 干电池1.5V和两节干电池3V升压到3.3V的测试数据 两节干电池输出500MA测试: PW ...
- 基于scrapy框架的分布式爬虫
分布式 概念:可以使用多台电脑组件一个分布式机群,让其执行同一组程序,对同一组网络资源进行联合爬取. 原生的scrapy是无法实现分布式 调度器无法被共享 管道无法被共享 基于 scrapy+redi ...
- Py-时间,随机,os,sys,jsonpickle序列化,shelve,xml模块
内置模块 1.时间模块 第一:time.time()是时间戳 时间戳默认是 从1970年到现在过的秒数,是一个很长的数值它可以做时间的计算以及显示 第二:localtime() 获取当前的时间,按元组 ...
- Ubuntu安装记录
好吧,这成功地让我想起了那些边肯红薯边黑苹果的早晨······ 本人纯属Windows用腻,后期请大佬多多指教 前面因为没U盘而碰壁的内容在此不说,接下来因为太兴奋,关于安装U盘制作没记录什么.最终, ...
- 代码托管从业者 Git 指南
本文作者:李博文 - CODING 后端开发工程师 前言 六七年前,我机缘巧合进入了代码托管行业,做过基于 Git 支持 SVN 客户端接入.Git 代码托管平台分布式.Git 代码托管读写分离.Gi ...
- 转 7 jmeter之参数化
7 jmeter之参数化 badboy里参数化(前面4 jmeter badboy脚本开发技术详解已讲过) jmeter里参数化-1 用户参数 1.打开badboy工具,点击红色按钮开始录制,在地 ...
- 每月一更的《HelloGitHub》第 58 期,来啦!
HelloGitHub 分享 GitHub 上有趣.入门级的开源项目.欢迎大家: 贡献代码 宣传你觉得优秀的项目 Star 项目️ 本月刊是每月 28 号更新,再见月刊就是年后了.在这里提前祝大家:新 ...
- Linux系统使用lvm扩展根分区
Linux系统使用lvm扩展根分区 背景:买的云主机虚拟机封装镜像是40G的系统盘,后期适用不规范或者其他需求需要扩展系统盘,而非挂载在一个盘至新建目录. 1.原本目录磁盘等信息: 2.使用vgdis ...
- HA工作机制
HA工作机制 HA:高可用(7*24小时不中断服务) 主要的HA是针对集群的master节点的,即namenode和resourcemanager,毕竟DataNode挂掉之后影响 不是特别大,重启就 ...
- JAVA中关于基本数据和引用数据参数传递过程
基本数据和引用数据参数传递过程 案例1:判断程序的输出结果 class Demo{ public static void main(String[] atgs){ int x =4; show(x); ...