libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
ch32_usb_endpoint_otghs.cpp
1#include <cstdint>
2
3#include "ch32_usb_endpoint.hpp"
4#include "ep.hpp"
5#include "libxr_time.hpp"
6#include "timebase.hpp"
7
8using namespace LibXR;
9
10#if defined(USBHSD)
11
12// NOLINTBEGIN
13static inline volatile uint8_t* get_tx_control_addr(USB::Endpoint::EPNumber ep_num)
14{
15 return reinterpret_cast<volatile uint8_t*>(
16 reinterpret_cast<volatile uint8_t*>(&USBHSD->UEP0_TX_CTRL) +
17 static_cast<int>(ep_num) * 4);
18}
19
20static inline volatile uint8_t* get_rx_control_addr(USB::Endpoint::EPNumber ep_num)
21{
22 return reinterpret_cast<volatile uint8_t*>(
23 reinterpret_cast<volatile uint8_t*>(&USBHSD->UEP0_TX_CTRL) +
24 static_cast<int>(ep_num) * 4 + 1);
25}
26
27static inline volatile uint16_t* get_tx_len_addr(USB::Endpoint::EPNumber ep_num)
28{
29 return reinterpret_cast<volatile uint16_t*>(
30 reinterpret_cast<volatile uint8_t*>(&USBHSD->UEP0_TX_LEN) +
31 static_cast<int>(ep_num) * 4);
32}
33
34static_assert(offsetof(USBHSD_TypeDef, UEP1_MAX_LEN) -
35 offsetof(USBHSD_TypeDef, UEP0_MAX_LEN) ==
36 4);
37
38static inline volatile uint16_t* get_rx_max_len_addr(USB::Endpoint::EPNumber ep_num)
39{
40 return reinterpret_cast<volatile uint16_t*>(
41 reinterpret_cast<volatile uint8_t*>(&USBHSD->UEP0_MAX_LEN) +
42 static_cast<int>(ep_num) * 4);
43}
44
45static inline volatile uint32_t* get_tx_dma_addr(USB::Endpoint::EPNumber ep_num)
46{
47 if (ep_num == USB::Endpoint::EPNumber::EP0)
48 {
49 return &USBHSD->UEP0_DMA;
50 }
51 return reinterpret_cast<volatile uint32_t*>(
52 reinterpret_cast<volatile uint32_t*>(&USBHSD->UEP1_TX_DMA) +
53 (static_cast<int>(ep_num) - 1));
54}
55
56static inline volatile uint32_t* get_rx_dma_addr(USB::Endpoint::EPNumber ep_num)
57{
58 if (ep_num == USB::Endpoint::EPNumber::EP0)
59 {
60 return &USBHSD->UEP0_DMA;
61 }
62 return reinterpret_cast<volatile uint32_t*>(
63 reinterpret_cast<volatile uint32_t*>(&USBHSD->UEP1_RX_DMA) +
64 (static_cast<int>(ep_num) - 1));
65}
66
67static void set_tx_len(USB::Endpoint::EPNumber ep_num, uint32_t value)
68{
69 *get_tx_len_addr(ep_num) = value;
70}
71
72static void set_tx_dma_buffer(USB::Endpoint::EPNumber ep_num, void* buffer,
73 uint32_t buffer_size, bool double_buffer)
74{
75 uint8_t* buf_base = reinterpret_cast<uint8_t*>(buffer);
76 uint8_t* buf_alt = buf_base + buffer_size / 2;
77
78 if (ep_num == USB::Endpoint::EPNumber::EP0)
79 {
80 USBHSD->UEP0_DMA = (uint32_t)buf_base;
81 }
82 else
83 {
84 *get_tx_dma_addr(ep_num) = (uint32_t)buf_base;
85 if (double_buffer)
86 {
87 *get_rx_dma_addr(ep_num) = (uint32_t)buf_alt;
88 }
89 }
90
91 int IDX = static_cast<int>(ep_num);
92 if (double_buffer && ep_num != USB::Endpoint::EPNumber::EP0)
93 {
94 USBHSD->BUF_MODE |= (1 << IDX);
95 }
96 else
97 {
98 USBHSD->BUF_MODE &= ~(1 << IDX);
99 }
100}
101
102static void set_rx_dma_buffer(USB::Endpoint::EPNumber ep_num, void* buffer,
103 uint32_t buffer_size, bool double_buffer)
104{
105 uint8_t* buf_base = reinterpret_cast<uint8_t*>(buffer);
106 uint8_t* buf_alt = buf_base + buffer_size / 2;
107
108 if (ep_num == USB::Endpoint::EPNumber::EP0)
109 {
110 USBHSD->UEP0_DMA = (uint32_t)buf_base;
111 }
112 else
113 {
114 *get_rx_dma_addr(ep_num) = (uint32_t)buf_base;
115 if (double_buffer)
116 {
117 *get_tx_dma_addr(ep_num) = (uint32_t)buf_alt;
118 }
119 }
120
121 int IDX = static_cast<int>(ep_num);
122 if (double_buffer && ep_num != USB::Endpoint::EPNumber::EP0)
123 {
124 USBHSD->BUF_MODE |= (1 << IDX);
125 }
126 else
127 {
128 USBHSD->BUF_MODE &= ~(1 << IDX);
129 }
130}
131
132static void enable_tx(USB::Endpoint::EPNumber ep_num)
133{
134 switch (ep_num)
135 {
136 case USB::Endpoint::EPNumber::EP0:
137 USBHSD->ENDP_CONFIG |= USBHS_UEP0_T_EN;
138 break;
139 case USB::Endpoint::EPNumber::EP1:
140 USBHSD->ENDP_CONFIG |= USBHS_UEP1_T_EN;
141 break;
142 case USB::Endpoint::EPNumber::EP2:
143 USBHSD->ENDP_CONFIG |= USBHS_UEP2_T_EN;
144 break;
145 case USB::Endpoint::EPNumber::EP3:
146 USBHSD->ENDP_CONFIG |= USBHS_UEP3_T_EN;
147 break;
148 case USB::Endpoint::EPNumber::EP4:
149 USBHSD->ENDP_CONFIG |= USBHS_UEP4_T_EN;
150 break;
151 case USB::Endpoint::EPNumber::EP5:
152 USBHSD->ENDP_CONFIG |= USBHS_UEP5_T_EN;
153 break;
154 case USB::Endpoint::EPNumber::EP6:
155 USBHSD->ENDP_CONFIG |= USBHS_UEP6_T_EN;
156 break;
157 case USB::Endpoint::EPNumber::EP7:
158 USBHSD->ENDP_CONFIG |= USBHS_UEP7_T_EN;
159 break;
160 case USB::Endpoint::EPNumber::EP8:
161 USBHSD->ENDP_CONFIG |= USBHS_UEP8_T_EN;
162 break;
163 case USB::Endpoint::EPNumber::EP9:
164 USBHSD->ENDP_CONFIG |= USBHS_UEP9_T_EN;
165 break;
166 case USB::Endpoint::EPNumber::EP10:
167 USBHSD->ENDP_CONFIG |= USBHS_UEP10_T_EN;
168 break;
169 case USB::Endpoint::EPNumber::EP11:
170 USBHSD->ENDP_CONFIG |= USBHS_UEP11_T_EN;
171 break;
172 case USB::Endpoint::EPNumber::EP12:
173 USBHSD->ENDP_CONFIG |= USBHS_UEP12_T_EN;
174 break;
175 case USB::Endpoint::EPNumber::EP13:
176 USBHSD->ENDP_CONFIG |= USBHS_UEP13_T_EN;
177 break;
178 case USB::Endpoint::EPNumber::EP14:
179 USBHSD->ENDP_CONFIG |= USBHS_UEP14_T_EN;
180 break;
181 case USB::Endpoint::EPNumber::EP15:
182 USBHSD->ENDP_CONFIG |= USBHS_UEP15_T_EN;
183 break;
184 default:
185 break;
186 }
187}
188
189static void disable_tx(USB::Endpoint::EPNumber ep_num)
190{
191 switch (ep_num)
192 {
193 case USB::Endpoint::EPNumber::EP0:
194 USBHSD->ENDP_CONFIG &= ~USBHS_UEP0_T_EN;
195 break;
196 case USB::Endpoint::EPNumber::EP1:
197 USBHSD->ENDP_CONFIG &= ~USBHS_UEP1_T_EN;
198 break;
199 case USB::Endpoint::EPNumber::EP2:
200 USBHSD->ENDP_CONFIG &= ~USBHS_UEP2_T_EN;
201 break;
202 case USB::Endpoint::EPNumber::EP3:
203 USBHSD->ENDP_CONFIG &= ~USBHS_UEP3_T_EN;
204 break;
205 case USB::Endpoint::EPNumber::EP4:
206 USBHSD->ENDP_CONFIG &= ~USBHS_UEP4_T_EN;
207 break;
208 case USB::Endpoint::EPNumber::EP5:
209 USBHSD->ENDP_CONFIG &= ~USBHS_UEP5_T_EN;
210 break;
211 case USB::Endpoint::EPNumber::EP6:
212 USBHSD->ENDP_CONFIG &= ~USBHS_UEP6_T_EN;
213 break;
214 case USB::Endpoint::EPNumber::EP7:
215 USBHSD->ENDP_CONFIG &= ~USBHS_UEP7_T_EN;
216 break;
217 case USB::Endpoint::EPNumber::EP8:
218 USBHSD->ENDP_CONFIG &= ~USBHS_UEP8_T_EN;
219 break;
220 case USB::Endpoint::EPNumber::EP9:
221 USBHSD->ENDP_CONFIG &= ~USBHS_UEP9_T_EN;
222 break;
223 case USB::Endpoint::EPNumber::EP10:
224 USBHSD->ENDP_CONFIG &= ~USBHS_UEP10_T_EN;
225 break;
226 case USB::Endpoint::EPNumber::EP11:
227 USBHSD->ENDP_CONFIG &= ~USBHS_UEP11_T_EN;
228 break;
229 case USB::Endpoint::EPNumber::EP12:
230 USBHSD->ENDP_CONFIG &= ~USBHS_UEP12_T_EN;
231 break;
232 case USB::Endpoint::EPNumber::EP13:
233 USBHSD->ENDP_CONFIG &= ~USBHS_UEP13_T_EN;
234 break;
235 case USB::Endpoint::EPNumber::EP14:
236 USBHSD->ENDP_CONFIG &= ~USBHS_UEP14_T_EN;
237 break;
238 case USB::Endpoint::EPNumber::EP15:
239 USBHSD->ENDP_CONFIG &= ~USBHS_UEP15_T_EN;
240 break;
241 default:
242 break;
243 }
244}
245
246static void enable_rx(USB::Endpoint::EPNumber ep_num)
247{
248 switch (ep_num)
249 {
250 case USB::Endpoint::EPNumber::EP0:
251 USBHSD->ENDP_CONFIG |= USBHS_UEP0_R_EN;
252 break;
253 case USB::Endpoint::EPNumber::EP1:
254 USBHSD->ENDP_CONFIG |= USBHS_UEP1_R_EN;
255 break;
256 case USB::Endpoint::EPNumber::EP2:
257 USBHSD->ENDP_CONFIG |= USBHS_UEP2_R_EN;
258 break;
259 case USB::Endpoint::EPNumber::EP3:
260 USBHSD->ENDP_CONFIG |= USBHS_UEP3_R_EN;
261 break;
262 case USB::Endpoint::EPNumber::EP4:
263 USBHSD->ENDP_CONFIG |= USBHS_UEP4_R_EN;
264 break;
265 case USB::Endpoint::EPNumber::EP5:
266 USBHSD->ENDP_CONFIG |= USBHS_UEP5_R_EN;
267 break;
268 case USB::Endpoint::EPNumber::EP6:
269 USBHSD->ENDP_CONFIG |= USBHS_UEP6_R_EN;
270 break;
271 case USB::Endpoint::EPNumber::EP7:
272 USBHSD->ENDP_CONFIG |= USBHS_UEP7_R_EN;
273 break;
274 case USB::Endpoint::EPNumber::EP8:
275 USBHSD->ENDP_CONFIG |= USBHS_UEP8_R_EN;
276 break;
277 case USB::Endpoint::EPNumber::EP9:
278 USBHSD->ENDP_CONFIG |= USBHS_UEP9_R_EN;
279 break;
280 case USB::Endpoint::EPNumber::EP10:
281 USBHSD->ENDP_CONFIG |= USBHS_UEP10_R_EN;
282 break;
283 case USB::Endpoint::EPNumber::EP11:
284 USBHSD->ENDP_CONFIG |= USBHS_UEP11_R_EN;
285 break;
286 case USB::Endpoint::EPNumber::EP12:
287 USBHSD->ENDP_CONFIG |= USBHS_UEP12_R_EN;
288 break;
289 case USB::Endpoint::EPNumber::EP13:
290 USBHSD->ENDP_CONFIG |= USBHS_UEP13_R_EN;
291 break;
292 case USB::Endpoint::EPNumber::EP14:
293 USBHSD->ENDP_CONFIG |= USBHS_UEP14_R_EN;
294 break;
295 case USB::Endpoint::EPNumber::EP15:
296 USBHSD->ENDP_CONFIG |= USBHS_UEP15_R_EN;
297 break;
298 default:
299 break;
300 }
301}
302
303static void disable_rx(USB::Endpoint::EPNumber ep_num)
304{
305 switch (ep_num)
306 {
307 case USB::Endpoint::EPNumber::EP0:
308 USBHSD->ENDP_CONFIG &= ~USBHS_UEP0_R_EN;
309 break;
310 case USB::Endpoint::EPNumber::EP1:
311 USBHSD->ENDP_CONFIG &= ~USBHS_UEP1_R_EN;
312 break;
313 case USB::Endpoint::EPNumber::EP2:
314 USBHSD->ENDP_CONFIG &= ~USBHS_UEP2_R_EN;
315 break;
316 case USB::Endpoint::EPNumber::EP3:
317 USBHSD->ENDP_CONFIG &= ~USBHS_UEP3_R_EN;
318 break;
319 case USB::Endpoint::EPNumber::EP4:
320 USBHSD->ENDP_CONFIG &= ~USBHS_UEP4_R_EN;
321 break;
322 case USB::Endpoint::EPNumber::EP5:
323 USBHSD->ENDP_CONFIG &= ~USBHS_UEP5_R_EN;
324 break;
325 case USB::Endpoint::EPNumber::EP6:
326 USBHSD->ENDP_CONFIG &= ~USBHS_UEP6_R_EN;
327 break;
328 case USB::Endpoint::EPNumber::EP7:
329 USBHSD->ENDP_CONFIG &= ~USBHS_UEP7_R_EN;
330 break;
331 case USB::Endpoint::EPNumber::EP8:
332 USBHSD->ENDP_CONFIG &= ~USBHS_UEP8_R_EN;
333 break;
334 case USB::Endpoint::EPNumber::EP9:
335 USBHSD->ENDP_CONFIG &= ~USBHS_UEP9_R_EN;
336 break;
337 case USB::Endpoint::EPNumber::EP10:
338 USBHSD->ENDP_CONFIG &= ~USBHS_UEP10_R_EN;
339 break;
340 case USB::Endpoint::EPNumber::EP11:
341 USBHSD->ENDP_CONFIG &= ~USBHS_UEP11_R_EN;
342 break;
343 case USB::Endpoint::EPNumber::EP12:
344 USBHSD->ENDP_CONFIG &= ~USBHS_UEP12_R_EN;
345 break;
346 case USB::Endpoint::EPNumber::EP13:
347 USBHSD->ENDP_CONFIG &= ~USBHS_UEP13_R_EN;
348 break;
349 case USB::Endpoint::EPNumber::EP14:
350 USBHSD->ENDP_CONFIG &= ~USBHS_UEP14_R_EN;
351 break;
352 case USB::Endpoint::EPNumber::EP15:
353 USBHSD->ENDP_CONFIG &= ~USBHS_UEP15_R_EN;
354 break;
355 default:
356 break;
357 }
358}
359// NOLINTEND
360
361CH32EndpointOtgHs::CH32EndpointOtgHs(EPNumber ep_num, Direction dir,
362 LibXR::RawData buffer, bool double_buffer)
363 : Endpoint(ep_num, dir, buffer), hw_double_buffer_(double_buffer), dma_buffer_(buffer)
364{
365 map_otg_hs_[EPNumberToInt8(GetNumber())][static_cast<uint8_t>(dir)] = this;
366
367 if (dir == Direction::IN)
368 {
369 set_tx_dma_buffer(GetNumber(), dma_buffer_.addr_, dma_buffer_.size_, double_buffer);
370 }
371 else
372 {
373 set_rx_dma_buffer(GetNumber(), dma_buffer_.addr_, dma_buffer_.size_, double_buffer);
374 }
375
376 if (dir == Direction::IN)
377 {
378 set_tx_len(GetNumber(), 0);
379 *get_tx_control_addr(GetNumber()) = USBHS_UEP_T_RES_NAK;
380 }
381 else
382 {
383 *get_rx_control_addr(GetNumber()) = USBHS_UEP_R_RES_NAK;
384 }
385}
386
387void CH32EndpointOtgHs::Configure(const Config& cfg)
388{
389 auto& ep_cfg = GetConfig();
390 ep_cfg = cfg;
391
392 const int EP_IDX = EPNumberToInt8(GetNumber());
393
394 const uint8_t IN_IDX = static_cast<uint8_t>(Direction::IN);
395 const uint8_t OUT_IDX = static_cast<uint8_t>(Direction::OUT);
396
397 const bool HAS_IN = (map_otg_hs_[EP_IDX][IN_IDX] != nullptr);
398 const bool HAS_OUT = (map_otg_hs_[EP_IDX][OUT_IDX] != nullptr);
399
400 // 双缓冲策略:EP0 不使用 double buffer。
401 // Double-buffer policy: EP0 does not use double buffering.
402 bool enable_double = (GetNumber() != EPNumber::EP0) && hw_double_buffer_;
403 if (enable_double && HAS_IN && HAS_OUT)
404 {
405 ASSERT(false); // 双缓冲端点必须是单向
406 // / Double-buffer endpoints must be single-direction.
407 enable_double = false;
408 }
409 ep_cfg.double_buffer = enable_double;
410
411 const size_t buffer_size = GetBuffer().size_;
412 if (ep_cfg.type == Type::BULK)
413 {
414 // CH32 USBHS bulk endpoints always use the hardware-fixed 512-byte packet size.
415 // CH32 USBHS 的 BULK 端点始终使用硬件固定的 512 字节包长。
416 ASSERT(buffer_size >= 512u);
417 ep_cfg.max_packet_size = 512u;
418 }
419 else if (ep_cfg.max_packet_size > buffer_size)
420 {
421 // 非 BULK 端点的包长按缓冲区大小截断。
422 // Clamp non-bulk packet sizes to the endpoint buffer size.
423 ep_cfg.max_packet_size = buffer_size;
424 }
425
426 if (GetDirection() == Direction::IN)
427 {
428 if (GetType() != Type::ISOCHRONOUS && GetNumber() != EPNumber::EP0)
429 {
430 *get_tx_control_addr(GetNumber()) = USBHS_UEP_T_RES_NAK | USBHS_UEP_T_TOG_AUTO;
431 }
432 else
433 {
434 *get_tx_control_addr(GetNumber()) = USBHS_UEP_T_RES_NAK;
435 }
436 set_tx_len(GetNumber(), 0);
437 }
438 else
439 {
440 if (GetType() != Type::ISOCHRONOUS && GetNumber() != EPNumber::EP0)
441 {
442 *get_rx_control_addr(GetNumber()) = USBHS_UEP_R_RES_NAK | USBHS_UEP_R_TOG_AUTO;
443 }
444 else
445 {
446 *get_rx_control_addr(GetNumber()) = USBHS_UEP_R_RES_NAK;
447 }
448
449 *get_rx_max_len_addr(GetNumber()) = ep_cfg.max_packet_size;
450 }
451
452 const int IDX = static_cast<int>(GetNumber());
453 if (GetDirection() == Direction::IN)
454 {
455 if (GetType() == Type::ISOCHRONOUS)
456 {
457 USBHSD->ENDP_TYPE |= (USBHS_UEP0_T_TYPE << IDX);
458 }
459 else
460 {
461 USBHSD->ENDP_TYPE &= ~(USBHS_UEP0_T_TYPE << IDX);
462 }
463 }
464 else
465 {
466 if (GetType() == Type::ISOCHRONOUS)
467 {
468 USBHSD->ENDP_TYPE |= (USBHS_UEP0_R_TYPE << IDX);
469 }
470 else
471 {
472 USBHSD->ENDP_TYPE &= ~(USBHS_UEP0_R_TYPE << IDX);
473 }
474 }
475
476 if (GetDirection() == Direction::IN)
477 {
478 if (GetType() != Type::ISOCHRONOUS)
479 {
480 enable_tx(GetNumber());
481 }
482 else
483 {
484 disable_tx(GetNumber());
485 }
486
487 if (!HAS_OUT)
488 {
489 disable_rx(GetNumber());
490 }
491
492 set_tx_dma_buffer(GetNumber(), dma_buffer_.addr_, dma_buffer_.size_, enable_double);
493 }
494 else
495 {
496 enable_rx(GetNumber());
497
498 if (!HAS_IN)
499 {
500 disable_tx(GetNumber());
501 }
502
503 set_rx_dma_buffer(GetNumber(), dma_buffer_.addr_, dma_buffer_.size_, enable_double);
504 }
505
506 SetState(State::IDLE);
507}
508
509void CH32EndpointOtgHs::Close()
510{
511 disable_tx(GetNumber());
512 disable_rx(GetNumber());
513
514 *get_tx_control_addr(GetNumber()) = USBHS_UEP_T_RES_NAK;
515 *get_rx_control_addr(GetNumber()) = USBHS_UEP_R_RES_NAK;
516
517 SetState(State::DISABLED);
518}
519
520ErrorCode CH32EndpointOtgHs::Transfer(size_t size)
521{
522 if (GetState() == State::BUSY)
523 {
524 return ErrorCode::BUSY;
525 }
526
527 auto buffer = GetBuffer();
528 if (buffer.size_ < size)
529 {
530 return ErrorCode::NO_BUFF;
531 }
532
533 bool IS_IN = (GetDirection() == Direction::IN);
534
535 if (IS_IN && UseDoubleBuffer() && GetType() != Type::ISOCHRONOUS)
536 {
537 SwitchBuffer();
538 }
539
540 if (GetNumber() == EPNumber::EP0)
541 {
542 if (!IS_IN && size == 0)
543 {
544 tog0_ = true;
545 tog1_ = false;
546 }
547 }
548
549 last_transfer_size_ = size;
550 SetState(State::BUSY);
551
552 if (IS_IN)
553 {
554 if (GetType() == Type::ISOCHRONOUS)
555 {
556 enable_tx(GetNumber());
557 }
558
559 set_tx_len(GetNumber(), size);
560 auto addr = get_tx_control_addr(GetNumber());
561
562 if (GetType() != Type::ISOCHRONOUS)
563 {
564 if (GetNumber() != EPNumber::EP0)
565 {
566 *addr = (*addr & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_ACK;
567 }
568 else
569 {
570 *addr = USBHS_UEP_T_RES_ACK |
571 (*addr & (~(USBHS_UEP_T_RES_MASK | USBHS_UEP_T_TOG_MDATA))) |
572 (tog0_ ? USBHS_UEP_T_TOG_DATA1 : 0);
573 }
574 }
575 else
576 {
577 *addr = (uint8_t)((*addr & ~(USBHS_UEP_T_RES_MASK | USBHS_UEP_T_TOG_MASK)) |
578 USBHS_UEP_T_TOG_AUTO);
579 }
580 }
581 else
582 {
583 auto addr = get_rx_control_addr(GetNumber());
584
585 if (GetType() != Type::ISOCHRONOUS)
586 {
587 if (GetNumber() != EPNumber::EP0)
588 {
589 *addr = (*addr & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_ACK;
590 }
591 else
592 {
593 if (size == 0u)
594 {
595 // 控制传输的 status OUT 固定从 DATA1 开始。
596 // Control status OUT always starts from DATA1.
597 *addr = USBHS_UEP_R_RES_ACK |
598 (*addr & (~(USBHS_UEP_R_RES_MASK | USBHS_UEP_R_TOG_MDATA))) |
599 USBHS_UEP_R_TOG_DATA1;
600 }
601 else
602 {
603 // EP0 多包 OUT 续挂时,这里只重新打开 ACK,不再用软件重算 DATA0/DATA1。
604 // 每个包成功收完后,由完成路径推进一次硬件 RX toggle。
605 // For EP0 multi-packet OUT, only reopen ACK here and keep the current
606 // hardware DATA0/DATA1 phase; the packet-complete path advances RX toggle.
607 *addr = (*addr & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_ACK;
608 }
609 }
610 }
611 else
612 {
613 *addr = USBHS_UEP_R_RES_ACK |
614 (*addr & (~(USBHS_UEP_R_RES_MASK | USBHS_UEP_R_TOG_MDATA)));
615 }
616 }
617
618 if (GetNumber() == EPNumber::EP0 && IS_IN)
619 {
620 tog0_ = !tog0_;
621 }
622
623 return ErrorCode::OK;
624}
625
626ErrorCode CH32EndpointOtgHs::Stall()
627{
628 const bool IS_IN = (GetDirection() == Direction::IN);
629 if (GetState() != State::IDLE && !(GetState() == State::BUSY && !IS_IN))
630 {
631 return ErrorCode::BUSY;
632 }
633
634 if (IS_IN)
635 {
636 *get_tx_control_addr(GetNumber()) |= USBHS_UEP_T_RES_STALL;
637 }
638 else
639 {
640 *get_rx_control_addr(GetNumber()) |= USBHS_UEP_R_RES_STALL;
641 }
642 SetState(State::STALLED);
643 return ErrorCode::OK;
644}
645
646ErrorCode CH32EndpointOtgHs::ClearStall()
647{
648 if (GetState() != State::STALLED)
649 {
650 return ErrorCode::FAILED;
651 }
652
653 bool IS_IN = (GetDirection() == Direction::IN);
654 if (IS_IN)
655 {
656 *get_tx_control_addr(GetNumber()) &= ~USBHS_UEP_T_RES_STALL;
657 }
658 else
659 {
660 *get_rx_control_addr(GetNumber()) &= ~USBHS_UEP_R_RES_STALL;
661 }
662 SetState(State::IDLE);
663 return ErrorCode::OK;
664}
665
666void CH32EndpointOtgHs::TransferComplete(size_t size)
667{
668 const bool IS_IN = (GetDirection() == Direction::IN);
669 const bool IS_OUT = !IS_IN;
670 const bool IS_EP0 = (GetNumber() == EPNumber::EP0);
671 const bool IS_ISO = (GetType() == Type::ISOCHRONOUS);
672
673 // UIF_TRANSFER/INT_FG 会在 IRQ handler 完成分发后统一清掉。
674 // UIF_TRANSFER/INT_FG are cleared by the IRQ handler after dispatch.
675
676 if (IS_IN)
677 {
678 auto* tx_ctrl = get_tx_control_addr(GetNumber());
679 *tx_ctrl = (*tx_ctrl & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_NAK;
680
681 size = last_transfer_size_;
682
683 if (IS_ISO)
684 {
685 set_tx_len(GetNumber(), 0);
686 disable_tx(GetNumber());
687 }
688 }
689 else
690 {
691 // 对 non-EP0 OUT 端点,完成后恢复到 NAK。
692 // For non-EP0 OUT endpoints, restore NAK on completion.
693 if (!IS_EP0)
694 {
695 auto* rx_ctrl = get_rx_control_addr(GetNumber());
696 *rx_ctrl = (*rx_ctrl & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_NAK;
697 }
698 }
699
700 // TOG 不匹配表示数据同步失败。
701 // TOG mismatch indicates data synchronization failure.
702 if (IS_OUT && !IS_EP0)
703 {
704 const bool TOG_OK =
705 ((USBHSD->INT_ST & USBHS_UIS_TOG_OK) == USBHS_UIS_TOG_OK); // NOLINT
706 if (!TOG_OK)
707 {
708 SetState(State::IDLE);
709 (void)Transfer(last_transfer_size_);
710 return;
711 }
712 }
713
714 if (IS_EP0 && IS_OUT)
715 {
716 auto* rx_ctrl = get_rx_control_addr(GetNumber());
717 // Do not leave EP0 OUT open here. The upper control stack will re-arm it after the
718 // current packet has been fully consumed; otherwise the next session may race stale
719 // EP0 software state and duplicate/skip DFU payload blocks.
720 // 这里不要直接把 EP0 OUT 留在 ACK。
721 // 上层控制传输栈会在“当前包已经被完整消费”后再重新挂接收;
722 // 否则下一轮 session 可能撞上陈旧的 EP0 软件状态,导致 DFU 数据块重复或丢失。
723 if (size > 0u)
724 {
725 // 每成功收完一个 EP0 OUT 包,都要推进一次 RX DATA0/DATA1 相位。
726 // CH32 USBHS 在多包 EP0 OUT 上,如果这里只是重新开 ACK 而不消费当前 toggle,
727 // 后续包会停在这里。
728 // Advance the RX DATA0/DATA1 phase once per successfully received EP0 OUT packet.
729 // On CH32 USBHS, EP0 multi-packet OUT will stall if we only reopen ACK
730 // without consuming the current hardware toggle.
731 *rx_ctrl = static_cast<uint8_t>(
732 ((*rx_ctrl ^ USBHS_UEP_R_TOG_DATA1) & ~USBHS_UEP_R_RES_MASK) |
733 USBHS_UEP_R_RES_NAK);
734 }
735 else
736 {
737 *rx_ctrl =
738 static_cast<uint8_t>((*rx_ctrl & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_NAK);
739 }
740 }
741 OnTransferCompleteCallback(true, size);
742}
743
744void CH32EndpointOtgHs::SwitchBuffer()
745{
746 if (GetDirection() == Direction::IN)
747 {
748 const auto* tx_ctrl = get_tx_control_addr(GetNumber());
749 const bool TOG_IS_DATA1 =
750 ((*tx_ctrl & USBHS_UEP_T_TOG_MASK) == USBHS_UEP_T_TOG_DATA1);
751 SetActiveBlock(!TOG_IS_DATA1);
752 }
753 else
754 {
755 const auto* rx_ctrl = get_rx_control_addr(GetNumber());
756 const bool TOG_IS_DATA1 =
757 ((*rx_ctrl & USBHS_UEP_R_TOG_MASK) == USBHS_UEP_R_TOG_DATA1);
758 SetActiveBlock(TOG_IS_DATA1);
759 }
760}
761
762#endif
原始数据封装类。 A class for encapsulating raw data.
size_t size_
数据大小(字节)。 The size of the data (in bytes).
EPNumber
端点号 Endpoint number
Definition ep.hpp:42
LibXR 命名空间
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举