原来IAR下还有这么神乎其技的宏文件(.mac)
大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是IAR内部C-SPY调试组件配套宏文件(.mac)用法。
痞子衡之前写过一篇 《JLink Script文件基础及其在IAR下调用方法》,那篇文章介绍了 J-Link 硬件调试器配套的 .JLinkScript 文件功能及用法,今天我们要讲的主角 .mac 文件之于 IAR 内部 C-SPY 调试组件的作用就像 .JLinkScript 之于 J-Link 调试器的作用一样,.mac 文件也是为了完成在 IAR 下的特殊调试需求而存在的。
一、C-SPY宏(macros)作用
我们知道在 IAR 开发环境下负责综合调度外部硬件调试器与芯片内部调试模块来完成用户实际调试需求的组件是 C-SPY,有了 C-SPY,你才可以愉快地在 IAR 里进行单步调试、打断点等操作。
宏文件(.mac)是 C-SPY 组件定义和解释执行的一种专用类脚本文件,它的语法比较像 C 语言,但本质上是一种脚本语言,由 CSpyBat.exe 在用户调试的过程中解释执行。
\IAR Systems\Embedded Workbench 9.10.2\common\bin\CSpyBat.exe
宏文件的功能主要有以下 5 点,其中第 2 点配置板级硬件是最常用的功能。比如你想在板载外部 SDRAM 里直接调试工程代码执行,但是调试组件在下载程序进 SDRAM 之前需要一个已经初始化好的 SDRAM,这个 SDRAM 初始化工作就可以由宏文件来完成(当然修改 IDE flashloader 去完成也是一种可选方法)。
1. 调试流程自动化,例如跟踪打印输出,打印变量值,设置断点。
2. 配置板级硬件,例如初始化硬件寄存器、初始化外存。
3. 在运行时为应用程序提供模拟数据。
4. 模拟外围设备(只适用于使用模拟器驱动程序的情况)
5. 开发小的调试工具函数,例如计算堆栈深度,参见示例 \arm\src\sim\stack.mac
二、C-SPY宏文件基础
C-SPY 宏文件这一套东西整体上由三大部分组成:基本语法、预定义系统宏函数、保留 setup 宏函数。
2.1 宏文件基础语法
C-SPY 宏语言并不是一个通用的脚本语言,因此其并不像你熟知的那些 Python 之类的脚本语言那样语法完善,它仅是为了配合 C-SPY 完成一些必要操作。C-SPY 宏语法跟 C 语言类似,支持 C 语言中允许的大多数语句(if else,while,变量声明,…),但不是所有的语句。
全部语法:\IAR Systems\Embedded Workbench 9.10.2\arm\doc\EWARM_DebuggingGuide.ENU 手册里的 BRIEFLY ABOUT THE MACRO LANGUAGE 章节
下面是一个典型的用户自定义 C-SPY 宏函数示例(设置地址 0x400D403C 处寄存器的值),涉及的语法包括函数定义(支持参数和返回值),变量定义(统一为 __var 类型), 逻辑表达式, do while 语句,系统宏函数调用(加 __ 前缀)。掌握示例函数里的语法基本就足够使用宏文件功能了。
// 定义函数,无参,默认返回值 0(缺省)
Peripheral_WaitSetDone()
{
// 定义 reg 变量
__var reg;
do
{
// 读取 0x400D403C 地址处的值 (32bit)
reg = __readMemory32(0x400D403C, "Memory");
// 延时 10 ms
__delay(10);
// 判断 reg[1:0] 是否为 0
}while((reg & 0x3) == 0);
// 将 0x3 写入 0x400D403C 地址处
__writeMemory32(0x00000003, 0x400D403C, "Memory");
// 输出信息到 IAR 调试窗口
__message "Message: Peripheral Reg Set Done\n";
}
2.2 预定义系统宏功能
C-SPY 宏体系里实现了很多基础操作功能,这些功能通过 API 函数接口形式开放给用户宏函数来调用,这些 API 全部以 __ 为前缀,大约有 100 多个 API。下面列举出最常用的一些宏 API:
系统宏原型 | 功能解释 |
---|---|
__delay(value) | ms级精度延时 |
__readAPReg(register) __readDPReg(register) __writeAPReg(data, register) __writeDPReg(data, register) | 读写内核 AP/DP 寄存器 |
__driverType(driver_id) __gdbserver_exec_command("string") __jlinkExecCommand(cmdstr) __jtagCommand(ir) | 与硬件调试器命令交互 |
__fillMemory8(value, address, zone, length, format) __fillMemory16(value, address, zone, length, format) __fillMemory32(value, address, zone, length, format) __fillMemory64(value, address, zone, length, format) | 按模板值设置指定内存范围 |
__writeMemory8(value, address, zone) __writeMemoryByte(value, address, zone) __writeMemory16(value, address, zone) __writeMemory32(value, address, zone) __writeMemory64(value, address, zone) __readMemory8(address, zone) __readMemoryByte(address, zone) __readMemory16(address, zone) __readMemory32(address, zone) __readMemory64(address, zone) | 读写指定内存地址处的数据 |
全部系统宏 API:\IAR Systems\Embedded Workbench 9.10.2\arm\doc\EWARM_DebuggingGuide.ENU 手册里的 Summary of system macros 表
2.3 保留setup宏函数
终于要讲到 C-SPY 宏最关键的部分了,前面都是基础,而 C-SPY 宏最核心的功能其实在保留 setup 宏函数里,这些 setup 宏函数由 C-SPY 预先定义,但是内部具体操作可由用户来编写。在 IAR 在线下载调试过程中按规定触发条件来调用执行这些函数,setup 宏函数里最常用的是 execUserPreload():
保留setup宏函数 | 应用场合 | 执行时机 |
---|---|---|
execConfigureTraceETM | 配置ETM/PTM模块相关寄存器 | 调试执行开始前 |
execConfigureTraceSWO | 配置SWO调试口相关寄存器 | 调试执行开始前 |
execUserPreload | 初始化板级硬件环境 | 调试器与CPU已建立连接但未下载应用程序前 |
execUserExecutionStarted | 用户自定义 | 调试器开始执行应用程序指令前 |
execUserExecutionStopped | 用户自定义 | 调试器结束执行应用程序指令后 |
execUserFlashInit | 辅助flashloader功能,设置Flash相关内存映射环境 | 在调试器将flashloader下载进RAM之前 |
execUserSetup | 初始化板级调试环境(硬件、断点、中断,宏文件) | 调试器将应用程序下载完成后 |
execUserFlashReset | 辅助flashloader功能 | 在调试器将flashloader下载进RAM之后,但还未开始执行flashloader前 |
execUserPreReset | 设置需要的设备状态 | 在每次系统复位命令执行前 |
execUserReset | 恢复数据 | 在每次系统复位命令执行后 |
execUserExit | 保存状态数据 | 调试执行结束后 |
execUserFlashExit | 辅助flashloader功能,保存状态数据 | Flash下载完成后 |
execUserCoreConnect | 做一些CPU连接前的准备动作 | 调试器刚建立连接,但尚未连接CPU |
三、宏文件在IAR下使用方法
宏文件在 IAR 下主要有两种调用执行方式,一种是由 C-SPY 在调试过程中自动执行(要借助保留 setup 宏函数),另一种是用户手动指定执行(此时可以不用保留 setup 宏函数):
3.1 在线调试时C-SPY自动执行
不管是哪种调用方式,用户都需要首先准备一个宏文件(.mac),然后在 IAR 工程选项 Debugger / Setup / Setup macros 里勾选 **Use macro file(s)**,并且指定宏文件路径。
我们以恩智浦软件包 \SDK_2.11.0_MIMXRT1170-EVK\boards\evkmimxrt1170\demo_apps\hello_world\cm7\iar 工程为例,在这个路径下创建一个测试用的 evkmimxrt1170_connect_cm7_test.mac 文件,并且将其指定为工程宏文件。
在这个测试用的 .mac 文件里定义全部 13 个保留 setup 函数,函数体内不需要真实内容,只有下面这样的一句打印信息即可,便于我们在 IAR 调试信息窗口观察其有没有被 C-SPY 调用执行。
execUserPreload()
{
__message "--------execUserPreload() is called";;
}
然后在 MIMXRT1170-EVK 板上借助板载 DAP-Link 调试器直接下载 RAM build 版本工程(即不涉及 flashloader),调试器复位类型为 Software,下面是 IAR 调试信息窗口的输出。从结果里看除了 ETM/SWO 相关 setup 宏函数和 flashloader 相关 setup 宏函数未被执行外,其余 setup 宏函数均如预期执行了:
1. 用户点击 IAR 在线调试按钮,启动 C-SPY
2. C-SPY 尝试调用 flashloader,但无数据需下载进Flash
3. C-SPY 预加载用户宏文件 evkmimxrt1170_connect_cm7_test.mac
4. C-SPY 与硬件调试器(DAP-Link)建立了连接
5. execUserCoreConnect() 被执行
6. C-SPY 连接上了芯片内核
7. execUserPreReset() 被执行
8. C-SPY 尝试执行软件复位(可能此处未执行成功)
9. execUserPreload() 被执行
10. C-SPY 将工程应用程序 hello_world_demo_cm7.out 下载进芯片内部 RAM
11. execUserPreReset() 被执行
12. C-SPY 执行了软件复位,芯片复位成功
13. execUserReset() 被执行
14. C-SPY 与芯片调试模块ETM交互
15. execUserSetup() 被执行
16. execUserExecutionStarted() 被执行
17. C-SPY 接管调试,断点停在 main 函数
18. execUserExecutionStopped() 被执行
19. 用户点击结束 IAR 在线调试
20. execUserExit() 被执行
同样的实验在 Flash build 版本工程(即涉及 flashloader)上再做一次,调试器复位类型也为 Software,结果如下。此时结果与 RAM build 差异较大,因为默认 flashloader 配套 FlashIMXRT1170_FlexSPI.mac 文件也加入了战斗,我们测试用的 evkmimxrt1170_connect_cm7_test.mac 文件是在应用程序下载进 Flash 之后才出场的(记住这里的顺序,非常重要,痞子衡后面会另写文章着重介绍),因此这个测试用的 .mac 文件里的 flashloader 相关宏函数根本派不上用场:
1. 用户点击 IAR 在线调试按钮,启动 C-SPY
2. C-SPY 预加载 flashloader 配套宏文件 FlashIMXRT1170_FlexSPI.mac(里面仅定义了execUserFlashInit )
3. C-SPY 与硬件调试器(DAP-Link)建立了连接
4. C-SPY 连接上了芯片内核
5. C-SPY 尝试执行软件复位(可能此处未执行成功)
6. execUserFlashInit() 被执行 - 来自 FlashIMXRT1170_FlexSPI.mac
7. C-SPY 将 flashloader 加载进芯片内部 RAM
8. C-SPY 借助 flashloader 将工程应用程序 hello_world_demo_cm7.out 下载进板载外部 Flash
9. C-SPY 预加载用户宏文件 evkmimxrt1170_connect_cm7_test.mac
10. execUserPreload() 被执行
11. C-SPY 完成 Flash 下载的数据校验
12. execUserPreReset() 被执行
13. C-SPY 执行了软件复位,芯片复位成功
14. execUserReset() 被执行
15. C-SPY 与芯片调试模块ETM交互
16. execUserSetup() 被执行
17. execUserExecutionStarted() 被执行
18. C-SPY 接管调试,断点停在 main 函数
19. execUserExecutionStopped() 被执行
20. 用户点击结束 IAR 在线调试
21. execUserExit() 被执行
3.2 自定义条件触发或Watch窗口里手动指定执行
宏文件的自定义触发或者手动调用方式主要跟深入调试有关,用于调试过程中的特殊需求,麦克泰写的一篇文章 《C-SPY setup macro file 的作用》 里给的两个示例就挺有参考意义的。比如我们可以在 IAR 的 Quick Watch 窗口手动填入 .mac 文件里宏函数,并单击执行,这时可在 IAR 调试信息窗口实时看到执行结果。
至此,IAR内部C-SPY调试组件配套宏文件(.mac)用法痞子衡便介绍完毕了,掌声在哪里~~~