大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是IAR下调试信息输出机制之半主机(Semihosting)

  在嵌入式世界里,输出打印信息是一种非常常用的辅助调试手段,借助打印信息,我们可以比较容易地定位和分析程序问题。在嵌入式应用设计里实现打印信息输出的方式有很多,本系列将以 IAR 环境为例逐一介绍 ARM Cortex-M 内核 MCU 下打印信息输出方法。

  上一篇文章 《IAR下调试信息输出机制之硬件UART外设》 里我们介绍了利用 MCU 芯片内的硬件 UART 外设去做打印输出的方式,这种方式很简单,还可以脱离在线调试环境去使用,但毕竟占用了芯片内部的外设资源,而且调试的时候还需要额外连接串口线路,稍微麻烦了一点。今天痞子衡介绍一种在 IDE 中结合仿真器直接做打印输出的方式,即半主机(Semihosting)技术。

  • Note: 本文使用的 IAR EWARM 软件版本是 v9.10.2。

一、打印输出整体框图

  老规矩先简介下本文介绍的打印输出方法整体软硬件框图,硬件上主要是 PC 主机、MCU 目标板、一个 ARM 仿真器(DAP-Link 或者 J-Link 都可以)。

  软件上 PC 这边就需要 IAR 开发环境即可,这里在编译目标板 MCU 应用程序时,除了需要包含打印输出相关代码(标准 I/O 库接口),底层接口实现必须选用 IAR 的 Semihosting 库。当 MCU 程序运行起来后(需要保持在线调试状态),仿真器实时捕获代码里的打印输出需求,将这种 I/O 访问需求转移到 PC 主机上来完成,然后我们在 IAR 的 Terminal I/O 窗口里可以看到打印信息。

  上图里 MCU 应用程序中的 printf() 打印输出需求到底是如何转移到 PC 主机上 IAR 软件里去完成的,这是本文要研究的重点。

二、Semihosting机制原理

  Semihosting 中文为半主机(半托管),这是一个在嵌入式系统中已经流传了几十年的技术。Semihosting 技术将应用程序中的 I/O 请求通过一定的通道传送到主机(host),由主机上的资源响应应用程序的 I/O 请求,而不是像在主机上执行本地应用程序一样,由应用程序所在的硬件系统来响应应用程序 I/O请求,简单说就是将目标板的输入/输出请求从应用程序代码传递到远程运行调试器的主机上的一种机制。

  ARM 也定义了这种 Semihosting 机制实现,我们在目标 ARM 开发板代码中加入 printf,scanf 等函数调用时,这些函数并不是链接到目标开发板的库函数,而是远程主机交叉编译器中带有的库函数,并且这些库函数被编译时会额外插入软件中断指令,早期的 ARMv7 架构下软中断使用得是 SVC 指令(SWI 指令),而对于 Cortex-M 处理器(ARMv6-M 或者 ARMv7-M 架构),这个软件中断指令是 BKPT。

  我们可以在 ARMv6/7/8-M Architecture RM 手册里找到 BKPT 指令定义,其中 imm8 是指定存储在指令中的 8 位值,这个值会被处理器忽略,但是调试器可以使用它来存储关于断点的附加信息。

  如果 BKPT 指令是用于触发 Semihosting 请求,其 imm8 值应该被设为 0xAB,这是 ARM 的规定。因此当仿真器捕获到 BKPT #0xab 指令时便会让主机响应接下来的 I/O 请求。

  现在可以触发 Semihosting 请求了,但是 I/O 请求的种类很多,主机该如何区分呢?别担心,ARM 还规定了 R0 寄存器来存放请求的类型(编译器应该在 BKPT 指令前,将请求类型值放到 R0 寄存器里),我们可以在 ARM 开发者官网找到这些请求类型定义以及详细解释。整个 Semihosting 机制至此就清楚了,各大 IDE 只需要按照这个规定去具体实现即可。

https://developer.arm.com/documentation/dui0471/g/Semihosting/Semihosting-operations?lang=en

  关于更详细的 Semihosting 机制,可以参考 SEGGER 整理的一篇博客 https://wiki.segger.com/Semihosting

三、IAR 对 Semihosting 机制的支持

  IAR 对 ARM 定义的 Semihosting 机制是有完善支持的,我们按上一篇的老办法,看工程编译链接后生成的 .map 文件,找到 IAR 实现 Semihosting 的相关源文件。

3.1 Terminal I/O 查看打印效果

  继续以上一篇文章使用的 \SDK_2.11.0_EVK-MIMXRT1060\boards\evkmimxrt1060\demo_apps\hello_world\iar 工程为例,简单改造一下工程里 hello_world.c 文件里的 main() 函数,将原来代码全部删掉(原来的打印输出涉及恩智浦 SDK 封装,本文没必要关心其实现),只要如下一句打印即可:

