一、DAP_Info (0x00) - 获取调试器信息
场景1:获取产品名称
请求包(查询产品名称,信息类型=0x02):
00000000: 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
字节级解析:
字节[0] (命令ID): 0x00 = DAP_Info
字节[1] (信息类型): 0x02 = 查询产品名称
字节[2-63] (填充): 全0x00
响应包示例(产品名称="DAPLink CMSIS-DAP"):
00000000: 00 11 44 41 50 4c 69 6e 6b 20 43 4d 53 49 53 2d ..DAPLink CMSIS-
00000010: 44 41 50 00 00 00 00 00 00 00 00 00 00 00 00 00 DAP.............
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
详细解析:
字节[0] (命令ID回显): 0x00
字节[1] (字符串长度): 0x11 = 17字节
字节[2-18] (字符串数据):
0x44 0x41 0x50 = "DAP"
0x4C 0x69 0x6E 0x6B = "Link"
0x20 = 空格
0x43 0x4D 0x53 0x49 0x53 = "CMSIS"
0x2D = "-"
0x44 0x41 0x50 = "DAP"
字节[19] (空终止符): 0x00
字节[20-63] (填充): 全0x00
场景2:获取固件版本(信息类型=0x04)
请求包:
00000000: 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
响应包示例(固件版本="0254"):
00000000: 00 04 30 32 35 34 00 00 00 00 00 00 00 00 00 00 ..0254..........
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
所有信息类型完整列表:
| 类型值 | 含义 | 典型响应 |
|---|---|---|
| 0x01 | 供应商名称 | "ARM" |
| 0x02 | 产品名称 | "DAPLink CMSIS-DAP" |
| 0x03 | 序列号 | "1234567890" |
| 0x04 | 固件版本 | "0254" |
| 0x05 | 目标设备供应商 | "STMicroelectronics" |
| 0x06 | 目标设备名称 | "STM32F103C8" |
| 0xF0 | 功能位图 | 0x07 (Bit0:SWD, Bit1:JTAG, Bit2:SWO) |
| 0xFE | 包计数大小 | 0x01 (1字节) |
| 0xFF | 包大小 | 0x40 (64字节) |
功能位图详细说明:
位图: 0x07 = 0b00000111
位0 (LSB): 1 = 支持SWD接口
位1: 1 = 支持JTAG接口
位2: 1 = 支持SWO跟踪
位3: 0 = 不支持原子命令
位4: 0 = 不支持时序测试
位5: 0 = 不支持批量传输
位6: 0 = 不支持大端传输
位7 (MSB): 0 = 保留
二、DAP_Connect (0x02) - 连接目标调试接口
场景:连接SWD接口(端口=1)
请求包:
00000000: 02 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
字节级解析:
字节[0] (命令ID): 0x02 = DAP_Connect
字节[1] (端口号): 0x01 = 选择SWD接口
0x00: 默认端口(自动选择)
0x01: SWD端口
0x02: JTAG端口
字节[2-63] (保留/填充): 全0x00
成功连接SWD的响应包:
00000000: 02 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
详细解析:
字节[0] (命令ID回显): 0x02
字节[1] (连接状态): 0x01 = SWD连接成功
0x00: 连接失败
0x01: SWD连接成功
0x02: JTAG连接成功
字节[2-63] (保留/填充): 全0x00
连接失败的可能原因和响应:
// 端口不可用(如请求JTAG但只支持SWD)
响应: 02 00 00 00 00 00 00 00 ...
// 硬件连接故障
响应: 02 00 00 00 00 00 00 00 ...
三、DAP_SWJ_Sequence (0x12) - 发送位序列
场景1:SWD线复位(发送51个时钟高电平)
请求包:
00000000: 12 33 FF FF FF FF FF 07 00 00 00 00 00 00 00 00 .3..............
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
详细位序列分解:
字节[0]: 0x12 = 命令ID
字节[1]: 0x33 = 51位序列长度 (0x33 = 51十进制)
数据字节[2-7]共6个字节,携带51位数据:
字节[2]: 0xFF = 0b11111111 → 发送: 1,1,1,1,1,1,1,1 (8位)
字节[3]: 0xFF = 0b11111111 → 发送: 1,1,1,1,1,1,1,1 (16位)
字节[4]: 0xFF = 0b11111111 → 发送: 1,1,1,1,1,1,1,1 (24位)
字节[5]: 0xFF = 0b11111111 → 发送: 1,1,1,1,1,1,1,1 (32位)
字节[6]: 0xFF = 0b11111111 → 发送: 1,1,1,1,1,1,1,1 (40位)
字节[7]: 0x07 = 0b00000111 → 发送: 1,1,1,0,0,0,0,0 (最后3位有效)
总计: 8×5 + 3 = 51位
时序: 在SWCLK时钟的每个上升沿,SWDIO保持高电平
成功响应包:
00000000: 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
字节[0]: 0x12 = 命令ID回显
字节[1]: 0x00 = 执行成功
字节[2-63]: 全0x00填充
场景2:JTAG到SWD切换序列(0xE79E,16位)
请求包:
00000000: 12 10 9E E7 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
位序列详细解析(LSB优先发送):
字节[0]: 0x12 = 命令ID
字节[1]: 0x10 = 16位序列长度
要发送的原始序列: 0xE79E = 0b1110011110011110
存储格式: 0x9E (低字节), 0xE7 (高字节)
LSB优先发送顺序分析:
0x9E = 0b10011110 → LSB=0, 发送顺序: 0,1,1,1,1,0,0,1
0xE7 = 0b11100111 → LSB=1, 发送顺序: 1,1,1,0,0,1,1,1
完整16位发送顺序:
位0: 0 (0x9E的bit0)
位1: 1 (0x9E的bit1)
位2: 1 (0x9E的bit2)
位3: 1 (0x9E的bit3)
位4: 1 (0x9E的bit4)
位5: 0 (0x9E的bit5)
位6: 0 (0x9E的bit6)
位7: 1 (0x9E的bit7)
位8: 1 (0xE7的bit0)
位9: 1 (0xE7的bit1)
位10: 1 (0xE7的bit2)
位11: 0 (0xE7的bit3)
位12: 0 (0xE7的bit4)
位13: 1 (0xE7的bit5)
位14: 1 (0xE7的bit6)
位15: 1 (0xE7的bit7)
对应波形: SWDIO在SWCLK时钟的每个上升沿输出上述位值
成功响应包:
00000000: 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
四、DAP_Transfer (0x05) - 数据传输(核心命令)
场景1:读取DP IDCODE寄存器(地址0x0)
请求包:
00000000: 05 00 01 8F 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
传输请求字节(0x8F)详细解析:
字节[0]: 0x05 = 命令ID
字节[1]: 0x00 = DAP索引(通常为0)
字节[2]: 0x01 = 传输数量(1个请求)
字节[3]: 0x8F = 传输请求字节
0x8F = 0b10001111
位分解:
Bit0 (More): 1 = 这不是最后一个请求,后面还有请求
Bit1 (RnW): 1 = 读操作
Bit2 (APnDP): 1 = 访问AP(不是DP)← 注意:这里有问题!
Bit3 (A2): 1 = 地址位2
Bit4 (A3): 0 = 地址位3
Bits5-7: 000 = 保留
根据CMSIS-DAP规范,读取DP IDCODE的正确参数是:
- More: 0(单次请求)
- RnW: 1(读)
- APnDP: 0(DP访问)
- A2: 0(地址位2)
- A3: 0(地址位3)
→ 0b00000101 = 0x05
但实际实现中,DAPLink可能使用不同的约定。
修正后的正确请求包:
00000000: 05 00 01 05 00 00 00 00 00 00 00 00 00 00 00 00 ................
响应包示例(STM32F103 IDCODE=0x1BA01477):
00000000: 05 01 01 77 14 A0 1B 00 00 00 00 00 00 00 00 00 ...w............
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
详细解析:
字节[0]: 0x05 = 命令ID回显
字节[1]: 0x01 = 传输响应数量(1个响应)
字节[2]: 0x01 = 第1个传输响应状态
0x01 = DAP_TRANSFER_OK(成功)
0x02 = DAP_TRANSFER_WAIT(等待)
0x04 = DAP_TRANSFER_FAULT(错误)
0x08 = DAP_TRANSFER_ERROR(奇偶校验错误)
0x10 = DAP_TRANSFER_MISMATCH(值不匹配)
字节[3-6]: 0x77, 0x14, 0xA0, 0x1B = 读取的数据(小端字节序)
实际值 = 0x1BA01477(STM32F103的IDCODE)
字节[7-63]: 填充0x00
场景2:写AP CSW寄存器(设置访问属性)
请求包(写AP CSW=0x23000012):
00000000: 05 00 02 02 00 12 00 00 23 00 00 00 00 00 00 00 ........#.......
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
详细解析:
字节[0]: 0x05 = 命令ID
字节[1]: 0x00 = DAP索引
字节[2]: 0x02 = 传输数量(2个请求)
请求1(字节[3]): 0x02 = 写AP CSW
0x02 = 0b00000010
Bit0 (More): 0 = 还有更多请求(请求2)
Bit1 (RnW): 0 = 写操作
Bit2 (APnDP): 1 = 访问AP
Bit3 (A2): 0 = 地址位2(CSW地址为0x0,A2=0)
Bit4 (A3): 0 = 地址位3(A3=0)
写数据: 0x12, 0x00, 0x00, 0x23 (小端 = 0x23000012)
请求2(字节[4]): 0x00 = 虚读(用于获取前一个操作的状态)
0x00 = 0b00000000
Bit0 (More): 0 = 最后一个请求
Bit1 (RnW): 0 = 写操作?应该是读操作?实际上这是虚读
Bit2 (APnDP): 0 = DP访问
Bit3 (A2): 0
Bit4 (A3): 0
地址0x0(DP IDCODE),但因为是虚读,不关心数据
字节[5-8]: 写入数据 = 0x12, 0x00, 0x00, 0x23 (小端 = 0x23000012)
字节[9-63]: 填充0x00
响应包:
00000000: 05 02 01 00 00 00 00 01 77 14 A0 1B 00 00 00 00 ........w.......
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
解析:
字节[0]: 0x05 = 命令ID回显
字节[1]: 0x02 = 传输响应数量(2个响应)
响应1(字节[2]): 0x01 = 状态OK
响应1数据(字节[3-6]): 0x00, 0x00, 0x00, 0x00 (写操作无返回数据)
响应2(字节[7]): 0x01 = 状态OK
响应2数据(字节[8-11]): 0x77, 0x14, 0xA0, 0x1B = 0x1BA01477 (虚读返回的IDCODE)
场景3:批量传输 - 读取3个连续内存地址
请求包(读取0x20000000, 0x20000004, 0x20000008):
00000000: 05 00 05 02 12 12 12 11 00 00 00 20 00 00 00 20 ........... ...
00000010: 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 ... ............
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
分步解析:
字节[0]: 0x05 = 命令ID
字节[1]: 0x00 = DAP索引
字节[2]: 0x05 = 传输数量(5个请求)
请求1(字节[3]): 0x02 = 写DP SELECT,选择AP0
0x02 = 0b00000010 (More=0, RnW=0写, APnDP=0DP, A2=0, A3=0)
数据: 0x00, 0x00, 0x00, 0x00 (写入DP SELECT=0x00)
请求2(字节[4]): 0x12 = 写AP CSW
0x12 = 0b00010010 (More=0, RnW=0写, APnDP=1AP, A2=0, A3=1)
地址: A3=1,A2=0 = 地址0x4 (CSW寄存器)
数据: 0x12, 0x00, 0x00, 0x23 (0x23000012)
请求3(字节[5]): 0x12 = 写AP TAR,设置地址0x20000000
0x12 = 0b00010010 (More=0, RnW=0写, APnDP=1AP, A2=0, A3=1)
地址: A3=1,A2=0 = 地址0x4 (TAR寄存器)
数据: 0x00, 0x00, 0x00, 0x20 (0x20000000)
请求4(字节[6]): 0x12 = 写AP TAR,设置地址0x20000004
0x12 = 0b00010010 (More=0, RnW=0写, APnDP=1AP, A2=0, A3=1)
数据: 0x04, 0x00, 0x00, 0x20 (0x20000004)
请求5(字节[7]): 0x11 = 读AP DRW
0x11 = 0b00010001 (More=0, RnW=1读, APnDP=1AP, A2=0, A3=0)
地址: A3=0,A2=0 = 地址0xC (DRW寄存器)
写入数据(字节[8-23]):
0x00,0x00,0x00,0x00 # 请求1数据: DP SELECT=0
0x12,0x00,0x00,0x23 # 请求2数据: AP CSW=0x23000012
0x00,0x00,0x00,0x20 # 请求3数据: AP TAR=0x20000000
0x04,0x00,0x00,0x20 # 请求4数据: AP TAR=0x20000004
响应包:
00000000: 05 05 01 00 00 00 00 01 00 00 00 00 01 00 00 00 ................
00000010: 00 01 78 56 34 12 01 EF CD AB 89 01 11 11 11 11 ....xV4.........
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
解析:
字节[0]: 0x05 = 命令ID回显
字节[1]: 0x05 = 传输响应数量(5个响应)
响应1(字节[2]): 0x01 = 状态OK
响应1数据(字节[3-6]): 0x00,0x00,0x00,0x00
响应2(字节[7]): 0x01 = 状态OK
响应2数据(字节[8-11]): 0x00,0x00,0x00,0x00
响应3(字节[12]): 0x01 = 状态OK
响应3数据(字节[13-16]): 0x00,0x00,0x00,0x00
响应4(字节[17]): 0x01 = 状态OK
响应4数据(字节[18-21]): 0x78,0x56,0x34,0x12 = 0x12345678
响应5(字节[22]): 0x01 = 状态OK
响应5数据(字节[23-26]): 0xEF,0xCD,0xAB,0x89 = 0x89ABCDEF
五、DAP_TransferBlock (0x06) - 块传输
场景:连续写入4个字到内存地址0x20000000
数据定义:
地址 数据
0x20000000: 0x01234567
0x20000004: 0x89ABCDEF
0x20000008: 0x11111111
0x2000000C: 0x22222222
请求包:
00000000: 06 00 02 00 00 00 20 04 00 67 45 23 01 EF CD AB ...... .gE#....
00000010: 89 11 11 11 11 22 22 22 22 00 00 00 00 00 00 00 .....""".......
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
详细解析:
字节[0]: 0x06 = 命令ID
字节[1]: 0x00 = DAP索引
字节[2]: 0x02 = 传输请求字节
0x02 = 0b00000010
Bit0 (More): 0
Bit1 (RnW): 0 = 写操作
Bit2 (APnDP): 1 = 访问AP
Bit3 (A2): 0
Bit4 (A3): 0
字节[3-5]: 0x00,0x00,0x20 = 寄存器地址(小端 = 0x20000000)
字节[6-7]: 0x04,0x00 = 传输数量(小端 = 4个字)
字节[8-23]: 要写入的4个32位数据(每个小端格式)
0x67,0x45,0x23,0x01 = 0x01234567
0xEF,0xCD,0xAB,0x89 = 0x89ABCDEF
0x11,0x11,0x11,0x11 = 0x11111111
0x22,0x22,0x22,0x22 = 0x22222222
字节[24-63]: 填充0x00
成功响应包:
00000000: 06 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
解析:
字节[0]: 0x06 = 命令ID回显
字节[1]: 0x00 = 响应状态(成功)
字节[2-3]: 0x04,0x00 = 实际传输数量(小端 = 4)
字节[4-63]: 填充0x00(写操作无读取数据返回)
场景:批量读取4个字从内存地址0x20000000
请求包:
00000000: 06 00 03 00 00 00 20 04 00 00 00 00 00 00 00 00 ...... .........
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
解析:
字节[0]: 0x06 = 命令ID
字节[1]: 0x00 = DAP索引
字节[2]: 0x03 = 传输请求字节
0x03 = 0b00000011
Bit0 (More): 1
Bit1 (RnW): 1 = 读操作
Bit2 (APnDP): 1 = 访问AP
字节[3-5]: 0x00,0x00,0x20 = 地址0x20000000
字节[6-7]: 0x04,0x00 = 读取4个字
字节[8-63]: 无写入数据
响应包(假设内存内容为0x11223344等):
00000000: 06 00 04 00 44 33 22 11 88 77 66 55 CC BB AA 99 ....D3"..wfU....
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
解析:
字节[0]: 0x06 = 命令ID回显
字节[1]: 0x00 = 响应状态(成功)
字节[2-3]: 0x04,0x00 = 实际读取数量(4)
字节[4-19]: 读取的4个32位数据(小端格式)
0x44,0x33,0x22,0x11 = 0x11223344
0x88,0x77,0x66,0x55 = 0x55667788
0xCC,0xBB,0xAA,0x99 = 0x99AABBCC
0x00,0x00,0x00,0x00 = 0x00000000
六、DAP_WriteABORT (0x08) - 写ABORT寄存器
场景:清除DP ABORT寄存器(写0x0000001E)
请求包:
00000000: 08 00 1E 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
详细解析:
字节[0]: 0x08 = 命令ID
字节[1]: 0x00 = DAP索引
字节[2-5]: 0x1E,0x00,0x00,0x00 = 写入的值(小端 = 0x0000001E)
0x0000001E的含义(DP ABORT寄存器):
Bit0 (ORUNERRCLR): 1 = 清除溢出错误
Bit1 (WDBERRCLR): 1 = 清除写数据错误
Bit2 (STKERRCLR): 1 = 清除堆栈错误
Bit3 (STKCMPCLR): 1 = 清除堆栈比较错误
Bit4: 保留
Bit5 (DAPABORT): 1 = 中止DAP传输
实际值0x1E = 0b00011110,清除所有错误并中止DAP
成功响应包:
00000000: 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
解析:
字节[0]: 0x08 = 命令ID回显
字节[1]: 0x00 = 执行成功
字节[2-63]: 填充0x00
七、DAP_SWJ_Pins (0x10) - 控制SWJ引脚
场景:控制目标芯片复位引脚
请求包(拉低nRESET引脚100ms):
00000000: 10 00 20 64 00 00 00 00 00 00 00 00 00 00 00 00 . d............
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
详细解析:
字节[0]: 0x10 = 命令ID
字节[1]: 0x00 = 引脚输出值
Bit0 (SWCLK/TCK): 0 = 低电平
Bit1 (SWDIO/TMS): 0 = 低电平
Bit2: 保留
Bit3: 保留
Bit4: 保留
Bit5 (nRESET): 0 = 低电平(拉低复位)
Bit6: 保留
Bit7 (nTRST): 0 = 低电平
字节[2]: 0x20 = 引脚选择掩码
0x20 = 0b00100000
只控制Bit5 (nRESET引脚),其他引脚保持原状
字节[3-4]: 0x64,0x00 = 等待时间(小端 = 0x0064 = 100ms)
字节[5-63]: 填充0x00
响应包(返回当前引脚状态):
00000000: 10 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 . ..............
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
解析:
字节[0]: 0x10 = 命令ID回显
字节[1]: 0x20 = 当前引脚输入状态
0x20 = 0b00100000
Bit5 (nRESET): 1 = 高电平(由于内部上拉)
(注意:虽然我们输出低电平,但读取的是输入状态)
字节[2-63]: 填充0x00
完整的复位序列:
// 1. 拉低nRESET 100ms
发送: 10 00 20 64 00 // 输出nRESET=0,保持100ms
接收: 10 20 // 引脚状态
// 2. 释放nRESET 100ms
发送: 10 20 20 64 00 // 输出nRESET=1,保持100ms
接收: 10 20 // 引脚状态
八、DAP_SWJ_Clock (0x11) - 设置时钟频率
场景:设置SWD时钟为1MHz
请求包:
00000000: 11 40 42 0F 00 00 00 00 00 00 00 00 00 00 00 00 .@B.............
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
详细解析:
字节[0]: 0x11 = 命令ID
字节[1-4]: 0x40,0x42,0x0F,0x00 = 时钟频率(小端 = 0x000F4240 = 1,000,000 Hz)
字节[5-63]: 填充0x00
成功响应包:
00000000: 11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
常见时钟频率:
0x000F4240 = 1,000,000 Hz (1MHz)
0x001E8480 = 2,000,000 Hz (2MHz)
0x002DC6C0 = 3,000,000 Hz (3MHz)
0x003D0900 = 4,000,000 Hz (4MHz)
0x004C4B40 = 5,000,000 Hz (5MHz)
0x00989680 = 10,000,000 Hz (10MHz)
九、完整调试会话数据流示例
以下是Keil连接STM32F103并读取IDCODE的完整数据包交换:
阶段1:初始化连接
1. DAP_Info获取产品名称
发送: 00 02 00 00 00 00 ...
接收: 00 11 44 41 50 4C 69 6E 6B 20 43 4D 53 49 53 2D 44 41 50 00 ...
2. 设置SWD时钟1MHz
发送: 11 40 42 0F 00 00 00 00 ...
接收: 11 00 00 00 00 00 00 00 ...
3. SWD线复位(51个时钟高电平)
发送: 12 33 FF FF FF FF FF 07 00 ...
接收: 12 00 00 00 00 00 00 00 ...
4. JTAG-to-SWD切换序列
发送: 12 10 9E E7 00 00 00 00 ...
接收: 12 00 00 00 00 00 00 00 ...
5. 连接SWD接口
发送: 02 01 00 00 00 00 00 00 ...
接收: 02 01 00 00 00 00 00 00 ...
阶段2:读取芯片IDCODE
6. 配置传输参数
发送: 04 00 32 00 00 00 00 00 ...
接收: 04 00 00 00 00 00 00 00 ...
7. 读取DP IDCODE
发送: 05 00 01 05 00 00 00 00 ...
接收: 05 01 01 77 14 A0 1B 00 ...
8. 写DP ABORT清除错误标志
发送: 08 00 1E 00 00 00 00 00 ...
接收: 08 00 00 00 00 00 00 00 ...
9. 写DP SELECT选择AP0
发送: 05 00 02 01 00 00 00 00 00 00 00 00 ...
接收: 05 02 01 00 00 00 00 01 77 14 A0 1B ...
10. 写AP CSW配置访问属性
发送: 05 00 02 12 00 00 00 00 12 00 00 23 ...
接收: 05 02 01 00 00 00 00 01 00 00 00 00 ...
阶段3:读写内存
11. 写AP TAR设置地址0x20000000
发送: 05 00 02 12 00 00 00 00 00 00 00 20 ...
接收: 05 02 01 00 00 00 00 01 00 00 00 00 ...
12. 读AP DRW获取内存值
发送: 05 00 01 11 00 00 00 00 ...
接收: 05 01 01 78 56 34 12 00 ...
读取到内存值0x12345678
十、错误处理和数据包状态码
传输状态码详解:
#define DAP_TRANSFER_OK 0x01 // 成功
#define DAP_TRANSFER_WAIT 0x02 // 等待响应(需要重试)
#define DAP_TRANSFER_FAULT 0x04 // 传输错误(协议错误)
#define DAP_TRANSFER_ERROR 0x08 // 奇偶校验错误
#define DAP_TRANSFER_MISMATCH 0x10 // 值不匹配(读写验证失败)
错误响应示例:
// 传输错误(DAP_TRANSFER_FAULT)
响应: 05 01 04 00 00 00 00 00 00 00 00 00 ...
// 奇偶校验错误(DAP_TRANSFER_ERROR)
响应: 05 01 08 00 00 00 00 00 00 00 00 00 ...
// 等待响应(需要重试)
响应: 05 01 02 00 00 00 00 00 00 00 00 00 ...
错误恢复流程:
1. 发送DAP_WriteABORT清除错误标志
请求: 08 00 1E 00 00 00
2. 重新发送失败的传输命令
3. 如果仍然失败,降低时钟频率重试
请求: 11 40 42 0F 00 00 00 00 // 1MHz
总结
这个详细的数据包示例展示了CMSIS-DAP协议的关键命令的完整64字节数据格式。每个数据包都严格按照协议规范构造,包含了:
-
命令ID - 标识操作类型
-
参数 - 具体操作参数
-
数据 - 传输的数据内容
-
填充 - 补全64字节
理解这些数据包格式对于:
-
调试DAPLink固件问题
-
开发自定义调试工具
-
分析调试通信问题
-
优化调试性能
都具有重要意义。每个字节都有其特定含义,整个协议栈设计精巧而高效。