软件|嵌入式开发:使用ITM提高调试效率

软件|嵌入式开发:使用ITM提高调试效率

文章图片


无论我们的调试工具变得多么复杂 , 老旧的printf语句总会有一席之地 。 printf往往是高效的 , 并且会极大地影响系统的实时性能 。 对于使用Arm Cortex?-M3或更高版本的嵌入式开发人员 , 可以将printf重新映射到Instrumentation Trace Macrocell (ITM) , 这不仅可以使用printf , 还可以显着提高其效率并消除任何实时性能损失 。 让我们来看看如何使用ITM 。

在我们深入细节之前 , 重要的是要注意ITM比通过UART或其他外围设备使用我们的普通printf更快、更高效 。 ITM速度更快有几个原因 , 例如:它旨在通过硬件传输printf样式的消息
它使用专用引脚SWO来传输消息
波特率基于内部时钟频率 , 可以使其非常快
它有多个刺激端口 , 可以轻松分离数据和跟踪消息
基本上 , 开发人员只需将一个字符放入ITM缓冲区 , 硬件添加时间戳和相关数据并自行传输 , 无需任何额外的软件交互 。 消息通过微控制器上的串行线输出 (SWO)引脚直接传输到调试器 。 然后调试器可以在IDE控制台中记录和显示消息 。
ITM包含32个独立的激励端口 , 可用于将不同的消息传输到开发环境 , 例如调试、数据和跟踪信息 。 通常 , 端口0用于printf消息 , 而端口31用于RTOS事件消息 。 除此之外 , 端口1到30可用于嵌入式开发人员想要传输的任何附加信息 。 这可能包括状态机状态、传感器读数或任何其他有助于调试系统的信息 。 每个激励端口还可以在同一ITM消息中传输多达10个字节 。

使用ITM传输 printf 消息很简单 Arm在ITM的Arm CMSIS标准中包含了三个不同的辅助函数 。 这些包括:
ITM_SendChar
ITM_ReceiveChar
ITM_CheckChar
通过这些API , 开发人员可以发送、接收和检查单个字符 。 默认情况下 , 这些API假定端口0刺激端口 , 这意味着如果要使用另一个端口或多个端口 , 开发人员将需要自己编写这些函数 。 使用API很简单 。 要传输一个字符 , 开发人员可以简单地编写:
ITM_SendChar(Character);
如果我们想传输单个字符 , 这很有帮助 , 但如果我们想重定向printf语句 , 我们需要对printf的工作方式进行一些更改 。 修改将取决于所使用的开发环境和编译器 。 对于使用GCC的基于Eclipse的IDE , 嵌入式开发人员可以修改write函数而不是更改printf 。 包含printf 的nanolib库使用具有以下原型的write函数将printf重定向到开发人员可能想要使用的任何源:
int _write(int file char *ptr int len);
默认情况下通常不实现此功能 。正如您从原型中看到的那样 , 所需要做的就是利用指向字符缓冲区的指针并使用定义缓冲区中字符数的长度 。 有了这些信息 , 开发人员可以创建一个使用ITM的写入函数 , 如下所示:

【软件|嵌入式开发:使用ITM提高调试效率】对于正在寻找一种快速有效的方法来使用printf语句的开发人员来说 , ITM是一个非常宝贵的工具 。我们已经大致了解了ITM以及一些在软件中启动和运行它的技巧 。 请注意 , 为了成功接收消息 , 嵌入式开发人员需要启用所使用的ITM激励端口 , 并且可能需要修改调试配置以用于串行线查看(SWV)以及微控制器时钟速率 。除此之外 , 享受快速确定性的printf消息!