libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
ch32_usb_devfs.cpp
1// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast,performance-no-int-to-ptr)
2// ch32_usb_devfs.cpp (classic FSDEV / PMA)
3#include "ch32_usb_dev.hpp"
4#include "ch32_usb_endpoint.hpp"
5#include "ch32_usb_rcc.hpp"
6#include "ch32_usbcan_shared.hpp"
7#include "ep.hpp"
8
9using namespace LibXR;
10using namespace LibXR::USB;
11
12#if defined(RCC_APB1Periph_USB)
13
14#ifdef USB_BASE
15static constexpr uintptr_t USBDEV_REG_BASE = USB_BASE;
16#else
17static constexpr uintptr_t USBDEV_REG_BASE = 0x40005C00UL;
18#endif
19
20static inline volatile uint16_t* usbdev_cntr()
21{
22 // 固定的 MMIO 物理基地址。
23 // Fixed MMIO physical base address.
24 // NOLINTNEXTLINE(performance-no-int-to-ptr)
25 return reinterpret_cast<volatile uint16_t*>(USBDEV_REG_BASE + 0x40U);
26}
27static inline volatile uint16_t* usbdev_istr()
28{
29 return reinterpret_cast<volatile uint16_t*>(USBDEV_REG_BASE + 0x44U);
30}
31static inline volatile uint16_t* usbdev_daddr()
32{
33 return reinterpret_cast<volatile uint16_t*>(USBDEV_REG_BASE + 0x4CU);
34}
35static inline volatile uint16_t* usbdev_btable()
36{
37 return reinterpret_cast<volatile uint16_t*>(USBDEV_REG_BASE + 0x50U);
38}
39static inline volatile uint16_t* usbdev_ep_reg(uint8_t ep)
40{
41 return reinterpret_cast<volatile uint16_t*>(USBDEV_REG_BASE +
42 static_cast<uintptr_t>(ep) * 4U);
43}
44
45// 兼容 classic USBLIB 风格的宏别名。
46// Compatibility aliases for classic USBLIB-style macro names.
47#if !defined(USB_ISTR_CTR) && defined(ISTR_CTR)
48#define USB_ISTR_CTR ISTR_CTR
49#endif
50#if !defined(USB_ISTR_RESET) && defined(ISTR_RESET)
51#define USB_ISTR_RESET ISTR_RESET
52#endif
53#if !defined(USB_ISTR_SUSP) && defined(ISTR_SUSP)
54#define USB_ISTR_SUSP ISTR_SUSP
55#endif
56#if !defined(USB_ISTR_WKUP) && defined(ISTR_WKUP)
57#define USB_ISTR_WKUP ISTR_WKUP
58#endif
59#if !defined(USB_ISTR_EP_ID) && defined(ISTR_EP_ID)
60#define USB_ISTR_EP_ID ISTR_EP_ID
61#endif
62
63#if !defined(USB_CNTR_FRES) && defined(CNTR_FRES)
64#define USB_CNTR_FRES CNTR_FRES
65#endif
66#if !defined(USB_CNTR_CTRM) && defined(CNTR_CTRM)
67#define USB_CNTR_CTRM CNTR_CTRM
68#endif
69#if !defined(USB_CNTR_RESETM) && defined(CNTR_RESETM)
70#define USB_CNTR_RESETM CNTR_RESETM
71#endif
72#if !defined(USB_CNTR_SUSPM) && defined(CNTR_SUSPM)
73#define USB_CNTR_SUSPM CNTR_SUSPM
74#endif
75#if !defined(USB_CNTR_WKUPM) && defined(CNTR_WKUPM)
76#define USB_CNTR_WKUPM CNTR_WKUPM
77#endif
78
79#if !defined(USB_DADDR_EF) && defined(DADDR_EF)
80#define USB_DADDR_EF DADDR_EF
81#endif
82
83#if !defined(USB_EP_CTR_TX) && defined(EP_CTR_TX)
84#define USB_EP_CTR_TX EP_CTR_TX
85#endif
86#if !defined(USB_EP_CTR_RX) && defined(EP_CTR_RX)
87#define USB_EP_CTR_RX EP_CTR_RX
88#endif
89#if !defined(USB_EP_SETUP) && defined(EP_SETUP)
90#define USB_EP_SETUP EP_SETUP
91#endif
92#if !defined(USB_EP_KIND) && defined(EP_KIND)
93#define USB_EP_KIND EP_KIND
94#endif
95#if !defined(USB_EP_T_FIELD) && defined(EP_T_FIELD)
96#define USB_EP_T_FIELD EP_T_FIELD
97#endif
98#if !defined(USB_EPADDR_FIELD) && defined(EPADDR_FIELD)
99#define USB_EPADDR_FIELD EPADDR_FIELD
100#endif
101
102#ifndef USB_ISTR_CTR
103#define USB_ISTR_CTR 0x8000u
104#endif
105#ifndef USB_ISTR_RESET
106#define USB_ISTR_RESET 0x0400u
107#endif
108#ifndef USB_ISTR_SUSP
109#define USB_ISTR_SUSP 0x0800u
110#endif
111#ifndef USB_ISTR_WKUP
112#define USB_ISTR_WKUP 0x1000u
113#endif
114#ifndef USB_ISTR_EP_ID
115#define USB_ISTR_EP_ID 0x000Fu
116#endif
117
118#ifndef USB_CNTR_FRES
119#define USB_CNTR_FRES 0x0001u
120#endif
121#ifndef USB_CNTR_CTRM
122#define USB_CNTR_CTRM 0x8000u
123#endif
124#ifndef USB_CNTR_RESETM
125#define USB_CNTR_RESETM 0x0400u
126#endif
127#ifndef USB_CNTR_SUSPM
128#define USB_CNTR_SUSPM 0x0800u
129#endif
130#ifndef USB_CNTR_WKUPM
131#define USB_CNTR_WKUPM 0x1000u
132#endif
133
134#ifndef USB_DADDR_EF
135#define USB_DADDR_EF 0x0080u
136#endif
137
138#ifndef USB_EP_CTR_RX
139#define USB_EP_CTR_RX 0x8000u
140#endif
141#ifndef USB_EP_CTR_TX
142#define USB_EP_CTR_TX 0x0080u
143#endif
144#ifndef USB_EP_SETUP
145#define USB_EP_SETUP 0x0800u
146#endif
147#ifndef USB_EP_KIND
148#define USB_EP_KIND 0x0100u
149#endif
150#ifndef USB_EP_T_FIELD
151#define USB_EP_T_FIELD 0x0600u
152#endif
153#ifndef USB_EPADDR_FIELD
154#define USB_EPADDR_FIELD 0x000Fu
155#endif
156
157#ifndef USB_EP_TX_NAK
158#define USB_EP_TX_NAK 0x0020u
159#endif
160#ifndef USB_EP_RX_DIS
161#define USB_EP_RX_DIS 0x0000u
162#endif
163#ifndef USB_EP_RX_STALL
164#define USB_EP_RX_STALL 0x1000u
165#endif
166#ifndef USB_EP_RX_NAK
167#define USB_EP_RX_NAK 0x2000u
168#endif
169#ifndef USB_EP_RX_VALID
170#define USB_EP_RX_VALID 0x3000u
171#endif
172
173#ifndef USB_EPREG_MASK
174#define USB_EPREG_MASK \
175 (USB_EP_CTR_RX | USB_EP_SETUP | USB_EP_T_FIELD | USB_EP_KIND | USB_EP_CTR_TX | \
176 USB_EPADDR_FIELD)
177#endif
178
179static inline void usbdev_clear_istr(uint16_t mask)
180{
181 *usbdev_istr() = static_cast<uint16_t>(~mask);
182}
183
184static inline void usbdev_set_ep_address(uint8_t ep, uint8_t addr)
185{
186 volatile uint16_t* reg = usbdev_ep_reg(ep);
187 const uint16_t CUR = *reg;
188
189 const uint16_t V = static_cast<uint16_t>(USB_EP_CTR_RX | USB_EP_CTR_TX |
190 (CUR & (USB_EPREG_MASK & ~USB_EPADDR_FIELD)) |
191 (addr & USB_EPADDR_FIELD));
192
193 *reg = V;
194}
195
196static LibXR::RawData select_buffer_dev_fs(USB::Endpoint::EPNumber ep_num,
198 const LibXR::RawData& buffer)
199{
200 if (ep_num == USB::Endpoint::EPNumber::EP0)
201 {
202 return buffer;
203 }
204
205 const size_t HALF = buffer.size_ / 2;
206 if (dir == USB::Endpoint::Direction::OUT)
207 {
208 return LibXR::RawData(buffer.addr_, HALF);
209 }
210 return LibXR::RawData(reinterpret_cast<uint8_t*>(buffer.addr_) + HALF, HALF);
211}
212
213static void drain_usbdev_fs_pending_irqs()
214{
215 while (true)
216 {
217 const uint16_t ISTR = *usbdev_istr();
218
219 if (ISTR & USB_ISTR_RESET)
220 {
221 usbdev_clear_istr(USB_ISTR_RESET);
222 continue;
223 }
224
225 if (ISTR & USB_ISTR_SUSP)
226 {
227 usbdev_clear_istr(USB_ISTR_SUSP);
228 continue;
229 }
230
231 if (ISTR & USB_ISTR_WKUP)
232 {
233 usbdev_clear_istr(USB_ISTR_WKUP);
234 continue;
235 }
236
237 if ((ISTR & USB_ISTR_CTR) == 0)
238 {
239 break;
240 }
241
242 const uint8_t EP_ID = static_cast<uint8_t>(ISTR & USB_ISTR_EP_ID);
243
244 uint16_t epr = *usbdev_ep_reg(EP_ID);
245 if (epr & USB_EP_CTR_RX)
246 {
247 LibXR::CH32EndpointDevFs::ClearEpCtrRx(EP_ID);
248 }
249
250 epr = *usbdev_ep_reg(EP_ID);
251 if (epr & USB_EP_CTR_TX)
252 {
253 LibXR::CH32EndpointDevFs::ClearEpCtrTx(EP_ID);
254 }
255
256 // We only drain the bits that are latched right now. If the host produces a
257 // new event after that point, hardware will assert the IRQ again and the next
258 // handler entry will observe it.
259 // 这里只清掉当前已经锁存的 pending 位;如果主机随后又产生了新事件,
260 // 硬件会重新拉起 IRQ,下一次进入 handler 时再处理。
261 }
262}
263
264static void usbdev_fs_irqhandler()
265{
266 auto* usb = LibXR::CH32USBDeviceFS::self_;
267 if (usb == nullptr || !usb->IsInited())
268 {
269 drain_usbdev_fs_pending_irqs();
270 return;
271 }
272
273 auto& map = LibXR::CH32EndpointDevFs::map_dev_fs_;
274
275 constexpr uint8_t OUT_IDX = static_cast<uint8_t>(LibXR::USB::Endpoint::Direction::OUT);
276 constexpr uint8_t IN_IDX = static_cast<uint8_t>(LibXR::USB::Endpoint::Direction::IN);
277 auto* out0 = map[0][OUT_IDX];
278 auto* in0 = map[0][IN_IDX];
279 ASSERT(out0 != nullptr);
280 ASSERT(in0 != nullptr);
281
282 while (true)
283 {
284 const uint16_t ISTR = *usbdev_istr();
285
286 // 总线 reset 需要先重建 PMA 分配器和 EP0 默认状态,
287 // 之后才继续处理新的 CTR 事件。
288 // Bus reset rebuilds the PMA allocator and EP0 default state before
289 // processing new CTR events again.
290 if (ISTR & USB_ISTR_RESET)
291 {
292 usbdev_clear_istr(USB_ISTR_RESET);
293
294 *usbdev_daddr() = USB_DADDR_EF;
295 *usbdev_btable() = 0;
296
297 LibXR::CH32EndpointDevFs::ResetPMAAllocator();
298
299 usb->Deinit(true);
300 usb->Init(true);
301
302 out0->SetState(LibXR::USB::Endpoint::State::IDLE);
304
305 LibXR::CH32EndpointDevFs::SetEpTxStatus(0, USB_EP_TX_NAK);
306 LibXR::CH32EndpointDevFs::SetEpRxStatus(0, USB_EP_RX_VALID);
307 continue;
308 }
309
310 // suspend 也走同一条控制端点恢复路径,
311 // 但会先把 EP0 RX 保持在 NAK,等协议栈重新挂起下一笔传输。
312 // Suspend follows the same control-endpoint recovery path, but keeps EP0 RX
313 // in NAK until the stack re-arms the next transfer.
314 if (ISTR & USB_ISTR_SUSP)
315 {
316 usbdev_clear_istr(USB_ISTR_SUSP);
317
318 usb->Deinit(true);
319 usb->Init(true);
320
321 out0->SetState(LibXR::USB::Endpoint::State::IDLE);
323
324 LibXR::CH32EndpointDevFs::SetEpTxStatus(0, USB_EP_TX_NAK);
325 LibXR::CH32EndpointDevFs::SetEpRxStatus(0, USB_EP_RX_NAK);
326 continue;
327 }
328
329 if (ISTR & USB_ISTR_WKUP)
330 {
331 usbdev_clear_istr(USB_ISTR_WKUP);
332 continue;
333 }
334
335 if ((ISTR & USB_ISTR_CTR) == 0)
336 {
337 break;
338 }
339
340 // 经典 FSDEV 通过 CTR 标志一次只上报一个端点。
341 // Classic FSDEV reports one endpoint at a time through CTR flags.
342 const uint8_t EP_ID = static_cast<uint8_t>(ISTR & USB_ISTR_EP_ID);
343
344 uint16_t epr = *usbdev_ep_reg(EP_ID);
345
346 if (epr & USB_EP_CTR_RX)
347 {
348 if (EP_ID == 0)
349 {
350 if (epr & USB_EP_SETUP)
351 {
352 // 新的 SETUP 会开始一笔全新的控制传输;
353 // 这里只清理挂起的 CTR 标志,EP0 RX/TX 由控制传输处理器重新挂起。
354 // A new SETUP starts a fresh control transfer; only clear pending CTR
355 // flags here, and let the control-transfer handlers re-arm EP0 RX/TX.
356 if (epr & USB_EP_CTR_TX)
357 {
358 LibXR::CH32EndpointDevFs::ClearEpCtrTx(0);
359 }
360 LibXR::CH32EndpointDevFs::ClearEpCtrRx(0);
361
362 out0->CopyRxDataToBuffer(sizeof(LibXR::USB::SetupPacket));
363 usb->OnSetupPacket(true, reinterpret_cast<const LibXR::USB::SetupPacket*>(
364 out0->GetBuffer().addr_));
365
366 continue;
367 }
368 else
369 {
370 // 普通 EP0 OUT 数据/状态阶段完成。
371 // Ordinary EP0 OUT data/status completion.
372 LibXR::CH32EndpointDevFs::ClearEpCtrRx(0);
373 const uint16_t LEN = LibXR::CH32EndpointDevFs::GetRxCount(0);
374 out0->TransferComplete(LEN);
375 }
376 }
377 else
378 {
379 // non-EP0 OUT 完成直接使用硬件锁存的该端点 RX 长度。
380 // Non-EP0 OUT completion uses the per-endpoint RX length latched by hardware.
381 LibXR::CH32EndpointDevFs::ClearEpCtrRx(EP_ID);
382 const uint16_t LEN = LibXR::CH32EndpointDevFs::GetRxCount(EP_ID);
383 if (map[EP_ID][OUT_IDX])
384 {
385 map[EP_ID][OUT_IDX]->TransferComplete(LEN);
386 }
387 }
388 }
389
390 epr = *usbdev_ep_reg(EP_ID);
391
392 if (epr & USB_EP_CTR_TX)
393 {
394 if (EP_ID == 0)
395 {
396 // EP0 IN 完成事件本身就足够,不需要额外长度信息。
397 // EP0 IN completion is self-sufficient; no extra length bookkeeping is needed.
398 LibXR::CH32EndpointDevFs::ClearEpCtrTx(0);
399 in0->TransferComplete(0);
400 }
401 else
402 {
403 // FSDEV 上的 non-EP0 IN 完成与 EP0 IN 一样,不额外携带长度信息。
404 // Non-EP0 IN completion follows the same rule as EP0 IN on FSDEV.
405 LibXR::CH32EndpointDevFs::ClearEpCtrTx(EP_ID);
406 if (map[EP_ID][IN_IDX])
407 {
408 map[EP_ID][IN_IDX]->TransferComplete(0);
409 }
410 }
411 }
412 }
413}
414
415static void usb_irq_thunk() { usbdev_fs_irqhandler(); }
416
417// NOLINTNEXTLINE(readability-identifier-naming)
418extern "C" __attribute__((interrupt("WCH-Interrupt-fast"))) void USBWakeUp_IRQHandler(
419 void)
420{
421#if defined(EXTI_Line18)
422 EXTI_ClearITPendingBit(EXTI_Line18);
423#endif
424}
425
426CH32USBDeviceFS::CH32USBDeviceFS(
427 const std::initializer_list<EPConfig> EP_CFGS,
428 USB::DeviceDescriptor::PacketSize0 packet_size, uint16_t vid, uint16_t pid,
429 uint16_t bcd,
430 const std::initializer_list<const USB::DescriptorStrings::LanguagePack*> LANG_LIST,
431 const std::initializer_list<const std::initializer_list<USB::ConfigDescriptorItem*>>
432 CONFIGS,
433 ConstRawData uid)
434 : USB::EndpointPool(EP_CFGS.size() * 2),
435 USB::DeviceCore(*this, USB::USBSpec::USB_2_1, USB::Speed::FULL, packet_size, vid,
436 pid, bcd, LANG_LIST, CONFIGS, uid)
437{
438 ASSERT(EP_CFGS.size() > 0 && EP_CFGS.size() <= CH32EndpointDevFs::EP_DEV_FS_MAX_SIZE);
439
440 auto cfgs_itr = EP_CFGS.begin();
441
442 auto ep0_out =
443 new CH32EndpointDevFs(USB::Endpoint::EPNumber::EP0, USB::Endpoint::Direction::OUT,
444 cfgs_itr->buffer, false);
445 auto ep0_in =
446 new CH32EndpointDevFs(USB::Endpoint::EPNumber::EP0, USB::Endpoint::Direction::IN,
447 cfgs_itr->buffer, false);
448
449 USB::EndpointPool::SetEndpoint0(ep0_in, ep0_out);
450
451 USB::Endpoint::EPNumber ep_index = USB::Endpoint::EPNumber::EP1;
452
453 for (++cfgs_itr, ep_index = USB::Endpoint::EPNumber::EP1; cfgs_itr != EP_CFGS.end();
454 ++cfgs_itr, ep_index = USB::Endpoint::NextEPNumber(ep_index))
455 {
456 if (cfgs_itr->is_in == -1)
457 {
458 auto ep_out = new CH32EndpointDevFs(
459 ep_index, USB::Endpoint::Direction::OUT,
460 select_buffer_dev_fs(ep_index, USB::Endpoint::Direction::OUT, cfgs_itr->buffer),
461 false);
462 USB::EndpointPool::Put(ep_out);
463
464 auto ep_in = new CH32EndpointDevFs(
465 ep_index, USB::Endpoint::Direction::IN,
466 select_buffer_dev_fs(ep_index, USB::Endpoint::Direction::IN, cfgs_itr->buffer),
467 false);
468 USB::EndpointPool::Put(ep_in);
469 }
470 else
471 {
472 auto ep = new CH32EndpointDevFs(
473 ep_index,
474 cfgs_itr->is_in ? USB::Endpoint::Direction::IN : USB::Endpoint::Direction::OUT,
475 cfgs_itr->buffer, true);
476 USB::EndpointPool::Put(ep);
477 }
478 }
479}
480
481LibXR::ErrorCode CH32USBDeviceFS::SetAddress(uint8_t address,
483{
484 if (context == USB::DeviceCore::Context::STATUS_IN_COMPLETE)
485 {
486 const uint8_t N_EP = static_cast<uint8_t>(CH32EndpointDevFs::EP_DEV_FS_MAX_SIZE);
487 for (uint8_t i = 0; i < N_EP; i++)
488 {
489 usbdev_set_ep_address(i, i);
490 }
491
492 *usbdev_daddr() = static_cast<uint16_t>(USB_DADDR_EF | address);
493
494 CH32EndpointDevFs::SetEpTxStatus(0, USB_EP_TX_NAK);
495 CH32EndpointDevFs::SetEpRxStatus(0, USB_EP_RX_VALID);
496 }
498}
499
500void CH32USBDeviceFS::Start(bool)
501{
502 // FSDEV 使用共享 USB 48 MHz 时钟;如果这个时钟来自 USBHS PHY PLL,
503 // 则必须先打开 USBHS 依赖时钟,再打开 USBDEV 本体时钟。
504 // FSDEV uses the shared USB 48 MHz clock; when that clock comes from the
505 // USBHS PHY PLL, keep the USBHS dependency clock enabled before USBDEV itself.
506 LibXR::CH32UsbRcc::ConfigureUsb48M();
507#if defined(RCC_USBCLK48MCLKSource_USBPHY) && defined(RCC_AHBPeriph_USBHS)
508 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_USBHS, ENABLE);
509#endif
510 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);
511
512#if defined(RCC_APB2Periph_GPIOA) && defined(GPIOA) && defined(GPIO_Pin_11) && \
513 defined(GPIO_Pin_12) && defined(GPIO_Mode_Out_PP) && defined(GPIO_Speed_50MHz) && \
514 defined(GPIO_Mode_IN_FLOATING)
515 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
516
517 GPIO_InitTypeDef gpio{};
518 gpio.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
519 gpio.GPIO_Speed = GPIO_Speed_50MHz;
520 gpio.GPIO_Mode = GPIO_Mode_Out_PP;
521 GPIO_Init(GPIOA, &gpio);
522 GPIO_ResetBits(GPIOA, GPIO_Pin_11 | GPIO_Pin_12);
523
524 gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
525 GPIO_Init(GPIOA, &gpio);
526#endif
527
528 *usbdev_cntr() = USB_CNTR_FRES;
529 *usbdev_cntr() = 0;
530
531 usbdev_clear_istr(0xFFFFu);
532 *usbdev_btable() = 0;
533
534 *usbdev_cntr() = static_cast<uint16_t>(USB_CNTR_RESETM | USB_CNTR_SUSPM |
535 USB_CNTR_WKUPM | USB_CNTR_CTRM);
536
537#if defined(EXTEN_USBD_LS)
538 EXTEN->EXTEN_CTR &= ~EXTEN_USBD_LS;
539#endif
540
541 NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
542 NVIC_EnableIRQ(USB_HP_CAN1_TX_IRQn);
543 NVIC_EnableIRQ(USBWakeUp_IRQn);
544
545#if defined(EXTEN_USBD_PU_EN)
546 EXTEN->EXTEN_CTR |= EXTEN_USBD_PU_EN;
547#endif
548
549 *usbdev_daddr() = USB_DADDR_EF;
550
551 CH32EndpointDevFs::SetEpTxStatus(0, USB_EP_TX_NAK);
552 CH32EndpointDevFs::SetEpRxStatus(0, USB_EP_RX_VALID);
553
554 // DeviceCore::Init() 可能早于 FSDEV reset/BTABLE 初始化就预挂起 OUT 端点;
555 // 因此这里在硬件初始化完成后补一次 non-EP0 OUT 端点重装填。
556 // DeviceCore::Init() may arm OUT endpoints before FSDEV reset/BTABLE
557 // initialization; re-arm non-EP0 OUT endpoints that remain BUSY afterwards.
558 auto& ep_map = LibXR::CH32EndpointDevFs::map_dev_fs_;
559 constexpr uint8_t OUT_IDX = static_cast<uint8_t>(LibXR::USB::Endpoint::Direction::OUT);
560 const uint8_t N_EP = static_cast<uint8_t>(LibXR::CH32EndpointDevFs::EP_DEV_FS_MAX_SIZE);
561 for (uint8_t ep = 1; ep < N_EP; ++ep)
562 {
563 auto* out = ep_map[ep][OUT_IDX];
564 if (out == nullptr)
565 {
566 continue;
567 }
568 if (out->GetState() != LibXR::USB::Endpoint::State::BUSY)
569 {
570 continue;
571 }
572 (void)out->Transfer(out->MaxTransferSize());
573 }
574
575 self_ = this;
576 LibXR::CH32UsbCanShared::usb_inited.store(true, std::memory_order_release);
577 LibXR::CH32UsbCanShared::register_usb_irq(&usb_irq_thunk);
578}
579
580void CH32USBDeviceFS::Stop(bool)
581{
582 LibXR::CH32UsbCanShared::register_usb_irq(nullptr);
583 LibXR::CH32UsbCanShared::usb_inited.store(false, std::memory_order_release);
584 self_ = nullptr;
585
586#if defined(EXTEN_USBD_PU_EN)
587 EXTEN->EXTEN_CTR &= ~EXTEN_USBD_PU_EN;
588#endif
589
590 if (!LibXR::CH32UsbCanShared::can1_active())
591 {
592 NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn);
593 NVIC_DisableIRQ(USB_HP_CAN1_TX_IRQn);
594 }
595 NVIC_DisableIRQ(USBWakeUp_IRQn);
596
597 *usbdev_cntr() = USB_CNTR_FRES;
598}
599
600#endif // defined(RCC_APB1Periph_USB)
601
602// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast,performance-no-int-to-ptr)
只读原始数据视图 / Immutable raw data view
可写原始数据视图 / Mutable raw data view
size_t size_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
USB 设备协议栈核心:EP0 控制传输、描述符、配置、标准/类/厂商请求 USB device core: EP0 control transfer, descriptors,...
Definition dev_core.hpp:22
Context
控制传输上下文 / Control transfer context
Definition dev_core.hpp:31
PacketSize0
控制端点0最大包长度枚举 Packet size for endpoint 0 (bMaxPacketSize0)
Definition desc_dev.hpp:75
EPNumber
端点号 Endpoint number
Definition ep.hpp:42
Direction
端点方向 Endpoint direction
Definition ep.hpp:31
@ IN
输入方向 / IN direction
@ OUT
输出方向 / OUT direction
static constexpr EPNumber NextEPNumber(EPNumber ep)
获取下一个端点号 / Get the next endpoint number
Definition ep.hpp:128
USB端点池类 / USB endpoint pool class.
Definition ep_pool.hpp:23
void SetEndpoint0(Endpoint *ep0_in, Endpoint *ep0_out)
设置端点0的IN/OUT对象 / Set Endpoint 0 IN/OUT objects
Definition ep_pool.cpp:96
LibXR 命名空间
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举
@ FULL
已满 | Full
@ OK
操作成功 | Operation successful
USB 标准请求 SETUP 包(固定8字节) Standard USB setup packet (8 bytes)
Definition core.hpp:58