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