在上一篇博文 U-Boot 之一 零基础编译 U-Boot 过程详解 及 编译后的使用说明 中,最后使用阶段遇到了一些错误,然后发现不能调试(靠打印信息)实在是难受,就开始摸索如何调试 U-Boot,于是就有了这篇博文。

  找了一下网上现有的资料,直接使用 GDB 命令行调试是一个选择,但是明显效率不高。于是开始探索直接使用 eclipse 对 U-Boot 进行编译及调试。发现网上有不少说明文章,但大多数都太老旧了,因此我决定重新整理一篇,使用的当前最新的工具环境如下:

  1. Ubuntu 20.04.3
  2. Eclipse IDE 2021-12 R Packages Eclipse IDE for Embedded C/C++ Developers
  3. U-boot 2021.10
  4. J-Link_Linux_V760b_x86_64.deb

下载安装 eclipse

  首先从官网下载最新的针对嵌入式 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 程序即可。这里我们直接下载嵌入式专用的版本,主要是出于以下几点:

  1. 根据官网提示 “The Eclipse Installer 2021‑12 R now includes a JRE for macOS, Windows and Linux.” ,我们不用再安装 Java 运行时 了。解压后直接使用就可以了。
  2. 包含了一些嵌入式使用的插件(例如 J-Link、OpenOCD 等调试插件 ),这省了我们在去安装这些插件。例如,选择 Eclipse IDE for C/C++ Developers,然后去安装各种插件。

