使用 Printf via SWO/SWV 输出调试信息

本文介绍如何在嵌入式开发中利用SWO技术,将应用程序中的stdout/stderr消息通过SWD接口传输到C-SPY Terminal I/O窗口。包括硬件配置、代码重定向以及使用步骤,实现软件调试和跟踪。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

IAR EWARM Printf via SWO

Stdout and stderr of the application can be redirected to ITM stimulus port #0.
It means that stdout/stderr messages (e.g. strings sent by printf) can be transferred
from the target application to the C-SPY Terminal I/O window via SWD.SWO pin <JTAG.TDO pin>.



Requirements:
Cortex-M3/M4 board; J-Link/J-Trace;
IAR Embedded Workbench for ARM, V5.50.5 or later.

1. plus rerouting stdout/stderr messages via SWO (library low-level interface implementation, see the figure below).

2. except for enabling ITM stimulus port #0 and using it for routing data to the C-SPY Terminal I/O window.

3. Open the Terminal I/O window from the View menu.
Start executing the application to collect Software Trace information.
Stdout messages sent by printf( ) in the application will be displayed here via SWO Trace.

 

Semihosting技术

将应用程序中的IO请求通过一定的通道传送到主机(host),由主机上的资源响应应用程序的IO请求,而不是像在主机上执行本地应用程序一样,由应用程序所在的计算机响应应用程序IO请求,也就是将目标板的输入/输出请求从应用程序代码传递到远程运行调试器的主机的一种机制。

简单来说,目标开发板上通常不会有输入/输出这些外设,开发板运行的代码想要将结果打印出来,或者获得用户的输入,可以通过请求远程主机IO设备来实现,如:显示器,键盘等。

目标开发板执行代码中加入对输入/输出设备进行访问函数,如:printf,scanf等,这些函数并不是目标开发板的库函数,而是远程主机交叉编译器中带有的库函数,这些库函数被编译时,编译成一条软件中断指令。

当目标开发板上电运行之后,执行到请求访问输入/输出设备指令时,产生特定中断号的软件中断SWI,与开发板相连的调试器会先截获目标板SWI请求,由于开发板程序中也可能存在用户自定义软件中断,为了区分二者,调试器会根据SWI的软中断号来判断是不是semihosting模式IO请求,如果是,则取出R0寄存器里代表的具体请求号,然后使用远程主机来响应目标板具体IO请求,而不是开发板本身去处理setmihosting请求。

semihosting仅仅是一种调试手段,它的工作原理就是利用调试器捕捉目标环境运行过程中产生SWI中断,然后向远程主机调试环境发送对应的调试信息。

也就是说目标开发板通过特定的软件中断指令,借用了远程主机的输入输出设备实现IO请求的访问。

Semihosting半主机调试模式,只能使用在开发板和调试主机通过仿真器连接的情况下,也就是说脱离了主机调试环境上述代码不能正常运行。

目标开发板上执行的IO实际上是交给了远程主机来处理实现,正是因为如此,这种方式只适合在调试模式下,真正的嵌入式系统不可能依赖于主机实现IO处理的,嵌入式系统要想独立出来实现IO请求的处理,这就需要将输入输出库函数的底层相关硬件实现重定向。

新一代调试机制

使用ITM机制实现调试,实现printf与scanf, ITM是ARM在推出semihosting之后推出的新一代调试机制。ITM机制要求使用SWD方式接口,并需要连接SWO线。

 

 

 

It is only TX and not RX but most people just use printf for tracing anyways.

If you have a USB serial adapter, you can also use it as a SWO viewer, SWO is actually very similar to UART except using a much faster speed,

for example, with JLink, I can push it to 6MHz, which most USB serial adapters do not support.

The speed is incredibly important in timing critical debugging.

Remember, SWO is not just an application software printf style debugging, it is tied to ITM (instrumentation trace macrocell)

which enables software & hardware trace with timestamp. i.e it allows you to debug OS and application events.

It's not a problem to use SWO out in production code.

The SWO is separate from the debugger.

You can even run the SWO console w/o the debugger connected. 

Target 使用 SWO 的条件

  • 硬件条件:你得把芯片的SWO脚接到调试口上,按JTAG接线的话,这个默认已经接上了.
  • 代码条件:你得把Printf的输出函数,替换成SWO输出函数,其实这个函数在CMSIS库里已经提供了,就在core_cm4.h里面,如下:
/** \brief  ITM Send Character

    This function transmits a character via the ITM channel 0.
    It just returns when no debugger is connected that has booked the output.
    It is blocking when a debugger is connected, but the previous character send is not transmitted.

    \param [in]     ch  Character to transmit
    \return             Character to transmit
 */
static __INLINE uint32_t ITM_SendChar (uint32_t ch)
{
  if ((CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk)  &&      /* Trace enabled */
      (ITM->TCR & ITM_TCR_ITMENA_Msk)                  &&      /* ITM enabled */
      (ITM->TER & (1UL << 0)        )                    )     /* ITM Port #0 enabled */
  {
    while (ITM->PORT[0].u32 == 0);
    ITM->PORT[0].u8 = (uint8_t) ch;
  }
  return (ch);
}

