利用FTDI开发MPSSE协议

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

MPSSE 协议开发 JTAG 完整指南

概述

本文档详细说明如何使用 FTDI MPSSE (Multi-Protocol Synchronous Serial Engine) 协议开发 JTAG 调试器。

适用场景

  • 基于 FT2232H/FT4232H/FT232H 的 JTAG 调试器
  • 需要高性能 JTAG/SWD 通信
  • 跨平台兼容性要求高

协议特点

  • FTDI 官方标准协议,由芯片固件直接解析
  • 符合 IEEE 1149.1 JTAG 标准
  • 支持 JTAG 和 SWD 协议
  • 最高支持 30+ MHz 频率

目录

  1. MPSSE 基础
  2. 核心命令详解
  3. JTAG TAP 状态机
  4. 完整 JTAG 操作流程
  5. 代码示例
  6. 性能优化
  7. 调试技巧

1. MPSSE 基础

1.1 硬件要求

支持的 FTDI 芯片:

芯片型号MPSSE 引擎数最高频率端口数
FT2232C26 MHzA/B
FT2232H230 MHzA/B
FT4232H430 MHzA/B/C/D
FT232H130 MHz1

1.2 软件依赖

# 必需库
libusb-1.0 >= 1.0.16

# 可选库
libftdi1 >= 1.5  # 高级 API(推荐)

# 编译工具
autoconf >= 2.69
automake >= 1.14
pkg-config >= 0.23

1.3 初始化流程

#include <libusb.h>
#include <stdio.h>

#define VID_FTDI  0x0403
#define PID_FT2232H 0x6010

// MPSSE 请求码
#define SIO_RESET_REQUEST        0x00
#define SIO_SET_LATENCY_TIMER_REQUEST 0x09
#define SIO_SET_BITMODE_REQUEST  0x0B

#define BITMODE_MPSSE 0x02

int mpsse_init(struct libusb_context **ctx, struct libusb_device_handle **dev) {
    // 1. 初始化 libusb
    if (libusb_init(ctx) < 0) {
        fprintf(stderr, "Failed to init libusb\n");
        return -1;
    }
    
    // 2. 打开设备
    *dev = libusb_open_device_with_vid_pid(*ctx, VID_FTDI, PID_FT2232H);
    if (!*dev) {
        fprintf(stderr, "Device not found\n");
        return -1;
    }
    
    // 3. 声明接口(通道 0)
    if (libusb_claim_interface(*dev, 0) < 0) {
        fprintf(stderr, "Failed to claim interface\n");
        return -1;
    }
    
    // 4. 设置延迟定时器(降低 USB 延迟)
    libusb_control_transfer(*dev,
        LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
        SIO_SET_LATENCY_TIMER_REQUEST,
        0x02,  // 2ms
        0,
        NULL, 0, 1000);
    
    // 5. 复位设备
    libusb_control_transfer(*dev,
        LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
        SIO_RESET_REQUEST,
        SIO_RESET_PURGE_RX | SIO_RESET_PURGE_TX,
        0,
        NULL, 0, 1000);
    
    // 6. 设置 MPSSE 模式
    libusb_control_transfer(*dev,
        LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
        SIO_SET_BITMODE_REQUEST,
        BITMODE_MPSSE,  // 启用 MPSSE
        0,
        NULL, 0, 1000);
    
    return 0;
}

1.4 Mode 标志定义

// src/jtag/drivers/mpsse.h:26-31
#define POS_EDGE_OUT 0x00  // TCK 上升沿输出 TDI
#define NEG_EDGE_OUT 0x01  // TCK 下降沿输出 TDI
#define POS_EDGE_IN  0x00  // TCK 上升沿采样 TDO
#define NEG_EDGE_IN  0x04  // TCK 下降沿采样 TDO
#define MSB_FIRST    0x00  // 高位优先
#define LSB_FIRST    0x08  // 低位优先

// JTAG 标准模式组合
// src/jtag/drivers/ftdi.c:98
#define JTAG_MODE (LSB_FIRST | POS_EDGE_IN | NEG_EDGE_OUT)
// 解释:
// - LSB_FIRST:  JTAG 标准使用 LSB 优先传输
// - POS_EDGE_IN:  在 TCK 上升沿采样 TDO
// - NEG_EDGE_OUT: 在 TCK 下降沿输出 TDI

