首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

代码调试跟踪与优化(二)--- 如何调试嵌入式代码?

  • 24-02-21 20:31
  • 4107
  • 5775
blog.csdn.net

文章目录

  • 前言:
  • 一、嵌入式系统调试原理
    • 1.1 嵌入式系统调试模型
    • 1.2 ARM CoreSight (Debug and Trace) 简介
  • 二、嵌入式系统调试工具
    • 2.1 J-LINK GDB Server 命令调试
    • 2.2 VS Code Cortex-Debug 可视化调试
    • 2.3 IDE 与Ozone 调试跟踪工具
    • 2.4 SystemView 调试跟踪工具
  • 更多文章:

前言:

前文介绍了GDB 调试原理,我们在进行嵌入式开发调试时,受限于嵌入式芯片资源和性能,一般采用远程调试。

GDB 远程调试需要在目标机上运行gdbserver 程序,对于裸机或RTOS 来说,gdbserver 占用的资源太多。而且在gdbserver 进程启动之前,我们无法对其进行调试,也就是说系统或驱动等底层代码的调试,单靠gdbserver 就无能为力了。我们如何调试嵌入式系统的底层代码呢?

有过嵌入式底层开发经验的朋友,都用过J-LINK、ST-LINK、CMSIS-DAP 等硬件调试器,借助这些硬件调试器可以访问嵌入式芯片的指令数据、内存数据、系统及外设寄存器等,而不要求目标芯片上提前执行什么代码。硬件调试器既然不依赖目标芯片的软件环境,自然是目标芯片在硬件上能处理这些调试跟踪信号,以ARM Cortex 架构芯片为例,目标芯片是如何处理这些调试跟踪信号的呢?

一、嵌入式系统调试原理

1.1 嵌入式系统调试模型

我们在GDB 远程调试模型的基础上,增加一个硬件调试器层级,得到嵌入式系统底层代码的调试模型如下:
嵌入式远程调试模型

嵌入式开发的目标芯片主流是ARM Cortex,本文以ARM Cortex 架构芯片为例简单介绍其调试模型:

  • GDB 调试工具:ARM Cortex 架构使用ARM GNU 工具链,又可细分为两类,Cortex -M/R 架构常用arm-none-eabi-gdb 调试工具,Cortex-A 架构常用arm-none-linux-eabihf-gdb 调试工具,可从ARM 开发者网站下载;
  • GDB Server 调试工具:这里的GDB Server 不是运行在目标机内的,也是运行在调试机内的程序(可以和GDB 调试工具运行在不同的调试机内,两个调试机通过网线相连),作为GDB 程序与硬件调试器之间沟通的桥梁,解释来自GDB 程序的调试命令和硬件调试器返回的调试数据。该程序通常与硬件调试器驱动程序一起发布,比如J-LINK 驱动程序包含的J-LINK GDB Server(仅支持J-LINK 调试器);也有一些开源的,比如OpenOCD(Open On-Chip Debugger) (可以支持多种硬件调试器,比如对ST-LINK 的支持更友好) 包含的OpenOCD GDB Server;
  • 硬件调试器:是一个内部烧录好程序的独立硬件设备,作为GDB Server 与目标芯片之间沟通的桥梁,翻译来自GDB Server 的调试命令和目标芯片返回的调试跟踪信号。硬件调试器需要配合相应的驱动程序使用,且不同调试器支持的目标芯片型号不同,常见的硬件调试器有J-LINK、ST-LINK、CMSIS-DAP 等;
  • 目标芯片:目标芯片为了方便开发人员调试代码,一般内部都集成了调试跟踪模块,比如ARM Cortex 架构集成了ARM CoreSight 调试跟踪组件,对内可以控制并访问几乎所有系统及外设存储空间,对外提供统一的Debug Port(支持SWD 和JTAG),开发者可借助硬件调试器对目标芯片进行调试跟踪。

GDB 和GDB Server 的调试原理在前篇博文已经介绍过了,这里简单介绍后两部分。我们进行软件开发调试的基础是目标芯片,硬件调试器应该选择支持目标芯片的型号,因此从目标芯片的调试跟踪模块及其接口介绍。

1.2 ARM CoreSight (Debug and Trace) 简介

目前在嵌入式领域ARM 架构是主流,RISC-V 架构是新锐(MIPS 架构也转投RISC-V 阵营),ARM Cortex 架构使用的调试跟踪系统是ARM CoreSight。

我们做嵌入式开发调试,只需要简单了解调试跟踪系统的大概组成结构和基本工作原理,帮助我们能善加利用这个强大的调试跟踪系统,可以大幅加快程序开发调试效率。硬件调试器配合调试软件已经帮我们封装了大量的细节,因此我们并不需要了解其过多的细节,下面以比较简单的单核Cortex-M3/M4 为例,展示ARM CoreSight 概貌。

