【原创】i.MXRT1050在线擦写QSPI Flash作数据备份
5赞幸好自己的老底还在,上一篇写完那一整个长篇大论之后,当年的感觉很快就找回来了,还是这种静下来思考并转换成文字的感觉让人踏实很多,无论是北京到山东的高铁上这难得的2个小时闲暇还是午饭后遛弯的那一二十分钟,我自己确实很享受这一刻既放松又保持思考的状态(有点装逼了。。。咳咳)。记得当年在AET论坛上,我还是忽悠了不少博友上了写博客这条船的,哈哈,整个AET博友圈写作的氛围很浓,只是不知道现在还再坚持的能有几个了,有句话虽然老生常谈但的确是真谛,很多事情你坚持个一两次不是很难,难的是能一直坚持下去,而一旦你坚持下来了再回过头来看就会发现,这种专注和坚持带来的益处是慢慢渗透到你的骨子里的(完了,我又开始忽悠了,Stop。。。呵呵)。其实在我上篇博客写完之后,收到很多博友的积极反馈(也有不少RT的真实用户获益),有朋友建议我直接在微信上开个公众号以后把文章直接更新到微信上去,好与时俱进一下,我刚开始是比较心动的,也看到有几个之前的AET老博主转战到公众号上去了,不过等回过神儿来细想想就发现有违开放的初衷,虽然不得不承认微信公众号目前的影响力和传播性,但是对这种技术问题分享类的文章我个人觉着不太适用,最主要的问题是微信看似是一个分享类的社区实际上却是一个封闭的分享社区(说句实在话,是腾讯系的分享社区),而且以腾讯的尿性它会越做越封闭(微信小程序就是典型的例子,把好好的APP Store这种生态给破坏了,所以你看最近华为,小米和阿里都在反对小程序),而回过来对我们技术类的总结性或者分享性的文章来说所谓的公众号不是看上去那么美好(对个人或者公司做宣传还可以),技术类文章的用户群大多数是通过搜索引擎来查找的,大家遇到技术问题都是百度或者Google,而微信公众号的接口目前只开放给了搜狗(我冒昧的说一句,有几个搞技术的会用搜狗去搜技术文章,略扯淡啊。。。),其他搜索引擎的网络爬虫根本就爬不到公众号的资源,那所谓的”公众号“难不成要我们拿着手机到北京的地铁上让大家扫码加好友吗,哎,当然这纯属个人一家之言啦,万一腾讯把百度和Google给收了呢,哈哈。好了,又闲扯了不少,下面咱开始正题了,走着。
之前提到RT1050在外部QSPI Flash启动并且Code在QSPI Flash执行是目前来讲比较常用的做法,那进而有用户会提出一种需求,很多应用都会有用到一些常数参数的存储(比如字库,数学上的三角函数查找表等等),以及重要数据的备份与实时记录或者整个应用firmware的在线升级,我们自然会想到外部那么大空间的QSPI Flash这下可以好好利用一番了,毕竟只是保存应用代码岂不是大大的浪费。所以下面就简单说明下实现RT1050在QSPI Flash XIP的同时还可以在线擦写QSPI Flash所需要注意的几点,并随本笔记附上测试代码供参考,实际上大家看了代码就弄明白怎么操作了,不过有以下几个方面我必须提出来,提醒大家需要重点注意的:
(1)我们的代码以XIP的方式在QSPI Flash上执行的同时还要能擦写自己,首先想到的就是冲突,QSPI Flash只接了一块(RT1050可以接两块独立的QSPI Flash,这种情况不提)而且QSPI Flash又不是双端口的,这样擦写QSPI flash相关的函数就务必要保证运行在SRAM里才行,是不能边执行边擦写自己的,这逻辑上肯定是不对的,所以需要把Flash操作相关操作的API分配到了SRAM里执行(代码基于Keil工程,为了尽量兼容且减少改动工程配置,我直接把相关函数分配到了SRAM的NoCacheable数据段,实际上分配到任意一个SRAM区都行,只是需要手动在.scf文件里RAM区新添加个地址段),然后将需要分配到SRAM区的Flash相关操作函数通过添加__attribute__((section("NonCacheable")))编译属性即可实现,如下图所示,我将flash擦除的操作放到RAM里了;
(2)外部QSPI Flash是通过RT1050的FlexSPI接口连接的,所以对其操作还得通过FlexSPI外设来进行。不过由于外部Boot模式已经选择了QSPI启动,所以系统每次复位后RT1050已经通过Flash配置信息字配置好了FlexSPI模块,所以我们千万不要再次对FlexSPI相关配置寄存器进行再次初始化了,因为一旦系统启动成功,代码已经通过FlexSPI正常运行在QSPI Flash上了,此时再去动态修改FlexSPI的寄存器会影响代码执行的(很容易hardfault或者程序执行乱套了),我们需要做的只是手动把擦写Flash相关的命令更新到FlexSPI的LUT查找表里就行了,如下图:
(3)上一步提到需要手动添加Flash擦写需要的相关命令到LUT表里,下面我就给出了擦写外部QSPI Flash需要用到的几个命令,把它放到自定义的LUT表里如下图,然后通过调用FLEXSPI_UpdateLUT将其更新到FlexSPI的真正LUT表。这里需要注意的是FlexSPI的LUT总共可以存放16个序列,每个序列最多可以存放8条可执行的指令,而QSPI启动时必须要前面几个LUT序列存放的是代码执行相关的指令(主要是第一个LUT,必须存放Flash读取命令供程序正常执行使用),所以这里我特意把前面的LUT都reserve了,而是使用第10到15个序列存放擦写Flash的命令(注意FLEXSPI_UpdateLUT时我也是特意只从第10个LUT表开始更新,10之前的LUT序列不受影响);
(4)另外需要注意的是RT1050的Dcache默认是打开的,这样我们在每次回读做校验的时候最好使用SCB_InvalidateDCache(); API用来清一下Dcache,避免回读的数据是cache里的从而造成校验失败。
最后就是告诉大家怎么编译测试本文档附带的工程和源文件,首先将压缩包中的hello_world_xip_flashdemo文件夹copy到\boards\evkmimxrt1050\demo_apps的路径下,然后还有个特别需要注意的地方就是 FlexSPI底层相关的部分函数也是需要copy到RAM里执行的(比如FLEXSPI_TransferBlocking),而FlexSPI底层函数是在SDK的Driver层的,所以需要将本文档附带的fsl_flexspi.c文件copy到\devices\MIMXRT1052\drivers路径下覆盖源文件(源文件最好备份一下),这样就可以编译连接整个工程并将代码下载到外部QSPI里打开串口终端进行测试了。
同样,继续本着开放的态度,参考代码和PDF版文档见如下附件: