FTDI JTAG 数据传输格式与 SCAN 命令完整规范
📋 文档概述
- 驱动文件:src/jtag/drivers/openjtag.c
- 适配变体:Standard FTDI (libftdi)
- 核心目的:定义 ftdi_write_data()/ftdi_read_data() 数据格式,规范 SCAN 命令在 IR/DR 切换中的完整使用流程
- 文档版本:1.2(2025-01-22)
目录
- 整体数据流
- 核心命令格式
- SCAN 命令完整使用流程
- 数据传输与解析
- 调试与问题排查
- 核心要点速查
1. 整体数据流
1.1 数据流向架构
1.2 缓冲区基础格式
| 缓冲区类型 | 格式 | 核心特点 |
|---|
| TX 缓冲区 | [命令1][数据1][命令2][数据2]... | 命令+数据成对出现(单字节命令除外) |
| RX 缓冲区 | [数据1][数据2]...[数据N] | 仅包含数据,无命令字节 |
2. 核心命令格式
2.1 命令字节总览
| 命令类型 | 命令码 | 功能描述 | 数据字节 |
|---|
| SET_STATE | 0x01 | 设置 JTAG TAP 状态机 | 1 |
| SCAN | 0x06 | 传输 IR/DR 比特流(核心) | 1 |
| SPEED | 0x00 | 设置 JTAG 通信速率 | 1 |
| RESET (TRST) | 0x03 | 硬件复位 TAP 状态机 | 0 |
| RESET (SRST) | 0x54 | 系统复位控制 | 0 |
| RUNTEST | 0x07 | 设置空闲周期数 | 1 |
| MSB 模式 | 0x75 | 启用高位优先传输 | 0 |
2.2 SCAN 命令(0x06)- 核心指令
2.2.1 命令格式(8位)
| 位 7-5 | 位 4 | 位 3-0 | 说明 |
|---|
| 位数编码 | TMS | 0x06 | 固定格式,TMS控制状态退出 |
2.2.2 位数编码映射
| 编码值 | 有效位数 | 应用场景 | 示例命令 |
|---|
| 0 | 1 | 最后1位(收尾) | 0x16 |
| 1 | 2 | 最后2位(收尾) | 0x26 |
| 2 | 3 | 最后3位(收尾) | 0x96 |
| 3 | 4 | 最后4位(收尾) | 0x36 |
| 4 | 5 | 最后5位(收尾) | 0x56 |
| 5 | 6 | 最后6位(收尾) | 0x56 |
| 6 | 7 | 最后7位(收尾) | 0x66 |
| 7 | 8 | 中间8位(继续传输) | 0xE6 |
2.2.3 TMS 位规则
0:中间块,保持 SHIFT 状态,继续传输1:最后块,退出 SHIFT 状态,切换到 EXIT1
2.2.4 典型示例
| 场景 | 二进制 | 十六进制 | 说明 |
|---|
| DR 中间块(8位) | 1110 0110 | 0xE6 | TMS=0,继续传输 |
| IR 最后5位 | 0101 0110 | 0x56 | TMS=1,5位 IR 收尾 |
| DR 最后1位 | 0001 0110 | 0x16 | TMS=1,41位 DR 最后1位 |
2.3 SET_STATE 命令(0x01)
2.3.1 命令格式
| 位 7-4 | 位 3-0 | 说明 |
|---|
| 状态码 | 0x01 | 控制 TAP 状态机切换 |
2.3.2 核心状态码映射
| 状态名称 | 状态码 | 命令字节 | 用途 |
|---|
| TAP_RESET | 0 | 0x01 | 复位状态机 |
| TAP_IRSHIFT | 11 | 0xB1 | 进入 IR 移位模式 |
| TAP_IRUPDATE | 15 | 0xF1 | 使 IR 指令生效 |
| TAP_DRSHIFT | 4 | 0x41 | 进入 DR 移位模式 |
| TAP_DRUPDATE | 8 | 0x81 | 使 DR 数据生效/触发读取 |
2.4 SPEED 命令(0x00)
| 速度编码 | 频率 (kHz) | 命令字节 |
|---|
| 0 | 48000 | 0x00 |
| 2 | 24000 | 0x20 |
| 4 | 12000 | 0x40 |
| 6 | 6000 | 0x60 |
| 8 | 3000 | 0x80 |
| 10 | 1500 | 0xA0 |
| 12 | 750 | 0xC0 |
| 14 | 375 | 0xE0 |
3. SCAN 命令完整使用流程
3.1 通用准备阶段(必选)
| 步骤 | 操作 | TX 缓冲区数据 | 说明 |
|---|
| 1 | 复位 TAP 状态机 | 0x01 0x00 | 初始化状态机 |
| 2 | 设置通信速率 | 0x00 0x00 | 48MHz(可按需调整) |
| 3 | 启用 MSB 模式 | 0x75 | 高位优先传输 |
3.2 IR 切换 + SCAN 传输流程(定义操作类型)
目标:写入 DMI 指令(5位 IR,值为 0x04)
| 阶段 | 步骤 | 操作 | TX 缓冲区数据 | 关键说明 |
|---|
| 状态准备 | 4 | 切换到 IRSELECT | 0x91 0x00 | 进入 IR 选择阶段 |
| 5 | 切换到 IRCAPTURE | 0xA1 0x00 | 准备捕获 IR 数据 |
| 6 | 切换到 IRSHIFT | 0xB1 0x00 | 核心:进入 IR 移位模式 |
| SCAN 传输 | 7 | 发送 IR 数据 | 0x56 0x04 | 0x56=最后5位+TMS=1,0x04=DMI指令 |
| 状态收尾 | 8 | 切换到 IREXIT1 | 0xC1 0x00 | 退出 IR 移位模式 |
| 9 | 切换到 IRPAUSE | 0xD1 0x00 | 暂存 IR 数据 |
| 10 | 切换到 IRUPDATE | 0xF1 0x00 | 核心:使 IR 指令生效 |
| 验证(可选) | 11 | 读取 IR 返回值 | RX[0] = 0x04 | 右移对齐:0x04 >> (8-5) = 0x04 |
3.3 DR 切换 + SCAN 传输流程(执行具体操作)
目标:写入 DMI 寄存器(地址0x10,数据0x12345678,41位 DR)
| 阶段 | 步骤 | 操作 | TX 缓冲区数据 | 关键说明 |
|---|
| 状态准备 | 12 | 切换到 DRSELECT | 0x21 0x00 | 进入 DR 选择阶段 |
| 13 | 切换到 DRCAPTURE | 0x31 0x00 | 准备捕获 DR 数据 |
| 14 | 切换到 DRSHIFT | 0x41 0x00 | 核心:进入 DR 移位模式 |
| SCAN 传输 | 15 | DR 中间块1 | 0xE6 0x10 | 地址[7:0] = 0x10 |
| 16 | DR 中间块2 | 0xE6 0x00 | 地址[15:8] = 0x00 |
| 17 | DR 中间块3 | 0xE6 0x00 | 地址[23:16] = 0x00 |
| 18 | DR 中间块4 | 0xE6 0x21 | op=2(写)+地址[28:24] |
| 19 | DR 中间块5 | 0xE6 0x78 | 数据[7:0] = 0x78 |
| 20 | DR 中间块6 | 0xE6 0x56 | 数据[15:8] = 0x56 |
| 21 | DR 中间块7 | 0xE6 0x34 | 数据[23:16] = 0x34 |
| 22 | DR 中间块8 | 0xE6 0x12 | 数据[31:24] = 0x12 |
| 23 | DR 最后块 | 0x16 0x00 | 0x16=最后1位+TMS=1,exec=0 |
| 状态收尾 | 24 | 切换到 DREXIT1 | 0x51 0x00 | 退出 DR 移位模式 |
| 25 | 切换到 DRPAUSE | 0x61 0x00 | 暂存 DR 数据 |
| 26 | 切换到 DRUPDATE | 0x81 0x00 | 核心:完成寄存器写入 |
3.4 完整 TX 缓冲区示例(IR+DR 组合操作)
// 通用准备 0x01 0x00 // TAP_RESET 0x00 0x00 // SPEED=48MHz 0x75 // MSB 模式 // IR 切换 0x91 0x00 // IRSELECT 0xA1 0x00 // IRCAPTURE 0xB1 0x00 // IRSHIFT 0x56 0x04 // SCAN: IR最后5位 + DMI指令 0xC1 0x00 // IREXIT1 0xD1 0x00 // IRPAUSE 0xF1 0x00 // IRUPDATE // DR 切换 0x21 0x00 // DRSELECT 0x31 0x00 // DRCAPTURE 0x41 0x00 // DRSHIFT 0xE6 0x10 // SCAN: DR中间块1 0xE6 0x00 // SCAN: DR中间块2 0xE6 0x00 // SCAN: DR中间块3 0xE6 0x21 // SCAN: DR中间块4 0xE6 0x78 // SCAN: DR中间块5 0xE6 0x56 // SCAN: DR中间块6 0xE6 0x34 // SCAN: DR中间块7 0xE6 0x12 // SCAN: DR中间块8 0x16 0x00 // SCAN: DR最后1位 0x51 0x00 // DREXIT1 0x61 0x00 // DRPAUSE 0x81 0x00 // DRUPDATE
4. 数据传输与解析
4.1 发送数据(TX 缓冲区)
4.1.1 核心规则
- 命令与数据严格成对(单字节命令除外)
- SCAN 命令分块规则:
- 数据长度 >8 位:n个中间块(0xE6) + 1个最后块(按剩余位数编码)
- 数据长度 ≤8 位:直接使用最后块编码
- 所有数据均为 MSB 优先传输
4.2 接收数据(RX 缓冲区)
4.2.1 解析流程核心代码
staticintopenjtag_execute_tap_queue(void){// 1. 发送 TX 数据openjtag_buf_write(usb_tx_buf,usb_tx_buf_offs,&written);// 2. 接收 RX 数据openjtag_buf_read(usb_rx_buf,usb_tx_buf_offs,&usb_rx_buf_len);// 3. 解析 SCAN 数据(核心:右移对齐)while(res_count<openjtag_scan_result_count){len=openjtag_scan_result_buffer[res_count].bits;buffer=openjtag_scan_result_buffer[res_count].buffer;while(len>0){if(len<=8){// <8位数据:右移对齐(MSB→LSB)buffer[count]=usb_rx_buf[rx_offs]>>(8-len);len=0;}else{// ≥8位数据:直接读取buffer[count]=usb_rx_buf[rx_offs];len-=8;}rx_offs++;count++;}res_count++;}returnERROR_OK;}
4.2.2 右移对齐示例
| 有效位数 | 接收字节 | 右移量 | 计算过程 | 最终结果 |
|---|
| 3 | 0x1A | 5 | 0x1A >> 5 = 0x03 | 0x03 |
| 5 | 0xD6 | 3 | 0xD6 >> 3 = 0x1A | 0x1A |
| 1 | 0x80 | 7 | 0x80 >> 7 = 0x01 | 0x01 |
4.3 典型 RX 缓冲区示例(DMI 读取)
场景:读取地址0x10,返回数据0xDEADBEEF
| RX 偏移 | 内容 | 说明 |
|---|
| 0x00 | 0x21 | status=0 + op=1(读操作) |
| 0x01 | 0xEF | data[7:0] = 0xEF |
| 0x02 | 0xBE | data[15:8] = 0xBE |
| 0x03 | 0xAD | data[23:16] = 0xAD |
| 0x04 | 0xDE | data[31:24] = 0xDE |
| 0x05 | 0x00 | exec=0(最后1位,右移后=0) |
解析结果:0xDEADBEEF
5. 调试与问题排查
5.1 调试技巧
5.1.1 启用 USB 通信日志
#define_DEBUG_USB_COMMS_// 输出示例:// USB WRITE: 0xB1 0xD1 0x56 0x04 0x61 0x41 0xE6 0x10// USB READ : 0x21 0xEF 0xBE 0xAD 0xDE 0x00
5.1.2 缓冲区内容打印
// 打印 TX 缓冲区LOG_DEBUG("TX Buf len=%d",usb_tx_buf_offs);for(inti=0;i<usb_tx_buf_offs;i++){LOG_DEBUG("TX[%d]=0x%02X",i,usb_tx_buf[i]);}// 打印 RX 缓冲区LOG_DEBUG("RX Buf len=%d",usb_rx_buf_len);for(inti=0;i<usb_rx_buf_len;i++){LOG_DEBUG("RX[%d]=0x%02X",i,usb_rx_buf[i]);}
5.2 常见问题排查
| 问题现象 | 可能原因 | 解决方法 |
|---|
| SCAN 命令失效 | 未进入 SHIFT 状态 | 先发送 0xB1(IRSHIFT)/0x41(DRSHIFT) |
| 接收数据错误 | 未执行右移对齐 | 对<8位数据执行 >> (8-len) 操作 |
| 状态机卡死 | TMS 位未设为1 | 最后块必须设置 TMS=1 |
| 数据长度不符 | 分块规则错误 | >8位拆分为中间块+最后块 |
| IR 指令不生效 | 未执行 IRUPDATE | 发送 0xF1 命令使 IR 指令生效 |
6. 核心要点速查
6.1 SCAN 命令使用三原则
- 状态准备:必须先切换到 IRSHIFT/DRSHIFT 状态才能传输数据
- 分块传输:>8位数据拆分为中间块(0xE6)+ 最后块(按位数编码)
- 收尾标记:最后块必须设置 TMS=1,确保退出 SHIFT 状态
6.2 数据解析核心公式
解析后数据 = RX缓冲区字节 >> (8 - 有效位数) (仅适用于<8位的最后块)
6.3 关键状态切换节点
| 操作类型 | 核心状态命令 | 作用 |
|---|
| IR 生效 | 0xF1 (IRUPDATE) | 使 IR 指令生效 |
| DR 生效 | 0x81 (DRUPDATE) | 完成 DR 写入/触发读取 |
| 进入传输 | 0xB1/0x41 | 进入 IR/DR 移位模式 |
6.4 简化记忆口诀
先复位,调速程,MSB模式要开启 IR定操作,DR传数据 SHIFT状态发SCAN,TMS=1才收尾 UPDATE指令生效,右移对齐读数据