3. 硬件调试接口:JTAG、SWD、CJTAG原理与对比
调试接口,说白了,就是芯片和我们开发工具沟通的物理通道。你写好的代码要下载进去,芯片跑到一半要停下来给你看寄存器状态,全得靠它。
早期江湖上基本是JTAG一统天下。后来ARM公司嫌JTAG引脚太多,搞了个SWD出来,省了两根线。再后来,有些厂家觉得“我既要SWD的省引脚,又想兼容JTAG的菊花链”,于是CJTAG就登场了。
我个人习惯把这三者的关系想象成:JTAG是标准VGA线,SWD是HDMI精简版,CJTAG则是那种“你插Type-C也能用、插老USB也能用”的转接头。
3.1 JTAG——老祖宗级的边界扫描协议
JTAG(Joint Test Action Group)最初是为了测试PCB板级连接而生的。它定义了一套边界扫描(Boundary Scan)机制,后来大家发现这东西不仅能测板子,还能用来调试CPU,于是就成了事实标准。
3.1.1 核心信号
| 信号 | 方向 | 作用 |
|---|---|---|
| TMS | 输出 | 模式选择——决定TAP状态机下一步去哪 |
| TCK | 输出 | 时钟——所有操作在它的上升沿或下降沿触发 |
| TDI | 输出 | 数据输入——把指令或数据串行送进芯片 |
| TDO | 输入 | 数据输出——芯片把结果串行吐出来 |
| nTRST(可选) | 输出 | 复位TAP控制器,不接的话可以用TMS硬复位 |
这里要记住一个关键点:JTAG是一个串行协议。你往里写数据,是1位1位往里塞的。TDI和TDO可以同时操作,相当于一条流水线。
3.1.2 TAP状态机
TAP(Test Access Port)是JTAG的大脑。它本质上是个16状态的有限状态机,通过TMS在TCK边沿上的电平组合来驱动状态跳转。
我见过有人调试JTAG连不上,卡了大半天,结果发现是TMS时序搞错了。TMS必须在TCK的上升沿之前稳定下来,否则状态机就跳到了不知道哪个州(State,谐音梗)。
核心口诀:JTAG调试的基本流程就是“先进入Shift-IR装指令 → 进入Shift-DR喂数据 → 回到Run-Test/Idle等结果 → 通过Shift-DR把TDO读回来”。
3.1.3 菊花链
JTAG一个很酷的特性是菊花链(Daisy Chain)。你可以把多个支持JTAG的芯片串在一起,只用一组JTAG接口就能访问所有芯片。
- 怎么串? 把上一颗芯片的TDO接到下一颗芯片的TDI。
- 怎么区分? 通过TMS控制TAP状态机,让不关心的芯片进入Bypass模式(只用1比特延迟就传过去),只让目标芯片进入数据模式。
我曾经在一款服务器主板上调试BMC和CPU之间的链路,板上串了5颗JTAG器件。最开始菊花链顺序我搞反了,结果TDI和TDO数据死活对不上。后来老老实实拿示波器看TDO信号,发现第一颗芯片的TDO根本什么都没吐,这才意识到链子接错了。
小技巧:调试菊花链时,先让所有芯片进Bypass,看看TDO能不能把TDI的数据延迟N个时钟后完整透传出来。能透传,说明链子物理上通了。
3.2 SWD——ARM阵营的精简革命
SWD(Serial Wire Debug)是ARM公司推出的调试接口。它只用了两根线,就能完成JTAG四根线才能干的事。
3.2.1 为什么只需两根线?
SWD把时钟和数据分开,但把TDI和TDO合并成了双向的SWDIO。这样省掉了一根线。同时,SWD也用SWCLK做时钟。状态机控制也编进了数据包里,不再需要独立的TMS。
| 信号 | 方向 | 作用 |
|---|---|---|
| SWCLK | 输出 | 时钟,一般4~10MHz |
| SWDIO | 双向 | 数据和控制复用 |
3.2.2 包格式
SWD的通信是有固定帧格式的。你对SWDIO发一串比特,格式如下:
起始位(1) + APnDP(1) + RnW(1) + 地址A[2:3](2) + 奇偶校验(1) + 停止位(1) + park位(1)
—— 主机发完这8位后,切换方向,等待目标返回 确认位(3) + 数据(32) + 奇偶校验(1)
为什么这么复杂?因为只有两根线,所有控制信息、地址信息、读写标志全得塞进一个串行序列里。
注意:SWDIO是双向线。主机发完请求包后,必须把IO口从输出切回输入,然后等目标返回响应。这个切换时机如果没处理好,轻则通信错乱,重则烧坏IO口——因为两边同时输出,就会VCC对GND直通。
3.2.3 速度与抗干扰
SWD的典型速率能跑到4~10MHz,比JTAG的10~50MHz低一些,但胜在引脚少。实际调试中,SWDIO线的容性负载比JTAG的独立TDI+TDO要敏感一些,线长了容易丢包。
我个人建议:SWD走线别超过15cm。如果一定要长线传输,考虑加个电平转换/缓冲芯片,或者降低SWCLK频率到2MHz以下。
3.3 CJTAG——兼容与切换的艺术
CJTAG(Compact JTAG)也叫SWJ-DP(Serial Wire JTAG Debug Port)。它是ARM的一种混合接口,物理上同时支持JTAG和SWD。上电时默认工作在JTAG模式,调试器通过一段特定的序列,就能让芯片切到SWD模式。
3.3.1 切换序列
CJTAG接口检测到SWD切换序列后,会把原本的JTAG引脚重新配置:
- TCK → SWCLK(不变)
- TMS → SWDIO(TMS被重映射成SWDIO)
- TDI、TDO、nTRST 在这个模式下就不用了。
切换序列很简单(我凭记忆写一个典型的):
// 伪代码,来自ARM CoreSight架构
// 先让TMS输出至少50个周期的1(确保回到Test-Logic-Reset)
for (i = 0; i < 50; i++) { TCK高 → TMS=1 → TCK低 }
// 然后输出SWD切换序列: 0b01111100 (注意LSB先发)
send_bits(0b01111100, 8);
// 等待目标返回确认
response = read_3_bits();
if (response == 0b001) // 确认
// 现在CJTAG进入SWD模式
切换成功后,SWCLK和SWDIO就接管了。你不需要重新接线,调试工具也没变,只是协议变了。
这个机制非常实用:同一套硬件调试器(比如J-Link、ST-Link)在CJTAG接口上,既能以JTAG方式连接传统ARM7/9,也能以SWD方式连接Cortex-M0。你不需要换电路板,换根线,只需要调试器发一段序列。
3.4 三者的横向对比
| 维度 | JTAG | SWD | CJTAG |
|---|---|---|---|
| 引脚数 | 4~5 | 2 | 4-5(但可切换) |
| 最大速率 | 通常10~50MHz | 通常4~10MHz | 取决于当前模式 |
| 菊花链 | 原生支持 | 不支持 | 仅JTAG模式下支持 |
| 调试带宽 | 高(TDI/TDO并行) | 中(半双工串行) | 同SWD或JTAG |
| 设计复杂度 | 中 | 低 | 中高 |
| 典型应用 | CPU、FPGA、板级测试 | Cortex-M全系列 | Cortex-A/R/M系列,一板多用 |
| 引脚成本 | 较高 | 最低 | 适中 |
3.5 如何选择?
- 如果你用的是MCU(Cortex-M0/3/4/7等),直接用SWD。省引脚,够用,成本低。
- 如果你调试的是应用处理器(Cortex-A系列),或者需要同时调试多核、FPGA与CPU协同,选CJTAG,预留JTAG接口,实际用SWD模式。
- 如果你在做板级测试(比如验证PCB上所有BGA焊点是否连接正常),那JTAG的边界扫描功能是无可替代的。SWD干不了这个。
我一个常用的设计惯例:在原理图上把JTAG的TMS和TCK与SWDIO、SWCLK合并成一个信号网络。板子上保留5针排针(SWCLK、SWDIO、GND、Vref、nSRST)。这样同一个连接器,既支持纯SWD调试器,也支持CJTAG调试器在JTAG模式下连接。多出来的TDI/TDO用0欧电阻可选的接到排针或者不接。
3.6 知识体系框架
下面这张图把三者的全貌串起来了。你可以看到它们之间的切换关系、物理引脚映射以及典型的调试器协议栈。
再强调一次:实物连线时,SWDIO不能另外接上拉或下拉电阻,因为它双向驱动。接了可能会把IO电平钳住,导致通信失败。JTAG的TDI/TDO则可以加弱上拉保证空闲电平。
好了,以上就是JTAG、SWD、CJTAG的原理和对比。你在实际项目中,根据板子的管脚数量和调试需求来做选择就行。没有的好坏,只有合不合适的方案。