4. 程序加载与运行控制:加载ELF/HEX文件、单步执行、全速运行与复位
好,咱们进入第四章。这一章讲的是调试器最基础、也最核心的操作——怎么把程序弄进去,怎么让它跑起来,又怎么让它停下来。说白了,就是你和芯片之间的“对话”方式。
我记得刚入行那会儿,带我的老工程师跟我说:“你连加载都不会,就别谈调试了。”当时觉得这话有点重,后来自己踩了坑才明白——加载这一步要是出问题,后面全是白忙活。
4.1 加载ELF与HEX文件
Trace32支持两种最常见的可执行文件格式:ELF(带调试信息)和HEX(纯二进制)。
我个人习惯在开发阶段用ELF,因为符号表、源码行号都在里面,单步调试时能看到C代码。量产阶段或者只需要烧录时,才用HEX。
4.1.1 加载ELF文件
命令很简单:
LOAD.ELF my_firmware.elf
执行后,Trace32会自动解析ELF中的段信息,把代码段、数据段放到对应的内存地址上。同时,调试器会把符号表加载进来,这样你就能在反汇编窗口里看到函数名和变量名了。
LOAD.ELF my_firmware.elf /NOCODE —— 只加载符号,不重复下载代码,省时间。
4.1.2 加载HEX文件
HEX文件是纯二进制,没有符号信息。命令:
LOAD.HEX my_firmware.hex
加载HEX时,Trace32会按地址把数据填进去。但要注意——HEX文件不包含调试符号,所以单步调试时你只能看到汇编,看不到C源码。
FLASH.Unlock 再试。
4.1.3 加载前后的内存检查
加载完成后,我习惯先看一眼内存,确认数据写对了:
Data.dump 0x08000000 // 查看Flash起始地址的内容
如果看到的内容全是0xFF或者乱码,那说明加载没成功。我曾经遇到过一例——HEX文件路径里有中文,Trace32解析失败,但没报错。折腾了半天才发现是路径问题。
4.2 单步执行:Step Into / Over / Out
单步执行是调试的“显微镜”。三种模式各有用途,别搞混了。
| 命令 | 快捷键 | 行为 | 适用场景 |
|---|---|---|---|
| Step Into | F8 | 进入函数内部 | 想查看子函数内部逻辑时 |
| Step Over | F10 | 跳过函数,不进入 | 确认函数返回值正确,不想看内部 |
| Step Out | F7 | 从当前函数跳出 | 误入了函数,想快速返回 |
4.2.1 Step Into 的坑
Step Into 会进入函数内部。但如果函数是库函数或者没有源码,Trace32会直接跳到汇编。这时候别慌,看一眼反汇编窗口就好。
我遇到过一个问题:Step Into 一个延时函数,结果卡在里面出不来。后来发现那个延时函数是纯汇编写的,没有返回指令。嗯,这种时候直接 Step Out 或者暂停就行。
4.2.2 Step Over 的妙用
Step Over 是最常用的。它把整个函数当成一个黑盒,执行完再停到下一行。适合调试主流程时,不想被子函数打断思路。
但要注意——如果函数内部有硬件操作(比如写Flash、清中断标志),Step Over 可能会让硬件状态发生变化。这时候我建议用 Step Into 进去看一眼。
4.2.3 Step Out 的救场
Step Out 是救命用的。比如你不小心 Step Into 了一个很长的函数,或者发现走错了分支,直接 Step Out 就能跳回调用处。
4.3 全速运行与暂停
全速运行(Go)和暂停(Break)是调试的“油门”和“刹车”。
4.3.1 全速运行
Go
执行后,芯片会以正常速度运行程序。这时候Trace32会进入“运行态”,大部分调试窗口会变灰,直到你手动暂停或者遇到断点。
我个人习惯在跑全速前,先设好关键断点。不然程序跑飞了,你都不知道它停在哪。
4.3.2 暂停
Break
暂停会强制停止CPU。Trace32会显示当前程序计数器(PC)的位置。这时候你可以查看寄存器、变量、堆栈。
但要注意——暂停不是万能的。如果芯片进入了死循环或者中断风暴,暂停可能不响应。这时候只能靠硬件复位了。
4.4 复位与重启
复位是调试的“重启键”。Trace32支持多种复位方式:
| 命令 | 效果 | 适用场景 |
|---|---|---|
| SYStem.RESET | 软件复位,不重置调试器 | 快速重启程序 |
| SYStem.RESET Target | 硬件复位,重置芯片 | 芯片跑飞或死机时 |
| SYStem.UP | 复位后重新连接调试器 | 调试器与芯片失联时 |
4.4.1 复位后的状态
复位后,芯片会回到启动向量处。这时候PC指向复位向量,大部分外设寄存器恢复默认值。
我建议复位后先检查一下PC值:
R.List // 查看寄存器列表,确认PC
如果PC指向0xFFFFFFFF或者0x00000000,说明复位没成功,或者芯片根本没启动。
4.4.2 复位与断点的关系
复位后,之前设的断点还在吗?看情况。
- 软件复位:断点通常保留
- 硬件复位:断点可能被清除,需要重新设置
- 断电重启:断点肯定没了
我习惯在复位后先执行一次 Break.Set 确认断点状态,免得跑起来才发现没停住。
4.5 本章知识结构
下面这张图把本章的核心流程串起来了:
4.6 实战建议
最后,分享几个我自己的习惯:
- 加载前先确认芯片状态:执行
SYStem.UP确保调试器已连接 - 加载后先看PC:确认程序入口正确
- 单步调试时配合Watch窗口:盯着关键变量变化
- 全速运行前设好断点:别让程序跑飞了找不到北
- 复位后重新检查断点:有些复位会清断点
一句话总结: 加载是基础,单步是手段,全速是验证,复位是兜底。把这四个环节练熟了,调试效率至少翻一倍。