在博文:ARM 代码烧录方案与原理详解 中已经介绍过ARM Cortex 提供的Debug Port,下图中颜色较深的模块都是ARM CoreSight 的组成部分,对外提供了Debug 和Trace 两个接口:
Cortex-M4 框图

ARM Cortex-M 调试跟踪模块主要包含以下几个部分:

  • FPB(Flash Patch and Breakpoint) Unit:闪存地址重载指的是将Code空间的指令或字面量重载到SRAM 中,断点单元可以产生断点事件,从而使处理器进入调试模式(暂停处理器模式或者调试监视器异常模式,后者不暂停处理器而是执行异常处理程序);
  • DWT(Data Watchpoint and Trace) Unit:数据观察点单元可以产生数据观察点事件,让处理器进入调试模式(halting mode or debug monitor exception mode)。数据跟踪单元可以产生跟踪数据包(包括数据值、数据地址、当前PC 值等信息),汇入到Advanced Trace Bus,经Trace Port 输出;
  • ITM(Instrumentation Trace Macrocell):测量跟踪单元(也称软件调试跟踪单元),可以将软件生成的调试信息封装到跟踪数据包中,并生成时间戳插入到跟踪流中,以帮助调试器重建事件的时序信息。也可以用作处理器内部的跟踪数据包合并设备,将DWT 数据包、软件调试数据包、时间戳数据包合并在一起(有一个FIFO 缓冲区以减少跟踪数据包的溢出),经Trace Port 输出;
  • ETM(Embedded Trace Macrocell):用于提供指令跟踪功能,可以生成包含指令执行流的跟踪数据包,以帮助调试器重建处理器执行的指令序列。ETM 还提供了一个FIFO 缓冲区,以便为TPIU 提供足够的时间去处理和序列化这些跟踪数据包;
  • TPIU(Trace Port Interface Unit):跟踪端口接口单元,用于把DWT、ITM 和ETM 汇聚来的跟踪数据包格式化,并输出到片外捕获设备(比如J-Trace、ULINKPro 等)。TPIU 有两种输出模式,一种是使用单根Serial Wire Output (SWO) 的Serial Wire Viewer (SWV) mode,另一种是使用四根parallel data output 加一根时钟信号引脚的Clocked mode。
    TPIU 框图

从上面对ARM CoreSight 的简单介绍可以看出,Debug 和Trace 是两个不同的通路,对外也分别提供了Debug Port 和Trace Port。从调试过程是否会显著影响程序原来的执行流程看,调试跟踪可分为两种类型:

  • 侵入式调试:可通过设置断点、数据观察点等让程序暂停执行或单步执行(可访问存储器及寄存器数据)。对于不能停止的程序(比如电机控制程序,突然暂停可能烧坏电机),还提供了调试监视器模式(中断号为12的系统异常Debug monitor),当发生调试事件(比如断点事件、数据观察点事件、外部调试请求事件等)时,去执行调试监视器异常处理程序(可更改内存堆栈数据),而不影响高优先级中断的响应;
  • 非侵入式调试:可通过指令跟踪、数据跟踪、软件生成的跟踪数据(可即时访问存储器及外设数据),获知处理器执行的指令序列、事件发生的时序信息等,分析软件执行过程中出现的Bug 或瓶颈。

了解了ARM CoreSight 调试跟踪系统的大概组成结构和基本工作原理,我们重点看下Debug Port 和Trace Port:
Debug and Trace Interface
我们经常使用的硬件调试器比如J-LINK、ST-LINK、CMSIS-DAP 等都支持SWD Debug Port + SWO Trace Port,支持Clocked Trace Port 的调试器比较少,比如J-Trace、ULINKPro 是支持这种Parallel Trace Port 的。5线的并行Trace Port 传输数据的速度更快,但占用的引脚更多,一般情况下都使用SWO Trace Port 以节省引脚。SWD Debug Port 也比JTAG Debug Port 使用更少的引脚数,因此上图最左边的组合更常用。

二、嵌入式系统调试工具

了解了调试原理,更重要的是会借用强大的调试工具,更高效的获取代码执行的详细信息,更快速的解决代码运行的bug 和瓶颈。本文使用nRF5 SDK 中的示例代码展示不同的调试工具和方法,开发调试环境搭建可参考博文:如何实现扫码连接BLE 设备的功能?

  • 硬件平台:nRF52 开发板,芯片型号为nRF52832_QFAA;
  • 软件平台:nRF5 SDK 版本 nRF5_SDK_17.0.2_d674dde,SoftDevice(BLE protocol stack)版本 s132_nrf52_7.20,基于Windows 10_x64;
  • 编译调试工具:代码编辑VSCodeUserSetup-x64-1.54.2,代码编译gcc-arm-none-eabi-9-2019-q4-major-win32-sha2,代码调试跟踪JLink_Windows_V696、Ozone_Windows_V322b_x64、SystemView_Windows_V330_x64;
  • 示例工程代码:.\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_uart

