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 // Double-buffer policy: EP0 does not use double buffering.
401 bool enable_double = (GetNumber() != EPNumber::EP0) && hw_double_buffer_;
402 if (enable_double && HAS_IN && HAS_OUT)
403 {
404 ASSERT(false); // Double-buffer endpoints must be single-direction.
405 enable_double = false;
406 }
407 ep_cfg.double_buffer = enable_double;
408
409 // Clamp max_packet_size to the endpoint buffer size.
410 if (ep_cfg.max_packet_size > GetBuffer().size_)
411 {
412 ep_cfg.max_packet_size = GetBuffer().size_;
413 }
414
415 if (GetDirection() == Direction::IN)
416 {
417 if (GetType() != Type::ISOCHRONOUS && GetNumber() != EPNumber::EP0)
418 {
419 *get_tx_control_addr(GetNumber()) = USBHS_UEP_T_RES_NAK | USBHS_UEP_T_TOG_AUTO;
420 }
421 else
422 {
423 *get_tx_control_addr(GetNumber()) = USBHS_UEP_T_RES_NAK;
424 }
425 set_tx_len(GetNumber(), 0);
426 }
427 else
428 {
429 if (GetType() != Type::ISOCHRONOUS && GetNumber() != EPNumber::EP0)
430 {
431 *get_rx_control_addr(GetNumber()) = USBHS_UEP_R_RES_NAK | USBHS_UEP_R_TOG_AUTO;
432 }
433 else
434 {
435 *get_rx_control_addr(GetNumber()) = USBHS_UEP_R_RES_NAK;
436 }
437
438 if (GetNumber() != EPNumber::EP0)
439 {
440 *get_rx_max_len_addr(GetNumber()) = ep_cfg.max_packet_size;
441 }
442 }
443
444 const int IDX = static_cast<int>(GetNumber());
445 if (GetDirection() == Direction::IN)
446 {
447 if (GetType() == Type::ISOCHRONOUS)
448 {
449 USBHSD->ENDP_TYPE |= (USBHS_UEP0_T_TYPE << IDX);
450 }
451 else
452 {
453 USBHSD->ENDP_TYPE &= ~(USBHS_UEP0_T_TYPE << IDX);
454 }
455 }
456 else
457 {
458 if (GetType() == Type::ISOCHRONOUS)
459 {
460 USBHSD->ENDP_TYPE |= (USBHS_UEP0_R_TYPE << IDX);
461 }
462 else
463 {
464 USBHSD->ENDP_TYPE &= ~(USBHS_UEP0_R_TYPE << IDX);
465 }
466 }
467
468 if (GetDirection() == Direction::IN)
469 {
470 if (GetType() != Type::ISOCHRONOUS)
471 {
472 enable_tx(GetNumber());
473 }
474 else
475 {
476 disable_tx(GetNumber());
477 }
478
479 if (!HAS_OUT)
480 {
481 disable_rx(GetNumber());
482 }
483
484 set_tx_dma_buffer(GetNumber(), dma_buffer_.addr_, dma_buffer_.size_, enable_double);
485 }
486 else
487 {
488 enable_rx(GetNumber());
489
490 if (!HAS_IN)
491 {
492 disable_tx(GetNumber());
493 }
494
495 set_rx_dma_buffer(GetNumber(), dma_buffer_.addr_, dma_buffer_.size_, enable_double);
496 }
497
498 SetState(State::IDLE);
499}
500
501void CH32EndpointOtgHs::Close()
502{
503 disable_tx(GetNumber());
504 disable_rx(GetNumber());
505
506 *get_tx_control_addr(GetNumber()) = USBHS_UEP_T_RES_NAK;
507 *get_rx_control_addr(GetNumber()) = USBHS_UEP_R_RES_NAK;
508
509 SetState(State::DISABLED);
510}
511
512ErrorCode CH32EndpointOtgHs::Transfer(size_t size)
513{
514 if (GetState() == State::BUSY)
515 {
516 return ErrorCode::BUSY;
517 }
518
519 auto buffer = GetBuffer();
520 if (buffer.size_ < size)
521 {
522 return ErrorCode::NO_BUFF;
523 }
524
525 bool IS_IN = (GetDirection() == Direction::IN);
526
527 if (IS_IN && UseDoubleBuffer() && GetType() != Type::ISOCHRONOUS)
528 {
529 SwitchBuffer();
530 }
531
532 if (GetNumber() == EPNumber::EP0)
533 {
534 if (size == 0)
535 {
536 tog0_ = true;
537 tog1_ = false;
538 }
539 }
540
541 last_transfer_size_ = size;
542 SetState(State::BUSY);
543
544 if (IS_IN)
545 {
546 if (GetType() == Type::ISOCHRONOUS)
547 {
548 enable_tx(GetNumber());
549 }
550
551 set_tx_len(GetNumber(), size);
552 auto addr = get_tx_control_addr(GetNumber());
553
554 if (GetType() != Type::ISOCHRONOUS)
555 {
556 if (GetNumber() != EPNumber::EP0)
557 {
558 *addr = (*addr & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_ACK;
559 }
560 else
561 {
562 *addr = USBHS_UEP_T_RES_ACK |
563 (*addr & (~(USBHS_UEP_T_RES_MASK | USBHS_UEP_T_TOG_MDATA))) |
564 (tog0_ ? USBHS_UEP_T_TOG_DATA1 : 0);
565 }
566 }
567 else
568 {
569 *addr = (uint8_t)((*addr & ~(USBHS_UEP_T_RES_MASK | USBHS_UEP_T_TOG_MASK)) |
570 USBHS_UEP_T_TOG_AUTO);
571 }
572 }
573 else
574 {
575 auto addr = get_rx_control_addr(GetNumber());
576
577 if (GetType() != Type::ISOCHRONOUS)
578 {
579 if (GetNumber() != EPNumber::EP0)
580 {
581 *addr = (*addr & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_ACK;
582 }
583 else
584 {
585 *addr = USBHS_UEP_R_RES_ACK |
586 (*addr & (~(USBHS_UEP_R_RES_MASK | USBHS_UEP_R_TOG_MDATA))) |
587 (tog0_ ? USBHS_UEP_R_TOG_DATA1 : 0);
588 }
589 }
590 else
591 {
592 *addr = USBHS_UEP_R_RES_ACK |
593 (*addr & (~(USBHS_UEP_R_RES_MASK | USBHS_UEP_R_TOG_MDATA)));
594 }
595 }
596
597 if (GetNumber() == EPNumber::EP0)
598 {
599 tog0_ = !tog0_;
600 }
601
602 return ErrorCode::OK;
603}
604
605ErrorCode CH32EndpointOtgHs::Stall()
606{
607 if (GetState() != State::IDLE)
608 {
609 return ErrorCode::BUSY;
610 }
611
612 bool IS_IN = (GetDirection() == Direction::IN);
613 if (IS_IN)
614 {
615 *get_tx_control_addr(GetNumber()) |= USBHS_UEP_T_RES_STALL;
616 }
617 else
618 {
619 *get_rx_control_addr(GetNumber()) |= USBHS_UEP_R_RES_STALL;
620 }
621 SetState(State::STALLED);
622 return ErrorCode::OK;
623}
624
625ErrorCode CH32EndpointOtgHs::ClearStall()
626{
627 if (GetState() != State::STALLED)
628 {
629 return ErrorCode::FAILED;
630 }
631
632 bool IS_IN = (GetDirection() == Direction::IN);
633 if (IS_IN)
634 {
635 *get_tx_control_addr(GetNumber()) &= ~USBHS_UEP_T_RES_STALL;
636 }
637 else
638 {
639 *get_rx_control_addr(GetNumber()) &= ~USBHS_UEP_R_RES_STALL;
640 }
641 SetState(State::IDLE);
642 return ErrorCode::OK;
643}
644
645void CH32EndpointOtgHs::TransferComplete(size_t size)
646{
647 const bool IS_IN = (GetDirection() == Direction::IN);
648 const bool IS_OUT = !IS_IN;
649 const bool IS_EP0 = (GetNumber() == EPNumber::EP0);
650 const bool IS_ISO = (GetType() == Type::ISOCHRONOUS);
651
652 // UIF_TRANSFER/INT_FG are cleared by the IRQ handler after dispatch.
653
654 if (IS_IN)
655 {
656 auto* tx_ctrl = get_tx_control_addr(GetNumber());
657 *tx_ctrl = (*tx_ctrl & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_NAK;
658
659 size = last_transfer_size_;
660
661 if (IS_ISO)
662 {
663 set_tx_len(GetNumber(), 0);
664 disable_tx(GetNumber());
665 }
666 }
667 else
668 {
669 // For non-EP0 OUT endpoints, restore NAK on completion.
670 if (!IS_EP0)
671 {
672 auto* rx_ctrl = get_rx_control_addr(GetNumber());
673 *rx_ctrl = (*rx_ctrl & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_NAK;
674 }
675 }
676
677 // TOG mismatch indicates data synchronization failure.
678 if (IS_OUT)
679 {
680 const bool TOG_OK =
681 ((USBHSD->INT_ST & USBHS_UIS_TOG_OK) == USBHS_UIS_TOG_OK); // NOLINT
682 if (!TOG_OK)
683 {
684 SetState(State::IDLE);
685 (void)Transfer(last_transfer_size_);
686 return;
687 }
688 }
689
690 if (IS_EP0 && IS_OUT)
691 {
692 tog0_ = true;
693 tog1_ = false;
694 *get_rx_control_addr(GetNumber()) = USBHS_UEP_R_RES_ACK;
695 }
696
697 OnTransferCompleteCallback(true, size);
698}
699
700void CH32EndpointOtgHs::SwitchBuffer()
701{
702 if (GetDirection() == Direction::IN)
703 {
704 const auto* tx_ctrl = get_tx_control_addr(GetNumber());
705 const bool TOG_IS_DATA1 =
706 ((*tx_ctrl & USBHS_UEP_T_TOG_MASK) == USBHS_UEP_T_TOG_DATA1);
707 SetActiveBlock(!TOG_IS_DATA1);
708 }
709 else
710 {
711 const auto* rx_ctrl = get_rx_control_addr(GetNumber());
712 const bool TOG_IS_DATA1 =
713 ((*rx_ctrl & USBHS_UEP_R_TOG_MASK) == USBHS_UEP_R_TOG_DATA1);
714 SetActiveBlock(TOG_IS_DATA1);
715 }
716}
717
718#endif
原始数据封装类。 A class for encapsulating raw data.
size_t size_
数据大小(字节)。 The size of the data (in bytes).
EPNumber
端点号 Endpoint number
Definition ep.hpp:41
LibXR 命名空间
Definition ch32_can.hpp:14