进一步,我们可以选择建立一个 eclipse 的快捷方式,方便后续启动:

  1. 新建 sudo gedit /usr/share/applications/eclipse.desktop
  2. 输入以下内容:
    [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;
    
  3. 赋予执行权限 sudo chmod u+x /usr/share/applications/eclipse.desktop
  4. 以上步骤之后我们就可以在桌面最左下角的菜单中找到 eclipse 了。当然还可以在进一步,将 /usr/share/applications/eclipse.desktop 复制到桌面,然后赋予执行权限(应该是还需要右键鼠标,选择 Allow Launching)。

附 tar 命令:

 # 压缩tar -czvf ***.tar.gztar -cjvf ***.tar.bz2# 解压缩tar -xzvf ***.tar.gztar -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)还要新的才会被打包进新建的档案中!

下载安装 J-Link 驱动

  这个就相当简单了,SEGGER 提供了安装包,直接从 https://www.segger.com/downloads/J-Link/ 下载对应的的 linux 的安装包(例如我的 Ubuntu 对应 64-bit DEB Installer),然后双击安装就可以了。安装之后默认位置是 ./opt/SEGGER 目录下。

里面的可执行程序都没有对应的桌面图标,运行后在左侧的工具栏上也是黑乎乎的。使用时直接使用命令行或者到目录下双击对应的可执行程序即可。

配置 eclipse

  eclipse 的配置分为全局、工作区、项目,优先级前者最低后者最高(后者会覆盖前者)。对于一些通用的配置(例如我们安装的 J-Link 驱动,无论工作区还是项目,应该都用一个),eclipse 推荐直接在全局或者工作区中配置,项目直接继承使用全局或工作区的配置就可以了。 启动 eclipse 会提示选择工作区,默认可以选择不再提示。

启动之后,直接 菜单 --> Window --> Preferences 打开配置界面,我们主要是配置更改 MCU 这个目录(这个好像是由于我们用的嵌入式版 eclipse 自带了 CDT 插件才有这个)下的内容,其他的配置项则根据自己的需要自行修改即可。具体如下:

我这里仅仅配置了编译工具链和 J-Link 的安装位置。之所以这里选择对全局配置项进行配置,主要还是方便在后续建立项目之后,项目自动继承这些配置,方便减少很多操作。

  这里再次说明,由于我们选择的是嵌入式专用的 eclipse(Eclipse IDE for Embedded C/C++ Developers ),因此,我们不需要安装 CDT 插件等操作。否则光是配置 eclipse 内容就挺多!

安装 CMSIS-Packs

  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 中安装非常简单,但是由于访问的是国外的服务器,速度相当慢(那些包都挺大的),而且经常出现某些芯片下载不下来报错。如果出现报错直接选择忽略即可。具体操作如下图所示:

  CMSIS Pack 的安装位置可以在 菜单--> Window-->Preferences --> C/C++ --> MCU Packages 下找到及更改。查看其中的内容,其实就是 Keil 中的那一套东西,因此一种变通的方法是将下载好的内容直接放到上面的目录中即可。SVD 文件就位于 CMSIS-Packs\Keil\STM32F7xx_DFP\2.14.1\CMSIS\SVD 目录下。

注意,上面的这个目录应该是个隐藏文件夹!

编译 U-Boot

新建项目

  准备好以上环境及工具之后,就可以直接建立项目了,对于 U-Boot ,我们选择 Makefile Project with Existing Code。我这里把步骤尽量把步骤合并到一张图,以节约篇幅。具体步骤如下图所示:

  其中,我们选择的编译工具链是 Arm Cross GCC。这里的选择主要是让 eclipse 能够主动使用适合我们的一些配置。如果选择其他的,后续也可以再次进行更改(步骤会多一些)。

注意,如果选择在配置章节说的已经在配置了全局或者工作区,下面有些配置其实可以不用更改。我这里就以没有配置来进行演示(覆盖全局配置),对于全局配置有影响的地方单独说明一下。

  点击 Finish 之后,默认在选择的源代码目录下新建两个(隐藏)文件:.cproject.project,这两个就是 eclipse 记录的项目配置信息文件(我之前以为会和 Windows 上的一些软件(例如 vs)似得放到选择的工作区目录下,要不然我选择工作区干啥!)。

项目配置

  点击右键菜单最下面的 Properties (也可以通过 菜单 --> Project --> Properties)之后,就打开了项目的配置页面,接下来就是更改一些项目专用的配置了。下面我们一步步说明需要做哪些更改:

  1. 新增环境变量。具体操作如下图所示:

    环境变量下原有的两个 CMDPWD 我们不用管它(PATH 变量默认也应该有,不知为何我这里没有)。我们最终需要新增三个环境变量 ARCHCROSS_COMPILEPATH(如果没有的话),其中, ARCHCROSS_COMPILE 就是我们使用命令行编译时指定的。PATH 主要是告诉 eclipse 我们是用的工具的位置。
      这里需要特殊注意 PATH 的值。我们需要先通过上面的 Variables 找到系统 PATH 变量,然后点击 OK,此时,eclipse 就会导入系统环境变量的值。我们需要编辑它,在其中添加我们自己的编译工具链位置(我这里是 /usr/share/gcc-arm-none-eabi-10.3.2021.10/bin,注意,bin 目录不止一个),否则在编译时会提示找不到相关工具。注意,如果在上面说的全局设置中已经添加了编译器的路径,这里不用再次添加。 最终添加后如下所示:

    我们添加的编译器路径用于让 eclipse 找到编译器,其他原有的系统环境变量可以让 eclipse 找到 make 程序。此外,最下面的 Append xxx 这句不要去掉。

  2. 更改我们使用的编译工具链以及选择使用的芯片。

    如果没有配置全局编译器路径,这里必须单独配置;如果设置了这里就会自动读取全局设置的编译工具链,查看一下是否正确即可。如果这里选择了芯片,在调试的时候会省略一些配置。

  3. [可选] 不使用 CDT 内建的编译工具链的相关设置(因为我们更换了编译工具链),注意,这里不更换也没啥问题!

  4. 新增我们自己的编译工具链的头文件路径。每一个编译工具链下都会有 include 文件夹用来存放编译器使用的各种头文件。需要注意的是, include 可能会有好几个,最好都添加上。如果在全局中配置了编译器路径,eclipse 就会自动识别指定的编译工具的相关头文件,这里就可以不用设置。

  5. [可选] 开启并行编译。就是指定 make -jn 参数(n 根据处理器来定) 。eclipse 配置如下:

  6. [可选] 增加 make stm32f769-disco_defconfig步骤。完整的构建 U-Boot 的步骤中,第一步是生成 .config 文件,而后是 make menuconfig,最后才是 make。如果不添加到 eclipse ,则需要先用命令行执行以上步骤,否则 eclipse 会提示错误。

    具体添加如下:

    之后,我们就可以在 菜单 --> Project --> Build Targets --> Build 中直接点击上面的配置,执行这一步了。

  7. [可选] 修改 make clean。默认情况下,我们执行 Clean 时,使用是 make clean,而我们编译 U-Boot 一般使用 make distclean。这个是 eclipse 默认的设置,我们可以通过如下位置进行修改:

    此外,还可以参考第 6 步中新建一个 Build Targets,只是使用起来没有上面这个方式简单。我第 6 步的图示中已经建立好了!

编译

经过以上步骤,完整的 U-Boot 编译环境就搭建好了,接下来就可以在 eclipse 中构建 U-Boot 了。

调试 U-Boot

J-Link 连接开发板

  调试之前肯定是先把 J-Link 连接到开发板(开发板上有个 20 针脚的 JTAG/SWD 调试接口),确保连接正确。测试连接具体可以使用我们安装的 J-Link 驱动里相应的工具:JFlashExe,新建一个 STM32F769 芯片的项目,然后连接一下:

提示 Connected successfully 即可。

eclipse 调试相关配置

  连接没有问题之后,接下来就是配置 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 源码文件解析及移植过程详解)。接下来就是配置界面中剩下的DebuggerStartupSourceCommonSVD Path 这 5 个 Tab 页面内容,下面我直接上图来说明每个页面需要的配置:

  1. MainDebuggerStartup

    如果已经在全局配置中设置了J-Link 的路径,这里默认是会自动读取全局的配置的 J-Link,不用更改也可以。当然这里再选择一下肯定没有问题。芯片类型如果在构建时选择了芯片,这里也会自动填上选择的芯片。还有就是 Startup --> Setbreakpoint at: 这个默认是 mian,但是 U-Boot 默认没有 main,这里根据实际情况选择。直接 reset,简单粗暴!还有可以使用 _main
  2. SourceCommonSVD Path

    如果按照前面说的安装了 CMSIS-Packs,那么这里就可以找到对应芯片的 SVD 文件,选择 SVD 文件之后,我们在调试时就可以查看外设寄存器的值,否则将无法查看!如下图所示:

      注意,eclipse 寄存器分为两部分:Registers 窗口中是 ARM Cortex 核的寄存器(例如,R0、PC),Peripherals 下面就是我们的 SVD 文件中描述的外设寄存器。

