【原创】i.MXRT1050常用厂家QSPI Flash Keil下Flash烧写算法(附源码)
2赞几个月没更新博客了,也好久没在高铁上抽空写篇文章了,一晃工作恰好迈过五年的坎(最近开始忧虑即将到来的中年危机,哎),博客竟然也写了7年多(当年在实验室第一次落笔写第一篇博客时真心没想到这一写就是7年)。不过最近这几年工作节奏不断加快,文章的出产率的确有点低(以前1个月写的就可以够现在憋一年的了,哈哈),工作、生活、家庭的琐事让静下心来思考的时间少了,总结梳理文章的机会自然也少了,这是一种妥协?估计是吧,不过俺的初心不变哈,毕竟我是和AET,也是和广大博友们确认过眼神的,呵呵。。。
本来这篇文章早就应该在上两篇文章写完之后一鼓作气搞出来的,也答应了博友赶紧写出来,结果事情太多竟然拖到现在也是心中惭愧的很,更无奈的是本想趁着上周修病假的时候写上个几篇一吐为快,结果修了个假竟然比不修时还忙,也是醉了。这次趁着去苏州出差,难得的高铁时刻硬是让俺文思泉涌啊,所以赶紧拿起电脑,时不我待,不然等车到站了又该做好一阵心理斗争了,哈哈。前段时间我真是花了好多心思在i.MXRT的QSPI Flash上了,仔细钻研了一番(包括前两篇已经写出来的QSPI启动和在线擦写),没办法,谁让咱家这颗片子不带内部Flash呢,所以本篇就重点说说我们在Keil下针对常用厂家的几种QSPI Flash型号的烧写算法(IAR的源码比较简单而且NXP官网也放出了修改后的源码,所以这里就不提了),这也是目前很多RT用户迫切想要的,当然我也看见有不少第三方甚至用户自己已经针对正在使用的QSPI Flash型号开发了算法,不过实际上用起来还是有不少tips需要注意,下面我就说一说侃一侃,各位看官,咱们走起:
1. 首先我觉着先有必要吐槽一下各家QSPI Flash的兼容性问题,虽然大家都号称符合JEDEC框架下的标准(实际上的确是大多数常用的读擦写命令是一样的),但是作为QSPI Flash最关键的‘Q’即4线使能位QE竟然不同家的Flash所在的寄存器位置是不一样的(更过分的,GD家竟然自家不同电压等级的Flash使能QE位的命令不一样,汗啊,博客里不支持微信表情包,不然我真想挂上一个捂眼睛的那个表情,呵呵),我们知道默认所有家的QSPI Flash是只能用单线和双线SPI模式的,如果要用4线SPI模式则需要先置位SPI Flash内部状态寄存器里面的QE位(QE默认为0,即单线或双线模式)才可以让Flash接收4线SPI的命令,所以两个问题就来了,第一个问题是开发环境下的Flash烧写算法需要适配不同家的Flash就需要根据不同的Flash写不同位置的QE位,第二个问题是QE位是不是每次下载都要写一次,如果是那RT岂不是启动的时候也需要手动去写它?见如下2、3点介绍;
2. 针对需要考虑的第一个问题,我下面列出了几家常用厂家的QSPI Flash的spec,可以看到这几家的QE位都是不一样的,尴尬不尴尬,尤其要提的是GD的QSPI Flash 1.8v和3.3v虽然QE的位置是一样的,但是写状态寄存器的命令是不一样的(3.3v需要专门的0x31命令单独写S2的8位寄存器才能行,而1.8v的直接用0x01可以连续写S1和S2 16位状态寄存器就可以了)
ISSI 1.8v/3.3v QSPI Flash
GD 3.3v QSPI Flash
Winbond 1.8v/3.3v and GD 1.8v QSPI Flash
3. 针对上面要考虑的第二个问题,手册里有一点写的比较明确,即QE位是非易失位(non-volatile,你可以理解它是写到内部某个专门的Flash区的,上电后load到状态寄存器里),也就是说实际上我只要写一次QE位即可,不需要每次下载代码的时候都去骚扰它,更何况它还禁不住骚扰(如果是非易失位,可以理解成都是有擦写寿命的,所以没事不用老碰它),所以在写Flash算法的时候最好还要加个判断,即如果QE位为0则写1,如果已经是1了就不写它了,节省擦写寿命;
4. 为啥为QE位操这么多心呢,实际上也是为了最大化我们RT的性能,如果我们的代码太大,只能以XIP的形式跑在QSPI Flash里,当然是4线启动的方式最好了(四条腿怎么也比单条腿或者两条腿跑的快),不过这里还需要提的一点是实际上Flash算法里面在擦写Flash的时候我还是用的单线模式(擦写Flash不需要那么快的速度,只需要稳定可靠的把代码写进去就完了),而是擦写完之后把QE位置位以便RT复位或者重新上电开始执行后可以正常的以4线去启动,另外也不用担心我置位QE位之后下次再下载时仍然用单线模式擦写Flash还行不行了,放心,即使QE位置位,单线命令还是可以工作的;
前面絮叨了一大堆,最后回到我上传的这套flash算法该怎么用这个主题上来。首先将附件中的工程解压到C:\Keil_v5\ARM\Flash\路径下,打开Flash\MIMXRT_v1.1目录下面的工程(刚打开后会提示找不到型号,默认选择ARM Cortex-M0内核,这个不需要修改,因为M0的指令集是M7的子集,而涉及到Flash烧写的指令都是M0指令集就可以cover的),里面我默认创建了三个工程选项即EVK板载的HyperFlash算法,GD 3.3v QSPI Flash和WinbondQSPI Flash,打开FlashPrg.c找到如下红色标注的地方,这里面我列出了根据QE位所在位置分类的配置,即如果是GD 3.3v QSPI Flash的话,如上面第2点我说的首先它所在的位置为状态寄存器的第1位上,另外这个位还需要单独的0x31命令去访问,所以相应的option0.U所在位需要改成4,同理如果是Winbond QSPI Flash则需要改成2,具体见如下截图后者直接参考附件源码,最后编译整个工程即可在C:\Keil_v5\ARM\Flash\目录下找到生成好的.FLM文件了。
说完Flash烧写算法,在用户的应用工程里面,需要注意的有两个问题,第一个问题是在Keil的debugger选项里面找到刚刚生成好的FLM文件即Flash烧写算法,然后有个特别注意的地方即配置Flash烧写算法的运行memory,官方的SDK里面把Start地址写的是0x20000000即RT的DTCM里面了,这在你的image小的时候没什么问题,但是当image大于500KB之后就会偶尔发现Flash烧写不稳定或者经常失败的情况,这里建议改成如下图0x00000000即RT的ITCM首地址,实测下来烧写速度更快且烧写几MB的代码也是木有问题的(还有个小细节,在烧写大image的时候会遇到烧写过程中Keil界面卡住的情况,这个时候不要做额外的任何操作,这是Keil debugger的bug,只需要耐心等待它烧写完成即可)。那还有第二个问题,就是如果RT配置成XIP 4线制启动,那XIP的配置信息如下图2也需要做相应的修改即可(在XIP文件夹flexspi_nor_config.c里面),主要是flashPadType参数和LUT查找表的参数都改成4线的;
说是一定要在高铁上把这篇文章写完,结果还是有一部分等到了酒店才把内容补上,短短几个小时还是不够边思考边撰文的,看来以后还是得提高写作的效率了,另外自己还有轻微的拖延症,毛病甚多啊,呵呵。索性不负所托,最终还是把这篇给屡完了,还是那句老话,未完待续~
附件源码:
链接: https://pan.baidu.com/s/15LYeUSMYgduJf2l6EPC_7Q 密码: h84q