Redirecting/retargeting printf()

#include <stdio.h>
#include <stm32f4xx.h>
 
int fputc(int c, FILE *stream)
{
   return(ITM_SendChar(c);
}

SWO printf in IAR

The following steps demonstrate how to configure the SWO pin to output printf() statements in IAR.

1) Add #include to the beginning of the file where you want to write your printf statement.

2) Enable SWO Output.

The simplest way of enabling the SWO line in the EFM32 is by using the setupSWO function.

You can find this function in the energyAware Profiler, in the left pane, when you open up the program.

Once this is run, the SWO output will be enabled to the correct pin on the Development Kit or the Starter Kit.

3) Configure the project in IAR to send printf statements through SWO:

4) Write printf('Hello world'); in your code after you have enabled the SWO output.

5) Compile the code and download it to the Starter Kit/Development Kit. Enter a debug session.

6) Once you are in debug mode, you should set the correct SWO clock speed (14 MHz) in J-link->SWO Configuration...:

(The SWO output is clocked by the auxiliary HFRCO oscillator which is running at 14MHz regardless of the chosen system clock frequency.)

7) Open up View->Terminal I/O.

8) When you hit Go you should see the printf statement show up as below:

#ifndef LOG_LEVEL_LOWEST
#define LOG_LEVEL_LOWEST    _LOG_LEVEL_DEBUG
#endif

/**
 * Defines the default log level.
 */
#ifndef LOG_LEVEL_DEFAULT
#define LOG_LEVEL_DEFAULT   _LOG_LEVEL_INFO
#endif

#if LOG_LEVEL_LOWEST <= _LOG_LEVEL_TRACE
#define logTrace(MSG, ...)       __logLine(&_log, LOG_LEVEL_TRACE, MSG, ##__VA_ARGS__)
#else
#define logTrace(MSG, ...)
#endif

#if LOG_LEVEL_LOWEST <= _LOG_LEVEL_DEBUG
#define logDebug(MSG, ...)      __logLine(&_log, LOG_LEVEL_DEBUG, MSG, ##__VA_ARGS__)
#else
#define logDebug(MSG, ...)
#endif

#if LOG_LEVEL_LOWEST <= _LOG_LEVEL_INFO
#define logInfo(MSG, ...)       __logLine(&_log, LOG_LEVEL_INFO, MSG, ##__VA_ARGS__)
#else
#define logInfo(MSG, ...)
#endif

#if LOG_LEVEL_LOWEST <= _LOG_LEVEL_WARN
#define logWarn(MSG, ...)       __logLine(&_log, LOG_LEVEL_WARN, MSG, ##__VA_ARGS__)
#else
#define logWarn(MSG, ...)
#endif