// SWD 模式
#define SWD_MODE (LSB_FIRST | POS_EDGE_IN | NEG_EDGE_OUT)

2. 核心命令详解

2.1 时钟数据命令 (MPSSE 核心命令)

2.1.1 按位传输(< 8 位)

命令格式

[0x02 | mode] [length-1] [data...]

参数说明

  • 0x02 | mode:命令码
  • length-1:位数 - 1(范围 0-7,即 1-8 位)
  • data:数据字节(低 length 位有效)

示例:发送 4 位数据 0b1010 (0xA)

uint8_t mode = JTAG_MODE;
uint8_t cmd[] = {
    0x02 | mode | 0x10,  // 0x10 = 发送标志
    0x03,                // 4 位 (length-1)
    0x0A                 // 数据: 1010b
};

libusb_bulk_transfer(dev, out_ep, cmd, sizeof(cmd), &transferred, 1000);
2.1.2 按字节传输(≥ 8 位)

命令格式

[0x10 | mode] [length-1 LSB] [length-1 MSB] [data...]

参数说明

  • 0x10 | mode:命令码
  • length-1 LSB/MSB:字节数 - 1(16 位,最多 65535 字节)
  • data:数据字节

示例:发送 32 位数据 0xDEADBEEF

uint8_t mode = JTAG_MODE | 0x10;  // 0x10 = 发送标志
uint8_t cmd[] = {
    0x10 | mode,        // 命令码
    0x03, 0x00,       // 4 字节 (4-1=3)
    0xEF, 0xBE, 0xAD, 0xDE  // LSB 优先:0xEF 是最低字节
};

libusb_bulk_transfer(dev, out_ep, cmd, sizeof(cmd), &transferred, 1000);

注意:JTAG 使用 LSB 优先,所以 0xDEADBEEF 发送顺序为:

  • 第 1 字节:0xEF (bit[7:0])
  • 第 2 字节:0xBE (bit[15:8])
  • 第 3 字节:0xAD (bit[23:16])
  • 第 4 字节:0xDE (bit[31:24])
2.1.3 接收数据

命令格式

[0x20 | mode] [length-1/length-1 MSB]  // 仅接收,不发送
[0x30 | mode] [length-1/length-1 MSB] [data...]  // 发送+接收

示例:接收 32 位数据

uint8_t mode = JTAG_MODE | 0x20;  // 0x20 = 接收标志
uint8_t cmd[] = {
    0x20 | mode,
    0x03, 0x00,       // 4 字节
};

// 发送命令
libusb_bulk_transfer(dev, out_ep, cmd, sizeof(cmd), &transferred, 1000);

// 接收数据
uint8_t rx_data[4];
libusb_bulk_transfer(dev, in_ep, rx_data, sizeof(rx_data), &received, 1000);

2.2 带 TMS 控制的时钟命令

命令格式

[0x42 | mode] [bits-1] [TMS/TDI byte]

TMS/TDI 字节格式

Bit 7Bit 6-0
TDI 值TMS 序列(每 bit 对应一个 TCK)

特点

  • 每次最多传输 7 位(受 MPSSE 限制)
  • Bit 7 是 TDI 数据
  • Bit 6-0 是 TMS 数据

示例:发送 5 个 TCK 周期,TMS=11111,TDI=0

uint8_t mode = JTAG_MODE | 0x42;  // 0x42 = 带 TMS 控制
uint8_t tms_seq = 0x1F;  // 00011111b
uint8_t tdi = 0;

uint8_t cmd[] = {
    0x42 | mode,
    0x04,               // 5 个 TCK 周期 (5-1=4)
    (tms_seq & 0x7F) | (tdi ? 0x80 : 0x00)  // TMS + TDI(bit7)
};

libusb_bulk_transfer(dev, out_ep, cmd, sizeof(cmd), &transferred, 1000);

带接收的 TMS 命令

uint8_t mode = JTAG_MODE | 0x42 | 0x20;  // 0x20 = 接收标志
// 其余相同

2.3 其他 MPSSE 命令

命令码功能参数
0x84设置低字节 GPIO[data] [direction]
0x85设置高字节 GPIO[data] [direction]
0x86读低字节 GPIO-
0x87SEND_IMMEDIATE-
0x8A禁用时钟分频[0x01]
0x8B设置时钟分频[divisor LSB] [divisor MSB]
0x9A调用延迟[length LSB] [length MSB]

频率计算

// FT2232H/FT4232H/FT232H
frequency = 60 MHz / (1 + divisor)

// 示例:30 MHz
divisor = 0x0001;  // 60 / 2 = 30 MHz

// 示例:6 MHz
divisor = 0x0009;  // 60 / 10 = 6 MHz

3. JTAG TAP 状态机

3.1 TAP 状态机图

               ┌─────┐
               │TEST-LOGIC
               │  RESET
               └───┬─┘
                   │ TMS=1
                   ▼
          ┌────────┴────────┐
          │     RUN-TEST/IDLE
          └────────┬───────┘
                   │ TMS=1
          ┌────────┴────────┐
          │  SELECT-DR-SCAN
          └────────┬───────┘
                   │ TMS=0        TMS=1
    ┌──────────────┴──┐   ┌───────┴────────┐
    │   CAPTURE-DR  │   │  SELECT-IR-SCAN│
    └──────┬───────┘   └───────┬────────┘
           │ TMS=0              │ TMS=0
    ┌──────┴──────┐   ┌──────┴──────┐
    │  SHIFT-DR   │   │  SHIFT-IR   │
    └──────┬──────┘   └──────┬──────┘
           │ TMS=1             │ TMS=1
    ┌──────┴──────┐   ┌──────┴──────┐
    │  EXIT1-DR   │   │  EXIT1-IR   │
    └──────┬──────┘   └──────┬──────┘
           │ TMS=1             │ TMS=1
    ┌──────┴──────┐   ┌──────┴──────┐
    │  PAUSE-DR   │   │  PAUSE-IR   │
    └──────┬──────┘   └──────┬──────┘
           │ TMS=1             │ TMS=1
    ┌──────┴──────┐   ┌──────┴──────┐
    │  EXIT2-DR   │   │  EXIT2-IR   │
    └──────┬──────┘   └──────┬──────┘
           │ TMS=0             │ TMS=0
    ┌──────┴──────┐   ┌──────┴──────┐
    │  UPDATE-DR  │   │  UPDATE-IR  │
    └──────┬──────┘   └──────┬──────┘
           │ TMS=0             │ TMS=0
           └────────┴─────────┘
                    │ RUN-TEST/IDLE

3.2 状态迁移表

当前状态TMS下一状态
TEST-LOGIC-RESET0RUN-TEST/IDLE
RUN-TEST/IDLE1SELECT-DR-SCAN
SELECT-DR-SCAN0CAPTURE-DR
SELECT-DR-SCAN1SELECT-IR-SCAN
CAPTURE-DR0SHIFT-DR
SHIFT-DR0SHIFT-DR (继续移位)
SHIFT-DR1EXIT1-DR
EXIT1-DR1PAUSE-DR
PAUSE-DR1EXIT2-DR
EXIT2-DR0UPDATE-DR
UPDATE-DR0RUN-TEST/IDLE

SELECT-IR-SCANUPDATE-IR 类似。

3.3 状态迁移代码示例

// 从 RUN-TEST/IDLE 切换到 SHIFT-IR
uint8_t tms_sequence_idle_to_shift_ir[] = {1, 1, 0, 0};

for (int i = 0; i < 4; i++) {
    mpsse_clock_tms_cs_out(ctx, &tms_sequence_idle_to_shift_ir[i], 0, 1, 0, JTAG_MODE);
    // 1 个 TCK 周期,TMS 值由数组元素决定
}
// 状态变化:
// IDLE --(1)--> SELECT-DR --(1)--> SELECT-IR --(0)--> CAPTURE-IR --(0)--> SHIFT-IR

4. 完整 JTAG 操作流程

4.1 IRSCAN 操作(写 IR 寄存器)

目标:写入 5 位 IR 值 0x04 (DMI 指令)