2.1 J-LINK GDB Server 命令调试

接着从前篇博文的末尾:GDB 远程调试开始介绍,ARM Cortex-M 一般使用arm-none-eabi-gcc 编译器进行编译,我们先找到工程代码的Makefile 文件 .\examples\ble_peripheral\ble_app_uart\pca10040\s132\armgcc\Makefile,然后使用make 命令编译工程代码,并将其烧录到nRF52 DK 内,图示如下:
ARM GCC 编译链接烧录工程代码图示
按照前篇博文GDB 远程调试的方法,启动调试代码,首先打开J-Link GDB Server.exe 程序,配置界面如下:
J-LINK GDB Server 配置界面
J-Link GDB Server 启动后,监听TCP/IP Port 为localhost:2331,我们在Terminal(cmd/shell) 执行arm-none-eabi-gdb 程序后,输入target remote localhost:2331 即可连接上J-Link GDB Server,再读入带调试信息的ELF 文件,就可以开始远程调试嵌入式代码了:
GDB target remote图示
GDB 命令调试并不直观,而且嵌入式系统更多的需要查看处理器及外设寄存器的值、内存数据、反汇编代码等比较靠近硬件底层的信息,为方便查看这些信息,常使用图形界面来进行调试跟踪。即便使用可视化调试界面,底层依然需要GDB 命令支持,GDB 查询寄存器数据、内存数据、反汇编代码的命令如下:

查询内存数据与反汇编代码命令描述
disassemble location显示当前调试环境中指定位置location 的反汇编代码,location 可以是函数名,也可以是存储地址;
                                  
info registers打印当前调试环境中处理器内的寄存器数据;
x/fmt addressExamine memory 查看内存,/fmt 为显示内存的长度和格式,比如/20xw 表示以十六进制显示20个字(也即4个字节32位)的内存数据,address 可以是函数名也可以是存储地址,指定查看内存的起始地址。

2.2 VS Code Cortex-Debug 可视化调试

VS Code 作为一款代码编辑器,提供了丰富的扩展库,对于Cortex-M 嵌入式芯片的调试也提供了一个扩展库Cortex-Debug,我们可以使用这个库实现嵌入式调试功能,Cortex-Debug 的下载和配置界面如下(参见博文:Cortex-debug 调试器使用介绍):
安装并配置Cortex-Debug

# settings.json
{
    "terminal.integrated.shell.windows": "C:\\WINDOWS\\System32\\cmd.exe",
    "cortex-debug.armToolchainPath": "C:\\Program Files (x86)\\GNU Tools Arm Embedded\\9 2019-q4-major\\bin",
    "cortex-debug.armToolchainPrefix": "arm-none-eabi",
    "cortex-debug.JLinkGDBServerPath": "C:\\Program Files (x86)\\SEGGER\\JLink\\JLinkGDBServerCL.exe",
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

配置好编译工具链路径cortex-debug.armToolchainPath 和JLinkGDBServerCL.exe 路径cortex-debug.JLinkGDBServerPath,就可以创建被调试工程的启动文件launch.json 了,创建过程如下:
创建Cortex Debug launch.json 文件
启动文件launch.json 中需要配置包含调试信息的ELF 文件路径executable,调试器类型servertype及调试接口interface,目标芯片型号device,目标芯片svd 文件路径svdFile 这几个属性值(还可以配置runToMain 为true,表示执行到main 函数起始位置暂停):

# launch.json
{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Cortex Debug",
            "cwd": "${workspaceRoot}",
            "executable": ".\\examples\\ble_peripheral\\ble_app_uart\\pca10040\\s132\\armgcc\\_build\\nrf52832_xxaa.out",
            "request": "launch",
            "type": "cortex-debug",
            "servertype": "jlink",
            "svdFile": "C:\\Users\\paul\\AppData\\Local\\Arm\\Packs\\NordicSemiconductor\\nRF_DeviceFamilyPack\\8.35.0\\SVD\\nrf52.svd",
            "interface": "swd",
            "device": "nRF52832_xxAA",
            "runToMain": true        
        }
    ]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

到这里Cortex-Debug 就配置好了,可以开始调试了,点击Start Debugging(Cortex Debug) 按钮,程序会暂停到main函数起始位置(设置了"runToMain": true),单步调试,我们可以从VS Code 界面获得的调试信息如下:
Cortex-Debug 调试界面

