1. 课程导入
各位同学,咱们今天聊聊JTAG。说实话,这玩意儿在嵌入式开发里就像医生的听诊器——你不会用,项目出了问题就只能干瞪眼。
JTAG的全称是Joint Test Action Group,也就是联合测试行动组。名字挺唬人,但说白了,它最初就是为了解决电路板测试问题而生的。1985年,一群欧洲的半导体公司凑在一起,想搞一个标准化的边界扫描测试方法。到了1990年,这个标准被IEEE采纳,编号1149.1。
嗯,这里要注意:JTAG最初的目标是测试,不是调试。但后来大家发现,这套机制用来调试芯片,简直太合适了。
1.1 JTAG协议起源
为什么会有JTAG?我给大家讲个故事。
80年代的电路板,元件越来越多,引脚越来越密。传统的飞针测试和针床测试,已经搞不定了。你想啊,一个BGA封装的芯片,几百个引脚全藏在肚子底下,测试探针根本碰不到。
这时候,有人提出了一个天才的想法:能不能在芯片内部做一套"虚拟探针"? 通过芯片自己的引脚,从内部读取其他引脚的状态。这就是边界扫描的雏形。
JTAG标准定义了四个必要的信号线:
| 信号 | 全称 | 方向 | 作用 |
|---|---|---|---|
| TDI | Test Data In | 输入 | 数据从调试器进入芯片 |
| TDO | Test Data Out | 输出 | 数据从芯片返回调试器 |
| TCK | Test Clock | 输入 | 同步时钟,所有操作跟着它走 |
| TMS | Test Mode Select | 输入 | 控制TAP状态机跳转 |
还有一个可选的TRST(Test Reset),用来异步复位TAP控制器。不过我个人习惯尽量不用它,靠TMS走复位序列更可靠。
1.2 TAP控制器状态机
TAP(Test Access Port)控制器,是JTAG的核心大脑。它是一个16状态的有限状态机,所有操作都通过TCK上升沿和TMS电平来驱动。
我刚开始学的时候,觉得这16个状态太复杂了。后来发现,你只需要记住几个关键状态:
- Test-Logic-Reset:上电后的默认状态,TMS保持高电平5个TCK周期就能进入
- Run-Test/Idle:空闲状态,啥也不干,等着你发指令
- Shift-DR:移位数据寄存器,往芯片里写数据或读数据
- Shift-IR:移位指令寄存器,告诉芯片你要干啥
- Update-DR:更新数据寄存器,把移位完的数据真正生效
下面这张图,是我自己画的TAP状态机简化版,大家先有个直观印象:
你想想看,这个状态机是怎么工作的?每次TCK上升沿,TMS的电平决定是留在当前状态还是跳到下一个。说白了,就是一根线(TMS)配合时钟(TCK),控制整个芯片的测试逻辑。
1.3 边界扫描与调试功能
边界扫描(Boundary Scan)是JTAG最基础的功能。每个芯片引脚旁边,都有一个边界扫描单元(BSC),它们串联成一个移位寄存器链。
我给大家拆解一下边界扫描的三种模式:
- EXTEST(外部测试):通过边界扫描单元,给芯片引脚施加测试向量,检测板级焊接和走线
- INTEST(内部测试):测试芯片内部逻辑,不依赖外部激励
- SAMPLE/PRELOAD:在不影响芯片正常工作的情况下,抓取引脚状态快照
调试功能是怎么来的?其实很简单。芯片厂商在CPU核内部,加入了调试专用的硬件模块,比如ARM的CoreSight、RISC-V的Debug Module。这些模块通过JTAG接口暴露出来,调试器就能:
- 暂停/恢复CPU:通过调试请求信号,让CPU停在某个指令边界
- 读写寄存器:通过调试总线,访问通用寄存器和特殊功能寄存器
- 读写内存:通过调试端口,直接操作内存空间
- 设置断点/观察点:硬件断点利用调试比较器,软件断点替换指令
- 单步执行:执行一条指令后自动暂停
1.4 调试器硬件架构
一个典型的JTAG调试器,内部长什么样?我画个框图给大家看:
调试器的核心,其实就是一个协议转换器。主机通过USB发命令,调试器主控芯片(比如FT2232)把这些命令转成JTAG时序,再通过电平转换电路适配目标板的电压(1.8V、3.3V或5V)。
我个人比较喜欢用FT2232方案的调试器,因为OpenOCD对它的支持最成熟,而且便宜。J-Link虽然快,但贵,而且协议是闭源的。