void jtag_irscan(uint8_t ir_value, unsigned ir_length) {
    uint8_t mode = JTAG_MODE | 0x10 | 0x20;  // 发送+接收
    
    // 1. 从 IDLE 切换到 SHIFT-IR
    uint8_t tms_to_irshift[] = {1, 1, 0, 0};
    for (int i = 0; i < 4; i++) {
        mpsse_clock_tms_cs_out(ctx, &tms_to_irshift[i], 0, 1, 0, JTAG_MODE);
    }
    
    // 2. 发送 IR 数据(ir_length 位)
    unsigned bytes = (ir_length + 7) / 8;
    uint8_t *ir_buffer = malloc(bytes);
    ir_buffer[bytes - 1] = ir_value << (8 - (ir_length % 8));
    
    // 发送前 ir_length-1 位
    if (ir_length > 8) {
        for (unsigned i = 0; i < bytes - 1; i++) {
            uint8_t cmd[] = {0x10 | mode, 0x00, ir_buffer[i]};
            libusb_bulk_transfer(dev, out_ep, cmd, sizeof(cmd), NULL, 1000);
        }
    }
    
    // 发送最后 1 位 + TMS=1 (退出 SHIFT-IR)
    uint8_t last_bit = ir_value & 0x01;
    uint8_t cmd_final[] = {
        0x02 | mode | 0x40,  // 0x42 = TMS 控制
        0x00,  // 1 位
        (last_bit ? 0x80 : 0x00) | 0x01  // TDI=last_bit, TMS=1
    };
    libusb_bulk_transfer(dev, out_ep, cmd_final, sizeof(cmd_final), NULL, 1000);
    
    // 3. 从 EXIT1-IR 切换到 IDLE
    uint8_t tms_to_idle[] = {1, 0};
    for (int i = 0; i < 2; i++) {
        mpsse_clock_tms_cs_out(ctx, &tms_to_idle[i], 0, 1, 0, JTAG_MODE);
    }
    
    free(ir_buffer);
}

4.2 DRSCAN 操作(写 DR 寄存器)

目标:写入 41 位 DR 值(示例)

void jtag_drscan(const uint8_t *dr_data, unsigned dr_length) {
    uint8_t mode = JTAG_MODE | 0x10 | 0x20;
    
    // 1. 从 IDLE 切换到 SHIFT-DR
    uint8_t tms_to_drshift[] = {1, 0, 0};
    for (int i = 0; i < 3; i++) {
        mpsse_clock_tms_cs_out(ctx, &tms_to_drshift[i], 0, 1, 0, JTAG_MODE);
    }
    
    // 2. 发送 DR 数据
    unsigned full_bytes = dr_length / 8;
    unsigned remaining_bits = dr_length % 8;
    
    // 发送完整字节
    for (unsigned i = 0; i < full_bytes; i++) {
        uint8_t cmd[] = {0x10 | mode, 0x00, dr_data[i]};
        libusb_bulk_transfer(dev, out_ep, cmd, sizeof(cmd), NULL, 1000);
    }
    
    // 发送剩余位 + TMS=1
    if (remaining_bits > 0) {
        uint8_t last_byte = dr_data[full_bytes] >> (8 - remaining_bits);
        uint8_t cmd[] = {
            0x02 | mode | 0x40,
            remaining_bits - 1,
            last_byte | 0x01  // TMS=1
        };
        libusb_bulk_transfer(dev, out_ep, cmd, sizeof(cmd), NULL, 1000);
    }
    
    // 3. 切换到 IDLE
    uint8_t tms_to_idle[] = {1, 0};
    for (int i = 0; i < 2; i++) {
        mpsse_clock_tms_cs_out(ctx, &tms_to_idle[i], 0, 1, 0, JTAG_MODE);
    }
}

4.3 完整 DMI 写入示例

目标:写入 DMI 寄存器(地址 0x10,数据 0x12345678)

void dmi_write(uint32_t address, uint32_t data) {
    // 1. IRSCAN: 写入 DMI 指令 (5 位)
    uint8_t dmi_write_op = 0x02;  // 写操作
    jtag_irscan((dmi_write_op << 1) | 0, 5);  // op 在 bit[1]
    
    // 2. 构建 DR 数据(41 位)
    uint8_t dr_buffer[6];  // 41 位 = 6 字节
    dr_buffer[0] = address & 0xFF;
    dr_buffer[1] = (address >> 8) & 0xFF;
    dr_buffer[2] = (address >> 16) & 0xFF;
    dr_buffer[3] = ((address >> 24) & 0x1F) | 0x00;  // exec=0
    dr_buffer[4] = data & 0xFF;
    dr_buffer[5] = (data >> 8) & 0xFF;
    dr_buffer[6] = (data >> 16) & 0xFF;
    dr_buffer[7] = (data >> 24) & 0xFF;
    
    jtag_drscan(dr_buffer, 41);
}

