IAR调试使用技巧汇总:数据断点、CallStack、设置堆栈、查看栈使用和栈深度、mac/icf/map file, FreeRTOS插件等
更多技术干货,欢迎扫码关注博主微信公众号:HowieXue,一起学习探讨软硬件技术知识经验,关注就有海量学习资料免费领哦:
目录 1.使用数据断点:2.Set next statement 手动执行到某行代码3.View->各窗口查看数据3.1 使用Register 窗口查看各寄存器3.2 使用Live Watch等窗口查看变量/表达式 4.设置堆栈大小5.静态查看程序Stack栈使用详情,以及栈深度5.1 如何设置正确的Stack Size 6.动态查看程序运行中Stack占用情况7.Call stack查看当前调用栈,8.使用Memory查看程序运行中各种过程数据9.IAR Map文件解析堆栈信息:10.IAR xx.icf存储资源文件解析:11.IAR各编译文件含义:12. Macro file (.mac) 文件使用与配置:13. 插件使用之FreeRTOS14.使用Terminal I/O查看log博主热门文章推荐:
1.使用数据断点:
1、选择要打断点的代码行,或在Memory中选中某一个要监测的数据,点击右键->Set Data Breakpoint: 或直接选择代码中的变量:
2、在弹出页面选择该Data断点实现的条件,例如该Data的读、写,或者可以在Conditions中设置断点产生条件,如Data == 100时进入断点。以及通过Action 在断点执行时产生相应的动作。
在Breakpoint工具栏也可以右键Edit
2.Set next statement 手动执行到某行代码
如果断点已经执行完,还想继续跳到该断点,或者想手动执行到某行代码,可以在断点处右键,选择Set next statement。
实际上 单步调试Debug->Step Into 就相当于 源文件语句的Debug->Next statement
3.View->各窗口查看数据
3.1 使用Register 窗口查看各寄存器
Debug中,View->打开Register窗口 然后在窗口内右键-> View new group ,去选择想去查看哪些寄存器组。 举个栗子,通过Register 查看 WatchDog有没有启动、或当前有没有reload ctn, 如下图:如果在Debug中IWDG为STOP为1,则WD其实并没有真正运行。
3.2 使用Live Watch等窗口查看变量/表达式
Debug模式下,View菜单下可以看到如下watch等窗口:
可以通过多种方式查看变量。如在源代码窗口,用鼠标右键点击在所要查看的变量 Add Watch/Live Watch…,或者通过View打开Locals、Watch、Live Watch、or Auto 窗口,直接将代码窗口的变量拖拽/Copy进窗口
Watch:普通Watch窗口。只能Debug查看当前堆栈的变量(处于断点或Debug暂停),跳出函数 就失效了Live Watch: 实时全局Watch。可以在运行时查看全局变量,定时刷新,(Debug停住也可查看局部变量)Quick Watch: 快速Watch窗口。速度更快,结合Quick Lunch菜单使用Auto:自动显示Watch。当程序暂停在某一个地方,自动显示暂停坐在位置的表达式/变量,而不需要像Watch要手动添加。Locals: 局部变量窗口。类似Atuo,但只显示局部变量Statics:静态变量窗口。类似Atuo类似,但只显示静态变量
注意: Watch中能查看的变量和编译优化等级有关,只有在优化等级为“None”时,所有变量才是Available的。
如果提高了优化等级,则有些局部变量会优化掉,不能再watch,这时候可以在要Debug的函数前,加上#pragma optimize=none,然后重新编译Debug,这样函数内所有变量都是可watch的了
4.设置堆栈大小
1、右键工程目录选择Options: 2、依次选择Linker -> config,然后点击Edit,选项卡选择Stack/Heap Size,编辑实际堆栈大小: 更改后需要rebuild
5.静态查看程序Stack栈使用详情,以及栈深度
在Option->linker中勾选Enable stack usage analysis,之后Rebuild编译完,可以在.map中查找Stack Usage 栈使用分析
5.1 如何设置正确的Stack Size
举个栗子: 上图是在map中找到的STACK USAGE,可以清晰的看到:
Program程序里使用最大的stack大小为1392bytes,Uncalled function(如中断)使用的stack大小为最大1824bytes和其他所占用的bytes。
所以,程序里要设置Stack Size要大于Program+Uncalled Function (1392 + 1824)占用的stack空间才行,否则会导致overwrite或程序跑飞等异常。
既; CSTACK Size >= Maxstack(“Program entry”) + Totalstack(“interrupt”) + Safety margin(100);
Maximum call chain: 最大调用链所占Stack大小
6.动态查看程序运行中Stack占用情况
程序运行中,可以查看Stack的当前占用量,以及总量 在Tools->Option->Stack中勾选如下图: 程序运行时(Debug),选中View->Stack 在程序运行中,打断点或者暂停程序,Stack窗口就会显示栈使用情况,如下图:可以看到当前栈指针位置、(该断点时刻栈的使用情况)、当前栈空间内容及地址、全部已使用的Stack空间、以及未使用的Stack空间。 关于Stack窗口 可以参考如下:
7.Call stack查看当前调用栈,
当前调用栈既此时正在执行的函数及Context:
在Debug模式下,IAR菜单栏选择View -> Call Stack,执行到某一断点,或者程序暂停时,就可以清晰的看到当前时刻的栈空间信息,以及所调用的函数等信息
好多攻城狮都会有疑问,这里多说明一下,什么是Call Stack:
Call Stack:调用堆栈,(当前函数执行过程的空间展示) 当发生函数调用的时候,栈空间中存放的数据是这样的:
1、 调用者函数把被调函数所需要的参数按照与被调函数的形参顺序相反的顺序压入栈中,即:从右向左依次把被调函数所需要的参数压入栈; 2、 调用者函数使用call指令调用被调函数,并把call指令的下一条指令的地址当成返回地址压入栈中(这个压栈操作隐含在call指令中); 3、 在被调函数中,被调函数会先保存调用者函数的栈底地址(push ebp),然后再保存调用者函数的栈顶地址,即:当前被调函数的栈底地址(mov ebp,esp); 4、 在被调函数中,从ebp的位置处开始存放被调函数中的局部变量和临时变量,并且这些变量的地址按照定义时的顺序依次减小,即:这些变量的地址是按照栈的延伸方向排列的,先定义的变量先入栈,后定义的变量后入栈;
所以,发生函数调用时,入栈的顺序为: 参数N 参数N-1 参数N-2 … 参数3 参数2 参数1 函数返回地址 上一层调用函数的EBP/BP 局部变量1 局部变量2 … 局部变量N
8.使用Memory查看程序运行中各种过程数据
例如查看某个指针指向的数据内容: Debug模式下,右键Watch 一个char *的指针dataC,这时只能看到指针指向的第一个数据: 同样在View菜单下,点击Memory1,将dataC指针存放的地址放到Goto的内容栏中,即可查看数据内容:
9.IAR Map文件解析堆栈信息:
通过Option->Linker勾选 map,则编译后会生成.map文件,包含了项目各种编译信息,如下图: 编译后,在编译目录中/list/文件夹中,找到并打开.map文件,文件最上面可以看到编译时间、Linker的版本、编译的程序文件等,
堆栈信息都在"PLACEMENT SUMMARY" 的"P2"中,我们向下拉,找到"P2"最后一个part,可以看到堆Heap 栈Stack的起始地址 再往下ENTRY LIST之后就是程序中各种函数/变量编译的信息: 可以看到函数名,地址等信息, 其中Code Gb代表全局函数:,其中code说明为代码,Gb说明为“全局的”函数(Global) 可以看到除了中断向量表,第一个编译的出的Object文件为 cmain.o,该入口函数位于main.c文件。
静态函数:类型为Code Lc,即静态(局部Local)函数; 全局变量也叫“全局数据”,因为它的类型为“Data Gb”。 (文件内)静态变量:“Data Lc ” 使用static关键字定义的变量,只有在当前文件内使用,所以它属于静态(“局部”Local)变量。 (函数内的)静态变量:定义在函数体内的静态变量,如上图中的,xxx::byteCounter
10.IAR xx.icf存储资源文件解析:
IAR中使用.icf文件 划分存储资源
11.IAR各编译文件含义:
首先工程文件主要了解以下几个:
.dep文件 ide所使用的文件依赖信息,这个会自动生成的,可以删掉 .ewp文件 工程文件/project,包含代码,编译,链接选项等,不包含调试设置等信息,这个不能删 .ewd文件 工程调试设置,保存的是IAR设置中的Debugger选项,这个最好不要删 .eww文件 解决方案/工作空间/workspace,可以直接双击打开,可以放多个工程文件,最好也不要删。
下图为各编译文件及其含义,常用的有.bss/.data/.text/.rodata/.intvect:
12. Macro file (.mac) 文件使用与配置:
.Mac file是在IAR debug将程序下载之前,由debugger load并执行,完成下载前的硬件初始化配置等。
(例如需要初始化的片外RAM控制器、寄存器,如HyperRAM,需要在代码下载进RAM前进行初始化,程序才能正常跑)
macro要使用系统或C-SPY macro,也可以自定义(在C-SPY 启动时调用“ _ _registerMacroFile(“MyMacroUtils.mac”);”提前注册)
C-SPY已经定义好每个阶段的Macro函数,用户只需要实现就可以了:
这里以常用的execUserPreload() 举例: execUserPreload()这个macro是在IAR和设备 建立通讯到下载程序前调用的,因此通常可以在这里面做些程序下载前的硬件初始化等操作
使用示例如下:
execUserPreload()
{_clock_init();_Flexspi_mpu();_HyperRam_Init();
}
其中
_clock_init()
{// Enable all clocks__writeMemory32(0xffffffff, 0x400FC068, "Memory");__writeMemory32(0xffffffff, 0x400FC06C, "Memory");__writeMemory32(0xffffffff, 0x400FC070, "Memory");__writeMemory32(0xffffffff, 0x400FC074, "Memory");__writeMemory32(0xffffffff, 0x400FC078, "Memory");__writeMemory32(0xffffffff, 0x400FC07C, "Memory");__writeMemory32(0xffffffff, 0x400FC080, "Memory");__writeMemory32(0xffffffff, 0x400FC084, "Memory");// Config PLL for FlexSPI__writeMemory32(0x00002001, 0x400D8030, "Memory");__writeMemory32(0x001D0000, 0x400D8100, "Memory");//PLL2PFD2-327M__writeMemory32(0x11AE8024, 0x400FC018, "Memory");//divide by 1 for FlexSPI2 root clk 327M, output CK 327/2 = 163M__message "clock init done\n";
}_Flexspi_mpu()
{__writeMemory32(0x70000018, 0xE000ED9C, "Memory");__writeMemory32(0x0303002f, 0xE000EDA0, "Memory"); //16M__writeMemory32(0x70e00019, 0xE000ED9C, "Memory");__writeMemory32(0x03080029, 0xE000EDA0, "Memory"); __writeMemory32(0x00000005, 0xE000ED94, "Memory");
}
其中__writeMemory32指令 描述如下(详情可参见IAR官方文档):
IAR配置: Options -> Debugger -> Use macro file
13. 插件使用之FreeRTOS
Option->Debugger->Plugins->勾选FreeRTOS" 这时候Debug起来,就会出现FreeRTOS菜单,勾选task/Queue:
运行起来后,手动暂停或断点,就能够看到当前Free RTOS 所有Task 和Queue的信息: 如图,每个Task的状态、优先级、Stack地址,Queue长度、Queue当前收发状态等都可以看到
把FreeRTOS-OpenRTOS -> Stack Checking 设置为ON后,可以查看每个task Stack情况(Min Free Stack 代表每个task剩余的可用Stack):
14.使用Terminal I/O查看log
通过C-SPY 的Terminal I/O,可以直接通过Debugger打印出log,非常方便调试 这样就不再需要借助串口打印log,免去串口接线,只需要接上调试器如常用的Jlink/STlink,就可以通过printf打印出log
Project ->Option中选择Stdout为via SWO(Serial Wire Output,串行线输出)
选择好相应的Debugger,下载程序运行,然后通过View->打开Teminal I/O窗口,就可直接查看printf 打印出的log。 (Printf不能被重定向到串口,否则将导致Terminal I/O无数据输出)
博主热门文章推荐:
一篇读懂系列:
一篇读懂无线充电技术(附方案选型及原理分析)一篇读懂:Android/iOS手机如何通过音频接口(耳机孔)与外设通信一篇读懂:Android手机如何通过USB接口与外设通信(附原理分析及方案选型)
LoRa Mesh系列:
LoRa学习:LoRa关键参数(扩频因子,编码率,带宽)的设定及解释LoRa学习:信道占用检测原理(CAD)LoRa/FSK 无线频谱波形分析(频谱分析仪测试LoRa/FSK带宽、功率、频率误差等)
网络安全系列:
ATECC508A芯片开发笔记(一):初识加密芯片SHA/HMAC/AES-CBC/CTR 算法执行效率及RAM消耗 测试结果常见加密/签名/哈希算法性能比较 (多平台 AES/DES, DH, ECDSA, RSA等)AES加解密效率测试(纯软件AES128/256)–以嵌入式Cortex-M0与M3 平台为例
嵌入式开发系列:
嵌入式学习中较好的练手项目和课题整理(附代码资料、学习视频和嵌入式学习规划)IAR调试使用技巧汇总:数据断点、CallStack、设置堆栈、查看栈使用和栈深度、Memory、Set Next Statement等Linux内核编译配置(Menuconfig)、制作文件系统 详细步骤Android底层调用C代码(JNI实现)树莓派到手第一步:上电启动、安装中文字体、虚拟键盘、开启SSH等Android/Linux设备有线&无线 双网共存(同时上内、外网)
AI / 机器学习系列:
AI: 机器学习必须懂的几个术语:Lable、Feature、Model…AI:卷积神经网络CNN 解决过拟合的方法 (Overcome Overfitting)AI: 什么是机器学习的数据清洗(Data Cleaning)AI: 机器学习的模型是如何训练的?(在试错中学习)数据可视化:TensorboardX安装及使用(安装测试+实例演示)
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!