jicheng0622

【原创】i.MXRT1050在线擦写QSPI Flash作数据备份

3
阅读(3334) 评论(10)

       幸好自己的老底还在,上一篇写完那一整个长篇大论之后,当年的感觉很快就找回来了,还是这种静下来思考并转换成文字的感觉让人踏实很多,无论是北京到山东的高铁上这难得的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里了;

clip_image002

clip_image004

(2)外部QSPI Flash是通过RT1050的FlexSPI接口连接的,所以对其操作还得通过FlexSPI外设来进行。不过由于外部Boot模式已经选择了QSPI启动,所以系统每次复位后RT1050已经通过Flash配置信息字配置好了FlexSPI模块,所以我们千万不要再次对FlexSPI相关配置寄存器进行再次初始化了,因为一旦系统启动成功,代码已经通过FlexSPI正常运行在QSPI Flash上了,此时再去动态修改FlexSPI的寄存器会影响代码执行的(很容易hardfault或者程序执行乱套了),我们需要做的只是手动把擦写Flash相关的命令更新到FlexSPI的LUT查找表里就行了,如下图:

clip_image006

(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序列不受影响);

clip_image008

clip_image010

(4)另外需要注意的是RT1050的Dcache默认是打开的,这样我们在每次回读做校验的时候最好使用SCB_InvalidateDCache(); API用来清一下Dcache,避免回读的数据是cache里的从而造成校验失败。

clip_image012

       最后就是告诉大家怎么编译测试本文档附带的工程和源文件,首先将压缩包中的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版文档见如下附件:

RT1050在线擦写QSPI Flash作数据备份.zip


  1. 您好,有个疑问,您提到的XIP模式qspi flash擦写,本质是flash擦除的时候不能读取指令。如果是这样的话,我觉得不管flash在芯片内部还是在芯片外部都会存在这个问题。正确是应该等flash擦除结束再去读指令,那么仅仅把擦写指令放到ram中也无法保证这一点,如果想保证这一点,编程者还需要遵守一个流程就是将“擦除+等待擦除结束的循环”这一套都放到ram中去。


    按理说外接flash的话,cup是无法知道每个flash厂子的擦写指令的,只是单纯的执行命令。所以想问楼主,LUT存在的意义是为了让cup知道所执行指令的含义吗?如果是,那么cup识别出来擦指令后来个flash锁死来避免擦写冲突是否更好?(内嵌flash时是不是就是这么干的?)

  2. 老纪下一篇文章啥时出来,等到花儿都谢了

  3. 牛气哄哄~

  4. @nicehope47   

    你好!程序员高手!看了你分享的這篇文章,我這邊有把HyperFlash硬件替換為OCTAL Flash,在替換後目前我寫了一段程序也能正常的讀取跟燒寫OCTAL Flash(在Debug模式底下),因為我是使用Keil IDE環境,在這個環境下如果要使用Keil IDE的Download至Flash,需要有.FLM的寫入算法,因為附件有提供MIMXRT_QSPIFLASH.FLM這個算法,所以想請教程序员高手這個算法該如何產生?或者是我能參考那邊的代碼來做出這個算法?

    请耐心等待我下篇文章,如果着急请把邮箱给我,我会把源码先发给你。

  5. 你好!程序员高手!看了你分享的這篇文章,我這邊有把HyperFlash硬件替換為OCTAL Flash,在替換後目前我寫了一段程序也能正常的讀取跟燒寫OCTAL Flash(在Debug模式底下),因為我是使用Keil IDE環境,在這個環境下如果要使用Keil IDE的Download至Flash,需要有.FLM的寫入算法,因為附件有提供MIMXRT_QSPIFLASH.FLM這個算法,所以想請教程序员高手這個算法該如何產生?或者是我能參考那邊的代碼來做出這個算法?

  6. @lwplwp2   

    是不是bootloader的加密和用户程序的加密要分开来,然后在自己设计的bootloader里面去对固件进行解密?

    呵呵 你走的太超前 我还没开始深入研究加密那块

  7. @zhangchunlei88   

    尊敬的程序员高手,我用函数flexspi_nor_flash_erase_sector擦除块后,读出的第一个字符怎么会是0x7F,在线调试时有时候也是0xFF,后面的数都是0xFF。不知道啥原因,是QSPI时钟跑的太快了吗。

    你在读的时候清cache了吗,必须得清cache再读,否则有可能是cache里数据

  8. 尊敬的程序员高手,我用函数flexspi_nor_flash_erase_sector擦除块后,读出的第一个字符怎么会是0x7F,在线调试时有时候也是0xFF,后面的数都是0xFF。不知道啥原因,是QSPI时钟跑的太快了吗。

  9. 是不是bootloader的加密和用户程序的加密要分开来,然后在自己设计的bootloader里面去对固件进行解密?

  10. 老前辈,请教一下如果通过cst工具对程序进行加密以后,在升级固件后,可以对固件进行加密吗?我的现在对加密过程的理解是,对程序加密后生成KeyBlob数据段,将解密信息放在KeyBlob数据段中,那升级固件后不对KeyBlob数据段进行更新如何加密?