IAR调试使用技巧汇总:数据断点、CallStack、设置堆栈、查看栈使用和栈深度、mac/icf/map file, FreeRTOS插件等

嵌入式开发 专栏收录该内容
28 篇文章 6 订阅

更多技术干货,欢迎扫码关注博主微信公众号:HowieXue,一起学习探讨软硬件技术知识经验,关注就有海量学习资料免费领哦:
在这里插入图片描述



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无数据输出)

在这里插入图片描述


博主热门文章推荐:

一篇读懂系列:

LoRa Mesh系列:

网络安全系列:

嵌入式开发系列:

AI / 机器学习系列:


在这里插入图片描述

  • 13
    点赞
  • 4
    评论
  • 73
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值