Skip to content

Commit 50fe713

Browse files
committed
docs: add SWD debug docs and refresh XRUSB stack documentation
1 parent 8d1a9f8 commit 50fe713

21 files changed

Lines changed: 1447 additions & 1161 deletions

File tree

docs/about.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
id: about
33
title: 关于
4-
sidebar_position: 11
4+
sidebar_position: 12
55
---
66

77
# 关于本项目

docs/adv_coding/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
id: adv-coding
33
title: 进阶编程
4-
sidebar_position: 9
4+
sidebar_position: 10
55
---
66

77
# 进阶编程

docs/con_guide/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
2-
id: adv-coding
2+
id: con-guide
33
title: 贡献指南
4-
sidebar_position: 10
4+
sidebar_position: 11
55
---
66

77
# 贡献指南

docs/debug/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
id: debug
3+
title: 调试接口
4+
sidebar_position: 8
5+
---
6+
7+
# 调试接口
8+
9+
本章将介绍如何使用本项目的调试接口,包括 SWD、JTAG 等。

docs/debug/swd/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
id: debug-swd
3+
title: SWD调试接口
4+
sidebar_position: 1
5+
---
6+
7+
# SWD调试接口
8+
9+
本章将介绍如何使用本项目的 SWD 调试接口实现。

docs/debug/swd/swd-base.md

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
---
2+
id: swd-base
3+
title: SWD基类
4+
sidebar_position: 1
5+
---
6+
7+
# SWD 基类(`LibXR::Debug::Swd`
8+
9+
本文档描述 `LibXR::Debug::Swd`:一个面向 **SWD 探针/链路后端** 的抽象基类。它提供最小的链路控制接口、一次传输原语(`Transfer()`),以及在其之上构建的 **WAIT 重试封装****DP/AP 辅助函数**,用于被更上层(例如 CMSIS-DAP、调试器、烧录器)复用。
10+
11+
---
12+
13+
## 1. 设计定位
14+
15+
`Swd` 的定位是“**可移植的 SWD 事务层抽象**”:
16+
17+
- 由派生类实现硬件相关部分:GPIO/USART/SPI/bitbang、时序、端点驱动、并发策略等。
18+
- 基类负责通用逻辑:
19+
- 传输策略(WAIT 重试 + IdleCycles 插入)
20+
- DP/AP 常用读写封装(含 posted read 的 RDBUFF 处理)
21+
- SELECT 写缓存(减少冗余写操作)
22+
23+
---
24+
25+
## 2. 数据结构
26+
27+
### 2.1 `TransferPolicy`
28+
29+
传输策略用于控制重试与空闲周期插入:
30+
31+
- `idle_cycles`:每次传输尝试后插入的空闲周期数(包含 WAIT 重试)。
32+
- `wait_retry`:ACK==WAIT 时的最大重试次数。
33+
- `clear_sticky_on_fault`:ACK==FAULT 时是否尽力清除 DP sticky 错误(通过写 DP ABORT)。
34+
35+
相关接口:
36+
37+
- `SetTransferPolicy(const TransferPolicy&)`
38+
- `GetTransferPolicy()`
39+
40+
---
41+
42+
## 3. 派生类必须实现的接口
43+
44+
以下接口为纯虚函数,必须由具体 SWD 后端实现:
45+
46+
1) 链路控制
47+
48+
- `ErrorCode SetClockHz(uint32_t hz)`
49+
设置 SWCLK 目标频率(是否真正可调由后端决定)。
50+
51+
- `void Close()`
52+
关闭探针并释放资源(可用于断开硬件、停止定时器等)。
53+
54+
- `ErrorCode LineReset()`
55+
执行 SWD line reset(常见为连续输出若干个 1,再进行必要的序列)。
56+
57+
- `ErrorCode EnterSwd()`
58+
进入 SWD 模式(例如从 JTAG 切换到 SWD 的序列)。
59+
60+
2) 传输原语
61+
62+
- `ErrorCode Transfer(const SwdProtocol::Request& req, SwdProtocol::Response& resp)`
63+
执行“一次 SWD 传输(不含重试)”。该函数应完成:
64+
- 请求发送、ACK 读取、(可选)读数据与校验
65+
- 填充 `resp.ack / resp.rdata / resp.parity_ok`
66+
67+
3) 序列与空闲周期
68+
69+
- `void IdleClocks(uint32_t cycles)`
70+
插入空闲时钟周期(通常表现为产生 SWCLK 脉冲,同时保持 SWDIO 空闲态)。
71+
72+
- `ErrorCode SeqWriteBits(uint32_t cycles, const uint8_t* data_lsb_first)`
73+
在 SWDIO 上按 LSB-first 输出 `cycles` 位并产生 SWCLK 脉冲。
74+
75+
- `ErrorCode SeqReadBits(uint32_t cycles, uint8_t* out_lsb_first)`
76+
产生 SWCLK 脉冲并采样 SWDIO,按 LSB-first 写入输出缓冲。
77+
78+
---
79+
80+
## 4. 带重试传输:`TransferWithRetry()`
81+
82+
`TransferWithRetry()``Transfer()` 之上增加策略控制,用于贴近 CMSIS-DAP 的典型行为。
83+
84+
核心规则:
85+
86+
- 每次尝试后都插入 `idle_cycles`(包括 WAIT 重试)。
87+
-`resp.ack == WAIT` 时,最多重试 `wait_retry` 次。
88+
- 若底层 `Transfer()` 返回非 `OK`(总线/实现级错误):
89+
-`resp.ack` 置为 `PROTOCOL`
90+
- 失效 SELECT 缓存(避免后续基于缓存做错误判断)
91+
- 立即返回该错误码
92+
- 若最终 ACK 非 OK:失效 SELECT 缓存
93+
- 若最终 ACK 为 FAULT 且 `clear_sticky_on_fault=true`:尽力写 ABORT 清 sticky
94+
95+
返回值语义:
96+
97+
- 返回 `ErrorCode` 表示“传输流程级”的结果:通常为 `OK`,除非底层 `Transfer()` 失败。
98+
- ACK 状态由 `resp.ack` 给出;上层应同时检查 `resp.ack``resp.parity_ok`
99+
100+
---
101+
102+
## 5. DP/AP 辅助接口
103+
104+
基类提供常用 DP/AP 事务封装,减少上层重复代码。
105+
106+
### 5.1 DP 读写
107+
108+
- `DpRead(...) / DpWrite(...)`:无重试版本(直接调用 `Transfer()`
109+
- `DpReadTxn(...) / DpWriteTxn(...)`:带重试版本(调用 `TransferWithRetry()`
110+
111+
注意事项:
112+
113+
- 读操作在 `resp.ack==OK``resp.parity_ok==true` 时才返回成功,并输出 `val`
114+
- 任何 ACK 非 OK 或奇偶校验失败都会返回 `FAILED`(并通过 `ack` 返回 ACK)。
115+
116+
### 5.2 AP 读写与 posted read
117+
118+
AP 读为 posted read,因此提供两种读法:
119+
120+
- `ApReadTxn(addr2b, val, ack)`
121+
执行一次 AP READ(posted),随后读 DP `RDBUFF`,将“本次 AP READ 的真实数据”输出到 `val`
122+
123+
- `ApReadPostedTxn(addr2b, posted_val, ack)`
124+
只执行 AP READ 并返回 `resp.rdata`(这是“上一笔” AP READ 的 posted 结果)。调用者若要拿到最后一次 AP READ 的真实数据,需要额外调用一次 `DpReadRdbuffTxn()`
125+
126+
写操作:
127+
128+
- `ApWriteTxn(addr2b, val, ack)`:带重试 AP WRITE。
129+
130+
### 5.3 其他常用封装
131+
132+
- `ReadIdCode(idcode, ack)`:读取 DP `IDCODE`(无重试)。
133+
- `WriteAbort(flags, ack)` / `WriteAbortTxn(flags, ack)`:写 DP `ABORT`(无重试/带重试)。
134+
- `DpReadRdbuffTxn(val, ack)`:读 DP `RDBUFF`(带重试)。
135+
136+
---
137+
138+
## 6. SELECT 写缓存
139+
140+
为减少冗余 SELECT 写入,基类维护一个简单缓存:
141+
142+
- `SetSelectCached(select, ack)`
143+
- 若缓存命中(`select_valid_ && select_cache_ == select`),直接返回 `OK``ack=OK`
144+
- 否则执行 `DpWriteTxn(SELECT, select, ack)`;写成功后更新缓存
145+
146+
- `InvalidateSelectCache()`
147+
将缓存标记为无效。以下情况会触发失效:
148+
- `TransferWithRetry()` 中遇到 ACK 非 OK
149+
- `TransferWithRetry()` 中底层 Transfer 返回非 OK
150+
- 上层也可以在链路重置、模式切换等场景主动调用
151+
152+
---
153+
154+
## 7. 实现建议(派生类)
155+
156+
1) `Transfer()` 的职责边界
157+
`Transfer()` 应只做“一次事务”,不要内置 WAIT 重试与 idle 插入(基类已提供策略封装)。如果必须在硬件层做最小化重试(例如采样时序问题),建议明确与 `wait_retry` 的关系,避免双重重试导致延迟放大。
158+
159+
2) 响应填充
160+
即使发生异常,也应尽量填充 `resp.ack``resp.parity_ok`,并在不可恢复错误时让 `Transfer()` 返回非 `OK`,由 `TransferWithRetry()` 统一处理缓存失效等副作用。
161+
162+
3) 线路空闲与方向切换
163+
`SeqWriteBits/SeqReadBits` 的方向控制与 turnaround 处理应符合 SWD 协议要求;特别是 ACK 阶段与数据阶段的 IO 方向切换。
164+
165+
---
166+
167+
## 8. 使用示例(概念性)
168+
169+
```cpp
170+
class MySwd : public LibXR::Debug::Swd {
171+
public:
172+
ErrorCode SetClockHz(uint32_t hz) override;
173+
void Close() override;
174+
ErrorCode LineReset() override;
175+
ErrorCode EnterSwd() override;
176+
ErrorCode Transfer(const SwdProtocol::Request& req,
177+
SwdProtocol::Response& resp) override;
178+
179+
void IdleClocks(uint32_t cycles) override;
180+
ErrorCode SeqWriteBits(uint32_t cycles, const uint8_t* data_lsb_first) override;
181+
ErrorCode SeqReadBits(uint32_t cycles, uint8_t* out_lsb_first) override;
182+
};
183+
184+
MySwd swd;
185+
LibXR::Debug::Swd::TransferPolicy pol;
186+
pol.idle_cycles = 0;
187+
pol.wait_retry = 100;
188+
swd.SetTransferPolicy(pol);
189+
190+
swd.EnterSwd();
191+
192+
uint32_t idcode = 0;
193+
LibXR::Debug::SwdProtocol::Ack ack;
194+
swd.ReadIdCode(idcode, ack);
195+
```

0 commit comments

Comments
 (0)