0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

MDK下99%用户都不知道的万能printf方法

安芯教育科技 来源:裸机思维 2023-04-12 10:21 次阅读

本篇将介绍MDK下99%用户都不知道的万能printf方法。

一、说在前面的话

你听说过J-Link的RTT么?官方的宣传是这样的:

63c967e4-d8d7-11ed-bfe3-dac502259ad0.jpg

简单来说,只要拥有了J-Link,你就可以享受以下的便利:

无需占用USART或者USB转串口工具,将printf重定位到一个由J-LINK提供的虚拟串口上;

支持任何J-LINK声称支持的芯片

高速通信,不影响芯片的实时响应

它的缺点也是明显的:

你必须拥有一个J-Link,如果你使用的是 CMSIS-DAP或者ST-Link之类的第三方调试工具,就无法享受这一福利;

你必须在工程中手动插入一段代码

曾几何时,J-Link的这一福利让多少非J-Link用户羡慕嫉妒恨,看看手中的ST-Link、ULINKpro和各类廉价的CMSIS-DAP板载调试器——“隔壁邻居的小孩都馋哭了”

如果我告诉你,其实MDK中内置了一种非常简单廉价的方式,可以让你实现类似的功能,并具有以下特点:

支持所有的调试仿真器,哪怕自己手搓的CMSIS-DAP都行

MDK原生功能,连CMSIS-Pack都不用安装

点几下鼠标就可以通过RTE完成部署

除了简单的初始化函数外,无需手动插入代码

可以将你的printf输出直接打印在MDK的Debug (printf) View窗口中

你是否心动了呢?

二、部署从未如此简单

2.1RTE配置

依次通过菜单 Project->Manage->Run-Time Environment 打开RTE配置窗口:

64312050-d8d7-11ed-bfe3-dac502259ad0.jpg

找到并展开Compiler选项卡,勾选Event Recorder,并确保Variant下拉列表选中的是默认的DAP。

644b642e-d8d7-11ed-bfe3-dac502259ad0.jpg

展开Compiler下的I/O,勾选STDOUT,并在Variant下拉列表中选择 EVR——这里EVR是Event Recorder的缩写。单击确定后,我们会在工程管理器中看到以下的内容:

64735330-d8d7-11ed-bfe3-dac502259ad0.jpg

至此,所需的工具都已经成功地加入到工程中了。

虽然这里EventRecorderConf.h是一个可以编辑的状态,但实践中,我们基本不用去碰他——使用默认配置即可。

2.2服务初始化

在包含main()函数的C代码文件中,按照如下的格式添加对头文件的包含:

#include 
#if defined(RTE_Compiler_EventRecorder)
#   include 
#endif

在main()函数中添加对EventRecorder服务的初始化:

void main(void)
{
    ...
#if defined(RTE_Compiler_EventRecorder) 
 && defined(RTE_Compiler_IO_STDOUT_EVR)
    EventRecorderInitialize(0, 1);
#endif
    ...
}

如果你从未使用过EventRecorder也不必惊慌,这段代码的主要作用是为printf专门开启一个数据通道。

理论上,到这里,我们就已经完成了部署,可以在进入调试模式后,通过MDK的Debug (printf) View窗口来观察printf的输出结果了。比如,我们在main()函数中打印一个 "hello world ":

#include 

#include 
#if defined(RTE_Compiler_EventRecorder)
#   include 
#endif