5. 代码示例

5.1 完整初始化代码

#include <libusb.h>
#include <stdio.h>
#include <stdlib.h>

#define VID_FTDI  0x0403
#define PID_FT2232H 0x6010

// MPSSE 模式
#define BITMODE_MPSSE 0x02

// Mode 标志
#define JTAG_MODE 0x44  // LSB_FIRST | POS_EDGE_IN | NEG_EDGE_OUT

// USB 端点
#define EP_IN   0x81
#define EP_OUT  0x02

struct mpsse_device {
    struct libusb_context *ctx;
    struct libusb_device_handle *dev;
    uint8_t mode;
};

int mpsse_init(struct mpsse_device *dev) {
    // 1. 初始化 libusb
    if (libusb_init(&dev->ctx) < 0) {
        return -1;
    }
    
    // 2. 打开设备
    dev->dev = libusb_open_device_with_vid_pid(dev->ctx, VID_FTDI, PID_FT2232H);
    if (!dev->dev) {
        return -2;
    }
    
    // 3. 声明接口
    if (libusb_claim_interface(dev->dev, 0) < 0) {
        return -3;
    }
    
    // 4. 设置 MPSSE 模式
    uint8_t mode = BITMODE_MPSSE;
    libusb_control_transfer(dev->dev,
        0x40,  // FTDI_REQUEST_TYPE
        0x0B,  // SIO_SET_BITMODE_REQUEST
        mode, 0,
        NULL, 0, 1000);
    
    // 5. 设置频率(30 MHz)
    uint16_t divisor = 0x0001;  // 60 / 2 = 30 MHz
    uint8_t freq_cmd[] = {0x86, divisor & 0xFF, divisor >> 8};
    libusb_bulk_transfer(dev->dev, EP_OUT, freq_cmd, sizeof(freq_cmd), NULL, 1000);
    
    dev->mode = JTAG_MODE;
    return 0;
}

void mpsse_close(struct mpsse_device *dev) {
    if (dev->dev) {
        libusb_release_interface(dev->dev, 0);
        libusb_close(dev->dev);
    }
    if (dev->ctx) {
        libusb_exit(dev->ctx);
    }
}

5.2 批量数据发送

int mpsse_send_bulk(struct mpsse_device *dev, const uint8_t *data, unsigned length) {
    uint8_t mode = dev->mode | 0x10;  // 发送标志
    
    unsigned offset = 0;
    while (offset < length) {
        unsigned remaining = length - offset;
        unsigned chunk = (remaining > 65535) ? 65535 : remaining;
        
        // 构建命令
        uint8_t cmd[3 + chunk];
        cmd[0] = 0x10 | mode;
        cmd[1] = (chunk - 1) & 0xFF;
        cmd[2] = (chunk - 1) >> 8;
        memcpy(&cmd[3], data + offset, chunk);
        
        // 发送
        int transferred;
        if (libusb_bulk_transfer(dev->dev, EP_OUT, cmd, sizeof(cmd), 
                                     &transferred, 1000) < 0) {
            return -1;
        }
        
        offset += chunk;
    }
    return 0;
}

5.3 TMS 序列发送

int mpsse_send_tms(struct mpsse_device *dev, const uint8_t *tms_seq, unsigned length) {
    uint8_t mode = dev->mode | 0x42;  // TMS 控制
    
    unsigned offset = 0;
    while (offset < length) {
        unsigned chunk = (length - offset) > 7 ? 7 : (length - offset);
        
        uint8_t cmd[] = {
            mode,
            chunk - 1,
            tms_seq[offset]
        };
        
        int transferred;
        if (libusb_bulk_transfer(dev->dev, EP_OUT, cmd, sizeof(cmd),
                                     &transferred, 1000) < 0) {
            return -1;
        }
        
        offset += chunk;
    }
    return 0;
}

6. 性能优化

6.1 批量传输优化

原理:累积多个 MPSSE 命令后一次性发送,减少 USB 往返次数