#include <stdio.h>
int main(void)
{
printf("hello world.\r\n");
while (1);
}

  然后注意工程选项里 Library low-level interface implementation 选项,这里我们选 Semihosted 方式,并且 stdout/stderr 选择 Via semihosting。这时候底层 I/O 完全由 IAR 内置 Semihosting 库来搞定了。

  我们将 MCU 目标板供上电,并连接调试器在线跑起来看看效果,在 IAR 菜单栏 View 里打开 Terminal I/O 窗口,全速运行,可以看到有 hello world. 字样打印输出,没有真实的串口线路物理连接,照样能实现打印了。

3.2 Semihosting库I/O响应设计

  IAR 的 Terminal I/O 窗口里怎么就能看到打印输出的呢?我们在 \IAR Systems\Embedded Workbench 9.10.2\arm\doc\EWARM_DevelopmentGuide.ENU 手册里找到了玄机,其实是 IAR 里的调试组件 C-SPY 负责响应调试器捕捉到的来自 MCU 的 I/O 访问需求,并负责解释 Semihosting 库源码,然后模拟了对应 I/O 操作。

3.3 Semihosting库相关源码实现

  现在我们再来查看生成的 hello_world.map 文件,除了 dl7M_tln.a 部分多了 XShttio.o 目标文件外,还增加了 shb_l.a 库(里面有一系列 .o 文件),这些增加的 .o 文件均是 Semihosting 库相关源码实现。我们可以在 \IAR Systems\Embedded Workbench 9.10.2\arm\src\lib\semihosting 目录下找到 XShttio.c 源文件,这个主要是 ARM 标准 Semihosting 实现层,但是偏 IAR 这一层的 iarttio.o、iarwrite.o、iarwstd.o 并没有公开源码,这可能属于 IAR 软件商业机密了吧。

*******************************************************************************
*** MODULE SUMMARY
*** Module ro code ro data rw data
------ ------- ------- -------
dl7M_tln.a: [10]
XShttio.o 8 8 8
abort.o 6
exit.o 4
low_level_init.o 4
printf.o 40
putchar.o 32
xfail_s.o 64 4
xprintfsmall_nomb.o 1'281
xprout.o 22
-----------------------------------------------
Total: 1'461 8 12 shb_l.a: [13]
dwrite.o 30
exit.o 20
iarttio.o 124
iarwrite.o 34
iarwstd.o 32
write.o 16
-----------------------------------------------
Total: 256

3.4 从反汇编文件看Semihosting实现

  最后我们再从工程反汇编文件角度看一下 Semihosting 机制是不是如第二小节原理里介绍得那样,先借助 IAR 小工具 ielfdumparm.exe 将工程可执行文件 hello_world.out 转换成反汇编文件 hello_world.dump。

ielfdumparm.exe --source --code .\hello_world.out -o .\hello_world.dump

  然后使用任意文本编辑器打开这个反汇编文件 hello_world.dump,在里面搜索 BKPT 指令,确实能够看到插入了多处软中断指令用于触发 Semihosting,并且软中断指令前都装载了 R0 寄存器,痞子衡截取的片段里 R0 装载的值是 5,从 ARM 文档里查询,这对应了 SYS_WRITE 访问请求。

  至此,IAR下调试信息输出机制之半主机(Semihosting)痞子衡便介绍完毕了,掌声在哪里~~~

欢迎订阅

文章会同时发布到我的 博客园主页CSDN主页知乎主页微信公众号 平台上。

微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。