void main(void)
{
    ...
#if defined(RTE_Compiler_EventRecorder) 
 && defined(RTE_Compiler_IO_STDOUT_EVR)
    EventRecorderInitialize(0, 1);
#endif
    ...

    printf("Hello World
");
    ...
}

编译,一切顺利的话,进入调试模式后通过菜单View->Serial Windows->Debug (printf) View打开窗口:

648ae8ba-d8d7-11ed-bfe3-dac502259ad0.jpg

运行后,可以在Debug (printf) View窗口中看到如下的结果:

三、常见问题

如果你的工程中从未提供过对 ".bss.noinit"数据段的处理,那么很可能会发现通过上述方法实现的printf输出似乎不是很稳定——时有时无——处于一种薛定谔的状态。

这是由于EventRecorder有一段数据放置在了 “.bss.noinit” section中——以求芯片复位后不会破坏其中原有的内容。

如果你的工程没有专门针对 “.bss.noinit” 的处理,那么就会在进入调试模式后,从Command窗口中看到类似如下的信息

64c850ec-d8d7-11ed-bfe3-dac502259ad0.jpg

即:

Warning: Event Recorder not located in uninitialized memory!

如果遇到这种情况应该怎么办呢?

打开工程配置窗口“Options for Target”,切换到“Linker”选项卡:

64dc63e8-d8d7-11ed-bfe3-dac502259ad0.jpg

首先,一定要确保你勾选了图中的“Use Memory Layout from Target Dialog”选项。在这一前提下,再次取消对它的勾选:

64eec3f8-d8d7-11ed-bfe3-dac502259ad0.jpg

我们会看到,MDK基于当前的Memory Layout,为我们在Out目录下生成了一个与工程同名的链接脚本(比如图中的工程名叫example,因此生成的链接脚本为example.sct)。

单击Edit按钮,可以看到脚本的内容:

65003e8a-d8d7-11ed-bfe3-dac502259ad0.jpg

先别着急半路开香槟——该文件是系统自动生成的,如果我们不移动它的位置,那么只要哪次手抖勾选了“Use Memory Layout from Target Dialog”,它的内容就会立即被覆盖掉——意味着我们在后续步骤中所做的修改就会付诸东流。

为了避免该问题,应该将它从Object目录中移动到工程目录下。具体步骤为:右键单击脚本文件名:

653b570e-d8d7-11ed-bfe3-dac502259ad0.jpg

选择“Open Container Folder”来打开文件所在目录:

655d868a-d8d7-11ed-bfe3-dac502259ad0.jpg

找到Scatter Script脚本文件后,将其拷贝到上一级目录下(也就是工程目录):

657a52e2-d8d7-11ed-bfe3-dac502259ad0.jpg

重新打开工程配置窗口:

6590af24-d8d7-11ed-bfe3-dac502259ad0.jpg

确保我们“没有”选中“Use Memory Layout from Target Dialog”选项,并在Scatter File文本框中直接填写我们刚刚拷贝出来的脚本文件名(由于我们直接放在工程目录下,因此这里直接用相对路径"./example.scat"或者"example.scat"就行)。单击OK保存配置。

打开example.sct,在RW_IRAM1后面追加如下的代码:

        ZI_RAM_UNINIT +0 UNINIT {
        .ANY (.bss.noinit)
    }

效果大约类似这样:

65a42838-d8d7-11ed-bfe3-dac502259ad0.jpg

保存后重新编译,再次进入 Debug 模式,问题就应该解决了。

这里步骤的核心思想是在scatter script内紧接着为RW和ZI的execution region为.bss.noinit提供一个属性为UNINIT的专属execution region。

在领会精神的情况下,如果你的工程原本就使用了scatter script也可以如法炮制。俗话说解铃还须系铃人,如果你还是不知道怎么处理,那么就去找 你工程中scatter script的作者吧。

值得强调的是:如果你的MDK版本太老,为了确保最佳的用户体验,还是推荐尽快升级吧。您可以在关注【裸机思维】公众号后发送关键字【MDK】来获取其最新的网盘链接。

四、说在后面的话

总的来说,MDK通过EventRecorder为我们提供了一个通用便捷的方式来重定向printf——无论你使用什么调试仿真器,甚至是FVP,都可以享受来自“MDK”的阳光普照。

对很多有分发自己工程作为模板的小伙伴来说,使用该方法后将不再限制用户必须使用J-Link之类的工具,而是可以放开手脚,获得了“开袋即食”的调试体验。

最后强调一下哦,EventRecorder只在调试阶段有意义,如果我们需要在产品的正常工作模式下使用printf,还是老老实实把Compiler->IO->STDOUT配置为User:

65c2b4c4-d8d7-11ed-bfe3-dac502259ad0.jpg

实现stdout_putchar()函数——用它来发送字符到具体的外设吧,比如:

int stdout_putchar(int ch)
{
    if ('
' == ch) {
        int temp = '
';
        while(Driver_USART0.Send(&temp, 1) != ARM_DRIVER_OK);
    }
    
    if (Driver_USART0.Send(&ch, 1) == ARM_DRIVER_OK) {
        return ch;
    }
    
    return -1;
}

审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • usb
    usb
    +关注

    关注

    59

    文章

    7432

    浏览量

    258145
  • 串口
    +关注

    关注

    14

    文章

    1483

    浏览量

    74511
  • MDK
    MDK
    +关注

    关注

    4

    文章

    208

    浏览量

    31770
  • J-Link
    +关注

    关注

    0

    文章

    77

    浏览量

    21951
  • Printf
    +关注

    关注

    0

    文章

    79

    浏览量

    13478

原文标题:MDK下99%用户都不知道的万能printf方法

文章出处:【微信号:Ithingedu,微信公众号:安芯教育科技】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    要学习protel了,不知道该学习是99还是***,更不知道在哪里找

    要学习protel了,不知道该学习是99还是***,更不知道在哪里找到适合win7的版本,高手 大虾帮忙啊
    发表于 03-15 02:07

    万能电路板正面布线的方法

    万能电路板正面布线的方法 各位电子爱好者在制作过程中最头疼的恐怕就是制板了吧!确实,电路板由于其工艺要求而制作非常麻烦,有时候制板的过程比设计电路过程花的时间还多。因此初学者大部分都选择了万能实验板
    发表于 05-30 17:41

    自己刚刚进入ARM行列,都不知道做什么?

    自己刚刚进入ARM行列,都不知道做什么?
    发表于 11-27 23:23

    电子万能试验机与液压万能试验机的区别

    ,而红山出来的试验机厂家多采用减速机。关于其优缺点,还有待探讨,但都不影响用户使用。在测力上电子万能试验机均采用负荷 传感器。  液压万能材料试验机,采用高压液压源为动力源。采用手动阀
    发表于 07-04 16:06

    手把手全程教你DIY制作万能

    就做的出来,面对下面的种种电子制作,头有点晕,但是焊接万能板的思路确实那么的清醒清醒,10 次成功率高达 99%,为啥还有一次不成功,因为直接照图片焊接,原理有误,最简单的 P0 口没接上拉电阻,烧上程序
    发表于 10-23 15:01

    PT2262万能遥控器的原理与制作

    遥控器都集合到一起呢?这里,笔者为大家介绍以PT2262编码规则设计的万能遥控萋器,分析其工作原理,介绍其详细制0 作方法。该万能遥控器对于SC2262、HS2262等与PT2262兼容的遥控器同样适用
    发表于 11-05 11:16

    万能角度尺怎么使用?

    万能角度尺的读数机构是根据游标原理制成的。主尺刻线每格为1°。游标的刻线是取主尺的29°等分为30格,因此游标刻线角格为29°/30,即主尺与游标一格的差值为2',也就是说万能角度尺读数准确度为2'。除此之外还有5'和10'两种精度。其读数
    发表于 11-06 09:10

    MDK99%用户都不知道万能printf方法

    提供一个属性为UNINIT的专属execution region。  在领会精神的情况,如果你的工程原本就使用了scatter script也可以如法炮制。俗话说解铃还须系铃人,如果你还是不知道
    发表于 03-21 11:57

    不知道电动车电池的型号怎么办?

    不知道电动车电池的型号怎么办?  近一年来给很多人换过电动车电池了,我发现大多数人都不知道自己的电动车电池是什么型号的,
    发表于 11-11 08:56 3218次阅读

    Miniplayer小技巧 保证有你不知道

    Miniplayer小技巧 保证有你不知道的 1,用电源充电完成后先别拔充电器,先按住开关别放再拔开线就不用更新歌曲库了。
    发表于 02-01 16:38 644次阅读

    不知道的 Vivo X9玩机小技巧!磨砂黑版你会买吗?

    Vivo x9新配色,磨砂黑版现已在火热预订中,不知道购置x9的小伙伴对手机的体验怎么样?
    发表于 03-11 10:19 2991次阅读
    你<b class='flag-5'>不知道</b>的 Vivo X9玩机小技巧!磨砂黑版你会买吗?

    涨知识——PROTEL 99中你可能不知道的用法

    PROTEL 99中你可能不知道的用法 你是不是还在为自己的刚刚绘制好的电路忘了保存而后悔不已啊?你是不是有些机密的文件不能让别人窥视啊?你是不是觉得99的功能太少,是不是觉得cadence的很多
    发表于 04-05 10:19 2504次阅读
    涨知识——PROTEL <b class='flag-5'>99</b>中你可能<b class='flag-5'>不知道</b>的用法

    关于你可能不知道printf

    你可能不知道printf
    的头像 发表于 02-05 12:28 2349次阅读
    关于你可能<b class='flag-5'>不知道</b>的<b class='flag-5'>printf</b>

    不知道的FPC,它的发展史竟然是这样的!

    不知道的FPC,它的发展史竟然是这样的!
    的头像 发表于 11-15 10:48 453次阅读

    7种MOSFET栅极电路的常见作用,不看不知道

    7种MOSFET栅极电路的常见作用,不看不知道
    的头像 发表于 12-15 09:46 393次阅读
    7种MOSFET栅极电路的常见作用,不看<b class='flag-5'>不知道</b>!