在上一篇博文 U-Boot 之一 零基础编译 U-Boot 过程详解 及 编译后的使用说明 中,最后使用阶段遇到了一些错误,然后发现不能调试(靠打印信息)实在是难受,就开始摸索如何调试 U-Boot,于是就有了这篇博文。
找了一下网上现有的资料,直接使用 GDB 命令行调试是一个选择,但是明显效率不高。于是开始探索直接使用 eclipse 对 U-Boot 进行编译及调试。发现网上有不少说明文章,但大多数都太老旧了,因此我决定重新整理一篇,使用的当前最新的工具环境如下:
首先从官网下载最新的针对嵌入式 C/C++ 的 tar 包(现在 eclipse 针对不同开发环境提供了不同的包,我记得之前并没有分开):Eclipse IDE for Embedded C/C++ Developers,地址:https://www.eclipse.org/downloads/packages/release/2021-12/r/eclipse-ide-embedded-cc-developers,然后进行安装(解压):
/opt/eclipse/eclipse
目录(我这里先建立了 eclipse 文件夹导致多了一级,大家可以直接解压到 /opt
)下直接双击运行 eclipse
程序即可。这里我们直接下载嵌入式专用的版本,主要是出于以下几点:
进一步,我们可以选择建立一个 eclipse 的快捷方式,方便后续启动:
sudo gedit /usr/share/applications/eclipse.desktop
[Desktop Entry]
Encoding=UTF-8
Name=Eclipse
Comment=Eclipse IDE
Exec=/opt/eclipse/eclipse/eclipse
Icon=/opt/eclipse/eclipse/icon.xpm
Terminal=false
StartupNotify=true
Type=Application
Categories=Application;Development;
sudo chmod u+x /usr/share/applications/eclipse.desktop
/usr/share/applications/eclipse.desktop
复制到桌面,然后赋予执行权限(应该是还需要右键鼠标,选择 Allow Launching)。附 tar 命令:
# 压缩 tar -czvf ***.tar.gz tar -cjvf ***.tar.bz2 # 解压缩 tar -xzvf ***.tar.gz tar -xjvf ***.tar.bz2 # 参数 -c :建立一个压缩档案的参数指令(create 的意思); -x :解开一个压缩档案的参数指令! -t :查看 tarfile 里面的档案!特别注意,在参数的下达中, c/x/t 仅能存在一个!不可同时存在!因为不可能同时压缩与解压缩。 -z :是否同时具有 gzip 的属性,亦即是否需要用 gzip 压缩 -j :是否同时具有 bzip2 的属性,亦即是否需要用 bzip2 压缩 -v :压缩的过程中显示档案!这个常用,但不建议用在背景执行过程! -f :使用档名。注意,在 f 之后要立即接档名,不要再加参数!例如使用『 tar -zcvfP tfile sfile 』就是错误的写法,要写成『 tar -zcvPf tfile sfile 』才对! -p :使用原档案的原来属性(属性不会依据使用者而变) -P :可以使用绝对路径来压缩! -N :比后面接的日期(yyyy/mm/dd)还要新的才会被打包进新建的档案中!
这个就相当简单了,SEGGER 提供了安装包,直接从 https://www.segger.com/downloads/J-Link/ 下载对应的的 linux 的安装包(例如我的 Ubuntu 对应 64-bit DEB Installer
),然后双击安装就可以了。安装之后默认位置是 ./opt/SEGGER
目录下。
eclipse 的配置分为全局、工作区、项目,优先级前者最低后者最高(后者会覆盖前者)。对于一些通用的配置(例如我们安装的 J-Link 驱动,无论工作区还是项目,应该都用一个),eclipse 推荐直接在全局或者工作区中配置,项目直接继承使用全局或工作区的配置就可以了。 启动 eclipse 会提示选择工作区,默认可以选择不再提示。
菜单 --> Window --> Preferences
打开配置界面,我们主要是配置更改 MCU 这个目录(这个好像是由于我们用的嵌入式版 eclipse 自带了 CDT 插件才有这个)下的内容,其他的配置项则根据自己的需要自行修改即可。具体如下:这里再次说明,由于我们选择的是嵌入式专用的 eclipse(Eclipse IDE for Embedded C/C++ Developers ),因此,我们不需要安装 CDT 插件等操作。否则光是配置 eclipse 内容就挺多!
CMSIS Pack 是 ARM 为 Cortex-M 核定义的一个规范,是一种有效的封装技术,目前支持近 9000 种不同的微控制器。它们为软件组件、设备参数和评估板支持提供了一种交付机制。软件包(文件集合)包括:
用过 MDK-ARM(Keil)的应该很熟悉,这个东西不仅可以在 MDK-ARM(Keil)中使用,现在 eclipse、IAR 都集成了 CMSIS Pack,通过 CMSIS Pack 我们可以在线安装一些芯片的包。
这里我们之所以安装 CMSIS Pack(确切的说是安装 CMSIS Pack 中提供的芯片的包),是因为从中我们可以获取到芯片的 SVD 文件,而 SVD 文件中记录了芯片中各种外设的寄存器,在调试时非常有用!如果不使用 SVD 文件,调试器将无法获取芯片中外设的寄存器,只能显示 ARM 核中的几个寄存器。
eclipse 中安装非常简单,但是由于访问的是国外的服务器,速度相当慢(那些包都挺大的),而且经常出现某些芯片下载不下来报错。如果出现报错直接选择忽略即可。具体操作如下图所示:
菜单--> Window-->Preferences --> C/C++ --> MCU Packages
下找到及更改。查看其中的内容,其实就是 Keil 中的那一套东西,因此一种变通的方法是将下载好的内容直接放到上面的目录中即可。SVD 文件就位于 CMSIS-Packs\Keil\STM32F7xx_DFP\2.14.1\CMSIS\SVD
目录下。 准备好以上环境及工具之后,就可以直接建立项目了,对于 U-Boot ,我们选择 Makefile Project with Existing Code
。我这里把步骤尽量把步骤合并到一张图,以节约篇幅。具体步骤如下图所示:
注意,如果选择在配置章节说的已经在配置了全局或者工作区,下面有些配置其实可以不用更改。我这里就以没有配置来进行演示(覆盖全局配置),对于全局配置有影响的地方单独说明一下。
点击 Finish 之后,默认在选择的源代码目录下新建两个(隐藏)文件:.cproject
和 .project
,这两个就是 eclipse 记录的项目配置信息文件(我之前以为会和 Windows 上的一些软件(例如 vs)似得放到选择的工作区目录下,要不然我选择工作区干啥!)。
点击右键菜单最下面的 Properties (也可以通过 菜单 --> Project --> Properties
)之后,就打开了项目的配置页面,接下来就是更改一些项目专用的配置了。下面我们一步步说明需要做哪些更改:
新增环境变量。具体操作如下图所示:
CMD
、PWD
我们不用管它(PATH
变量默认也应该有,不知为何我这里没有)。我们最终需要新增三个环境变量 ARCH
、CROSS_COMPILE
、PATH
(如果没有的话),其中, ARCH
和 CROSS_COMPILE
就是我们使用命令行编译时指定的。PATH
主要是告诉 eclipse 我们是用的工具的位置。PATH
的值。我们需要先通过上面的 Variables 找到系统 PATH 变量,然后点击 OK,此时,eclipse 就会导入系统环境变量的值。我们需要编辑它,在其中添加我们自己的编译工具链位置(我这里是 /usr/share/gcc-arm-none-eabi-10.3.2021.10/bin
,注意,bin 目录不止一个),否则在编译时会提示找不到相关工具。注意,如果在上面说的全局设置中已经添加了编译器的路径,这里不用再次添加。 最终添加后如下所示:更改我们使用的编译工具链以及选择使用的芯片。
[可选] 不使用 CDT 内建的编译工具链的相关设置(因为我们更换了编译工具链),注意,这里不更换也没啥问题!
新增我们自己的编译工具链的头文件路径。每一个编译工具链下都会有 include
文件夹用来存放编译器使用的各种头文件。需要注意的是, include
可能会有好几个,最好都添加上。如果在全局中配置了编译器路径,eclipse 就会自动识别指定的编译工具的相关头文件,这里就可以不用设置。
[可选] 开启并行编译。就是指定 make -jn
参数(n 根据处理器来定) 。eclipse 配置如下:
[可选] 增加 make stm32f769-disco_defconfig
步骤。完整的构建 U-Boot 的步骤中,第一步是生成 .config
文件,而后是 make menuconfig
,最后才是 make
。如果不添加到 eclipse ,则需要先用命令行执行以上步骤,否则 eclipse 会提示错误。
菜单 --> Project --> Build Targets --> Build
中直接点击上面的配置,执行这一步了。 [可选] 修改 make clean
。默认情况下,我们执行 Clean 时,使用是 make clean
,而我们编译 U-Boot 一般使用 make distclean
。这个是 eclipse 默认的设置,我们可以通过如下位置进行修改:
Build Targets
,只是使用起来没有上面这个方式简单。我第 6 步的图示中已经建立好了! 经过以上步骤,完整的 U-Boot 编译环境就搭建好了,接下来就可以在 eclipse 中构建 U-Boot 了。
调试之前肯定是先把 J-Link 连接到开发板(开发板上有个 20 针脚的 JTAG/SWD 调试接口),确保连接正确。测试连接具体可以使用我们安装的 J-Link 驱动里相应的工具:JFlashExe
,新建一个 STM32F769 芯片的项目,然后连接一下:
连接没有问题之后,接下来就是配置 eclipse 了:菜单 --> Run --> Debug Configuration...
,总的来说配置并不麻烦,我这里使用是 J-Link,因此,选择 GDB SEGGER J-link Debugging
,然后点击上面的新建图标(或者直接双击 GDB SEGGER J-link Debugging
)就会出现一个新的配置,具体步骤如下图所示:
C/C++ Application
这一项,我们需要从众多执行程序中选择出我们最终需要 u-boot(这个是最终编译出的带调试信息的,不是 u-boot.bin。具体见博文U-Boot 之三 U-Boot 源码文件解析及移植过程详解)。接下来就是配置界面中剩下的Debugger
、Startup
、Source
、Common
、SVD Path
这 5 个 Tab 页面内容,下面我直接上图来说明每个页面需要的配置:
Main
、Debugger
、Startup
Startup --> Setbreakpoint at:
这个默认是 mian,但是 U-Boot 默认没有 main,这里根据实际情况选择。直接 reset
,简单粗暴!还有可以使用 _main
。Source
、Common
、SVD Path
默认情况下,U-Boot 的编译已经进行了优化,且默认并不开启调试的,因此我们需要更改一下 U-Boot 的配置。第一个是需要取消 General Setup --> Optimise for size
,在一个就是开启 General Setup --> Configure standard U-Boot features (expert users) -> enable debug information for tools
,具体如下图所示:
make distclean
会清理所有文件,这就会导致以上的配置被清理!所以除非必要,否则还是使用 make clean
好一些。目前来看 make menuconfig
这一步还是需要在终端中执行。
警告:目前我在测试中发现,去掉 General Setup --> Optimise for size 可能导致程序无法运行,暂时没找到解决方法!我目前是在仅开启了 General Setup --> Configure standard U-Boot features (expert users) -> enable debug information for tools 的情况进行调试的。就是偶尔会出现断点位置不正确,不影响正常调试!
这里有个比较严重的问题,去掉 General Setup --> Optimise for size
之后,会导致程序变大,从而原来默认的 SPL 的大小(0x8000)不能容纳实际 SPL 大小,进一步导致了 U-Boot 无法启动。因此,这里我们必须要修改 U-Boot 的基地址。目前,有如下地方需要修改(图里面的 stm32f769-eval 是我移植的,上文暂时还没有更换):
接下来还有个问题:在启动调试之后,调试的程序在调试时只能执行一部分代码,此后就会失败,而且如果不调试想要直接运行是无法直接启动!具体现象如下图所示:
make distclean
那么每次都需要重新配置上面的选项。u-boot.dtb
,这个就是设备数编译之后的文件,而我们可执行程序的结束地址可以从源码的根目录下的 u-boot.map
文件中的 __end
符号找到。u-boot.dtb
和 __end
之后,我们就可以在 eclipse 中通过命令来解决: 经过以上两种方法的任意一种,再次启动调试时,就可以正常执行 board_inti_f
这个函数了!注意,由于这个函数里包含很多接口,执行速度可能有些慢!
接下来的问题就是内存重定位,U-Boot 中存在一段内存重定位的代码,重定位之后将导致调试失败!这主要是因为,在重定位之后,eclipse 正确加载符号表中的各符号。
add-symbol-file u-boot 重定位后的地址
。重定位后的地址就位于 gd
中的成员变量 unsigned long relocaddr;
中。 经过上面的配置之后,我们就可以使用 eclipse 对 U-Boot 进行调试了。这里需要注意的是,我们调试的如果是 U-Boot 本身,需要现将 SPL 烧写好,当然我们也可以调试 SPL。启动调试如下图所示:
联系客服