最近公司准备启动一个新的项目,使用NXP的MIMXRT1170芯片作为主控,在熟悉芯片的过程中发现RT1176具备ITM和SWO功能模块,于是针对之前项目中因工程庞大导致调试困难的问题,决定使用SWO输出调试信息,这样既可以节省硬件的一个串口,同时还可以通过PC指针信息对工程资源进行分析,经过与芯片厂家沟通,RT1170芯片目前不支持MDK配置SWO,又因为NXP的IDE因为某些个人原因不想用,所以该功能实现都是通过软件寄存器直接配置和开源解析工具实现。
ITM(Instrumentation Trace Macrocell)和SWO(Serial Wire Output)是Arm Cortex-M处理器中用于调试和跟踪的两个重要功能模块。ITM是一种用于在微控制器上进行实时跟踪的调试技术,它允许程序在运行时输出调试信息,例如变量值、函数调用等。ITM通过SWO(Serial Wire Output)接口将这些信息输出到调试工具,例如调试器或者调试控制台。
1、初始化TRACE_SWO引脚
IOMUXC_SetPinMux(IOMUXC_GPIO_LPSR_11_ARM_TRACE_SWO, 0);
IOMUXC_SetPinConfig(IOMUXC_GPIO_LPSR_11_ARM_TRACE_SWO, 0x02U);
2、SWO的寄存器配置代码如下所示:
#define ITM_TER0 *(volatile unsigned int *)0xE0000E00
#define ITM_TPR *(volatile unsigned int *)0xE0000E40
#define ITM_TCR *(volatile unsigned int *)0xE0000E80
#define ITM_TER_PORT0 (1<<0)
#define ITM_TCR_ENABLE_ITM (1<<0)
#define ITM_TCR_ENABLE_DWT (1<<3)
#define ITM_TCR_BUS_ID (1<<16)
#define DEBUG_DEMCR *(volatile unsigned int *)0xE000EDFC
#define BASE_CSSYS_SWO 0xE0048000
#define BASE_CSSYS_TSGEN 0xE0047000
#define BASE_CSSYS_TPIU 0xE0046000
#define BASE_CSSYS_ATB_FUNNUL 0xE0045000
#define BASE_CSSYS_CTI 0xE0044000
#define BASE_ATB_FUNNUL 0xE0043000
#define BASE_CTI 0xE0042000
#define BASE_ETM 0xE0041000
#define SWO_CODR *(volatile unsigned int *)(BASE_CSSYS_SWO+0x10)
#define SWO_SPPR *(volatile unsigned int *)(BASE_CSSYS_SWO+0xf0)
#define SWO_LOCK *(volatile unsigned int *)(BASE_CSSYS_SWO+0xfb0)
#define CSSYS_ATB_FUNNUL_CTRL *(volatile unsigned int *)(BASE_CSSYS_ATB_FUNNUL+0)
#define CSSYS_ATB_FUNNUL_LOCK *(volatile unsigned int *)(BASE_CSSYS_ATB_FUNNUL+0xfb0)
#define ATB_FUNNUL_CTRL *(volatile unsigned int *)(BASE_ATB_FUNNUL+0)
#define ATB_FUNNUL_LOCK *(volatile unsigned int *)(BASE_ATB_FUNNUL+0xfb0)
void BOARD_InitHardware(void)
{
CLOCK_EnableClock(kCLOCK_Cstrace);
DEBUG_DEMCR = 0x01000000; // Enable trace and debug block
CSSYS_ATB_FUNNUL_LOCK = 0xC5ACCE55;
CSSYS_ATB_FUNNUL_CTRL = 0x000003FF;
ATB_FUNNUL_LOCK = 0xC5ACCE55;
ATB_FUNNUL_CTRL = 0x000003FF;
SWO_LOCK = 0xC5ACCE55;
SWO_SPPR = 0x00000002; // Select NRZ protocol
SWO_CODR = 0x00000015; // 5 MHz
ITM_TCR = ITM_TCR_BUS_ID | ITM_TCR_ENABLE_DWT | ITM_TCR_ENABLE_ITM; //0x0001040A
ITM_TER0 = ITM_TER_PORT0; // Enable stimulus ports 0
*(volatile unsigned int *)0xE0001000 = 0x40000001 // DWT_CTRL [Disable cycle counter and PC events]
*(volatile unsigned int *)0xE0001004 = 0x00000000 // DWT_CYCCNT [Clear the cycle counter]
*(volatile unsigned int *)0xE0001000 = 0x40001199 // DWT_CTRL [Program Counters]
}
软件寄存器配置大致如上,其中SWO的寄存器配置参考数据手册《Armv7-M Architecture Reference Manual》、《i.MX RT1170 Processor Reference Manual》,详细配置可参考以上手册。
3、如果需要使用SWO的printf输出功能,那么则需要重新定向printf,本工程中直接使用的NXP的《MCUXpressoIDE》安装自带的重定向文件“retarget_itm.c”,如果需要可自行安装下载或者使用其它重定向方法。
4、在程序调用printf输出日志,将初始化的外部SWO引脚与jink的swo引脚相连接,如果你一切顺利都配置成功,通过Jlink SWO Viewer软件即可看到printf输出的日志(注意输入正确的CPU和SWO的频率)。
5、 接下来进来PC值的采样及分析,本项目使用的Openocd对SWO输出的日志进行存储。OpenOCD(Open On-Chip Debugger)是一个开源的调试和编程工具,它用于与嵌入式系统中的调试接口(例如JTAG、SWD等)进行通信,从而实现对目标芯片的调试、烧录和编程等功能,类似于jlink软件。
6、Openocd的文件配置。本项目使用的是openocd 0.12.0版本(据测试openocd的不同版本调用指令好像有些差异,使用时应该注意一下,避免后面造成不必要的使用问题),jlink.cfg文件配置如下:
adapter driver jlink
transport select swd
7、接下来配置芯片的配置文件,本项目使用rt1170芯片,所以在openocd的对应目录下创建相应的芯片配置文件名(如果有可以不创建)"mimxrt1170.cfg",配置如下:
source [find ../tcl/target/swj-dp.tcl]
source [find ../tcl/mem_helper.tcl]
#定义MCU型号
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME MIMXRT1170
}
#内存小端
set _ENDIAN little
adapter speed 1000
swd newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f -enable
dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
target create $_CHIPNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap
#RT1170的SWO配置基地址 --- 0xE0048000
tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0048000
#配置trace及swo引脚时钟、输出文件、使能
$_CHIPNAME.tpiu configure -protocol uart
$_CHIPNAME.tpiu configure -traceclk 132000000 -pin-freq 6000000
$_CHIPNAME.tpiu configure -output trace.fifo
$_CHIPNAME.tpiu enable
itm port 0 on
8、修改USB串口驱动,因为openocd使用的winusb驱动,所以我们需要将jlink的驱动程序替换成USB驱动程序,以解决驱动问题,本项目使用的zadig软件进行的替换,替换步骤如下:
9、启动openocd,进入openocd.exe文件目录下,输入指令分别调用上面配置的jlink.cfg和mimxrt1170.cfg文件,如下所示:
10、 如果不出意外,在你的openocd.exe的根目录下会自动生成一个trace.fifo文件,里边便是SWO的日志文件。
11、解析trace.fifo文件,本项目使用的是itm-tools,链接如下:https://github.com/japaric/itm-tools,下载后需要搭建rust环境进行编译,如下所示:
12、itm-tools编译成功后, 进入debug目录下,将上面生成的trace.fifo和工程文件的.elf或.axf拷贝到这个目录下,输入指令:pcsampl trace.fifo -e 文件名.axf/elf,输入指令如下所示说明解析成功。
参考文章链接: https://interrupt.memfault.com/blog/profiling-firmware-on-cortex-m#enabling-pc-sampling-with-itm-and-openocd