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