|
本帖最后由 eddy0317 于 2018-5-11 10:29 编辑
前言
作为一个不太会写文章的我来说,很少写这类教材类笔记,不过IMXRT系列芯片实际太会折腾了,文档不多,错误遗漏不少,例如如何在NOR上实现non-XIP Image在AN12108只字不提,只有在AN12107提过在SDCard上实现。对于我这个从来没打算在SDCard和hyperflash跑程序的人来说,AN12107压根就没打算看。也导致了花了不少时间找资料上。本人在NOR跑程序这个问题上,已经足足花了30个小时左右了,因此记下这些心得,目的就是让其他初学者尽量少走弯路,尽快让程序先跑起来。
如何让程序跑起来
第一次接触芯片时,一般的教程都是教大家直接在内部RAM中进行运行调试。只要将程序load到RAM里面,设置SP,PC和中断向量,就可以动起来了。但是,如果脱离仿真器启动,就需要烧写到各种非易失性存储上,通过芯片固化在BOOT ROM上的引导程序,根据配置(BOOT ROM如何配置不在这里说明,可参阅RM的第八章)从对应存储器上读取程序并运行起来。BOOT ROM不支持直接运行用户程序,需要将用户程序(Application)进行封装,打包成BOOT ROM可识别的可启动的程序镜像(Bootable Image,RM里面也称之为Program Image,在本文下面简称为程序镜像或Image)。因此,我们需要了解这个程序镜像是如何生成的。而程序镜像可分为XIP Image和non-XIP Image。XIP指直接在非易失性存储器上运行,non-XIP指需要从非易失性存储器上加载到其他地方(如ITCM,OCRAM,SDRAM等)再运行。对于non-XIP,本文以在ITCM上运行作为例子进行说明。
程序镜像的组成
程序镜像如上图所示,包括以下几个部分:
IVT:Image Vector Table,用于记录程序镜像各个部分的地址,程序镜像的各个部分是可以分散开来的,通过IVT内容进行寻址。
Boot Data:用于指示程序镜像位置和大小等信息。
DCD:Device configuration data,设备配置数据,这是可选部分。当用户程序需要用到一些BOOT ROM没有初始化的外设时使用。如用户程序的数据段在SDRAM里,就必须在用户程序运行前就对SDRAM进行初始化,这个时候就用到DCD了。
Application:我们的用户程序二进制代码。
CSF:签名,加密用的内容,这是可选部分。(现在普通的用户程序都没跑起来呢,本文才不管这个。)
如何确定程序镜像是XIP还是non-XIP呢?就看镜像里面那些地址参数(entry,dcd,boot_data,csf,start)是否均为Boot Device Memory内的地址(本文就是FlexSPI的地址了,0x60000000-0x7F7FFFFF )。如果为其他存储器的地址,那就是non-XIP了。
在了解了程序镜像的组成之后,那么,我们怎么去生成这个镜像呢?目前主流的有两个方法:
- 利用官方的Flashloader_RT1050工具进行生成,XIP Image 和 non-XIP Image 均可生成。缺点是刚开始用的时候会遇到不少问题(又不能调试,刚学难以定位问题)。
- 自己在程序上定义IVT,Boot Data,和DCD,可生成XIP Image。优点是可以进行仿真调试。
FlexSPI NOR 上的程序镜像布局
要在FlexSPI NOR上启动程序镜像,还需要一个FlexSPI配置块(FlexSPI Configuration Block,FCB)。FCB包含了FlexSPI以及NOR的信息,如FlexSPI上是NOR还是NAND,工作频率,工作模式,操作时序等。BOOT ROM需要先通过FCB里面的信息,对FlexSPI进行正确配置,才开始读取程序镜像。
BOOT ROM 要求 FCB 必须存放在起始地址为0x6000000的4K字节存储空间里(当前版本的NOR FCB只占用了512个字节),IVT 必须存放在起始地址为0x60001000的存储空间里。其他部分的地址不作强制要求。但是习惯上 Boot Data 和 DCD紧跟着 IVT存放,存放在同一个4K字节空间里面,Application 则从0x60002000开始存放。至于CSF,一般放在Application后面。经典布局如下:
起始地址 结束地址 存放内容 0x60000000 0x60000FFF FCB 0x60001000 0x60001FFF IVT(在最前) + Boot Data + DCD 0x60002000 --------------- Application
注意,由于non-XIP复制的是整个程序镜像,因此non-XIP的Application 起始地址也必须跟随在FlexSPI上偏移量。本文的附件甚至是直接与上面的布局完全对应,则non-XIP Application的起始地址为0x00002000。IVT的起始地址为0x00001000。
05.11更新:之前以为只复制程序镜像,今天通过调试查看ITCM内容发现,实际上连FCB都会复制过去,因此,实际运行Application的存储器上的布局,需要跟NOR上一致。这里还有一个疑问,之前在官方论坛看到相关的帖子,里面说hyperflash的时候,起始地址不需要修改(原帖地址:https://community.nxp.com/thread/471056),如果使用hyperflash的兄弟验证一下吧。
FCB 的详细定义可以查看Flashloader_RT1050工具里面的文档MCUX Flashloader Reference Manual的8.2.1部分说明(为什么不是看RM?因为最新版的RM这部分说明都没这个文档多!),IVT,Boot Data,和DCD可以看RM的8.7 Program image。
这部分网上也有人写过笔记了,这里就不详细说明。
实战前的准备
- MDK / IAR 等,本文以MDK进行说明。
- 官方的Flashloader_RT1050
- 一个已经创建好可以在RAM上运行的项目。
快速创建 XIP Image 所需的 Application
新建一个target,然后添加包含IVT,Boot Data,和DCD的c文件到项目里面(见附件的 flexspi_nor_cfg_block.c 和 boot_conf_def.h )。在target选项的Linker页,Scatter file选择附件的 MIMXRT1052xxxxx_flexspi_nor_AC6.scf(用AC6的话)或 MIMXRT1052xxxxx_flexspi_nor.scf。Misc Controls添加 --keep *.o(.boot_hdr.*) --entry=Reset_Handler 。如果用的是SDK里面的配置MPU例子,需要在C/C++添加XIP_EXTERNAL_FLASH宏定义,让NOR Flash使用L1 Cache。这样就可以编译出烧写在 NOR Flash 的XIP Image了,可以通过仿真器直接下载(需要用到的下载算法,不同开发板用对应的算法文件就行)。
如果想通过Flashloader_RT1050来生成XIP Image,则不需要添加 flexspi_nor_cfg_block.c,Linker页的Misc Controls也不用添加 --keep *.o(.boot_hdr.*),编译出来的srec文件可通过Flashloader_RT1050生成 XIP Image。
快速创建non-XIP Image 所需的 Application
新建一个target,在target选项的Linker页,Scatter file选择附件的 MIMXRT1052xxxxx_flexspi_ram2_AC6.scf(用AC6的话)或 MIMXRT1052xxxxx_flexspi_ram2.scf,Misc Controls添加 --entry=Reset_Handler。编译出来的srec文件可通过Flashloader_RT1050生成 non-XIP Image。直接编译出来的文件同样可以直接进行仿真调试(初始化文件需要修改为附件evkbimxrt1050_ram2.ini)。
05.11更新:之前以为axf文件也支持(因为能够弄出来,没有报错,简单看了一下添加的东西也没什么大问题),实际上就是有问题!这也是为什么我之前一直在下面说的初始化问题的坑上浪费那么多时间!使用axf的时候,获取的entry是有问题的,例如我的Reset_Handler入口地址为0x24D9,但是用axf的时候它弄成0x24DA。程序长度也是错的,用axf的时候会在尾部少了一部分东西,导致运行出问题!!!MDK生成的是axf文件,在User选项页,After Build里面添加一行命令来生成srec文件:- fromelf --m32combined --output "$L@L.srec" "!L"
复制代码
通过Flashloader_RT1050创建程序镜像
在 Tools\bd_file\imx10xx文件夹里面,复制 imx-itcm-unsigned.bd,imx-flexspinor-normal-unsigned.bd 和 program_flexspinor_image_qspinor.bd 三个文件到Tools\elftosb\win(或linux)目录下,同时将相应的axf或srec文件复制到该目录下。imx-itcm-unsigned.bd 和 imx-flexspinor-normal-unsigned.bd 用于生成程序镜像,需要按实际情况修改里面的两个参数:startAddress 和 ivtOffset。如 imx-itcm-unsigned.bd 将这两个参数修改为 0 和 0x1000。
执行以下命令生成 XIP Image(假如Application文件为 demo_xip.srec)
elftosb -f imx -V -c imx-itcm-unsigned.bd -o ivt_xip_unsigned.bin demo_xip.srec
执行以下命令生成 non-XIP Image(假如Application文件为 demo_nonxip.srec)
elftosb -f imx -V -c imx-flexspinor-normal-unsigned -o ivt_nonxip_unsigned.bin demo_nonxip.srec
上述生成指令会生成两个bin文件,一个为-o指定的名字的文件,一个为-o指定的名字添加_nopadding标识的文件。如果ivtOffset不为0时,前一个文件会在前面填充ivtOffset的数据。生成使用mfgtools下载的sb文件时,使用_nopadding文件。
执行以下命令生成基于XIP Image 的 sb文件:
elftosb -f kinetis -V -c program_flexspinor_image_qspinor.bd -o boot_image.sb ivt_xip_unsigned.bin
烧写到目标板
将上面生成的 boot_image.sb 复制到 Tools\mfgtools-rel\Profiles\MXRT105X\OS Firmware,并检查Tools\mfgtools-rel下的 cfg.ini 的 [LIST] 下的 name 是否为 MXRT105X-DevBoot 。如下:
[LIST]
name = MXRT105X-DevBoot
然后打开Tools\mfgtools-rel\MfgTool2.exe,将目标板设置为USB下载模式并将USB连接到电脑,点start下载即可。详细步骤说明可阅读AN12107和AN12108。
最后
到这里,程序就基本上可以通过两种方式跑起来了。虽然这样一看起来不算复杂,但是在实际操作中,因为很多东西并不清楚,就导致很多问题。我光看elftosb生成的文件,以及从NOR上直接load出来的完整二进制镜像都不知道多少次了。
今天遇到的坑,就是直接RAM调试没问题,生成non-XIP Image烧到NOR运行就有问题了:可能是linker里面没有加 --entry=Reset_Handler。实际上,无论是MDK还是IAR,生成的入口地址都不是我们以为的Reset_Handler,如MDK的是__main,初始化RW和ZI段数据等操作后,再跳转到用户定义的main函数。查看Reset_Handler源码可知道,Reset_Handler依次设置了中断向量表,调用SystemInit,之后再调用了__main。所以需要告知BOOT ROM需要从Reset_Handler开始运行。我在这里可是坑了不少时间,一开始用SDK的例子生成的Image可以正常运行,自己编写的则不行,考虑了不少方面,最后怀疑是hardfault而不是没有运行。才发现原来是在初始化RTX5时出现问题了,有时候是RW数据段没初始化,导致RTX5初始参数有问题,有时候又是中断向量没有正确设置。这个大坑硬汉其实早说了,见http://www.armbbs.cn/forum.php?mod=viewthread&tid=86521,unknownuser大神也说了相关解决方案的。
今天就先写到这里吧,本来还有些说明要写的,以后再补充吧。还有signed,encrypted这两个特性要搞呢,心有点累啊。这里不得不再次吐槽一下,NXP的文档真的不行,看FCB说明那里就看到不少笔误,而且很多地方的说明又是冲突的。有些文档说 encrypted Image有两种,单纯的encrypted和encrypted+signed,又有文档说 encrypted 的前提必须是 signed。简直无语。
|
评分
-
查看全部评分
|