2.3 IDE 与Ozone 调试跟踪工具

我们开发调试嵌入式系统也经常使用IDE(Intergreated Development Environment) 工具,比如调试开发Cortex-M 芯片的Keil MDK(Microcontroller Development Kit)、IAR Embedded Workbench、SEGGER Embedded Studio 等。比如nRF5 SDK 就支持四种开发调试工具,除了ARMGCC 需要配合代码编辑器比如VS Code外(前面我们已经展示了VS Code 配合ARMGCC 如何实现代码编辑、编译、调试的),其余三个都是兼具代码编辑、编译链接、调试跟踪的IDE 工具:
nRF5 SDK 支持的四种开发工具
Nordic 官方推荐使用SEGGER Embedded Studio,这里就简单展示下该IDE 的调试跟踪界面(打开.\examples\ble_peripheral\ble_app_uart\pca10040\s132\ses\ble_app_uart_pca10040_s132.emProject 工程,然后点击菜单Debug–>Go 或按F5 键):
SEGGER Embedded Studio 调试界面
如果不想使用IDE,也可以使用比较轻便的调试信息展示工具,比如SEGGER 开发的Ozone,该工具安装包只有20MB,可单独配置使用,也可由SEGGER Embedded Studio 通过菜单Debug–> Debug With Ozone 启动。Ozone 不仅可以图形化显示前面介绍的调试信息(比如变量、断点、数据观察点、寄存器、内存、反汇编、调用栈等),还可以展示数据采样信息、指令跟踪信息、甚至是实时功耗信息等,可以帮助我们分析代码的覆盖率和执行效率,帮助我们定位软件执行bug 与瓶颈。Ozone 调试信息图形化显示界面如下(可参考博文Ozone Analyzer或点击Help–> User Guide 查看说明文档):
Ozone 调试界面
这里重点关注下 Trace 信息,主要是上图View 菜单Advanced 部分的内容。来自DWT、ITM、ETM 的跟踪数据可以帮助我们了解处理器执行的指令序列、数据或事件的时许、功耗的变化曲线等信息,配合ITM 为跟踪数据包添加的时间戳信息,我们可以查看包含Data、Power、Code 的Timeline 界面如下:
Data/Code/Power Timeline 图示

2.4 SystemView 调试跟踪工具

如果在目标芯片上运行了RTOS 操作系统或者通信协议栈这类相对复杂的任务调度或事件驱动代码,也可以使用SystemView 展示嵌入式系统内实时发生的任务切换或事件回调时序信息,帮助我们了解系统或协议栈运行时的细节,从而更高效的定位系统运行过程中的bug 或瓶颈。

SystemView 包含两部分代码(仅可用于J-LINK 或J-Trace 调试器,仅使用Debug Port,不需要Trace Port):

  1. PC 上运行的可视化应用程序SystemView,安装包只有不到7MB,独立使用;
  2. 目标芯片上运行的系统信息监测代码,在开发嵌入式系统代码时需要移植并集成到目标系统内,需要占用约2KB 的ROM 空间和约0.6 KB 的RAM 空间。

使用SystemView 的关键是向目标系统内添加移植SystemView 目标芯片端的代码,需要移植的代码可以到SystemView 安装目录.\Program Files\SEGGER\SystemView\Src 找到,移植说明可以参考文档.\SEGGER\SystemView\Doc\UM08027_SystemView.pdf,需要移植的文件如下:
SystemView 移植代码
这里就不展示SystemView 目标芯片端代码移植过程了,可以参考pdf 文档逐步操作,SystemView 以图形化方式展现出来的任务调度或事件触发回调时序图如下:
SystemView 展示任务事件时序信息图示
通过SystemView,可以分析执行了哪些中断、任务和软件计时器?它们使用了多少次、何时执行以及使用了多少时间?SystemView 向我们展示了嵌入式系统内到底发生了什么、以什么顺序?哪个中断触发了哪个任务切换?哪个中断和任务调用了底层模块的哪个API函数?这些信息的实时采集精度可以精确到一个CPU 周期,然后以时序图的形式呈现出来,放大时序图可以看到细节。

更多文章:

  • 《代码调试跟踪与优化(三)— 如何调试Fault 异常?》
  • 《代码调试跟踪与优化(一)— 如何用GDB 调试代码?》
  • 《如何实现扫码连接BLE 设备的功能(以nRF5 为例)?》
  • 《Cortex-debug 调试器使用介绍》
  • 《RT-Thread SystemView 使用指南》
注:本文转载自blog.csdn.net的流云IoT的文章"https://blog.csdn.net/m0_37621078/article/details/114918430"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top