libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
swd_general_gpio.hpp
1#pragma once
2
3#include <cmath>
4#include <cstdint>
5
6#include "gpio.hpp"
7#include "libxr_def.hpp"
8#include "swd.hpp"
9#include "timebase.hpp"
10
11namespace LibXR::Debug
12{
23template <typename SwclkGpioType, typename SwdioGpioType>
24class SwdGeneralGPIO final : public Swd
25{
26 static constexpr uint32_t MIN_HZ = 10'000u;
27 static constexpr uint32_t MAX_HZ = 100'000'000u;
28
29 static constexpr uint32_t NS_PER_SEC = 1'000'000'000u;
30 static constexpr uint32_t LOOPS_SCALE = 1000u; // ns -> us 的缩放分母
31 static constexpr uint32_t CEIL_BIAS = LOOPS_SCALE - 1u; // ceil(x/LOOPS_SCALE) 的偏置
32
33 static constexpr uint32_t HalfPeriodNsFromHz(uint32_t hz)
34 {
35 // ceil(1e9 / (2*hz))
36 return (NS_PER_SEC + (2u * hz) - 1u) / (2u * hz);
37 }
38
39 static constexpr uint32_t HALF_PERIOD_NS_MAX = HalfPeriodNsFromHz(MIN_HZ);
40 static constexpr uint32_t MAX_LOOPS_PER_US =
41 (UINT32_MAX - CEIL_BIAS) / HALF_PERIOD_NS_MAX;
42
43 static_assert(MIN_HZ > 0u);
44 static_assert(MAX_HZ >= MIN_HZ);
45 static_assert(HALF_PERIOD_NS_MAX > 0u);
46
47 public:
55 explicit SwdGeneralGPIO(SwclkGpioType& swclk, SwdioGpioType& swdio,
56 uint32_t loops_per_us, uint32_t default_hz = DEFAULT_CLOCK_HZ)
57 : swclk_(swclk), swdio_(swdio), loops_per_us_(loops_per_us)
58 {
59 if (loops_per_us_ > MAX_LOOPS_PER_US)
60 {
61 loops_per_us_ = MAX_LOOPS_PER_US;
62 }
63
64 // SWCLK baseline
65 swclk_.SetConfig(
66 {SwclkGpioType::Direction::OUTPUT_PUSH_PULL, SwclkGpioType::Pull::NONE});
67 swclk_.Write(true);
68
69 // SWDIO baseline
70 (void)SetSwdioDriveMode();
71 swdio_.Write(true);
72
73 (void)SetClockHz(default_hz);
74 }
75
76 ~SwdGeneralGPIO() override = default;
77
78 SwdGeneralGPIO(const SwdGeneralGPIO&) = delete;
79 SwdGeneralGPIO& operator=(const SwdGeneralGPIO&) = delete;
80
81 ErrorCode SetClockHz(uint32_t hz) override
82 {
83 if (hz == 0u)
84 {
85 clock_hz_ = 0u;
86 half_period_ns_ = 0u;
87 half_period_loops_ = 0u;
88 return ErrorCode::OK;
89 }
90
91 if (hz < MIN_HZ)
92 {
93 hz = MIN_HZ;
94 }
95 if (hz > MAX_HZ)
96 {
97 hz = MAX_HZ;
98 }
99
100 clock_hz_ = hz;
101
102 // 半周期计算改为浮点(double),最终再转为整型。Half period computed in double, then
103 // converted to integer.
104 const double DEN = 2.0 * static_cast<double>(hz);
105 const double HALF_PERIOD_NS_F = std::ceil(static_cast<double>(NS_PER_SEC) / DEN);
106 half_period_ns_ = static_cast<uint32_t>(HALF_PERIOD_NS_F);
107
108 if (loops_per_us_ == 0u)
109 {
110 half_period_loops_ = 0u;
111 return ErrorCode::OK;
112 }
113
114 // half_period_loops 使用浮点计算,最终再转为整型(ceil)。
115 // 允许 < 1 时转换为 0,用于进入 no-delay 路径。
116 // Compute loops in double, then convert to integer (ceil). Allow < 1 to become 0
117 // to enter no-delay path.
118 const double HALF_PERIOD_LOOPS_F =
119 (static_cast<double>(loops_per_us_) * static_cast<double>(half_period_ns_)) /
120 static_cast<double>(LOOPS_SCALE);
121
122 if (HALF_PERIOD_LOOPS_F < 1.0)
123 {
124 half_period_loops_ = 0u;
125 }
126 else
127 {
128 const double LOOPS_CEIL_F = std::ceil(HALF_PERIOD_LOOPS_F);
129 half_period_loops_ = (LOOPS_CEIL_F >= static_cast<double>(UINT32_MAX))
130 ? UINT32_MAX
131 : static_cast<uint32_t>(LOOPS_CEIL_F);
132 }
133
134 return ErrorCode::OK;
135 }
136
137 void Close() override
138 {
140
141 // 安全状态:Safe state:
142 // - SWCLK 高电平(历史行为)。SWCLK high (legacy).
143 // - SWDIO 上拉输入(不驱动)。SWDIO input with pull-up (no drive).
144 swclk_.Write(true);
145 (void)SetSwdioSampleMode();
146 }
147
148 ErrorCode LineReset() override
149 {
151 // SWD 线复位:SWDIO = 1 持续 >= 50 个周期;此处使用 64 个周期。SWD line reset: SWDIO
152 // = 1 for >= 50 cycles; here use 64 cycles.
153 (void)SetSwdioDriveMode();
154 swdio_.Write(true);
155 for (uint32_t i = 0; i < LINE_RESET_CYCLES; ++i)
156 {
157 GenOneClk();
158 }
159 return ErrorCode::OK;
160 }
161
162 ErrorCode EnterSwd() override
163 {
164 ErrorCode ec = LineReset();
165 if (ec != ErrorCode::OK)
166 {
167 return ec;
168 }
169
170 WriteByteLSB(JTAG_TO_SWD_SEQ0);
171 WriteByteLSB(JTAG_TO_SWD_SEQ1);
172
173 ec = LineReset();
174 if (ec != ErrorCode::OK)
175 {
176 return ec;
177 }
178
179 swdio_.Write(false);
180 WriteByteLSB(0x00);
181
182 return ErrorCode::OK;
183 }
184
185 ErrorCode Transfer(const SwdProtocol::Request& req,
186 SwdProtocol::Response& resp) override
187 {
188 // 目标:当 half_period_loops_ == 0 时,整次 Transfer 走无延时路径,
189 // 避免每半周期 BusyLoop(0) 的空转判断开销。
190 if (half_period_loops_ == 0u)
191 {
192 return TransferWithoutDelay(req, resp);
193 }
194 else
195 {
196 return TransferWithDelay(req, resp);
197 }
198 }
199
200 void IdleClocks(uint32_t cycles) override
201 {
202 // CMSIS-DAP 空闲周期插入。CMSIS-DAP idle cycles insertion.
203 // 保留历史序列:周期内驱动 SWDIO 高电平,结束后拉低。Keep the legacy sequence: drive
204 // SWDIO high during cycles, then pull low.
205 (void)SetSwdioDriveMode();
206 swdio_.Write(true);
207
208 for (uint32_t i = 0; i < cycles; ++i)
209 {
210 GenOneClk();
211 }
212
213 swdio_.Write(false);
214 }
215
216 ErrorCode SeqWriteBits(uint32_t cycles, const uint8_t* data_lsb_first) override
217 {
218 if (cycles == 0u)
219 {
220 swclk_.Write(false);
221 return ErrorCode::OK;
222 }
223 if (data_lsb_first == nullptr)
224 {
225 return ErrorCode::ARG_ERR;
226 }
227
228 (void)SetSwdioDriveMode();
229
230 // Keep legacy: start from SWCLK low and end low
231 swclk_.Write(false);
232
233 for (uint32_t i = 0; i < cycles; ++i)
234 {
235 const bool BIT = (((data_lsb_first[i / 8u] >> (i & 7u)) & 0x01u) != 0u);
236 swdio_.Write(BIT);
237
238 // one clock cycle: low->high (with DelayHalf inside GenOneClk)
239 // NOTE: your GenOneClk ends at high; to keep "end low" legacy for SeqWrite,
240 // we explicitly pull low after each cycle (no extra DelayHalf added).
241 GenOneClk();
242 swclk_.Write(false);
243 }
244
245 return ErrorCode::OK;
246 }
247
248 ErrorCode SeqReadBits(uint32_t cycles, uint8_t* out_lsb_first) override
249 {
250 if (cycles == 0u)
251 {
252 swclk_.Write(false);
253 return ErrorCode::OK;
254 }
255 if (out_lsb_first == nullptr)
256 {
257 return ErrorCode::ARG_ERR;
258 }
259
260 const uint32_t BYTES = (cycles + 7u) / 8u;
261 Memory::FastSet(out_lsb_first, 0, BYTES);
262
263 (void)SetSwdioSampleMode();
264
265 // start from low, end low
266 swclk_.Write(false);
267
268 for (uint32_t i = 0; i < cycles; ++i)
269 {
270 // Use the updated read phase (CMSIS-style)
271 bool bit = false;
272 if (half_period_loops_ == 0u)
273 {
274 swclk_.Write(false);
275 bit = swdio_.Read();
276 swclk_.Write(true);
277 }
278 else
279 {
280 swclk_.Write(false);
281 DelayHalf();
282 bit = swdio_.Read();
283 swclk_.Write(true);
284 DelayHalf();
285 }
286
287 if (bit)
288 {
289 out_lsb_first[i / 8u] =
290 static_cast<uint8_t>(out_lsb_first[i / 8u] | (1u << (i & 7u)));
291 }
292
293 // keep legacy end-low for next bit
294 swclk_.Write(false);
295 }
296
297 return ErrorCode::OK;
298 }
299
300 private:
301 static inline uint8_t MakeReq(bool apndp, bool rnw, uint8_t addr2b)
302 {
303 const uint8_t A2 = addr2b & 0x1u;
304 const uint8_t A3 = (addr2b >> 1) & 0x1u;
305 const uint8_t PAR = static_cast<uint8_t>((apndp ^ rnw ^ A2 ^ A3) & 0x1u);
306
307 // 请求字节位域:start(1), APnDP, RnW, A2, A3, PAR, stop(0), park(1)。Request bit
308 // fields: start(1), APnDP, RnW, A2, A3, PAR, stop(0), park(1).
309 return static_cast<uint8_t>((1u << 0) | (static_cast<uint8_t>(apndp) << 1) |
310 (static_cast<uint8_t>(rnw) << 2) |
311 (static_cast<uint8_t>(A2) << 3) |
312 (static_cast<uint8_t>(A3) << 4) |
313 (static_cast<uint8_t>(PAR) << 5) | (0u << 6) | (1u << 7));
314 }
315
316 static inline uint8_t Parity32(uint32_t x)
317 {
318 x ^= x >> 16;
319 x ^= x >> 8;
320 x ^= x >> 4;
321 x &= 0xFu;
322 static constexpr uint8_t LUT[16] = {
323 0, 1, 1, 0, 1, 0, 0, 1,
324 1, 0, 0, 1, 0, 1, 1, 0};
326 return LUT[x];
327 }
328
329 static inline SwdProtocol::Ack DecodeAck(uint8_t ack_bits)
330 {
331 switch (ack_bits)
332 {
333 case 0x1:
334 return SwdProtocol::Ack::OK;
335 case 0x2:
336 return SwdProtocol::Ack::WAIT;
337 case 0x4:
338 return SwdProtocol::Ack::FAULT;
339 case 0x0:
340 return SwdProtocol::Ack::NO_ACK;
341 default:
342 return SwdProtocol::Ack::PROTOCOL;
343 }
344 }
345
346 private:
351 enum class SwdioMode : uint8_t
352 {
353 UNKNOWN = 0,
354 DRIVE_OD,
355 SAMPLE_IN,
356 };
357
358 ErrorCode SetSwdioDriveMode()
359 {
361 {
362 const ErrorCode EC = swdio_.SetConfig(
363 {SwdioGpioType::Direction::OUTPUT_OPEN_DRAIN, SwdioGpioType::Pull::UP});
364 if (EC != ErrorCode::OK)
365 {
366 return EC;
367 }
368 }
369
371 return ErrorCode::OK;
372 }
373
374 ErrorCode SetSwdioSampleMode()
375 {
376 const ErrorCode EC = SetSwdioDriveMode();
377 if (EC != ErrorCode::OK)
378 {
379 return EC;
380 }
381
382 // 约束:GPIO::Read() 需要在开漏输出模式下返回实际引脚电平(而不是输出锁存值)。
383 // Constraint: GPIO::Read() must sample the physical pin level in open-drain output
384 // mode (not just the output latch).
385 //
386 // 开漏输出高电平表示释放总线,目标可驱动 ACK/数据 / Open-drain high releases line
387 // so target can drive ACK/data.
388 swdio_.Write(true);
390 return ErrorCode::OK;
391 }
392
393 inline void DelayHalf() { BusyLoop(half_period_loops_); }
394
395 inline void GenOneClk()
396 {
397 swclk_.Write(false);
398 DelayHalf();
399 swclk_.Write(true);
400 DelayHalf();
401 }
402
403 inline void GenOneClkWithoutDelay()
404 {
405 swclk_.Write(false);
406 swclk_.Write(true);
407 }
408
409 inline void WriteBit(bool bit)
410 {
411 swdio_.Write(bit);
412 GenOneClk();
413 }
414
415 inline void WriteBitWithoutDelay(bool bit)
416 {
417 swdio_.Write(bit);
418 GenOneClkWithoutDelay();
419 }
420
421 inline void WriteByteLSB(uint8_t b)
422 {
423 for (uint32_t i = 0; i < BYTE_BITS; ++i)
424 {
425 WriteBit(((b >> i) & 0x1u) != 0u);
426 }
427 }
428
429 inline void WriteByteLSBWithoutDelay(uint8_t b)
430 {
431 for (uint32_t i = 0; i < BYTE_BITS; ++i)
432 {
433 WriteBitWithoutDelay(((b >> i) & 0x1u) != 0u);
434 }
435 }
436
437 inline bool ReadBitAndClock()
438 {
439 swclk_.Write(false);
440 DelayHalf();
441 const bool BIT = swdio_.Read();
442 swclk_.Write(true);
443 DelayHalf();
444 return BIT;
445 }
446
447 inline bool ReadBitAndClockWithoutDelay()
448 {
449 swclk_.Write(false);
450 const bool BIT = swdio_.Read();
451 swclk_.Write(true);
452 return BIT;
453 }
454
455 inline uint8_t ReadByteLSB()
456 {
457 uint8_t v = 0u;
458 for (uint32_t i = 0; i < BYTE_BITS; ++i)
459 {
460 if (ReadBitAndClock())
461 {
462 v = static_cast<uint8_t>(v | (1u << i));
463 }
464 }
465 return v;
466 }
467
468 inline uint8_t ReadByteLSBWithoutDelay()
469 {
470 uint8_t v = 0u;
471 for (uint32_t i = 0; i < BYTE_BITS; ++i)
472 {
473 if (ReadBitAndClockWithoutDelay())
474 {
475 v = static_cast<uint8_t>(v | (1u << i));
476 }
477 }
478 return v;
479 }
480
481 static void BusyLoop(uint32_t loops)
482 {
483 volatile uint32_t sink = loops;
484 while (sink--)
485 {
486 }
487 }
488
489 private:
490 ErrorCode TransferWithDelay(const SwdProtocol::Request& req,
491 SwdProtocol::Response& resp)
492 {
493 resp.ack = SwdProtocol::Ack::PROTOCOL;
494 resp.rdata = 0u;
495 resp.parity_ok = true;
496
497 const bool APNDP = (req.port == SwdProtocol::Port::AP);
498 const uint8_t REQUEST_BYTE = MakeReq(APNDP, req.rnw, req.addr2b);
499
500 (void)SetSwdioDriveMode();
501 WriteByteLSB(REQUEST_BYTE);
502
503 (void)SetSwdioSampleMode();
504 GenOneClk(); // turnaround Host -> Target
505
506 // ACK: CMSIS SW_READ_BIT phase (sample in low phase)
507 uint8_t ack_raw = 0u;
508 for (uint32_t i = 0; i < ACK_BITS; ++i)
509 {
510 if (ReadBitAndClock())
511 {
512 ack_raw |= static_cast<uint8_t>(1u << i);
513 }
514 }
515 resp.ack = DecodeAck(static_cast<uint8_t>(ack_raw & 0x7u));
516
517 if (resp.ack != SwdProtocol::Ack::OK)
518 {
519 GenOneClk(); // turnaround Target -> Host (skip data)
520 (void)SetSwdioDriveMode();
521 swdio_.Write(true);
522 swclk_.Write(false);
523 return ErrorCode::OK;
524 }
525
526 if (req.rnw)
527 {
528 uint32_t data = 0u;
529 for (uint32_t byte = 0; byte < 4u; ++byte)
530 {
531 const uint32_t B = ReadByteLSB();
532 data |= (B << (8u * byte));
533 }
534
535 const bool PARITY_BIT = ReadBitAndClock();
536 resp.rdata = data;
537 resp.parity_ok = (static_cast<uint8_t>(PARITY_BIT) == Parity32(data));
538
539 (void)SetSwdioDriveMode();
540 swdio_.Write(true);
541 GenOneClk();
542
543 swclk_.Write(false);
544 }
545 else
546 {
547 (void)SetSwdioDriveMode();
548 GenOneClk();
549
550 const uint32_t DATA = req.wdata;
551 for (uint32_t byte = 0; byte < 4u; ++byte)
552 {
553 const uint8_t B = static_cast<uint8_t>((DATA >> (8u * byte)) & 0xFFu);
554 WriteByteLSB(B);
555 }
556
557 const bool PARITY_BIT = (Parity32(DATA) & 0x1u) != 0u;
558 WriteBit(PARITY_BIT);
559
560 swdio_.Write(true);
561 swclk_.Write(false);
562 }
563
564 return ErrorCode::OK;
565 }
566
567 ErrorCode TransferWithoutDelay(const SwdProtocol::Request& req,
568 SwdProtocol::Response& resp)
569 {
570 resp.ack = SwdProtocol::Ack::PROTOCOL;
571 resp.rdata = 0u;
572 resp.parity_ok = true;
573
574 const bool APNDP = (req.port == SwdProtocol::Port::AP);
575 const uint8_t REQUEST_BYTE = MakeReq(APNDP, req.rnw, req.addr2b);
576
577 (void)SetSwdioDriveMode();
578 WriteByteLSBWithoutDelay(REQUEST_BYTE);
579
580 (void)SetSwdioSampleMode();
581 GenOneClkWithoutDelay(); // turnaround Host -> Target
582
583 // ACK: CMSIS SW_READ_BIT phase (sample in low phase)
584 uint8_t ack_raw = 0u;
585 for (uint32_t i = 0; i < ACK_BITS; ++i)
586 {
587 if (ReadBitAndClockWithoutDelay())
588 {
589 ack_raw |= static_cast<uint8_t>(1u << i);
590 }
591 }
592 resp.ack = DecodeAck(static_cast<uint8_t>(ack_raw & 0x7u));
593
594 if (resp.ack != SwdProtocol::Ack::OK)
595 {
596 GenOneClkWithoutDelay();
597 (void)SetSwdioDriveMode();
598 swdio_.Write(true);
599 swclk_.Write(false);
600 return ErrorCode::OK;
601 }
602
603 if (req.rnw)
604 {
605 uint32_t data = 0u;
606 for (uint32_t byte = 0; byte < 4u; ++byte)
607 {
608 const uint32_t B = ReadByteLSBWithoutDelay();
609 data |= (B << (8u * byte));
610 }
611
612 const bool PARITY_BIT = ReadBitAndClockWithoutDelay();
613 resp.rdata = data;
614 resp.parity_ok = (static_cast<uint8_t>(PARITY_BIT) == Parity32(data));
615
616 (void)SetSwdioDriveMode();
617 swdio_.Write(true);
618 GenOneClkWithoutDelay();
619
620 swclk_.Write(false);
621 }
622 else
623 {
624 (void)SetSwdioDriveMode();
625 GenOneClkWithoutDelay();
626
627 const uint32_t DATA = req.wdata;
628 for (uint32_t byte = 0; byte < 4u; ++byte)
629 {
630 const uint8_t B = static_cast<uint8_t>((DATA >> (8u * byte)) & 0xFFu);
631 WriteByteLSBWithoutDelay(B);
632 }
633
634 const bool PARITY_BIT = (Parity32(DATA) & 0x1u) != 0u;
635 WriteBitWithoutDelay(PARITY_BIT);
636
637 swdio_.Write(true);
638 swclk_.Write(false);
639 }
640
641 return ErrorCode::OK;
642 }
643
644 private:
645 static constexpr uint32_t DEFAULT_CLOCK_HZ =
646 500'000u;
647 static constexpr uint32_t LINE_RESET_CYCLES =
648 64u;
649 static constexpr uint32_t BYTE_BITS = 8u;
650 static constexpr uint32_t ACK_BITS = 3u;
651
652 static constexpr uint8_t JTAG_TO_SWD_SEQ0 =
653 0x9Eu;
654 static constexpr uint8_t JTAG_TO_SWD_SEQ1 =
655 0xE7u;
656
657 SwclkGpioType& swclk_;
658 SwdioGpioType& swdio_;
659
660 uint32_t clock_hz_ = 0u;
661
662 uint32_t loops_per_us_ = 0u; // 手调系数:BusyLoop 每微秒大约需要的迭代数
663 uint32_t half_period_ns_ = 0u; // 当前半周期(ns)
664 uint32_t half_period_loops_ = 0u; // 当前半周期对应的 BusyLoop 迭代数
665
668};
669
670} // namespace LibXR::Debug
基于 GpioType 轮询 bit-bang 的 SWD 探针。 SWD probe based on polling bit-bang using GpioType.
SwdioMode
SWDIO 管脚当前模式。Current SWDIO pin mode.
@ SAMPLE_IN
采样阶段(保持开漏释放)。Sampling phase (line released by OD high).
@ UNKNOWN
未知/未初始化。Unknown / uninitialized.
@ DRIVE_OD
开漏输出(高电平=释放总线)。Open-drain output (high=release).
ErrorCode Transfer(const SwdProtocol::Request &req, SwdProtocol::Response &resp) override
执行一次 SWD 传输(不含重试)。Perform one SWD transfer (no retry).
ErrorCode EnterSwd() override
进入 SWD 模式(如需从 JTAG 切换)。Enter SWD mode (e.g., switch from JTAG if needed).
SwdGeneralGPIO(SwclkGpioType &swclk, SwdioGpioType &swdio, uint32_t loops_per_us, uint32_t default_hz=DEFAULT_CLOCK_HZ)
构造函数。Constructor.
SwdioGpioType & swdio_
SWDIO GPIO。GPIO for SWDIO.
ErrorCode LineReset() override
执行 SWD 线复位。Perform SWD line reset.
static constexpr uint32_t ACK_BITS
ACK 比特数。ACK bits.
uint32_t clock_hz_
当前 SWCLK 频率(Hz)。Current SWCLK frequency (Hz).
static constexpr uint8_t JTAG_TO_SWD_SEQ0
JTAG->SWD 序列字节 0。JTAG-to-SWD sequence byte 0.
SwclkGpioType & swclk_
SWCLK GPIO。GPIO for SWCLK.
static constexpr uint32_t DEFAULT_CLOCK_HZ
默认 SWCLK 频率(Hz)。Default SWCLK frequency (Hz).
static uint8_t Parity32(uint32_t x)
SwdioMode swdio_mode_
SWDIO 当前模式缓存。Cached current SWDIO mode.
static constexpr uint8_t JTAG_TO_SWD_SEQ1
JTAG->SWD 序列字节 1。JTAG-to-SWD sequence byte 1.
ErrorCode SetClockHz(uint32_t hz) override
设置 SWCLK 频率(可选)。Set SWCLK frequency (optional).
void IdleClocks(uint32_t cycles) override
插入空闲时钟周期。Insert idle clock cycles.
void Close() override
关闭探针并释放资源。Close probe and release resources.
static constexpr uint32_t LINE_RESET_CYCLES
线复位时钟周期数。Line reset clock cycles.
static constexpr uint32_t BYTE_BITS
每字节比特数。Bits per byte.
SWD 探针抽象基类,提供链路控制、传输与 DP/AP 辅助接口。 Abstract SWD probe base class providing link control,...
Definition swd.hpp:17
void InvalidateSelectCache()
失效 SELECT 缓存。Invalidate SELECT cache.
Definition swd.hpp:422
static void FastSet(void *dst, uint8_t value, size_t size)
快速内存填充 / Fast memory fill
SWD 传输请求 / SWD transfer request.
SWD 传输响应 / SWD transfer response.