#if LOG_LEVEL_LOWEST <= _LOG_LEVEL_ERROR
#define logError(MSG, ...)       __logLine(&_log, LOG_LEVEL_ERROR, MSG, ##__VA_ARGS__)
#else
#define logError(MSG, ...)
#endif
#ifdef DEBUG
   dbgPrintf(MSG, ...)     printf(MSG, ##__VA_ARGS__)
#else
   dbgPrintf(MSG, ...) 
#endif

 

 

<think>嗯,用户现在想了解支持Trace功能的DAP型号,特别是针对STM32系列。之前我已经详细解释过Trace功能的技术细节和应用场景,现在用户显然进入了实操阶段,需要具体硬件选型建议。 从用户引用的资料来看,ta应该已经接触过STM32F103C8T6的CMSIS-DAP方案,但注意到这个型号其实不支持硬件Trace(属于Cortex-M3内核)。用户可能遇到了调试复杂问题的瓶颈,需要升级调试工具。有趣的是用户特别标注"不是真正的需求",说明ta更关注实际解决方案而非理论描述。 用户可能存在的认知盲区是混淆了DAP调试器本身和芯片Trace能力的区别。需要强调两点:1)调试器硬件必须支持Trace数据转发 2)目标芯片需内置ETM/ITM模块。比如即使用户手头的DAP支持SWO,如果连接STM32F103仍然无法使用Trace。 翻看ST官方资料,硬件Trace能力从Cortex-M4F内核开始才普遍支持(如F4系列),而M7/M33内核支持更完整的ETM。因此回复要分层说明:先列出支持Trace的STM32芯片系列,再对应推荐调试器型号。特别提醒H7系列需要高速USB3.0调试器这类易忽略的细节。 注意到用户引用中提到正点原子DAP,可以推测ta可能倾向性价比方案。所以除了高端商用调试器,也要包含开源方案(如基于FT601的DIY高速DAP),并强调F407等型号用SWO就能实现基础Trace功能。 最后用对比表格直观呈现不同调试器的差异,避免用户被参数迷惑。补充的"替代方案"段落很重要——很多用户意识不到FreeRTOS Trace这类软件方案在低成本场景的价值。</think>根据STM32芯片的Trace功能支持情况及DAP调试器要求,以下是支持Trace功能的完整解决方案: --- ### 一、支持硬件Trace的STM32芯片系列 需满足两个条件: 1. **芯片内置ETM/ITM模块** - ✅ Cortex-M7内核:STM32H7/F7系列 - ✅ Cortex-M4F内核:STM32F4/G4/L4系列(**仅部分型号**) - ❌ Cortex-M3/M0+:**不支持硬件Trace**(如STM32F103)[^1] > 验证方法:查看芯片数据手册的**Debug and trace**章节,确认存在`ETM`或`ITM`模块 2. **芯片需预留Trace引脚** | 功能 | 引脚要求 | 示例型号引脚配置 | |--------------|----------------------------|-----------------------| | SWO | 单线输出(PB3或指定引脚) | STM32F407VGT6: PB3 | | 全Trace | 4-5引脚并行接口 | STM32H743ZI: PE2~PE6 | --- ### 二、支持Trace的DAP调试器型号 #### 1. **基础SWO追踪**(低成本方案) - **适用场景**:函数调用追踪、事件日志、性能采样 - **推荐调试器**: | 型号 | 特点 | Trace支持 | |--------------------------|-----------------------------|---------------------| | **ST-Link V3** | 官方调试器,支持SWO | ✅ SWO单线输出 | | **DAPLink固件+SWO引脚** | 开源方案(需硬件支持SWO) | ✅ 需手动连接SWO线 | | **J-Link EDU Mini** | SEGGER方案,兼容性强 | ✅ SWO + 基础事件 | > 配置示例(Keil MDK): > ```c > // 启用SWO输出(STM32CubeIDE) > HAL_DBGMCU_EnableDBGSleepMode(); // 允许调试状态下运行 > ITM->TER |= (1UL << 0); // 使能端口0 > ``` #### 2. **高速全指令追踪**(专业级) - **适用场景**:指令级流水线分析、硬实时系统诊断 - **必备调试器**: | 型号 | 带宽 | 接口要求 | |--------------------------|--------|-------------------| | **ULINKpro** | 100MB/s | 专用ETM接口 | | **J-Trace Pro** | 500MB/s | 高速并行Trace接口 | | **PEMicro Cyclone** | 200MB/s | HS-SWD + ETM | > ⚠️ 注意:需芯片提供**Trace并行接口**(如STM32H743的TRACEDATA[0:3]) --- ### 三、硬件连接要点 1. **SWO单线连接** ```mermaid graph LR DAP[ST-Link V3] -- SWO引脚 --> STM32[STM32F4 PB3] DAP -- SWDIO/SWCLK --> STM32 ``` 2. **全Trace连接**(以STM32H743为例) | DAP调试器引脚 | 芯片引脚 | 功能 | |---------------|-----------|-------------| | TRACECLK | PE2 | 时钟同步 | | TRACED0 | PE3 | 数据位0 | | TRACED1 | PE4 | 数据位1 | | TRACED2 | PE5 | 数据位2 | | TRACED3 | PE6 | 数据位3 | --- ### 四、软件配置步骤(以STM32CubeIDE + ST-Link V3为例) 1. **启用芯片Trace功能** ```c // 在main.c中添加 HAL_DBGMCU_EnableDBGTrace(void); // 激活ITM和ETM ``` 2. **IDE配置** ```diff Debug Configurations → Trace → Enable Trace: ✔ Trace Protocol: SWV Core Clock: 168000000 # 填写实际HCLK频率 SWO Frequency: 2000000 # ST-Link V3最高支持2MHz ``` 3. **实时数据查看** ```c printf("Via SWO: value=%d\n", var); // 重定向到ITM_SendChar() ``` --- ### 五、替代方案(无专用Trace硬件时) 若使用**STM32F103等无Trace模块**的芯片: 1. **软件模拟事件追踪** ```c // 在关键代码插入标记 ITM_SendChar('E'); // 事件开始 critical_function(); ITM_SendChar('X'); // 事件结束 ``` 2. **使用SEGGER SystemView** - 实时任务调度可视化 - 动态内存监控 - 支持FreeRTOS/ThreadX --- ### 六、验证Trace是否工作 1. 在**STM32CubeMonitor**中查看实时波形 ![SWO波形示例](https://www.st.com/bin/ecommerce/api/image.PF259887.feature-description-include-personalized-no-cpn-large.jpg) 2. 检查**ITM寄存器**状态: ```armasm LDR R0, =0xE0000E00 ; ITM基地址 LDR R1, [R0, #0xE80] ; 查看ITM_TCR寄存器 ; 若bit[3:0]=0001表示Trace已激活 ``` > 📌 **关键结论**: > - **SWO基础追踪**:选择 **ST-Link V3 + STM32F4/G4/L4/H7** > - **全指令追踪**:必须选用 **J-Trace/ULINKpro + STM32H7** > - **低成本方案**:DAPLink固件调试器 + SWO引脚改造[^1][^2] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值