最近公司准备启动一个新的项目,使用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

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