U-Boot 调试修改

开启调试选项

  默认情况下,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 是我移植的,上文暂时还没有更换):

修改设备树配置

  接下来还有个问题:在启动调试之后,调试的程序在调试时只能执行一部分代码,此后就会失败,而且如果不调试想要直接运行是无法直接启动!具体现象如下图所示:

根本原因是由于调试的程序有没有设备树!默认情况下,U-Boot 的可执行程序是 bin 后拼接上 dtb 组成的,而我们调试的程序只有 bin,没有 dtb!解决方法如下有如下两种:

  • 将设备树直接编译进 U-Boot 的 bin 文件中,而不是将 设备树单独出来!U-Boot 本身就有这方面的配置,具体如下:

    如果执行过 make distclean 那么每次都需要重新配置上面的选项。
  • 在 eclipse 中指定设备树地址。如果使用的是 U-Boot 默认的分离设备树模式,那么在编译成功之后,会在源码的根目录下生成 u-boot.dtb ,这个就是设备数编译之后的文件,而我们可执行程序的结束地址可以从源码的根目录下的 u-boot.map 文件中的 __end 符号找到。

    有了 u-boot.dtb__end 之后,我们就可以在 eclipse 中通过命令来解决:

    如果 U-Boot 的可执行程序大小有变化,每次都需要更改这里!而且在刚开始启动调试时,eclipse 会报一个错误,稍等一会即可正常进入调试。

  经过以上两种方法的任意一种,再次启动调试时,就可以正常执行 board_inti_f 这个函数了!注意,由于这个函数里包含很多接口,执行速度可能有些慢!

重定位配置

  接下来的问题就是内存重定位,U-Boot 中存在一段内存重定位的代码,重定位之后将导致调试失败!这主要是因为,在重定位之后,eclipse 正确加载符号表中的各符号。

  目前,我还没有找到比较好的解决方法,官网推荐的方法是 使用 gdb 命令行来手动加载符号表 。命令非常简单:add-symbol-file u-boot 重定位后的地址。重定位后的地址就位于 gd 中的成员变量 unsigned long relocaddr; 中。

调试

  经过上面的配置之后,我们就可以使用 eclipse 对 U-Boot 进行调试了。这里需要注意的是,我们调试的如果是 U-Boot 本身,需要现将 SPL 烧写好,当然我们也可以调试 SPL。启动调试如下图所示:

参考

  1. https://boundarydevices.com/debugging-using-segger-j-link-jtag/
  2. https://www.cnblogs.com/humaoxiao/p/4166230.html
  3. https://m2m-tele.com/blog/2021/09/19/how-to-debug-u-boot/
  4. https://community.element14.com/products/devtools/single-board-computers/riotboard/b/blog/posts/automate-uboot-build-with-eclipse
  5. https://programmerclick.com/article/68662419084/