痞子衡嵌入式:浅析IAR下调试信息输出机制之半主机(Semihosting)的更多相关文章

  1. 痞子衡嵌入式:浅析IAR下调试信息输出机制之硬件UART外设

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是IAR下调试信息输出机制之硬件UART外设. 在嵌入式世界里,输出打印信息是一种非常常用的辅助调试手段,借助打印信息,我们可以比较容易地 ...

  2. 痞子衡嵌入式:IAR在线调试时设不同复位类型可能会导致i.MXRT下调试现象不一致(J-Link / CMSIS-DAP)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是IAR在线调试时设不同复位类型可能会导致i.MXRT下调试现象不一致. 做Cortex-M内核MCU嵌入式软件开发,可用的集成开发环境( ...

  3. 痞子衡嵌入式:IAR内部C-SPY调试组件配套宏文件(.mac)用法介绍

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是IAR内部C-SPY调试组件配套宏文件(.mac)用法. 痞子衡之前写过一篇 <JLink Script文件基础及其在IAR下调用 ...

  4. 痞子衡嵌入式:ARM Cortex-M调试那些事(1)- 4线协议标准(JTAG)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家讲的是嵌入式调试里的接口标准JTAG. 在结束<ARM Cortex-M文件那些事>系列文章之后,痞子衡休整了一小段时间,但是讲课的 ...

  5. 痞子衡嵌入式:在IAR开发环境下为工程开启CRC完整性校验功能的方法

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是在IAR开发环境下为工程开启CRC完整性校验功能的方法. CRC校验在嵌入式领域里的应用非常广,比如在通信领域,CRC检验值可以作为数据 ...

  6. 痞子衡嵌入式:大话双核i.MXRT1170之在线联合调试双核工程的三种方法(IAR篇)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是i.MXRT1170下在线联合调试双核工程的方法(基于IAR). 前段时间痞子衡写过一篇<双核i.MXRT1170之单独在线调试从 ...

  7. 痞子衡嵌入式:MCUXpresso IDE下使用J-Link下载算法在Flash调试注意事项(i.MXRT500为例)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是MCUXpresso IDE下使用J-Link下载算法在Flash调试注意事项. 痞子衡前段时间写过一篇小文<为i.MXRT设计更 ...

  8. 痞子衡嵌入式:JLink Script文件基础及其在IAR下调用方法

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是JLink Script文件基础及其在IAR下调用方法. JLink可以说是MCU开发者最熟悉的调试工具了,相比于其他调试器(比如DAP ...

  9. 痞子衡嵌入式:Keil在线调试时设不同复位类型可能会导致i.MXRT下调试现象不一致(J-Link/DAPLink)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是Keil在线调试时设不同复位类型可能会导致i.MXRT下调试现象不一致. 本篇是 <IAR EWARM复位类型>.<M ...

随机推荐

  1. Istio 中实现客户端源 IP 的保持

    作者 尹烨,腾讯专家工程师, 腾讯云 TCM 产品负责人.在 K8s.Service Mesh 等方面有多年的实践经验. 导语 对于很多后端服务业务,我们都希望得到客户端源 IP.云上的负载均衡器,比 ...

  2. python自动将新生成的报告作为附件发送并进行封装

    发送报告作为自动化部署来讲是一个重要的环节,废话不多说直接上代码吧,如果想更细致的了解内容查阅本博主上篇基本发送文章 特别叮嘱一下:SMTP协议默认端口25,qq邮箱SMTP服务器端口是465 别出丑 ...

  3. JS:三目运算符

    语法:条件表达式?表达式1:表达式0 注:当条件表达式为true则选择表达式1,反之false则选择表达式0 例: var a = 0; var b = 1; re=a>b?a:b consol ...

  4. iOS全埋点解决方案-APP和H5打通

    前言 ​ 所谓的 APP 和 H5 打通,是指 H5 集成 JavaScript 数据采集 SDK 后,H5 触发的事件不直接同步给服务器,而是先发给 APP 端的数据采集 SDK,经过 APP 端数 ...

  5. 理论+案例,带你掌握Angular依赖注入模式的应用

    摘要:介绍了Angular中依赖注入是如何查找依赖,如何配置提供商,如何用限定和过滤作用的装饰器拿到想要的实例,进一步通过N个案例分析如何结合依赖注入的知识点来解决开发编程中会遇到的问题. 本文分享自 ...

  6. 记住这几个git命令就够了

    git clone: 下载初始化git add:添加git commit -m ' ' :提交 带消息git push:推送git pull: 拉取 git config --global user. ...

  7. 好用到爆!GitHub 星标 32.5k+的命令行软件管理神器,功能真心强大!

    前言(废话) 本来打算在公司偷偷摸摸给星球的用户写一篇编程喵整合 MongoDB 的文章,结果在通过 brew 安装 MongoDB 的时候竟然报错了.原因很简单,公司这台 Mac 上的 homebr ...

  8. 训练一个图像分类器demo in PyTorch【学习笔记】

    [学习源]Tutorials > Deep Learning with PyTorch: A 60 Minute Blitz > Training a Classifier   本文相当于 ...

  9. mariadb安装配置(主从配置)

    主服务器192.168.206.183 从服务器192.168.206.193 1.创建并编辑 /etc/yum.repos.d/MariaDB.repo文件(主从都要做) [mariadb] nam ...

  10. 图片64base转码与解码

    场景一:图片转码成base64,传输,接收后解码成png等格式图片 import base64 # 读取图片,转换为base64编码格式 with open("F:\Archer\pictu ...