【博文精选】i.MXRT1050 从外部QSPI Nor Flash启动
晕,不看不知道一看吓一跳,都快两年没有更新我的博客了,哎,惭愧的同时也是感叹时间过的真快啊,之前写博客还高喊着自己快奔三的人了,结果现在都已经迈过去了。。。不继续说了,都暴露年龄了,咳咳。不过虽然时光易逝,但是还好激情尚在,这两年尽是韬光养晦了,虽然波折蛮多,经验和收获也还好,这不,趁着我们NB的号称跨界处理器的i.MXRT系列的推出一睹为快吧(想起当年也是Kinetis刚出来,我在学校正好开始写它的那一系列技术文档,这是啥,缘分呐)。其实在发表到AET之前,我先把此文发到阿莫论坛上了试了试水,收到的一句话挺让我心情激荡的,就是“FSL又活了”,my answer is “灵魂依在。。。”,哎,啥也不说了,下面开整吧。
在此文正式成型之前,历经了3个版本的修改和优化,最终fixed掉了已知的bug和稳定性才敢拿出来献丑,希望让广大AET的博友们继续能有所收获有所体会,也算为了RT1050的未来发展贡献点力量吧,貌似不少人在观望RT系列,也有很多第三方设计公司和开源项目在蠢蠢欲动,所以也希望我抛的这块砖能在RT的广泛市场激起一点涟漪多引出几块好玉来。。。
2018新年伊始,I.MXRT105x已经推向市场有一段儿时间了,以其极高的性价比引起了不少工业和消费领域客户的兴趣,毕竟相比于目前市场上已有的多数“高价低配”的高端ARM Cortex-M7产品,RT105x最高600MHz主频、极丰富的外设和3美金起步的定位着实算是业界良心了(还有马上要面世的LQFP封装I.MXRT1020更是让人期待),只是当然这种“低价高配”是有代价的,其内部不自带Flash需要外挂串行SPI Nand/Nor Flash或者并行的Nand/Nor Flash(貌似一下子给不少心动的人泼了凉水,呵呵),不过这一消息倒是有人欢喜有人忧,对欢喜的客户来说,他们的应用代码本身内部Flash就装不下需要外扩,这一下反倒好了,省的内心纠结了再也不用担心老板整天催自己优化代码精简应用看看能不能只用内部Flash搞定了,哈哈,而且动则几Mb或者几十Mb的外部SPI Flash价格便宜以后升级也是绰绰有余,而对忧的客户来说,外部Flash启动方式带来的启动配置复杂、代码安全性问题和对系统性能的影响等都是潜在的棘手问题。
关于外部Flash的代码安全问题和代码在外部执行对整个系统性能的影响,RT105x的加密启动(HAB)功能和32KB的L1 ICache/DCache是可以解决的,只是本文先从RT105x的启动配置问题着手,毕竟系统如果都Boot不起来,其他的问题都是空谈了,呵呵。另外,如上面所说,RT105x支持的启动方式有不少,不过个人觉着外部串行SPI Flash启动会是大多数人的折中选择。由于RT105x的官方EVK板上是带有两块串行SPI Nor Flash(一个是Cypress高性能8线高速的Hyper Flash S26KS512SDPBHI02,一个是ISSI物美价廉的4线QSPI Flash IS25WP064AJBLE),所以咱就手上有啥来啥,以板载的Hyper Flash和QSPI Flash为例详细说明下串行SPI Nor Flash的启动流程和具体使用方法。
当RT105x EVK板载的Boot模式选择开关SW7设定为如下Table1-1所示的前两者时(其他BOOT_CFG 管脚默认被下拉到地,即OFF状态),系统会通过片上的FlexSPI接口执行外部串行SPI Nor Flash的启动,其启动地址为Table1-2所示的0x6000_0000(如果是从并行的Nor Flash启动则启动地址为0x8000_0000),关于其他Boot pin对启动模式的配置影响,见RT105x的RM手册8.6章节,这里就不细说了。
Table1-1 典型的启动模式设定
SW7-1 |
SW7-2 |
SW7-3 |
SW7-4 |
启动模式 |
OFF |
ON |
ON |
OFF |
Hyper Flash启动 |
OFF |
OFF |
ON |
OFF |
QSPI Flash启动 |
ON |
OFF |
ON |
OFF |
SD卡启动 |
Table1-2 启动相关地址
Start Address |
End Address |
Size |
Description |
0x80000000 |
0xDFFFFFFF |
1.5GB |
SEMC 外部存储器接口 (SDRAM, 并行NOR Flash, PSRAM, 并行NAND Flash) |
0x60000000 |
0x7F7FFFFF |
504MB |
FlexSPI |
0x20200000 |
0x2027FFFF |
512KB |
OCRAM |
0x20000000 |
0x2007FFFF |
512KB |
DTCM |
0x00000000 |
0x0007FFFF |
512KB |
ITCM |
如图1所示为完整的SPI Nor Flash启动流程图,当RT105x的片上ROM在检测到启动模式为FlexSPI接口后,会根据Boot Pin的配置信息配置该模式下需要使用的FlexSPI接口管脚的复用模式并将FlexSPI的时钟配置成默认的低速30MHz,然后会以0x6000_0000为首地址读取前512个字节作为外部Flash的配置信息(即Flash Configuration Parameters,包括几线制的SPI Flash,SPI的时钟频率,LUT查找表,DDR/SDR模式以及片选CS管脚的Hold/Setup Time等信息,见RM8.6.3章节)并以此来配置FlexSPI模块以满足外部Flash的特性,待配置完毕后,RT105x CPU以后即会以AHB总线读取数据和指令的方式(虽然从外部来看仍然是FlexSPI接口,但是由于LUT查找表读取数据的指令已经配置好,CPU只是通过AHB总线发送读取指令即可触发LUT以操作外部Flash,也就是说在内部对CPU来讲已经屏蔽掉了FlexSPI的底层)来读取接下来的跟用户Image相关的几个关键信息,即IVT(Image Vector Table),Boot Data和DCD(Device configuration data)如图2,其中IVT需要放在外部Flash的固定偏移地址(如图3,对Nor Flash来说其需要存储在基地址 + 4KB的偏移地址,比如0x60000000+4*1024)供ROM读取以便让系统知道用户Image的第一条可执行指令放在了哪里以及BootData和DCD的存放地址,BootData则保存了完整Image的首地址和整个image所占的空间大小,而DCD则包含了一些配置命令以便在跳到用户程序入口之前供ROM调用配置内部外设以更好的匹配外部IC,一般如果系统外挂了SDRAM的情况则需要配置好DCD(因为有时需要主程序在跑起来之前,外部SDRAM就得处在ready状态,以供CPU把data或者code copy到SDRAM里时不会出错)。
图1 SPI Nor Flash启动流程
图2 完整Image组成元素
图3 IVT针对不同存储介质的存放地址
综上所述,我们实际上就可以得出结论来,如果要让系统能正常Boot起来,则烧写到外部串行SPI Flash里面的完整image必须要包括五个重要元素,即Flash Configuration Parameters,IVT,Boot Data,DCD和用户image,而其中Flash Configuration Parameters和IVT是存放在固定的地址的,而后三者则由IVT的内容来决定,无论是直接编译生成或者通过辅助工具手动添加,只要我们最后形成的image里面包含了这几个元素,CPU就会认可这个image并执行(先不谈安全加密的事)。所以我们只要搞清楚这个基本原理了,无论是什么方法,最后都是殊途同归,下面就可以放心大胆地去解决RT105x的FlesSPI启动问题了。
前面提到如果想要RT105x能正常从外部串行SPI Nor Flash启动的话,待烧写的image是必须要集成五个元素的(Flash Configuration Parameters, IVT, Boot Data, DCD and User Image, 重要事情要多说几遍 呵呵),那具体的实现方法我目前想到的无非两种,一种是在编译链接过程中直接把这几个元素和应用代码链接到一块,并将这几个元素指定好链接地址,最后通过IDE的Flashloader下载到SPI Flash里,第二种则是通过辅助工具在编译链接好的裸应用代码前面手动的添加一个信息头(头里面包含这几个元素),然后通过单独的下载工具或者MCU内部的ROM Bootloader ISP下载进去。这两种各有优劣势,前者比较适合在前期调试的时候使用,这样在IDE里面编辑修改应用代码后做印证测试的时候可以直接在线download和debug(比如单步,断点,查看寄存器和Memory等等),我相信这也是目前大家比较迫切需要的,但是缺点的话则是前期配置过程稍微复杂些且需要对Boot过程和外部SPI Flash的Spec有一定了解(当然这些配置是一劳永逸的,配置一次即可),而后者则是客户不需要关心其他几个元素的配置只专注用户应用的开发,待开发完毕后通过辅助工具生成最终的Image用于小批测试或者量产,缺点是前期调试的话会比较麻烦,每次修改完重新编译生成用户image还需要用辅助工具手动添加信息头然后再通过Bootloader下载进去验证(我想想都有点累的慌。。。这种情况workaround只能是前期先在RAM里调试,待成熟了之后再走这个流程)。
第二种使用辅助工具的方法,官方已经提供了一整套工具链(可以从RT105x官方主页的”Flashloader i.MX-RT1050”软件包里找到)且有了相应的AN应用笔记介绍其具体操作步骤,这里就不再赘述了。本次我们重点介绍第一种方法,即在IDE环境里通过对工程的配置达到生成并下载调试完整image的目的,说到这里我再啰嗦几句,实际上这种方法做下来不只方便了在线download和debug,好处也不少,一是所有的这几个元素配置信息都以C语言的常量形式体现在应用工程文件里面,会加深我们对Boot的理解程度不说,这样的话如果更换外部SPI Flash也可以很方便的更改适配信息,第二呢则是这种方式形成的image文件会是通用的image格式(比如.bin, .hex和.S19),也会兼容市面上大多数可以直接烧写SPI Flash的量产工具的批量烧写。好了,不再多说了,再说就有点话痨了,呵呵,因为板载有Hyper Flash和QSPI Flash两种,下面就分别详细说明下这两种Flash在IDE环境下的配置方法(我使用的IAR,Keil的可以参考第四章节自行配置,需要添加的几个文件是IAR,Keil和GCC三个环境兼容的)。
开发测试环境:
Hardware Platform: MIMRT1050-EVK (SCH-29538 REV A1)
Software Package: SDK_2.3.0_EVK-MIMXRT1050(mcuxpresso.nxp.com)
IDE: IAR_v8.20.1
Debugger: On-Board CMSIS-DAP
2.1 Cypress 1.8v Hyper Flash启动
RT105x的EVK板子默认是使用Hyper Flash启动的,所以硬件不需要改动,只需要将SW7启动模式修改成Table1-1第一行配置使能Hyper Flash启动即可,如下图4,然后我们以SDK2.3中的hello world为例介绍具体配置方法。实际上在最新的SDK2.3里面Keil和MCUXpresso版本已经有针对Hyper Flash启动的hello_world_xip的样例了,只是IAR反倒是没有,不过这下正好我们来走一遍完整的配置过程,这样也可以为下一小节的QSPI启动打下基础(官方例程里是没有QSPI XIP例程的),毕竟大多数客户估计还是会倾向于选择QSPI的。
图4 Hyper Flash启动模式
(1)打开SDK2.3的hello world例程\boards\evkmimxrt1050\demo_apps\hello_world\iar,在Workspace下可以看到默认是有8种配置的,包括在SDRAM调试,OCRAM调试和spi nor Flash调试,原始的flexspi_nor_debug配置是没有其他几种元素的,所以这种配置下当把代码下进去外部Hyper Flash上的时候可以在线debug但是当重新上电或者外部复位后系统是Boot不起来的,因为没有其他元素信息RT1050启动的时候识别不了它的。接下来我们在此配置基础上新建一个配置出来然后在新的工程配置上添加文件和修改配置,点击IAR菜单栏Project->Edit Configurations,然后在打开的窗口下选择New,在新的工程配置下起一个新的名字“HyperFlash_bootok”,Base on Configuration则选择原有的flexspi_nor_debug以最大限度的保留原有的配置,改好之后点击Ok即当前工程会进入新添加的HyperFlash_bootok配置状态;
(2)在此工程配置下,新添加一个Group(右键工程->Add->Add Group)并命名为“xip”,然后右键该Group->Add->Add Files,找到根目录\devices\MIMXRT1052\xip路径下的四个文件,将该四个文件都添加到当前工程上来,如下所示,我们可以打开这两个.c文件即可看到除了User Image之外的其他四个元素信息都以常量的方式被定义在指定的段地址内,以便在编译链接之后将这几个元素配置信息分配到指定的地址上以保存在最终的Image上,且这四个文件是可以兼容IAR,Keil和GCC三大编译器的所以可以随意Porting,当然不要忘了在工程配置中头文件搜索路径上添加那两个头文件的路径,另外如果没有XIP_EXTERNAL_FLASH这个宏的话也要加上;
(3)由于四个元素被分别定义到指定的段内,但是默认的原始工程里面的链接文件是没有这几个段的定义的(Keil和MCUXpresso由于有xip的样例,它们是定义好的了),所以还需要在原始的链接文件基础上添加这几个段的定义并分配好地址,我们将原来的链接文件MIMXRT1052xxxxx_flexspi_nor.icf复制一份重命名为MIMXRT1052xxxxx_hyperflash_nor_bootok.icf(名字倒是无所谓),然后打开该文件,添加这几个段的定义和地址分配如下(修改好的源文件见随本文档附带的压缩包),然后在工程配置Options->Linker里选择新修改的链接文件,最后点击确认;
(4)不要以为这样就结束了,呵呵,我们这两步说到几个重要的元素信息是以常量的形式通过链接文件保存在指定的地址段内,不过我们的应用工程却没有调用它们,在编译的时候编译器会默认把他们又给优化掉了搞的最后没有体现在Image里面,前面的工作白搭了,所以还需要额外一步告诉编译器把这几个常量给Keep住,具体配置如下图,然后点击确认;
(5)这样工程配置就结束了,我们重新编译整个工程,然后在生成的.map文件里即可看到如下这四个元素信息都已经正确的分配到指定地址了,这样就万事俱备,就差IDE IAR的Flashloader这个“东风”了;
(6)在IAR v8.20.1以上的版本已经有HyperFlash的Flashloader了,我们在Options->Debugger选项下选择CMSIS-DAP,然后接下来需要注意的是在Options->CMSIS-DAP选项下,Reset类型需要选择Core Reset(CMSIS-DAP默认的Reset方式会导致调试的时候打不了断点,J-link倒是没有这个问题),然后点击Ok保持配置,最后开始Debug即可完美的把带有几个重要元素信息的配置数据都下载到外部Hyper Flash里面并进入Debug模式,正常单步或者断点,并且按键复位或者重新给板子上电都可以让RT105x正常Boot起来,最后有图有真相,发个串口打印的结果“hello world”, Enjoy it…
2.2 ISSI 1.8v QSPI启动
上面说完Hyper Flash的启动方法,接下来继续说说QSPI启动。由于板子上的Hyper Flash和QSPI时钟、片选和部分数据线是共用的,所以在测试QSPI启动的时候需要把Hyper Flash焊掉(跟板子硬件设计有关系,不焊掉会影响时序,稍微有点心疼,毕竟Hyper Flash比较贵而且又是BGA的焊下来就焊不上去了,当然,如果是客户自己设计的板子只会有一种SPI Nor Flash,那就没这个问题了),然后将下图中DNP的0欧姆电阻焊上,最后特别注意的是需要在QSPI Flash的第7脚和3脚即Reset和WP管脚上拉4.7k的电阻到电源Flash_VCC。因为我发现有个别型号的QSPI Flash,比如板子用的ISSI这个,在系统启动的时候Reset和WP这两个脚是悬空态,而QSPI Flash默认上电都是单线方式,这样的话Reset和WP如果是低电平则QSPI一直处于复位和写保护状态,从而造成系统RT1050读取QSPI信息失败进而导致启动失败,所以需要在这两个脚上加个上拉电阻给它有效的高电平,后来我测试的QD和Winbond的QSPI这两个脚里面是有上拉电阻的,系统启动后是固定的高电平就没有问题了,不过我的建议是最好外部再加一个保证可靠,也不会影响后续的4线通信。另外,别忘了SW7启动模式需要修改成Table1-1第二行配置使能QSPI Flash启动,如下图5:
图5 QSPI Flash启动模式
(1)我们仍然以上面的hello world工程为例,有前面章节打基础,本章说起来就轻松不少了,在当前工程下,点击IAR菜单栏Project->Edit Configurations继续新建一个工程配置并以HyperFlash_bootok为蓝本将新的配置命名为“Qspi_nor_bootok”如下图,然后点击Ok进入该配置模式下;
(2)此时xip的Group文件组仍然有效,不过由于Boot的Flash类型发生了变化,所以需要修改外部SPI Flash的前512字节的Flash Configuration Parameters元素信息(其他几个元素无需修改)。打开fsl_flexspi_nor_flash.c文件,然后在hyperflash_config常量前面添加如下图Qspiflash_config的常量(修改后的源文件见随本文档附带的压缩包),实际上只是修改了外部SPI Flash的Pads类型、SPI时钟频率、Flash的大小(包括总大小以及page和sector的大小)和最重要的LUT查找表指令,这里我使用了外部QSPI Flash的四线Quad I/O Read模式(即0xEB),此模式下SPI的时钟频率可以跑到133MHz,总带宽可以达到532Mbps即66.5MByte/s(实际上很多MCU片内的Flash时钟也差不多这个频率甚至比这个低,不过内部的Flash线宽会大些),这个速度虽然相比于CPU 600MHz的主频慢很多,但是实际上RT1050的一级缓存ICache和DCache各有32KB且在程序里默认是打开的,实测下来对大部分代码来说外部SPI Flash的带宽几乎不会拖累CPU性能,针对特定应用的复杂代码留待大家自行测试(实测Opus音频编解码,跑在外部QSPI Flash上的性能大概为跑在内部SRAM上的70%~80%);
(3)上一步通过预编译QSPI_BOOT宏来使能QspiFlash的配置信息主要是为方便跟前面HyperFlash启动兼容,只需在当前工程配置下添加QSPI_BOOT宏即可,如下图所示,这样即使再跳回HyperFlash_bootok工程时也不必麻烦地来回修改Flash Configuration Parameters元素信息了,同时该工程配置下的链接文件由于各个段地址没有变化则不用修改,只是需要Keep的常量记得替换成Qspiflash_config,然后点击确认保存;
(4)此时整个工程的配置工作就完成了,点击Build完成对整个工程的编译和链接,查看.map文件也可以看到其他4个主要元素配置信息也都链接到整个image里了。不过接下来需要解决的是QSPI Flash的Flashloader问题了。在IAR For ARM v8.20.2以上的版本的Flashloader里已经加入了对QSPI Flash的支持了,但是该Flashloader只支持ISSI的QSPI Flash,我在此基础上做了修改和优化加入了对GD和Winbond QSPI Flash的支持,该新的Flashloader见随本文档附带的压缩包文件,将压缩包路径Firmware\IAR_8.20_Flashloader下的四个文件copy到IAR安装目录下C:\Program Files (x86)\IAR Systems\Embedded Workbench 8.0\arm\config\flashloader\NXP并覆盖源文件。此外,该修改后的Flashloader同时支持HyperFlash和QSPI Flash的download和debug(通过查询外部Boot模式来切换这两种烧写算法);
(5)一切准备就绪,在点击debug之前记得确认options->debugger下选择好CMSIS-DAP并且确保Reset类型必须要选择Core Reset,然后点击确认保存,最后debug将代码下载到外部QSPI Flash里并调试或者重新上电测试,hello world仍然让人激动不已,不容易啊不容易。
上述两种外部SPI Nor Flash的启动配置方式仅仅是以hello world工程为例了,实际上大家可以参照如上几个步骤任意porting到SDK的其他工程实例里面去,而且由于SDK_2.3.0_EVK-MIMXRT1050\devices\MIMXRT1052\xip目录是共享的文件(包括Flashloader也是共享的),所以添加的那四个文件内容不需要再修改了,只需要手动添加文件到工程和配置IAR相关选项即可,操作起来还是比较快的。
前面比较详细的讲了HyperFlash和QSPI Flash的启动方式,趁着兴致尚在我们再加点餐。我相信在很多客户开发RT105x过程中,将code跑在外部SPI Flash里,而数据存放在外部SDRAM里面会是比较常用的一种选择(比如一些会用到高分辨率的GUI显示方面,内部RAM不够用了)。虽然前面提到的xip那四个文件(两个.c和两个.h)里面的fsl_flexspi_nor_boot.c文件有定义dcd_sdram这个常量,不过很快就会发现这个常量数组里面的数据很大且看不出什么意义来(看不出意义就意味着不知道怎么修改),这是因为这个常量数组里面是编译后的可执行命令,它是根据不同的SDRAM编译后的结果,也就意味着不同的SDRAM这个数组是不一样的,这就尴尬了,客户如果不是使用EVK板载的SDRAM的话该怎么搞呢?哈哈,这个倒是不用担心,官方很快会推出一个辅助工具来生成不同SDRAM的DCD常量数组,不过在此之前我们也不能干等着吧,所以本章节的“加餐”就是提出一种workaround先提前解决下这个问题。
我们要知道,在系统上电前无论代码还是数据都是存在SPI Flash这些非易失存储介质里面的,待上电后程序会有一个Copy过程将数据或者想要在RAM里执行的代码copy到RAM里面去,对内部RAM来讲无所谓(因为一上电内部的SRAM就已经初始化完成了)而对外部SDRAM来说是需要事先初始化RT105x的SDRAM控制器才能往该SDRAM可寻址的空间copy内容的。幸运的是在Copy之前我们是有段缓冲时间的,恰恰就是这段缓冲时间给了我们有可以不使用DCD配置的机会(实际上DCD也是ROM在跳到应用代码之前读取其内容对SDRAM进行初始化)。以IAR的启动代码为例,打开startup_MIMXRT1052.s文件找到CPU的起始入口Reset_Handler如下图,执行的Copy过程实际上是在__iar_program_start这个函数里面实现的(具体内容使用的是IAR自己的库, Keil是在__main里实现的),而在该函数之前(即在SystemInit函数里面)我们只需要将SDRAM初始化好让其Ready了就不会影响后续数据的copy和使用,所以下面我就简单介绍下具体操作方法。
(1)仍然是在当前hello world工程下,点击IAR菜单栏Project->Edit Configurations继续新建一个工程配置并以上面的HyperFlash_bootok为蓝本将新的配置命名为“flexspi_code_sdram_data”如下图,然后点击Ok进入该配置模式下;
(2)打开system_MIMXRT1052.c系统配置文件,也就是SystemInit函数所在的文件里面添加如下图所示SDRAM初始化相关的函数并在SystemInit的最后调用就可以在使用SDRAM之前将其初始化(具体修改后的源文件见随文档附带的压缩包),而且初始化函数均是以C语言形式读写配置SDRAM相关寄存器,这样的话即使SDRAM更换了也可以随时修改初始化寄存器配置以适配不同的SDRAM了,俗话说未知是最可怕的,而一旦都是开放的话就没那么难了。至于SDRAM这块的初始化是怎么找到的呢,实际上就是将SDRAM的预处理文件(当前目录下的evkmimxrt1050_sdram_init.mac)里面的命令用C语言实现了而已;
(3)由于仍然是为了兼容性问题,上面使用了预编译命令判断HYBERFLASH_SDRAM宏来决定是否初始化SDRAM,所以在当前工程配置下需要添加HYBERFLASH_SDRAM宏声明以使在当前工程配置下SDRAM初始化生效;
(4)然后需要修改下链接文件,将数据都分配到SDRAM地址范围内,将MIMXRT1052xxxxx_hyperflash_nor_bootok.icf复制后重命名为MIMXRT1052xxxxx_flexspi_code_sdram_data.icf,打开该文件,添加data3相关信息之后保存该链接文件,并在Options->Linker文件里选择新的链接文件(源文件见随文档附带的压缩包),点击确定保存配置;
(5)一切都修改完毕之后,点击编译链接,再打开.map文件即可看到所有的数据变量已经被分配到外部SDRAM的寻址空间里面了,最后再点击debug将代码下载到外部SPI Flash里面(注意SW7启动模式记得修改成HyperFlash启动,因为本例子演示的是code跑在HyperFlash里,数据跑在SDRAM里),这样就完美实现代码在SPI Flash里执行而数据跑在SDRAM里。当然,hello world本身没多少数据,大家可以把该功能照本宣科的poring到复杂一点的应用里面或者在当前工程里面自己memory alloc一段足够大的数据区,然后读修改写的去操作以测试该方法的可靠性,我这里就不多说了。
在第2.2章节里我已经介绍了RT1050 EVK板载1.8v ISSI的QSPI Flash的启动方法,不过经过一段时间客户的反馈,实际上市面上常用的QSPI Flash目前以GD和Winbond的3.3v产品居多,物美价廉且采购渠道丰富,所以我特意增加了第4章用来专门介绍下GD和Winbond 3.3v QSPI Flash启动方法并修改优化了Keil下对这两家QSPI Flash的烧写算法供客户在keil下擦写和debug。
硬件上仍然是以我们官方RT1050的EVK板子为调试平台,在2.2章节的硬件改动基础上焊掉ISSI的QSPI Flash,换成GD的GD25Q32CSIG 3.3v QSPI Flash(3脚和7脚仍然上拉电阻到VDD),然后将下图中EVK板子R49的0欧姆电阻去掉,R301用0欧姆电阻短接,即将Flash电源由之前的1.8v改成3.3v,其他部分硬件与2.2章节保持一致,接下来我介绍Keil环境下的配置方法(前面的示例用的IAR,这次用keil让大家对IAR和keil下的开发配置都熟悉一遍):
(1)首先打开Keil下SDK开发包的hello_world_xip工程(路径demo_apps\hello_world_xip\mdk,Keil自带xip的工程),默认只有hello_world_xip Flexspi_nor_debug和hello_world_xip Flexspi_nor_release两个跑在板载HyperFlash的工程配置,点击Keil菜单栏Project->Manage->Project Items,我们新添加一个工程配置hello_world_xip Qspi_nor_debug如下图,然后选择该工程配置为当前工程,最后点击OK确认:
(2)在新建的工程配置里,右键工程Options->C/C++,添加QSPI_BOOT和XIP_EXTERNAL_FLASH这两个宏如下图1,然后打开工程目录下xip->fsl_flexspi_nor_flash.c文件,参考2.2章节中(2)点,手动添加QSPI的Flash Configuration Parameters元素信息如下图2,有一点不同的是我们官方板子的ISSI QSPI Flash的最高时钟可以到133MHz,而Winbond的QSPI最高到80MHz,GD QSPI最高到120MHz,我板子上自己焊了一块GD的GD32Q32CSIG QSPI Flash,所以将serialClkFreq设定为kFlexSpiSerialClk_100MHz,然后sflashA1Size改成4M Bytes;
(3)由于keil下自带了xip的工程,所以我们就直接复用其现成的.scf链接文件即可不用做修改,如下图Options->Linker。而且keil下也已经添加了Keep变量以防止xip这几个元素信息因为程序里没有调用而自动被编译器优化掉(注意:下图显示窗口有限,实际上要keep的信息段包括.boot_hdr.ivt,.boot_hdr.boot_data,.boot_hdr.dcd_data和.boot_hdr.conf,格式参考下图);
(4)至此我们编译整个工程,最后打开生成的.map文件如下图可以看到我们想要的几个QSPI启动必须的元素信息头都已经正确的分配到image文件里了;
(5)支持QSPI启动的完整image文件通过以上几步我们已经解决了,接下来要解决keil下download、Erase和debug需要的QSPI Flash烧写算法问题,本文档附带的压缩包文件里路径Firmware\Keil_Algorithm下MIMXRT_QSPIFLASH.FLM文件为我已经优化修改好的可以支持ISSI,GD和Winbond烧写的Flash算法,将其copy到keil安装路径下C:\Keil_v5\ARM\Flash即可,然后右键工程options->Debug-> CMSIS-DAP debugger,进入settings->Flash Download,点击Add找到如下图所示的MIMXRT_QSPIFLASH(4KB Sec),另外建议给Flash算法预留的RAM空间大一些否则可能会导致算法运行失败,因为这个flash算法比较占空间,我这里修改成了0x4000大小是没有问题的;
(6)设置完毕之后,我们再次重新编译整个工程,然后点击F8或者keil菜单栏Flash->Download即可完成对外部QSPI的擦除和写入,待烧写完毕之后我们点击debug即可正常调试(建议:如果程序做了修改,在编译之后进入debug之前先Download一次,再点debug),重新断电之后程序也可以。