U-Boot 之二 详解使用 eclipse + J-Link 进行编译及在线调试相关推荐

  1. Spring Boot 集成 FreeMarker 详解案例

    年轻就不应该让自己过得太舒服" – From yong 一.Springboot 那些事 SpringBoot 很方便的集成 FreeMarker ,DAO 数据库操作层依旧用的是 Myba ...

  2. Java web 开发的概念、环境配置、创建项目过程详解(Eclipse)

    Java Web 开发 Java Web 开发概念 搭建过程 详解 在eclipse创建Dynamic Web Project 创建时选择Tomcat的版本 创建项目成功 eclipse环境下如何配置 ...

  3. SpringBoot2.1.5(16)--- Spring Boot的日志详解

    SpringBoot2.1.5(16)--- Spring Boot的日志详解 市面上有许多的日志框架,比如 JUL( java.util.logging), JCL( Apache Commons ...

  4. ABP VNext系列(二)-详解ABP的依赖注入

    ABP VNext系列(二)-详解ABP的依赖注入 上一篇 : ABP VNext系列(一)-第一个ABP VNext 目录 ABP VNext系列(二)-详解ABP的依赖注入 一.什么是依赖注入 1 ...

  5. U-Boot 之三 详解使用 eclipse + J-Link 进行编译及在线调试

      在上一篇博文 U-Boot 之二 移植过程详解. STM32F769I-EVAL 开发板适配 中,最后使用阶段遇到了一些错误,然后发现不能调试(靠打印信息)实在是难受,就开始摸索如何调试 U-Bo ...

  6. Spring Boot (4)---配置文件详解

    Spring2.0 Boot配置文件详解 配置文件说明 Spring Boot 配置文件允许为同一套应用,为不同的环境用不同的配置文件.比如开发环境.测试环境.生成环境.你可以用 properties ...

  7. Spring Boot(3)---Spring Boot启动器Starter详解

    Spring Boot的启动器Starter详解 Spring Boot 简化了 Spring 应用开发,不需要配置就能运行 Spring 应用, Spring Boot 管理 Spring 容器.第 ...

  8. Spring Boot事务管理详解

    什么是事务? 我们在开发企业应用时,对于业务人员的一个操作实际是对数据读写的多步操作的结合.由于数据操作在顺序执行的过程中,任何一步操作都有可能发生异常,异常会导致后续操作无法完成,此时由于业务逻辑并 ...

  9. 企业分布式微服务云SpringCloud SpringBoot mybatis (二)Spring Boot属性配置文件详解...

    相信很多人选择Spring Boot主要是考虑到它既能兼顾Spring的强大功能,还能实现快速开发的便捷.我们在Spring Boot使用过程中,最直观的感受就是没有了原来自己整合Spring应用时繁 ...

最新文章

  1. 用好idea这几款插件,可以帮你少写30%的代码!
  2. 这个冬天,将是共享单车最艰难的时刻
  3. 李彦宏喊你来坐出租车,无人驾驶的那种;百度还要继续搞芯片,联手华为的那种...
  4. OpenYurt — Yurtctl
  5. WPF 快速制作可拖拽的对象和窗体
  6. VS2010重构学习总结
  7. SAP MM 移动类型-入门篇
  8. vc连接mysql 查询_vc连接数据库中查询代码如何写呀 急急急!!!!!!
  9. 在WPF中处理Windows消息
  10. 怎样打开mysql进程数_mysql查看最大打开进程数
  11. .Net的类型构造器-static构造函数
  12. php 两个类 相互调用_如何在 PHP 和 Laravel 中使用 Traits
  13. 在 for 循环里写加号拼接字符串的那个同事,不见了~
  14. 【计算大于这个整数的最小质数】
  15. WebRTC-NACK、Pacer和拥塞控制和FEC
  16. 配置JAVA_HOME
  17. python moving average_Python实现滑动平均(Moving Average)的代码教程
  18. LFS(Linux From Scratch)构建过程全记录(一):准备工作
  19. oracle闪回空间满的原因,处理Oracle数据库闪回区空间满的问题
  20. revit二次开发2016

热门文章

  1. 企业级 SpringBoot 教程 (十七)上传文件
  2. C++运算符重载(10)
  3. Java 常见内存溢出异常与代码实现
  4. 某房产中介服务器托管及安全方案(下)
  5. pandas(二) -- Dataframe创建及索引
  6. java 图形库_OpenGL开放图形java库jogamp-all-platforms.7z
  7. 高可用延迟队列设计与实现
  8. go mod导入本地包的正确引入方法:require + replace
  9. Spark3.1.1 Docker镜像中修改/etc/hosts
  10. kubesphere添加新节点