基于ARM Cortex-M和Eclipse的SWO单总线输出

基于ARM Cortex-M和Eclipse的SWO单总线输出nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp 最近在 MCUonEclipse 网站上看到 ErichStyger 所写的一篇有关通过 SWD 的跟踪接口 SWO 获取 ARMCortex M 相关信息的文章 文章结构明晰 讲解透彻 本人深受启发 特意将其翻译过来供各位同仁参考 当然限于个人水平 有不当之处恳请指正 原文网址 https mcuoneclipse com 2016 10 17 tutorial using single

        最近在MCU on Eclipse网站上看到Erich Styger所写的一篇有关通过SWD的跟踪接口SWO获取ARM Cortex-M相关信息的文章,文章结构明晰,讲解透彻,本人深受启发,特意将其翻译过来供各位同仁参考。当然限于个人水平,有不当之处恳请指正。原文网址:https://mcuoneclipse.com/2016/10/17/tutorial-using-single-wire-output-swo-with-arm-cortex-m-and-eclipse/

 

        作为一个标准过程,我将一些控制台功能添加到我的嵌入式应用程序中。这样我就有了一个命令行接口,可以检查和修改目标系统。ARM Cortex-M的一个有趣的硬件特性是单线输出(SWO) ,它允许通过一根线路将数据(例如字符串)发送到32个不同的激励端口。

 基于ARM Cortex-M和Eclipse的SWO单总线输出

ARM调试器接头上的SWO引脚

调试跟踪输出?SWO

        我使用普通的UART/SCI作为标准的文本和命令行与目标板的接口。然而,在许多板上,UART被应用程序使用。

有一个Semihosting(半托管),但是速度非常慢,而且取决于调试器和工具链/库,加上需要消耗FLASHRAM,所以我不建议在任何情况下使用Semihosting

【注】Semihosting是针对ARM目标机的一种机制,它能够根据应用程序代码的输入/输出请求,与运行有调试功能的主机通讯。这种技术允许主机为通常没有输入和输出功能的目标硬件提供主机资源。

        也有一个USB CDC,但这需要一个USB接口,一个USB栈和一个具有USB功能的微控制器。不适用于所有情况。

        还有一个Segger RTT,它很小,速度快,最好的是不需要任何特殊的引脚。但只能工作于Segger的调试探测器。

ARM SWO

        但还有另一件事:ARM SWO跟踪端口是由ARMCortexm-M定义的。从技术上讲,SWO是一个单一的跟踪引脚,它被用来以从CPU核心时钟中提取一个特定的时钟频率发送数据包。您可以将SWO看作是一种使用特殊格式发送数据包的UART TX引脚。可以使用多达32种包类型(或激励)。发送什么样的数据取决于应用程序,并且只需要很少的CPU处理或代码。

        常见SWO用法是:

  •  按字符串发送调试信息
  •  记录中断的进入与退出
  •  记录函数的进入与退出
  •  周期性的PC值采样
  •  事件提示
  •  变量或内存单元修改超时

        最常见的用法之一就是第一种:使用SWOUART样式打印来自目标的调试消息。并且这也正是我再这篇文章中将要表达的。还有另一种编码(曼彻斯特编码),这里不做介绍。

ARM CoreSight

        SWOARM CoreSight调试功能块的一部分,而ARM CoreSight则通常是Cortex-M3M4M7的一部分:

 基于ARM Cortex-M和Eclipse的SWO单总线输出

