Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
J-LINK
J-Trace
J-Trace入门系列:2)ART-PI 也能玩转Stream Trace
发布于 2022-08-16 20:02:54 浏览:2494
订阅该版
[tocm] # 前言 往期回顾:[J-Trace入门系列:1)感动人心的功能与更感动人心的售价] 距离上一篇更新已经过了很长时间,很多小伙伴都在催更,属实惭愧。拖更太久就印证了一句话,有些事情现在不去做,以后便再也不会去做。言归正传,在我使用J-Trace这段时间里,大多数场景是拿它作为正版J-Link使用,只有很少的情况下,才会用到它的核心功能。 朋友间打趣交流的时候,都会说,普通调试器能解决95%以上的问题,高端调试器用来解决剩下的5%问题。 事实的确如此,很多时候我们并没有太在乎代码在MCU内部实时运行的情况,直到撞到了瓶颈(性能不达标、死机异常),成为一堵绕不开的墙之后,才会想到使用这样的工具。 由于Trace在ARM Cortex-M上,相比SWD/JTAG需要单独拉起Trace信号,本篇将着重篇幅介绍**软硬件搭建**环节。 # 1. 连接ART-PI 事实上J-Trace包装盒内附赠了一块STM32F407的板子,用于下载官网Trace例程,学习Ozone调试流程之用: ![STM32F407_refboard.png](https://oss-club.rt-thread.org/uploads/20220816/2b32606ee92396ae8fc356b6ffd87a5c.png.webp "STM32F407_refboard.png") 这张板子太丐了,还卖$99,除了点灯就没别的了,所以在验证过J-Trace之后,我们直接上手去对接ART-PI。 ## 1.1 硬件连接 首先确定ART-PI是否有Trace Pin的扩展能力,通过查看ART-PI硬件原理图,确定了如下管脚: | IO管脚 | Trace Pin复用 | | ------ | ------------- | | PE2 | TCLK | | PG13 | TD0 | | PG14 | TD1 | | PE5 | TD2 | | PE6 | TD3 | 确定IO这一步的过程是比较让人激动的,毕竟说明书里没有注明这个扩展,可以认为,ART-PI设计初期的IO选定是花了心思的。 当然,知道IO之后我们就要去连接它,根据[上篇]的介绍我们知道,实现Stream Trace需要SWD+Trace共同实现,Segger也提供了1.27mm间距的2x10Pin接口。所以结合ART-PI背面预留的SWD焊盘,使用不同高度的【PogoPin】,这种测试接针,在接触面上有弹性,可作为烧录架使用,完美解决了调试部分,同时不会损失原有的扩展性。据此,可以简单画个孔位对齐的板子出来: ![ART-PI_basement.png](https://oss-club.rt-thread.org/uploads/20220816/7d7b8788332ff039c280681a747169e2.png.webp "ART-PI_basement.png")
焊接好器件,使用M3孔径的螺柱就能锁紧开发板,可以看见PogoPin的连接非常稳健: ![pogopin_side.jpg](https://oss-club.rt-thread.org/uploads/20220816/b005211193eb4d7655f5efc6d5c4268c.jpg.webp "pogopin_side.jpg") 在硬件连通阶段建议结合逻辑分析仪抓一抓波形,能够很容易确定当前内核Trace的工作状态。
整体装配图: ![art-pi_stackup.jpg](https://oss-club.rt-thread.org/uploads/20220816/bcfc1791a1ea71a853388be41ee60567.jpg.webp "art-pi_stackup.jpg") 以上,就完成了ART-PI的外部调试器的引入,细心的同学可能会发现,在SWD部分,信号和ST-Link直连的,出现了两个调试器接入一个MCU的情况,这个的确不合理,但实测ST-Link只当串口情况下,**几乎不会干扰SWD总线**,两个调试器分时复用就好了。此外,这样也能用ST-Link下载,Jlink调试,属实NTR了。。 ## 1.2 信号通路 在开展这一步之前,需要明确 Core -> ETM -> TPIU 这条信号通路(ATB Bus)上的初始条件。 ### 1.2.1 STM32H7 Trace 信号通路 查阅STM32H7手册(rm0433),可以看见APB-D信号流需要从Core到ETM,处理后的trace信号送至CSTF合路器,最后送到TPIU并由Trace Pin输出到片外调试器。 ![rm0433_dbg_diagram.png](https://oss-club.rt-thread.org/uploads/20220816/2671a00aa5dbd74358416a9e350c87e1.png.webp "rm0433_dbg_diagram.png") **名词解释: >| 缩写 | 全称 | 释义 | >| ---- | ------------------------- | ---------------- | >| ETM | Embedded Trace Macrocell | 嵌入式追踪宏单元 | >| CSTF | Trace bus funnel | 追踪总线合路器 | >| TPIU | Trace port unit interface | 追踪端口界面单元 | 可以看出,Cortex-M7的CoreSight界面相比Cortex-M4有更多扩充,总线通路上要更灵活,在TPIU这一侧就可以支持: - ETM信号经合路器旁路到TPIU直出。 - ETM信号经合路器送入ETF进行FIFO缓冲,再由TPIU输出。 - ITM经Replicator分配到合路器,经由TPIU输出。 - ETF/TPIU 均可由外部触发源刷新行为。 我们不需要一一实现,只需要实现最基础的Trace流输出。
更深入的,可以参考ARM官方CoreSight文档: >1. IHI 0031C (ID080813) - Arm® Debug Interface Architecture Specification ADIv5.0 to ADIv5.2, Issue C >2. DDI 0480F (ID100313) - Arm® CoreSight™ SoC-400 r3p2 Technical Reference Manual, Issue G >3. DDI 0461B (ID010111) - Arm® CoreSight™ Trace Memory Controller r0p1 Technical Reference Manual, Issue B >4. DDI 0314H - Arm® CoreSight™ Components Technical Reference Manual, Issue H >5. DDI 0403D (ID100710) - Arm®v7-M Architecture Reference Manual, Issue E.b >6. DDI 0494-2a (ID062813) - Arm® CoreSight™ ETM™-M7 r0p1 Technical Reference Manual, Issue D ### 1.2.2 时钟域与电源域 上述Trace电路原理上与SWD/JTAG的最大区别是,**需要手动初始化它才可以使用**。我们使能它之前需要再了解它的Power Domain和Clock Domain。 ![rm0433_pwr_diagram.png](https://oss-club.rt-thread.org/uploads/20220816/3d4d56d9df1b73e65e99a4aecb01b2dd.png.webp "rm0433_pwr_diagram.png") 可以看见,D1 电源域覆盖了Trace全程,所以可以忽略这部分的初始化,除非有在shutdown模式时还要Trace的需求。
![rm0433_clk_diagram.png](https://oss-club.rt-thread.org/uploads/20220816/7d8956e49cfe2c543ff2777ead0cf9ef.png.webp "rm0433_clk_diagram.png") 时钟域也是如此,但我们需要关注:rcc_c_ck时钟、TRACECLK。这里给个我浅显的理解:**CPU作为指令流的生产者,设计原理上它不会停止,作为指令流的接收者,受限于【带宽】,同时需要结合Trace粒度需求,给出合适的时钟搭配。**
例如,多数高速MCU平台下,如果想要每个指令都捕捉到,就需要给CPU降速运行,如果需要全速运行,Cortex-M7可以实现一定限度的Trigger-Buffered Stream,取决于厂商平台为这部分预留的SRAM大小。 Notice:【带宽】这里的制约条件: - J-Trace 的最高Stream Trace clock。 - Trace IO 信号翻转能力,STM32H7 上限是133Mhz。 ## 1.3 手动配置时钟 根据前面列举的条件,我们可以尝试计算出适合ART-PI能被Trace住的最高主频参数: ``` 预定的要求: 1. 跑满 Trace IO 翻转速率。 2. 尽可能CPU频率更高。 使用 cubeMX 辅助调整时钟树: - TraceCLK 分频到最高 133Mhz。 - CPU 主频为TraceCLK 3倍频,即400Mhz。 ``` Notice: CPU时钟实际为TraceCLK的6倍,TraceCLK由于TPIU机制(DDR),输出66.6Mhz频率。 得出以下时钟树: ![config_clock.png](https://oss-club.rt-thread.org/uploads/20220816/f400f156ab045f97b24423925793af4d.png.webp "config_clock.png") 图中的时钟树配置,应当用在被调试的工程中去。 到这一步之前,我们都在讲实现原理,可能之前没有接触过的同学此时已经云里雾里了,这里做下本章的总结:**使用Trace之前,需要初始化Trace通路上的一切{时钟、电源域、信号通路、IO}。** # 2. Ozone工程准备 ## 2.1 创建具备Stream Trace功能的Ozone工程 可以根据上述的Demo,基于它作为模板,简单搭建Ozone工程。 ### 2.1.1 创建Ozone工程 需要先理解Ozone是个什么类型的软件: > Ozone只需要编译产物就可以支持图形界面的调试,不依赖工具链,具备完善的调试交互体验。 选用Ozone的原因: - 只要是Jlink就能使用。 - 去IDE化,不依赖IDE环境。 - Ozone能够发挥J-Trace优势。 我们装好Ozone之后就直接打开使用,可以使用project wizard辅助创建一个工程,这步也可以跟着demo做。 ![ozone_wizard1.png](https://oss-club.rt-thread.org/uploads/20220816/9e3e625b39887a853184c71e2d3250ea.png "ozone_wizard1.png") 添加了对应MCU的SVD文件,方便手动访问完整的外设寄存器,如果没有也可跳过。 ![ozone_wizard2.png](https://oss-club.rt-thread.org/uploads/20220816/a962f6dbbe5ef84e670c591cca83542e.png "ozone_wizard2.png") 添加Jlink连接方式,这步也可以之后做。 ![ozone_wizard3.png](https://oss-club.rt-thread.org/uploads/20220816/01aae3906e9a2b6aec12a9730af91fd6.png "ozone_wizard3.png") 添加.axf、.elf等对应IDE产物文件,如果只有.bin,提供ROM偏移量,则可以基于disassemby的调试。 ![ozone_prj.png](https://oss-club.rt-thread.org/uploads/20220816/a0d2ca6e322911710dd81fdf499bdebb.png "ozone_prj.png") Notice: 如果顺利检索elf文件,则可以通过elf解析到的路径打开对应的源文件。 首次使用Ozone可以先不打开Trace,先熟悉各类调试窗口、按钮和工具。 由于Ozone支持启动前后各阶段的弱函数,可以在一些特殊启动场景,例如:debug on RAM / debug after bootloader 这些,可以实现对应阶段的弱函数,手动干预MCU的运行。 Notice: 有关Ozone的深入使用,请务必参考[《Ozone_UM08025》.pdf] ### 2.1.2 配置JlinkScript 之前谈到,Trace需要手动初始化。我们当然可以在芯片初始化阶段,将Trace相关的参数全部初始化完毕,Ozone在线调试时,只有在Trace模块初始化之后的指令流才能被抓住,这样做是没有问题的。 Segger推荐了第二种做法,即利用Jlink自动化脚本,在每次需要Trace时,例如每次Halt CPU之后,jlink会通过SWD直接访问外设寄存器,并写入对应配置。所以在ART-PI的jdebug工程中,通过实现`BeforeTargetConnect()`函数的方式,在每次连接MCU时配置好Trace功能: ```C void BeforeTargetConnect (void) { // // Trace pin init is done by J-Link script file as J-Link script files are IDE independent // Project.SetJLinkScript("$(ProjectDir)/Ozone/ST_STM32H750_400Mhz_Traceconfig.JLinkScript"); } ``` 对于ART-PI,我们要在jlinkscript脚本中实现: - GPIO初始化为Trace Pin复用,并配置好合适的IO推力。 - MCUDBG寄存器开启D1DBGCKEN/D3DBGCKEN时钟。 参考资源: - 可以参考segger官方测试小板[Tracing_on_ST_STM32F407],这个例程提供了jlinkscript脚本,如果要适配自己的平台,这部分的内容需要仔细揣摩。 - 也可以参考segger官方的[STM32H743_Trace_Demo],但是这个例程对jlinkscript脚本进行了编译,变成了pex格式,反而没有太多参考价值。 这里也给出我自己按照上述流程思路,独立写好的jlinkscript脚本,实测比较稳定: ```C /********************************************************************* File : ST_STM32H750_400Mhz_Traceconfig.JLinkScript Author : stackryan (yuanjyjyj@outlook.com) Purpose : Examplescript to modify TracePortWidth and Pin init Literature: [1] J-Link User Guide Additional information: For more information about public functions that can be implemented in order to customize J-Link actions, please refer to [1] */ /********************************************************************* * * ConfigTargetSettings * * Function description * Called before InitTarget(). Mainly used to set some global DLL variables to customize the * normal connect procedure. For ARM CoreSight devices this may be specifying the base * address of some CoreSight components (ETM, …) that cannot be auto-detected by J-Link * due to erroneous ROM tables etc. May also be used to specify the device name in case * debugger does not pass it to the DLL. * * Notes * (1) May not, under absolutely NO circumstances, call any API functions that perform target communication. * (2) Should only set some global DLL variables * * Return value * >= 0 O.K. * < 0 Error * -1 Unspecified error */ int ConfigTargetSettings(void) { // // Enable erase for all flash banks (e.g. QSPI) // JLINK_SYS_Report("-ConfigSettings.-"); JLINK_ExecCommand("CORESIGHT_SetCSTFBaseAddr = 0xE00F3000 ForceUnlock = 1 APIndex = 2"); JLINK_ExecCommand("CORESIGHT_SetTPIUBaseAddr = 0xE00F5000 ForceUnlock = 1 APIndex = 2"); JLINK_ExecCommand("CORESIGHT_SetTMCBaseAddr = 0xE00F4000 ForceUnlock = 1 APIndex = 2"); return 0; } /********************************************************************* * * OnTraceStart() * * Function description * If present, called right before trace is started. * Used to initialize MCU specific trace related things like configuring the trace pins for alternate function. * * Return value * >= 0: O.K. * < 0: Error * * Notes * (1) May use high-level API functions like JLINK_MEM_ etc. * (2) Should not call JLINK_TARGET_Halt(). Can rely on target being halted when entering this function */ int OnTraceStart(void) { U32 RCC_AHB4ENR_Addr; U32 GPIOE_MODER_Addr; U32 GPIOE_PUPDR_Addr; U32 GPIOE_OSPEEDR_Addr; U32 GPIOE_AFRL_Addr; U32 GPIOG_MODER_Addr; U32 GPIOG_PUPDR_Addr; U32 GPIOG_OSPEEDR_Addr; U32 GPIOG_AFRH_Addr; U32 DBGMCU_CR_Addr; U32 iTCLK; U32 iTD0; U32 iTD1; U32 iTD2; U32 iTD3; U32 EdgeTCLK; U32 EdgeTD; U32 v; U32 PortWidth; // // Adjust sampling point of trace pin (Optional: not needed for this cpu) // //JLINK_ExecCommand("TraceSampleAdjust TD=2000"); // // Set Trace Portwidth(Optional): Default 4 Pin Trace, other possibilities: 1, 2, 4 // //JLINK_TRACE_PortWidth = 4; // // RCC_AHB4ENR_Addr 0x580244E0 Periphal clock register // GPIOE_MODER: 0x58021000 GPIO Port mode register // GPIOE_PUPDR: 0x5802100C GPIO Pullup/Puldown register // GPIOE_OSPEEDR: 0x58021008 GPIO output speed register // GPIOE_AFRL: 0x58021020 GPIO Alternate function low register // DBGMCU_CR: 0x5C001004 Debug MCU register // // PE2 => TCLK // PG13 => TD0 // PG14 => TD1 // PE5 => TD2 // PE6 => TD3 // // // Init register addresses // JLINK_SYS_Report("Start: Initializing trace pins."); RCC_AHB4ENR_Addr = 0x580244E0; GPIOE_MODER_Addr = 0x58021000; GPIOE_PUPDR_Addr = 0x5802100C; GPIOE_OSPEEDR_Addr = 0x58021008; GPIOE_AFRL_Addr = 0x58021020; GPIOG_MODER_Addr = 0x58021800; GPIOG_PUPDR_Addr = 0x5802180C; GPIOG_OSPEEDR_Addr = 0x58021808; GPIOG_AFRH_Addr = 0x58021824; DBGMCU_CR_Addr = 0x5C001004; iTCLK = 2; iTD0 = 13; iTD1 = 14; iTD2 = 5; iTD3 = 6; PortWidth = JLINK_TRACE_PortWidth; // // Set drivestrength // 0: Low speed // 1: Medium speed // 2: High speed // 3: Very high speed // EdgeTCLK = 3; EdgeTD = 3; // // Init pins // v = JLINK_MEM_ReadU32(RCC_AHB4ENR_Addr); JLINK_MEM_WriteU32(RCC_AHB4ENR_Addr, v | 1 << 6); // Enable clock for GPIOG v = JLINK_MEM_ReadU32(RCC_AHB4ENR_Addr); JLINK_MEM_WriteU32(RCC_AHB4ENR_Addr, v | 1 << 4); // Enable clock for GPIOE // // TCLK init // v = JLINK_MEM_ReadU32(GPIOE_MODER_Addr); v &= ~(3 << (2 * iTCLK)); // Mask Mode register v |= (2 << (2 * iTCLK)); // Set alt function mode JLINK_MEM_WriteU32(GPIOE_MODER_Addr, v); v = JLINK_MEM_ReadU32(GPIOE_PUPDR_Addr); v &= ~(3 << (2 * iTCLK)); // Mask PUP register v |= (1 << (2 * iTCLK)); // Set PUP register (Pullup) JLINK_MEM_WriteU32(GPIOE_PUPDR_Addr, v); v = JLINK_MEM_ReadU32(GPIOE_OSPEEDR_Addr); v &= ~(3 << (2 * iTCLK)); // Mask OSPEED register v |= (EdgeTCLK << (2 * iTCLK)); // Set OSPEED register (very high speed) JLINK_MEM_WriteU32(GPIOE_OSPEEDR_Addr, v); v = JLINK_MEM_ReadU32(GPIOE_AFRL_Addr); v &= ~(15 << (4 * iTCLK)); // Select alt func 0 JLINK_MEM_WriteU32(GPIOE_AFRL_Addr, v); // // TD0 init // v = JLINK_MEM_ReadU32(GPIOG_MODER_Addr); v &= ~(3 << (2 * iTD0)); // Mask Mode register v |= (2 << (2 * iTD0)); // Set alt function mode JLINK_MEM_WriteU32(GPIOG_MODER_Addr, v); v = JLINK_MEM_ReadU32(GPIOG_PUPDR_Addr); v &= ~(3 << (2 * iTD0)); // Mask PUP register v |= (1 << (2 * iTD0)); // Set PUP register (Pullup) JLINK_MEM_WriteU32(GPIOG_PUPDR_Addr, v); v = JLINK_MEM_ReadU32(GPIOG_OSPEEDR_Addr); v &= ~(3 << (2 * iTD0)); // Mask OSPEED register v |= (EdgeTD << (2 * iTD0)); // Set OSPEED register (very high speed) JLINK_MEM_WriteU32(GPIOG_OSPEEDR_Addr, v); v = JLINK_MEM_ReadU32(GPIOG_AFRH_Addr); v &= ~(15 << (4 * (iTD0 - 8))); // Select alt func 0 JLINK_MEM_WriteU32(GPIOG_AFRH_Addr, v); // // TD1 init // if (PortWidth > 1) { v = JLINK_MEM_ReadU32(GPIOG_MODER_Addr); v &= ~(3 << (2 * iTD1)); // Mask Mode register v |= (2 << (2 * iTD1)); // Set alt function mode JLINK_MEM_WriteU32(GPIOG_MODER_Addr, v); v = JLINK_MEM_ReadU32(GPIOG_PUPDR_Addr); v &= ~(3 << (2 * iTD1)); // Mask PUP register v |= (1 << (2 * iTD1)); // Set PUP register (Pullup) JLINK_MEM_WriteU32(GPIOG_PUPDR_Addr, v); v = JLINK_MEM_ReadU32(GPIOG_OSPEEDR_Addr); v &= ~(3 << (2 * iTD1)); // Mask OSPEED register v |= (EdgeTD << (2 * iTD1)); // Set OSPEED register (very high speed) JLINK_MEM_WriteU32(GPIOG_OSPEEDR_Addr, v); v = JLINK_MEM_ReadU32(GPIOG_AFRH_Addr); v &= ~(15 << (4 * (iTD1 - 8))); // Select alt func 0 JLINK_MEM_WriteU32(GPIOG_AFRH_Addr, v); } // // TD2 & TD3 init // if (PortWidth > 2) { // // TD2 init // v = JLINK_MEM_ReadU32(GPIOE_MODER_Addr); v &= ~(3 << (2 * iTD2)); // Mask Mode register v |= (2 << (2 * iTD2)); // Set alt function mode JLINK_MEM_WriteU32(GPIOE_MODER_Addr, v); v = JLINK_MEM_ReadU32(GPIOE_PUPDR_Addr); v &= ~(3 << (2 * iTD2)); // Mask PUP register v |= (1 << (2 * iTD2)); // Set PUP register (Pullup) JLINK_MEM_WriteU32(GPIOE_PUPDR_Addr, v); v = JLINK_MEM_ReadU32(GPIOE_OSPEEDR_Addr); v &= ~(3 << (2 * iTD2)); // Mask OSPEED register v |= (EdgeTD << (2 * iTD2)); // Set OSPEED register (very high speed) JLINK_MEM_WriteU32(GPIOE_OSPEEDR_Addr, v); v = JLINK_MEM_ReadU32(GPIOE_AFRL_Addr); v &= ~(15 << (4 * iTD2)); // Select alt func 0 JLINK_MEM_WriteU32(GPIOE_AFRL_Addr, v); // // TD3 init // v = JLINK_MEM_ReadU32(GPIOE_MODER_Addr); v &= ~(3 << (2 * iTD3)); // Mask Mode register v |= (2 << (2 * iTD3)); // Set alt function mode JLINK_MEM_WriteU32(GPIOE_MODER_Addr, v); v = JLINK_MEM_ReadU32(GPIOE_PUPDR_Addr); v &= ~(3 << (2 * iTD3)); // Mask PUP register v |= (1 << (2 * iTD3)); // Set PUP register (Pullup) JLINK_MEM_WriteU32(GPIOE_PUPDR_Addr, v); v = JLINK_MEM_ReadU32(GPIOE_OSPEEDR_Addr); v &= ~(3 << (2 * iTD3)); // Mask OSPEED register v |= (EdgeTD << (2 * iTD3)); // Set OSPEED register (very high speed) JLINK_MEM_WriteU32(GPIOE_OSPEEDR_Addr, v); v = JLINK_MEM_ReadU32(GPIOE_AFRL_Addr); v &= ~(15 << (4 * iTD3)); // Select alt func 0 JLINK_MEM_WriteU32(GPIOE_AFRL_Addr, v); } // // Config DBUGMCU // v = JLINK_MEM_ReadU32(DBGMCU_CR_Addr); // Debug MCU enables traceclk (STM32H7 specific) v &= ~(1 << 20); // Mask Traceclk Register v |= (1 << 20); // Enable Traceclk v |= (1 << 21); // D1DBGCKEN v |= (1 << 22); // D3DBGCKEN JLINK_MEM_WriteU32(DBGMCU_CR_Addr, v); JLINK_SYS_Report("End: Initializing trace pins."); return 0; } ``` ### 2.1.3 实现 Stream Trace 按照上述配置并刷新好工程之后,可以尝试打开Trace功能,并进入调试状态,在点击halt或者任意step按键后,Trace信号就会被正常开启,此时逻辑分析仪上可以抓到正常的Trace波形了。 ![logic_signal.jpg](https://oss-club.rt-thread.org/uploads/20220816/cd30b4205ebe533bb7f18bed7a169bd2.jpg "logic_signal.jpg") 这里逻辑分析仪选用了4通道数量,采样频率400Mhz,TD3并未采集,不影响预期效果。 此时,Ozone上可以打开Instruction Trace窗口,并且能够看见海量指令流的记录了。在非侵入式调试下,能够快速回溯历史指令流,找到死机的原因。 ![ozone_inst_trace.png](https://oss-club.rt-thread.org/uploads/20220816/520f41f641c662a2476b9ac78ab2d23f.png "ozone_inst_trace.png") 通过code profile窗口可以看见,对于只有点灯任务的ART-PI来说,系统资源主要都在idle线程上运行着。通过较长时间的挂测,可以统计各函数体的实时代码覆盖率和指令覆盖率。这项功能在需要优化的业务中会非常实用,能够轻松看出哪些资源需要被优化。 ![ozone_code_profile.png](https://oss-club.rt-thread.org/uploads/20220816/104e94caf733e13670e27ea470777cea.png "ozone_code_profile.png") # 3. 总结 使用Ozone配合J-Trace完整体验stream trace的流程,相比基于IDE的调试是复杂些的,但它提供了工程师以更全的视角,更有说服力的去解决剩下5%的问题,用好它,能够提供远超调试器本身的价值。 当然,相比更贵的调试系统Lauterbach,J-Trace还不够与其相提并论,这款产品更像是面向嵌入式开发者的、灵活的解决方案。如果根据自己的产品需求,能够设计配套的工具脚本,实现更简便的调试闭环,那么这把利器也会跟着越磨越快。 下篇,我将会代入更多的调试视角,将这个话题进一步完善,希望这次不会鸽太久。。 [上篇]:https://club.rt-thread.org/ask/article/bbcce3088af30a9b.html [J-Trace入门系列:1)感动人心的功能与更感动人心的售价]:https://club.rt-thread.org/ask/article/bbcce3088af30a9b.html [STM32H743_Trace_Demo]:https://wiki.segger.com/STM32H7 [Tracing_on_ST_STM32F407]:https://wiki.segger.com/Tracing_on_ST_STM32F407_(SEGGER_Cortex-M_Trace_Reference_Board) [《Ozone_UM08025》.pdf]:https://www.segger.com/downloads/jlink/UM08025_Ozone.pdf
7
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
StackYuan
这家伙很懒,什么也没写!
文章
3
回答
223
被采纳
38
关注TA
发私信
相关文章
1
使用RT_Thread studio的j-link下载程序,出现无法识别装置
2
下载程序时弹出j-link窗口,点了yes之后结果是无法检测到j-link
3
j-link问题,下载程序时,弹出窗口并且说无法检测到程序
4
STM32开发板ST-Link转J-Link下载报错:hex文件未生成
5
RT-Thread Studio目录下有2个版本J-LINK驱动怎么设置
6
关于野火RT1052 pro板 RT-Thread
7
RT-thread studio如何添加J-link的外部flash算法?
8
j-link下载无反应
9
RT-Studio J-LINK debug 没有显示复位按钮
10
j-link无法仿真
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
线程
RT-Thread Nano
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
SFUD
msh
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1443
个答案
289
次被采纳
张世争
807
个答案
174
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
4
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
1
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部