FPGA实现SWD接口协议
1 SWD 协议简介
SWD的全称是The Serial Wire Debug Port(SW-DP),也就是串行调试端口,是ARM目前支持的两种调试端口之一,另一种是JTAG。SWD通信只需SWDIO、SWDCLK两根线;SWDIO为双向Data线,SWDCLK为时钟线。
2 SWD 读写操作流程
2.1 写操作流程
写操作的流程包括以下:
(1)发送8bit操作命令;
(2)一个空转周期;
(3)接收3bit的ACK;
(4)一个空转周期;
(5)发送32bit的写数据;
(6)发送1bit写数据的奇偶校验值;
2.2 读操作流程
读操作的流程包括以下:
(1)发送8bit操作命令;
(2)一个空转周期;
(3)接收3bit的ACK;
(4)接收32bit的读数据;
(5)接收1bit读数据的奇偶校验值;
(6)一个空转周期;
2.3 术语含义
Start | 起始位,值为1 |
APnDP | 指示访问调试端口是DP还是AP,0:DP,1:AP |
RnW | 指示当次访问是写操作还是读操作,0:写,1:读 |
A[2:3] | 指示DP/AP寄存器地址的Addr[3:2]字段 |
Parity | 前一个数据包的奇偶校验位 |
Stop | 停止位,值为0 |
Park | 暂存位,为了被目标设备读取为高,值为1 |
Trn | 调转周期,用于SWDIO切换IO方向,默认调转周期是一个时钟周期 |
ACK[0:2] | 3bit的目标设备返回主机的响应,ACK[0:2]=0b100:OK,ACK[0:2]=0b010:,ACK[0:2]=0b001:FAULT |
WDATA[0:31] | 32bit的主机到目标设备的写数据,LSB传输 |
RDATA[0:31] | 32bit的目标设备到主机的读数据,LSB传输 |
3 SWD 操作时序
从第2章的流程协议图看来,看似收发数据是上升沿切换,下降沿采样,但实际上并不是。从ARM Debug InterfaceArchitecture Specification ADIv6.0里查看得知,也就是上图标红位置。协议指出,SWD目标设备是在SWCLK的上升沿采样数据,也是在SWCLK的上升沿切换数据。那么反过来,主机需要在SWCLK的下降沿去切换数据,SWCLK的下降沿去采集数据。这里,不知道是否个人理解有误,一般正常的逻辑是主从机都是在同一个沿去切换数据/采集数据,而SWD协议给我感觉要另类一点。
3 FPGA实现逻辑
从第2张的读写协议流程看来,读和写的完整通信流程都有6个步骤,但步骤并不完全一样。这样具有明确的流程性通信,显然在FPGA中,使用状态机来实现是最合适的。状态机的状态跳转如下:
注意的是,若ACK接收不是OK指令,则需要多发送一个Trn周期才能结束当次通信请求。
状态机的Verilog代码如下:

// ----------------------------------State Machine---------------------------------// always @(posedge i_clk) begin if(!i_rst_n) state <= IDLE; else case(state) IDLE: if(data_req_vld) state <= CMD; else state <= state; CMD: if(cmd_send_done) state <= TRN0; else state <= state; TRN0: if(div_clk_done) state <= ACK; else state <= state; ACK: if(ack_rcv_ok && ack_rcv_done && ~swd_send_cmd[2]) // Write Data -->Need to switch directions state <= TRN1; else if(ack_rcv_ok && ack_rcv_done && swd_send_cmd[2]) // Read Data -->No need to switch directions state <= DATA; else if(!ack_rcv_ok && ack_rcv_done) // Ack false --> stop flow state <= TRN2; else state <= state; TRN1: if(div_clk_done) state <= DATA; else state <= state; DATA: if(data_flow_done) state <= PAR; else state <= state; PAR: if(div_clk_done && ~swd_send_cmd[2]) // Write state <= IDLE; else if(div_clk_done && swd_send_cmd[2]) // Read state <= TRN2; else state <= state; TRN2: if(div_clk_done) state <= IDLE; else state <= state; default:state <= IDLE; endcase end
4 逻辑分析结果
4.1 读时序
4.2 写时序
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通