本帖最后由 6552918 于 2023-6-30 17:23 编辑
#申请原创# #技术资源# @21小跑堂
我们平时调试时都会用到printf输出调试信息,使用printf有很多种重定向的实现方法,用的最多的是串口的,有用SWO的,还有用JLINK RTT的,但上述几种方法都是有限制的,串口用于调试就不能被应用占用,SWO需要内核支持才行,JLINK RTT必须使用JLINK工具才能使用,有没有其他方式呢?
下面为大家介绍一种MDK赠送的万能printf输出调试的方法,不再受上述条件限制,这种方法有如下特点:
支持所有的调试仿真器,哪怕自己手搓的CMSIS-DAP都行;
MDK原生功能,连CMSIS-Pack都不用安装;
点几下鼠标就可以通过RTE完成部署;
除了简单的初始化函数外,无需手动插入代码;
可以将你的printf输出直接打印在MDK的Debug (printf) View窗口中。
接下来我在AC7802上展示实现过程,让我们发车。
首先找一个基础例程,我用的是01_GPIO_Basic
打开工程后 打开RTE配置
因为例程里使用了串口重用映射的printf,我们需要先关掉原工程内的串口printf映射。操作如下
找到并展开Compiler选项卡,勾选Event Recorder,并确保Variant下拉列表选中的是默认的DAP。
展开 Compiler 下的 I/O ,勾选STDOUT,并在 Variant 下拉列表中选择 EVR——这里 EVR 是 Event Recorder 的缩写。单击确定后,我们会在工程管理器中看到以下的内容:
至此,所需的工具都已经成功地加入到工程中了。
虽然这里EventRecorderConf.h 是一个可以编辑的状态,但实践中,我们基本不用去碰他——使用默认配置即可。其中相关配置好后可实现简单的程序运行时长的测量,但不是本贴的主要内容,在此不详细介绍。
然后 勾选使用微库选项
接着我们再程序中添加相关的初始化操作
在包含 main() 函数的C代码文件中,按照如下的格式添加对头文件的包含:
#include <RTE_Components.h>
#if defined(RTE_Compiler_EventRecorder)
# include <EventRecorder.h>
#endif
在 main() 函数中添加对EventRecorder服务的初始化:
#if defined(RTE_Compiler_EventRecorder) \
&& defined(RTE_Compiler_IO_STDOUT_EVR)
EventRecorderInitialize(0, 1);
#endif
运行后,可以在 Debug (printf) View窗口中看到如下的结果:
但在进入仿真时,有个警告提示
并且 printf 输出似乎不是很稳定——时有时无,别慌,这个问题接着盘它!
打开工程配置窗口“Options for Target”,切换到“Linker”选项卡:
首先,一定要确保你勾选了图中的“Use Memory Layout from Target Dialog”选项。在这一前提下,再次取消对它的勾选:
我们会看到,MDK基于当前的Memory Layout,为我们在Out目录下生成了一个与工程同名的链接脚本(比如图中的工程名叫Demo,因此生成的链接脚本为 Demo.sct)。
“Linker”选项卡,单击 Edit 按钮,可以看到脚本的内容:
该文件是系统自动生成的,如果我们不移动它的位置,那么只要哪次手抖勾选了“Use Memory Layout from Target Dialog”,它的内容就会立即被覆盖掉——意味着我们在后续步骤中所做的修改就会付诸东流。
为了避免该问题,应该将它从 Object 目录中移动到工程目录下。
这样在勾选Use Memory Layout from Target Dialog”选项时,Scatter File使用的是Objects目录下的.sct文件
在不勾选Use Memory Layout from Target Dialog”选项时,Scatter File使用的是工程目录下的.sct文件
在不勾选Use Memory Layout from Target Dialog”选项时,“Linker”选项卡,单击 Edit 按钮在 RW_IRAM1 后面追加如下的代码: ZI_RAM_UNINIT +0 UNINIT {
.ANY (.bss.noinit)
}
保存后重新编译,再次进入 Debug 模式,问题就应该解决了。
这里步骤的核心思想是在 scatter script 内紧接着为 RW和ZI的 execution region为 .bss.noinit 提供一个属性为UNINIT的专属execution region。
MDK 通过 EventRecorder 为我们提供了一个通用便捷的方式来重定向 printf——无论你使用什么调试仿真器。使用该方法后将不再限制用户必须使用 J-Link 之类的工具,和其他限制。
最后强调一下,EventRecorder只在调试阶段有意义,产品发布时,就不要使用了。
|