大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是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 只需要按照这个规定去具体实现即可。

  1. 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 封装,本文没必要关心其实现),只要如下一句打印即可:

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

  然后注意工程选项里 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 软件商业机密了吧。

  1. *******************************************************************************
  2. *** MODULE SUMMARY
  3. ***
  4. Module ro code ro data rw data
  5. ------ ------- ------- -------
  6. dl7M_tln.a: [10]
  7. XShttio.o 8 8 8
  8. abort.o 6
  9. exit.o 4
  10. low_level_init.o 4
  11. printf.o 40
  12. putchar.o 32
  13. xfail_s.o 64 4
  14. xprintfsmall_nomb.o 1'281
  15. xprout.o 22
  16. -----------------------------------------------
  17. Total: 1'461 8 12
  18. shb_l.a: [13]
  19. dwrite.o 30
  20. exit.o 20
  21. iarttio.o 124
  22. iarwrite.o 34
  23. iarwstd.o 32
  24. write.o 16
  25. -----------------------------------------------
  26. Total: 256

3.4 从反汇编文件看Semihosting实现

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

  1. 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. MySQL - 数据库设计步骤

    需求分析:分析用户的需求,包括数据.功能和性能需求. 概念结构设计:主要采用E-R模型进行设计,包括画E-R图. 逻辑结构设计:通过将E-R图转换成表,实现从E-R模型到关系模型的转换,进行关系规范化 ...

  2. @vue/cli3+配置build命令构建测试包&正式包

    上一篇博客介绍了vue-cli2.x配置build命令构建测试包和正式包,但现在前端开发vue项目大多数使用新版@vue/cli脚手架搭建vue项目(vue create project-name) ...

  3. Eureka属性配置

    一:Eureka Instance实例信息配置   里面的配置以"-"隔开 其实也支持驼峰命名代替"-" 首先是入门时的配置: server: port: 80 ...

  4. 适配抖音!三角面转换和3d模型体量减小,轻量化一键即可完成!

    抖音3d特效,可谓是越来越火爆了,这个有着迪士尼画风的3D大眼,就刷屏了国内外用户的首页! 有人好奇这些特效究竟是怎么制作的?其实就是把3D模型调整适配到头部模型上,调整位置或者大小就可以制作出一个简 ...

  5. BUUCTF-LSB

    LSB 看到这个题目应该是LSB隐写,StegSolve打开,在红绿蓝0号上发现图片信息 然后在Analyse选择data extract Save bin保存图片即可 得到的是个二维码,解码即可.

  6. Vue3.0系列——「vue3.0学习手册」第一期

    一.项目搭建 vite是尤大大开发的一款意图取代webpack的工具.其实现原理是利用ES6的import发送请求加载文件的特性.拦截这些请求,做一些编译,省去webpack冗长的打包时间.并将其与R ...

  7. go Cobra命令行工具入门

    简介 Github:https://github.com/spf13/cobra Star:26.5K   Cobra是一个用Go语言实现的命令行工具.并且现在正在被很多项目使用,例如:Kuberne ...

  8. RPA教程

    匠厂出品,必属精品   Uipath中文社区qq交流群:465630324 uipath中文交流社区:https://uipathbbs.comRPA之家qq群:465620839 第一课--UiPa ...

  9. 使用EasyExcel导出图片及异常处理

    1.使用String类型导出   定义自己的Converter,不使用默认的StringImageConverter 如果图片路径为空或者图片路径是错误的,返回相应的内容 import java.io ...

  10. Educational Codeforces Round 129 (Rated for Div. 2) A-D

    Educational Codeforces Round 129 (Rated for Div. 2) A-D A 题目 https://codeforces.com/contest/1681/pro ...