CoreSight功能块(来自:http://www.arm.com/files/pdf/AT_-_Advanced_Debug_of_Cortex-M_Systems.pdf

如上图所示,通过SWO(SWV)ITMDWT跟踪消息可以发送。对于指令跟踪需要4个额外的跟踪引脚

SWO引脚

        使用SWO的前提条件是这个引脚可以在调试头中使用。这是我的TWR-K64F120M板的情况:

 基于ARM Cortex-M和Eclipse的SWO单总线输出

trace swo引脚(来自:TWR-K64F120M原理图)

        如上图所示,SWO跟踪引脚是与JTAG TDO引脚共享的。所以这就意味着SWO不能在JTAG中使用,而只能在SWD中使用。

所以仔细检查你板子的原理图确定他是否支持SWO。例如FRDM-K64F(是TWR-K64F120M上一个版本),它的SWO是没有被引到调试头的:

 基于ARM Cortex-M和Eclipse的SWO单总线输出

FRDM-K64F上没有SWO

调试探针与SWO

        为了能够使用SWO,我需要一个能够读取SWO引脚的调试探测器。例如,Freescale/NXP OpenSDAFreedomTower模块板载调试接口硬件就不支持SWO

        然而,外部的Segger J-Link却支持SWO引脚。下面我有一个J-Link EDU连接到TWR-K64F120M板的调试和跟踪端口:

 基于ARM Cortex-M和Eclipse的SWO单总线输出

j-link edu连接到跟踪端口

通过SWO引脚发送调试信息的源码

        为了通过SWO写调试消息到主机,需要一小段代码。在Github上有一个可用的完整代码的例子项目:

https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/TWR-K64F120M/TWR-K64F120M_Demo/Sources

        外部工具(比如Segger RTT查看器)可以在硬件中设置SWO。我的建议是从应用程序初始化它。因为SWO跟踪输出时钟是从CPU时钟派生而来的,所以初始化函数需要这个时钟加上SWO端口号来初始化。下面是我用来初始化SWO输出的代码,默认为64k波特率:

/*!

 * \brief Initialize the SWO trace port for debug message printing

 * \param portBits Port bit mask to be configured

 * \param cpuCoreFreqHz CPU core clock frequency in Hz

 */

void SWO_Init(uint32_t portBits, uint32_t cpuCoreFreqHz) {

  uint32_t SWOSpeed = 64000; /* default 64k baud rate */

  uint32_t SWOPrescaler = (cpuCoreFreqHz / SWOSpeed) – 1; /* SWOSpeed in Hz, note that cpuCoreFreqHz is expected to be match the CPU core clock */

 

  CoreDebug->DEMCR = CoreDebug_DEMCR_TRCENA_Msk; /* enable trace in core debug */

  *((volatile unsigned *)(ITM_BASE + 0x400F0)) = 0x00000002; /* “Selected PIN Protocol Register”: Select which protocol to use for trace output (2: SWO NRZ, 1: SWO Manchester encoding) */

  *((volatile unsigned *)(ITM_BASE + 0x40010)) = SWOPrescaler; /* “Async Clock Prescaler Register”. Scale the baud rate of the asynchronous output */

  *((volatile unsigned *)(ITM_BASE + 0x00FB0)) = 0xC5ACCE55; /* ITM Lock Access Register, C5ACCE55 enables more write access to Control Register 0xE00 :: 0xFFC */

  ITM->TCR = ITM_TCR_TraceBusID_Msk | ITM_TCR_SWOENA_Msk | ITM_TCR_SYNCENA_Msk | ITM_TCR_ITMENA_Msk; /* ITM Trace Control Register */

  ITM->TPR = ITM_TPR_PRIVMASK_Msk; /* ITM Trace Privilege Register */

  ITM->TER = portBits; /* ITM Trace Enable Register. Enabled tracing on stimulus ports. One bit per stimulus port. */

  *((volatile unsigned *)(ITM_BASE + 0x01000)) = 0xFE; /* DWT_CTRL */

  *((volatile unsigned *)(ITM_BASE + 0x40304)) = 0x00000100; /* Formatter and Flush Control Register */

}

        在我的主应用程序中,我像这样初始化它(对于一个有24MHz核心时钟的系统)

#define CPU_CORE_FREQUENCY_HZ /* CPU core frequency in Hz */

 SWO_Init(0x1, CPU_CORE_FREQUENCY_HZ);

SWO_PrintChar()函数中完成打印:

/*!

 * \brief Sends a character over the SWO channel

 * \param c Character to be sent

 * \param portNo SWO channel number, value in the range of 0 to 31

 */

void SWO_PrintChar(char c, uint8_t portNo) {

  volatile int timeout;

 

  /* Check if Trace Control Register (ITM->TCR at 0xE0000E80) is set */

  if ((ITM->TCR&ITM_TCR_ITMENA_Msk) == 0) { /* check Trace Control Register if ITM trace is enabled*/

    return; /* not enabled? */

  }

  /* Check if the requested channel stimulus port (ITM->TER at 0xE0000E00) is enabled */

  if ((ITM->TER & (1ul<

    return; /* requested port not enabled? */

  }

  timeout = 5000; /* arbitrary timeout value */

  while (ITM->PORT[0].u32 == 0) {

    /* Wait until STIMx is ready, then send data */

    timeout–;

    if (timeout==0) {

      return; /* not able to send */

    }

  }

  ITM->PORT[0].u16 = 0x08 | (c<<8);

}

        上面的代码使用了一个非常简单的超时机制:重要的一点是,如果SWO没有启用或者SWO端口没有准备好,那么应用程序就会被阻塞。

        为了更方便地打印字符串,我使用以下函数:

/*!

 * \brief Sends a string over SWO to the host

 * \param s String to send

 * \param portNumber Port number, 0-31, use 0 for normal debug strings

 */

void SWO_PrintString(const char *s, uint8_t portNumber) {

  while (*s!=’\0′) {

    SWO_PrintChar(*s++, portNumber);

  }

}

        要通过SWO发送一个“hello”,它就像这样简单:

SWO_PrintString(“hello world with SWO\r\n”, 0);

        第一个参数是要发送的字符串,第二个是SWO跟踪通道号。

GNU ARM Eclipse查看器

        要接收主机上的SWO跟踪输出,GNU ARM Eclipse插件内置了Segger J-Link探测器的SWO支持。

        SWO仅支持SWD(单线调试)模式,不支持JTAG模式。所以确保SWD被选为调试协议:

 基于ARM Cortex-M和Eclipse的SWO单总线输出

SWD调试

        在GNU ARM Eclipse调试配置中,启用SWO并指定CPU频率和SWO频率(请参见http://gnuarmeclipse.github.io/debug/jlink/上的有关频率的文档)。我必须提供CPU频率(在我的情况下为120 MHz),并且可以将SWO频率设置为0,以便J-Link自动确定速度)。在端口掩码中指定使用的端口(作为位掩码),因此0x1用于使用端口0

 基于ARM Cortex-M和Eclipse的SWO单总线输出

SWO的设置

        这样,在目标板上运行应用程序就会在Eclipse控制台视图中显示输出:

 基于ARM Cortex-M和Eclipse的SWO单总线输出

Eclipse控制台视图

Segger SWO Viewer

        Segger有一个特殊的SWO Viewer(命令行和GUI版本)。

        在GUI版本中,我指定使用的设备,它可以感测跟踪时钟:

 基于ARM Cortex-M和Eclipse的SWO单总线输出

segger gui swo viewer

        在查看器中,我可以打开/关闭端口,并查看收到的数据:

 基于ARM Cortex-M和Eclipse的SWO单总线输出

segger j-link swo viewer

Telnet: Putty

        但是,没有需要查看SWO数据的花哨的查看器或EclipseSegger默认使用端口2332

 基于ARM Cortex-M和Eclipse的SWO单总线输出

SEGGER SWO端口

        我可以配置任何telnet客户端(例如PuTTY)在端口2332上打开会话:

 基于ARM Cortex-M和Eclipse的SWO单总线输出

putty telnet会话设置

        我在PuTTY中得到的输出:

 基于ARM Cortex-M和Eclipse的SWO单总线输出

SWOPuTTY中的输出

综述

        ARM SWO跟踪引脚允许向主机发送跟踪消息。一个常见的用法是向主机发送调试或其他消息。SWO只需要一个引脚,仅适用于SWD(而不是JTAG),并且在目标上需要很少的代码和资源。不幸的是,许多电路板没有将SWO跟踪引脚路由到调试头,因此如果您正在进行自己的设计,则至少应考虑将SWO路由到调试头。

        虽然SWO跟踪输出很大,但是限于高端Cortex-M,我没有在Cortex-M0+)中找到它,它只是输出,需要一个支持它的调试探针/接口。至少与EclipseGNU ARM Eclipse插件结合Segger J-Link探针SWO输出对我来说非常棒。

        另一方面,Segger RTT的功能更加多样化,也非常快。它适用于所有ARM Cortex,最重要的是不需要额外的引脚。然而,它在目标系统上需要更多的开销和RAM资源。此外,它允许发送和接收数据。所以对于串行调试消息打印,Segger RTT对我来说听起来更好的解决方案。

        接下来就是快乐SWO中了!

相关链接

  •  SWO on Kinetishttps//community.nxp.com/thread/
  •  SWOGNU ARM Eclipse插件:http : //gnuarmeclipse.github.io/debug/jlink/
  •  Segger SWO Viewerhttps : //www.segger.com/j-link-swo-viewer.html
  •  GNU ARM Eclipse插件:http : //gnuarmeclipse.github.io/debug/
  •  Eclipse RxTx插件,用于解析SWO数据:http : //forum.segger.com/index.php? page=Thread&threadID=1010
  •  ARM CoreSight概述:http : //www.arm.com/files/pdf/AT_-_Advanced_Debug_of_Cortex-M_Systems.pdf
  •  GitHub上的示例代码:https//github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/TWR-K64F120M/TWR-K64F120M_Demo/Sources

欢迎关注:

基于ARM Cortex-M和Eclipse的SWO单总线输出

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/200508.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月20日 上午10:41
下一篇 2026年3月20日 上午10:41


相关推荐

  • SQL语句–mysql高级查询[关联查询|多表查询](连接查询、子查询、联合查询、图解说明几种常见的连接[联合]查询)

    SQL语句–mysql高级查询[关联查询|多表查询](连接查询、子查询、联合查询、图解说明几种常见的连接[联合]查询)一 常用的高级查询语句连接查询 如果条件和结果分布于多张表 使用多表连接 子查询 如果最终结果在一张表中 优先选择子查询 再考虑连接查询 嵌套查询 将一个查询结果作为另一个查询条件或组成部分的查询 联合查询 全连接 联合查询 并集去交集等 将两个结果集联合到一起的查询 应用 连接查询和子查询配合使用 数据量较大时连接查询较慢 先过滤再连接 子查询嵌套层次较大也影响性能 s

    2026年2月7日
    2
  • 线性插值 多项式插值 样条插值 牛顿插值总结

    线性插值 多项式插值 样条插值 牛顿插值总结1 什么是插值在数值分析中 插值 interpolatio 是一种通过已知的 离散的数据点 在范围内推求新数据点的过程或方法 求解科学和工程的问题时 通常有许多数据点借由采样 实验等方法获得 这些数据可能代表了有限个数值函数 其中自变量的值 而根据这些数据 我们往往希望得到一个连续的函数 也就是曲线 或者更密集的离散方程与已知数据互相吻合 这个过程叫做拟合 与插值密切相关的另一个问题是通过

    2026年3月17日
    2
  • django drf_django 消息队列

    django drf_django 消息队列前言我们上篇文章使用到了Serializer类,可能有小伙伴说太过复杂,那么本篇就为大家带来更加简便的序列化类ModelSerializerModelSerializer先来看下ModelSer

    2022年7月29日
    19
  • 部署禅道至外网

    部署禅道至外网结论:采用Cpolar映射工具和netsh命令netsh命令可以将对本地/局域网的某个端口的请求转发给本地/局域网的另一端口接收处理,假设利用Cpolar映射工具将本地的12345端口映射到外网,再利用netsh命令将本地12345端口转发到192.168.10.188的8000端口,这样,我在外网用http请求本地12345端口时,实际上是在请求禅道(192.168.10.188:8000)网址结论:可行工具:cpolar内网穿透工具和一台内网开着的电

    2022年5月29日
    86
  • 震惊!你的AI代码助手竟然可以这样玩?Claude Code Router + cpolar,效率直接起飞!

    震惊!你的AI代码助手竟然可以这样玩?Claude Code Router + cpolar,效率直接起飞!

    2026年3月15日
    2
  • 建立access数据库的两种方法_e4a上传数据到数据库

    建立access数据库的两种方法_e4a上传数据到数据库本章内容 ◆数据库的设计概念与创建数据库。◆表的创建及表与表之间的关系。◆数据库的修改、设计与编辑。  一、数据库的设计 1.概念及准则 下面介绍数据库设计的概念,及由此而产生的数据库设计准则。Access2003数据库是所有相关对象的集合,包括表、查询、窗体、报表、宏、模块、Web页等。每一个对象都是数据库的一个组成部分,其中,表是数据库的

    2025年11月12日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号