第5章JTAG调试
本章节将介绍如何使用TI官方的CCS开发工具及XDS100V2仿真器连接龙泉BB板的JTAG接口进行软件调试。
5.1 准备工作
一、准备硬件:龙泉BB板一块,5V电源适配器,XDS100V2仿真器(也可以用其它的型号的仿真器,如JLINK、XDS100V3、XDS560、Hawk等等,但目前只测过XDS100V2,推荐用这个型号),USB转UART线。请将SD卡启动跳线短接,连接好所有线缆(龙泉BB板上是JTAG接口是20PIN,XDS100V2的接口是14PIN,请按原理图一一对应接上,余下的6PIN不用连接)。
二、准备软件:CCS5.5(也可以用更高版本,但作者只亲自测试过5.5版),AM335x的Startware及BBB的patch。建议WINDOWS版和LINUX版都安装。安装程序自带XDS100V2的驱动程序,无需另外安装。如需要调试u-boot,请自行准备LINUX开发环境。
WINDOWS下安装好后示例代码如下图:
5.2 Startware中的BBB示例代码调试。
打开CCS,把CCS的Workspace切换到以下目录:D:\program\ti\am335x\build\armv7a\cgt_ccs\am335x\beaglebone
以gpioLEDBlink为例,工程属性设置如下图。
图:工程属性设置
请注意上图中的编译器版本改为V5.1.1,connection即是仿真器,改为xds100v2,板子改为beaglebone_black(cortex A)。此处若选Cortex-M,可能是用来调试其中的PRU。检查并更正include路径,检查并更正lib路径。注意此工程需要四个库:system,utils,drivers,platform(先import和编译这几个库)。
Build完毕,debug as CC debug session即可开始调试,光标定位在main()第一行。如下图:
按F6单步运行,运行到下图位置,蓝色LED D4会变亮。
再往下运行,此灯会灭。
5.3 u-boot调试。
u-boot调试比较复杂。一般来说,应该安装linux版的CCS进行调试,然而,跨平台的CCS也支持用WINDOWS版CCS调试LINUX主机里面的u-boot。两种方式都需要用LINUX主机去编译u-boot。也许可以用cygwin在WINDOWS下编译,但需要修改makefile,非常麻烦,故而不推荐这种方式。
5.3.1 龙泉BBB的LINUX启动过程
AM335xLinux的启动主要包括ROM,SPL, U-Boot 和kernel四个启动步骤:
一、ROM code
ROMcode是固化在芯片内部的代码,当上电时序正确,而且晶振等芯片启动所需的条件都具备时,AM335x会从ROM code开始运行。
ROMcode首先会读取sys_boot引脚上的配置,以确定存放SPL的存储器,或者可以获取SPL的外设。
具体可以参考AM335x technical reference manual中的第26章 Initialization。
ROMcode会从相应的地方读取/获取SPL,并运行SPL。
二、SPL
SPL和U-Boot 是bootloader的两个阶段。这里分为两个阶段的原因是, ROMcode中不会配置DDR,时钟等最小系统,所以ROM code只能把bootloader加载到片上SRAM中,而片上SRAM对成本影响很大,所以通常很小,例如在AM335x上只有64K,不足够放下整个U-Boot,所以将U-Boot分成两部分,SPL和U-Boot。
SPL主要的职责就是初始化DDR,时钟等最小系统,以读取U-Boot,并加载到DDR中。具体来看,SPL 由ROMcode加载到片上SRAM的起始位置,也就是0x402F0400。SPL会进一步对芯片进行配置,主要包括以下几个方面以完成其主要职责:
Ø 配置ARM core。 主要包括对中断向量表,cache,MMU等的配置。
Ø 配置时钟系统,主要是PLL等。这个是配置各个功能模块的基础。
Ø 配置UART,timer等。主要用于输出必要的调试信息,或者提供些时钟工具。
Ø 配置I2C和PMIC。这个主要是为了配置电源管理芯片。
Ø 配置DDR。
Ø 配置 U-Boot所在的存储器或者外设。
完成配置后,SPL会读取U-Boot,并运行U-Boot。
三、U-Boot
U-Boot主要的工作就是正确加载Kernel。和SPL类似,U-Boot也是要加载下一个阶段的image,但是U-Boot提供了更多外设的支持和更多的调试工具。所以,U-Boot也要进行各个模块的配置,上述SPL配置的部分, 除了DDR外,U-Boot也会根据需求重新配置(这里重置主要是U-Boot是一个开源工程,其要兼容某些特殊的芯片,从而需要做重载)。此外,U-Boot也会对网口,SD卡等根据需求进行配置。
U-Boot和SPL的工作流程比有一点是有较大差异的,就是会对自身进行一次重载。这个在后面介绍U-Boot调试的时候,会有具体介绍。
完成配置后,U-Boot 会从相应的存储器或者外设读取Kernel,并传递参数给kernel,运行kernel。
四、Kernel
Kernel运行起来就代表Linux运行起来了,表明了启动过程的结束。
1.2 U-Boot/SPL 调试代码的准备
1.2.1下载U-Boot/SPL 代码
U-Boot/SPL的代码在一个包里面,通过编译宏来分别编译。目前TI U-Boot/SPL 代码发布主要有两个渠道,具体如下
A. 通过Git开源的方式发布:
git://arago-project.org/git/projects/U-Boot-am33x.git
可以获取最新的代码,包含了最新的bug的修复。
B. 通过TI的官网的EZSDK发布:
http://software-dl.ti.com/dsps/dsps_public_sw/am_bu/sdk/AM335xSDK/latest/index_FDS.html
EZSDK是正式发布的软件包,经过全面测试,性能稳定,U-Boot/SPL在board-support 目录中。可以选择EZSDK作为开发的基础代码。当有问题时, 可到GIT上查找最新的代码是否有bug fix。
5.3.2 U-Boot/SPL的编译
为了便于用CCS进行调试, 在编译上需要注意两点,其一,是要加入调试信息,就是为了加入symbol等信息;其二,去掉编译器的性能优化编译选项,这个主要是因为,优化后的代码执行顺序相对C代码会有调整。
针对这两点,在Uboot/SPL中,需要在config.mk中进行修改:
A. 在CFLAG 和 AFLAG中加入调试编译选项,从而加入调试信息:
278ALL_AFLAGS = $(AFLAGS)$(AFLAGS_$(BCURDIR)/$(@F)) $(AFLAGS_$(BCURDIR))–g
279ALL_CFLAGS = $(CFLAGS)$(CFLAGS_$(BCURDIR)/$(@F)) $(CFLAGS_$(BCURDIR))–g
B. 去掉 CFLAG中的编译选项, -O2(U-Boot中默认是-O2)
61HOSTCFLAGS =-Wall-Wstrict-prototypes -fomit-frame-pointer
编译过程可以参考http://processors.wiki.ti.com/index.php/AM335x_U-Boot_User_Guide
5.3.3 可执行文件
经过编译后,就会生成可执行文件,也就是我们通常所说的image,这里会生成的image主要用AM335xLinux启动的两个阶段,MLO(SPL)和U-Boot。
这里,SPL生成的image在am335x/U-Boot-am33x/am335x/spl中,
A. am335/U-Boot-am33x/MLO 负责AM335x启动的第一阶段。
B. U-Boot-spl 作为带有调试信息的image,可以在CCS中用作导入调试信息。
C. U-Boot-spl.bin 包含有调试信息,是调试时需要的image。
D. U-Boot-spl.map 这个文件里面存储了spl的memory map信息,可以找到各函数入口的地址。
U-Boot生成的image在U-Boot-am33x/am335x中,具体如下:
A. U-Boot.img负责AM335x启动的第二阶段
B. U-Boot 包含有调试信息,属于ELF格式,是调试时需要的image。
C. U-Boot.map这个文件里面存储了U-Boot的memory map信息,可以找到各函数入口的地址
5.3.4导入CCS代码。
在CCS中, Menu File ->Import … 选择 Makefile 方式导入,如下图所示:
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image010.jpg
在ezsdk中,U-Boot/SPL所对应的Makefile的具体路径如下:
/home/sitara/ti-sdk-am335x-evm-05.05.00.00/board-support/U-Boot-2011.09-psp04.06.00.08,笔者的则是Z:\lsbbb\uboot,其中Z是用samba通过网络共享给windows映射的盘符,建议用这种方式,因为导入后CCS需要以相对路径的方式载入所有源代码。
如前面所提到,U-Boot 和SPL的源码在同一个文件夹的,通过不同的Makefile管理不同的编译宏来区分的。这里导入的是U-Boot的代码对应的Makefile,会相应的导入U-Boot对应的预编译选项,因为其包含了所有的代码。而对于SPL,也会相应的一起带入,只是在CCS中看到的代码的宏定义有些不对,但这个不影响调试。
5.3.5 CCS 连接 AM335x.
主要分成仿真器的连接,target连接和Debug配置等几部分:
一、仿真器的连接
1.CCS的配置
CCS的配置主要包括Target的配置和连接两部分。
A.Target 配置
Target的配置包含两个部分,一个是仿真器(XDS100v2),另一个就是SOC(AM335x)。具体操作如下:
i. View -> Target Configurations
ii. 点右键选择New TargetConfiguration.
iii.新建一个叫做AM3352的target.
iv.connection选择 Texas Instruments XDS100v2 USB Emulator.
vi.在Board or Device 中选择AM3352.
vii.点击Save 保存。
viii.点击Test Connection 看是否能够正常连接。
配置target成功后,会看到如下界面
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image012.jpg
二、Target 连接
A.右键选中Target Configurations中已配置好的target:AM3352.ccxml, 在右键菜单中选择LaunchSelectedConfiguration,连接成功后,可以得到下图
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image014.jpg
此时,PC 和仿真器以及仿真器和SOC的JTAG连接成功,但是ARMcore还没有连上。从图中可以看到,有多个core的配置选项,由于U-Boot/SPL, Linux 运行在ARM coretex-A8 core上,这里只关注ARM core。
B.在Debug窗口中,右键点击CortxA8 core, 选择Connect Target. 连接成功后,如下图所示:
file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image016.jpg
此时,已经成功连上AM335x的Cortex-A8 core了。
三、Debug配置
这里的debug配置,是对emulator连上core后行为的设置。 可以通过菜单run-debugconfiguration,得到以下界面:
在该页配置中,在调试过程需要调整的就是Auto Run Options,可以根据需要设置,当加载了image后,core自动运行到指定的symbol,并且被JTAG接口所停住
5.3.6 SPL的调试
调试U-Boot/SPL 的方式有两种,主要涉及如何加载image:一种是把image通过JTAG下载到片上RAM或者DDR中,然后导入symbol,重置 PC指针到image的入口处,进行调试;另一种,把image烧到SD卡或者其他启动存储器上,启动板子,通过JTAG停住core的PC指针,导入symbol,重置 PC指针到image的入口处,进行调试。
下面会在具体步骤中说明这两种方式如何操作:
A. 下载SPL image到AM335x中。
如果AM335x是从SD卡方式启动,此时SPL image已经被ROM code成功读到片上 RAM中,就不需要加载 SPL image了。
如果选择SPL image通过CCS下载,鼠标左键选择CortxA8 core , 然后在CCS菜单中,Tools -> Load Memory, 选择编译好的SPL imageU-Boot-spl.bin,如下图所示:
选择加载的地址。由于加载的U-Boot-spl.bin是RAW data,所以需要指定load address,这个地址就是SPL的入口地址,对于AM335x,SPL的入口地址是 0x402F0400,对应的宏定义为CONFIG_SPL_TEXT_BASE, 该宏定义在include/configs/am335x_evm.h中。通过编译出的map文件U-Boot-spl.map也可以查到,是__start symbol对应的地址。
设定加载image内型。由于所有的代码都是运行在ARM(32bit)模式下。所以Type-size也要设成32bit。设置界面如下:
最后点击Finish,SPL就会被load到片上RAM中了。如果在console窗口中有错误信息,需要把SPL image重新加载一遍。
B. 加载 symbol。
在上一步里,只是加载了RAW image,还没有加载调试所需要的带有调试信息的symbol。
可以通过Run ->Load -> Load Symbols 加载symbol信息,界面如下:
这里选择的是带有symbol信息的U-Boot-spl.
C. 设置Cortex-A8 core到ARM状态。
ARMcore 启动后,默认在Thumb(16bit)模式下,如前面所说,需要将其切换到ARM(32bit)下。具体做法是,View->Registers,展开CPSR寄存器,把T位设置为0。界面如下:
D. SPL的单步调试。
a. 从SPL编译的memory map可知,SPL从0x402f0400开始执行,所以首先就要把寄存器PC的值设为0x402f0400。可以通过View->Registers中设置PC指针的值即可, 界面如下,将红色框里面的改为0x402f0400即可。
b. 点击Debug窗口(view->debug)上tool bar中的汇编单步按钮,如下图所示,就开始调试了。
这时,在反汇编窗口(view->disassembly)中,如下图所示,看到的是汇编代码,而且在编辑窗口这边看不到源码。这是由于开始执行的代码在/arch/arm/cpu/armv7/start.s 中,反汇编和汇编一样,所以没有显示源码。
同时,可以看到PC指针运行到0x402f0458处。这里只是单步执行了一条指令,为什么跳过了这么大块地址?这里的单步运行,指令地址空间跳转了n指令,而不是一条指令,这是因为0x402f0400处存放的是异常中断向量表,通过默认启动的入口跳到reset symbol对应的地址了,也就是在0x402f0400处跳转到0x402f0458了,具体代码(arch/arm/cpu/armv7/start.S)如下:
_start: b reset
reset:
bl save_boot_params
接下来,可以在C代码中设置断点,进行调试了。有两点值得注意:
i.如果编译的时候,交叉编译器的性能优化选项是开着的,那么优化后编译生成的代码,其执行循序和C源码有差别,这时设置断点时,其实际的位置不会很准。所以,这里可以根据需要,决定是否关闭-O2选项。
ii.在CCS中,把core停下来时,CCS会根据image中调试信息所包含的源码路径,找到对应的源码和symbol。由于U-Boot/SPL是在Linux中编译,所以其路径都是Linux下的路径,所以Linux版本的CCS可以直接找到对应的源码,而对于Windows版本的CCS不能直接找到,需要通过手动找到源码,但是找到一个文件的源码后,CCS会根据相对路径找到其他文件。除了这点外,Linux和Windows的CCS配置使用是一样的。
5.3.7 U-Boot的调试
总体来说, U-Boot的调试过程和SPL调试过程是类似的,这里主要说明不同的几点:
A.从AM335x的启动过程可知,U-Boot是运行在DDR中的,而DDR是由SPL来初始化的,SPL还会初始化相关底层功能。所以,加载U-Boot前,先加载并运行SPL。
B.此版本的UBOOT使用了FDT(扁平设备树文件)。编译后的文件意义如下
所以我们需要导入u-boot.bin文件,此文件包含了uboot和.dtb所有信息。这是和不使用设备树的uboot的调试不同之处。
C.UBOOT代码执行过程中会有重定位操作,在board_init_f和board_init_f之间的relocate_code中实现。这个版本中的relocaddr= 0x8FF57000。为了能够调试重定位前、后的两部分代码。在LOADsymbols时,通过offset来区分。
1、调试relocation之前的 UBOOT代码
(1)加载U-Boot-spl.bin
(2)运行U-Boot-spl.bin之后立刻停住,如下所示
(3)加载u-boot.bin,start address: CONFIG_SYS_TEXT_BASE 0x80800000 file:///C:/Users/Miles/AppData/Local/Temp/msohtmlclip1/01/clip_image034.gif
(4)load symbols->u-boot
加载完成后界面如下:
可以看到起始地址是0x80800000,还可以看到相应的源文件vectors.s
(5)设置断点
找到重定位前的C函数board_init_f,打断点,如下;
点击运行后看到停在断点处,如下图所示:
(6)单步调试执行
至此,可以单步执行相应的代码调试。
注意:这样就可以调试relocate_code之前的代码。
2、调试relocation之后的 UBOOT代码
参考relocation之前的调试方法,relocation之后的 UBOOT代码调试在第(4)步有区别,之前(1)(2)(3)步一样,体现为加载symbols时有offset,offset这里为relocaddr = 0x8FF57000。
如下图所示:
(4)load symbols->u-boot
加载之后界面如下:
与relocation之前的调试步骤对比,在这时并不能看到相应的源码或文件,我的理解是因为在此时符号表被加载到了0x8FF57000,固在0x80800000看不到相应代码(symbols)。不过没关系,这里我们只是为了调试relocation之后的代码。
(5)设置断点
在board_init_r函数中打断点
点击运行,会看到代码停在断点处。如下图所示:
此时,就可以通过单步运行来进行相关代码调试。
文中图片可能显示不正常,本想一个个地插入或修正,但是太辛苦了,于是上传PDF格式的附件,请多包涵!
|