// 优化前:每个命令单独发送
mpsse_clock_tms_cs_out(ctx, tms, 0, 1, 0, mode);  // 1 次 USB 传输
mpsse_clock_data(ctx, data, 0, NULL, 0, 32, mode);  // 1 次 USB 传输
mpsse_clock_tms_cs_out(ctx, tms, 0, 1, 0, mode);  // 1 次 USB 传输
// 总计:3 次 USB 传输

// 优化后:合并命令
uint8_t tx_buffer[256];
unsigned pos = 0;

// 添加命令 1
tx_buffer[pos++] = 0x42 | mode;
tx_buffer[pos++] = 0x00;
tx_buffer[pos++] = tms[0];

// 添加命令 2
tx_buffer[pos++] = 0x10 | mode;
tx_buffer[pos++] = 0x03;
tx_buffer[pos++] = 0x00;
memcpy(&tx_buffer[pos], data, 4);
pos += 4;

// 添加命令 3
tx_buffer[pos++] = 0x42 | mode;
tx_buffer[pos++] = 0x00;
tx_buffer[pos++] = tms[1];

// 一次性发送
libusb_bulk_transfer(dev, EP_OUT, tx_buffer, pos, NULL, 1000);
// 总计:1 次 USB 传输

6.2 频率优化

// FT2232H: 最高 30 MHz
mpsse_set_frequency(dev, 30000000);

// FT232H: 最高 30 MHz
mpsse_set_frequency(dev, 30000000);

// FT4232H: 最高 30 MHz
mpsse_set_frequency(dev, 30000000);

// 根据目标芯片调整
// ARM Cortex-M: 推荐使用 10-20 MHz
mpsse_set_frequency(dev, 15000000);

// 老旧芯片:降低频率
mpsse_set_frequency(dev, 1000000);

6.3 USB 延迟优化

// 设置最小延迟(2 ms)
libusb_control_transfer(dev,
    0x40, 0x09, 0x02, 0, NULL, 0, 1000);

// 禁用时钟分频(最高频率)
uint8_t disable_div[] = {0x8A, 0x01};
libusb_bulk_transfer(dev, EP_OUT, disable_div, sizeof(disable_div), NULL, 1000);

7. 调试技巧

7.1 启用详细日志

# OpenOCD 调试模式
openocd -d3 -f your_config.cfg

# 查看 MPSSE 命令
# 添加到 mpsse.c
#define DEBUG_MPSSE_COMMANDS
#ifdef DEBUG_MPSSE_COMMANDS
    LOG_DEBUG("MPSSE: 0x%02X 0x%02X 0x%02X",
              cmd[0], cmd[1], cmd[2]);
#endif

7.2 USB 监控

# 使用 usbmon
sudo modprobe usbmon
sudo cat /sys/kernel/debug/usb/usbmon/2u > capture.pcap

# 使用 Wireshark 分析
wireshark capture.pcap
# 过滤: usb.device_address == YOUR_DEVICE_ADDR

7.3 常见问题

问题可能原因解决方法
数据错误Mode 标志错误检查 JTAG_MODE = 0x44
频率不稳定USB 延迟过高设置 latency timer = 2ms
设备未找到VID/PID 错误使用 lsusb 确认设备 ID
TAP 状态卡死TMS 序列错误使用正确的 TMS 状态迁移

参考资料

  1. FTDI MPSSE 规范
    https://www.ftdichip.com/Support/Documents/AppNotes/AN2232C-01_MPSSE_Cmnd.pdf

  2. FT2232H 数据手册
    https://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT2232H.pdf

  3. IEEE 1149.1 JTAG 标准
    https://standards.ieee.org/

  4. OpenOCD 源码

    • src/jtag/drivers/mpsse.c
    • src/jtag/drivers/mpsse.h
    • src/jtag/drivers/ftdi.c

总结

MPSSE 协议开发要点

  1. 初始化:设置 MPSSE 模式 + 频率
  2. Mode 标志:JTAG_MODE = 0x44 (LSB | POS_EDGE_IN | NEG_EDGE_OUT)
  3. 命令类型
    • 0x02/0x10:时钟数据(按位/按字节)
    • 0x42:带 TMS 控制
  4. 状态迁移:通过 TMS 序列驱动 TAP 状态机
  5. 性能优化:批量传输 + 高频率 + 低延迟

与 OpenJTAG 协议的区别

  • MPSSE:由 FTDI 芯片固件解析,标准 JTAG
  • OpenJTAG:由设备固件解析,自定义协议

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值