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 usbdev_fs_irqhandler()
214{
215 auto& map = LibXR::CH32EndpointDevFs::map_dev_fs_;
216
217 constexpr uint8_t OUT_IDX = static_cast<uint8_t>(LibXR::USB::Endpoint::Direction::OUT);
218 constexpr uint8_t IN_IDX = static_cast<uint8_t>(LibXR::USB::Endpoint::Direction::IN);
219 auto* out0 = map[0][OUT_IDX];
220 auto* in0 = map[0][IN_IDX];
221 ASSERT(out0 != nullptr);
222 ASSERT(in0 != nullptr);
223
224 while (true)
225 {
226 const uint16_t ISTR = *usbdev_istr();
227
228 // 总线 reset 需要先重建 PMA 分配器和 EP0 默认状态,
229 // 之后才继续处理新的 CTR 事件。
230 // Bus reset rebuilds the PMA allocator and EP0 default state before
231 // processing new CTR events again.
232 if (ISTR & USB_ISTR_RESET)
233 {
234 usbdev_clear_istr(USB_ISTR_RESET);
235
236 *usbdev_daddr() = USB_DADDR_EF;
237 *usbdev_btable() = 0;
238
239 LibXR::CH32EndpointDevFs::ResetPMAAllocator();
240
241 LibXR::CH32USBDeviceFS::self_->Deinit(true);
242 LibXR::CH32USBDeviceFS::self_->Init(true);
243
244 out0->SetState(LibXR::USB::Endpoint::State::IDLE);
246
247 LibXR::CH32EndpointDevFs::SetEpTxStatus(0, USB_EP_TX_NAK);
248 LibXR::CH32EndpointDevFs::SetEpRxStatus(0, USB_EP_RX_VALID);
249 continue;
250 }
251
252 // suspend 也走同一条控制端点恢复路径,
253 // 但会先把 EP0 RX 保持在 NAK,等协议栈重新挂起下一笔传输。
254 // Suspend follows the same control-endpoint recovery path, but keeps EP0 RX
255 // in NAK until the stack re-arms the next transfer.
256 if (ISTR & USB_ISTR_SUSP)
257 {
258 usbdev_clear_istr(USB_ISTR_SUSP);
259
260 LibXR::CH32USBDeviceFS::self_->Deinit(true);
261 LibXR::CH32USBDeviceFS::self_->Init(true);
262
263 out0->SetState(LibXR::USB::Endpoint::State::IDLE);
265
266 LibXR::CH32EndpointDevFs::SetEpTxStatus(0, USB_EP_TX_NAK);
267 LibXR::CH32EndpointDevFs::SetEpRxStatus(0, USB_EP_RX_NAK);
268 continue;
269 }
270
271 if (ISTR & USB_ISTR_WKUP)
272 {
273 usbdev_clear_istr(USB_ISTR_WKUP);
274 continue;
275 }
276
277 if ((ISTR & USB_ISTR_CTR) == 0)
278 {
279 break;
280 }
281
282 // 经典 FSDEV 通过 CTR 标志一次只上报一个端点。
283 // Classic FSDEV reports one endpoint at a time through CTR flags.
284 const uint8_t EP_ID = static_cast<uint8_t>(ISTR & USB_ISTR_EP_ID);
285
286 uint16_t epr = *usbdev_ep_reg(EP_ID);
287
288 if (epr & USB_EP_CTR_RX)
289 {
290 if (EP_ID == 0)
291 {
292 if (epr & USB_EP_SETUP)
293 {
294 // 新的 SETUP 会开始一笔全新的控制传输;
295 // 这里只清理挂起的 CTR 标志,EP0 RX/TX 由控制传输处理器重新挂起。
296 // A new SETUP starts a fresh control transfer; only clear pending CTR
297 // flags here, and let the control-transfer handlers re-arm EP0 RX/TX.
298 if (epr & USB_EP_CTR_TX)
299 {
300 LibXR::CH32EndpointDevFs::ClearEpCtrTx(0);
301 }
302 LibXR::CH32EndpointDevFs::ClearEpCtrRx(0);
303
304 out0->CopyRxDataToBuffer(sizeof(LibXR::USB::SetupPacket));
305 LibXR::CH32USBDeviceFS::self_->OnSetupPacket(
306 true,
307 reinterpret_cast<const LibXR::USB::SetupPacket*>(out0->GetBuffer().addr_));
308
309 continue;
310 }
311 else
312 {
313 // 普通 EP0 OUT 数据/状态阶段完成。
314 // Ordinary EP0 OUT data/status completion.
315 LibXR::CH32EndpointDevFs::ClearEpCtrRx(0);
316 const uint16_t LEN = LibXR::CH32EndpointDevFs::GetRxCount(0);
317 out0->TransferComplete(LEN);
318 }
319 }
320 else
321 {
322 // non-EP0 OUT 完成直接使用硬件锁存的该端点 RX 长度。
323 // Non-EP0 OUT completion uses the per-endpoint RX length latched by hardware.
324 LibXR::CH32EndpointDevFs::ClearEpCtrRx(EP_ID);
325 const uint16_t LEN = LibXR::CH32EndpointDevFs::GetRxCount(EP_ID);
326 if (map[EP_ID][OUT_IDX])
327 {
328 map[EP_ID][OUT_IDX]->TransferComplete(LEN);
329 }
330 }
331 }
332
333 epr = *usbdev_ep_reg(EP_ID);
334
335 if (epr & USB_EP_CTR_TX)
336 {
337 if (EP_ID == 0)
338 {
339 // EP0 IN 完成事件本身就足够,不需要额外长度信息。
340 // EP0 IN completion is self-sufficient; no extra length bookkeeping is needed.
341 LibXR::CH32EndpointDevFs::ClearEpCtrTx(0);
342 in0->TransferComplete(0);
343 }
344 else
345 {
346 // FSDEV 上的 non-EP0 IN 完成与 EP0 IN 一样,不额外携带长度信息。
347 // Non-EP0 IN completion follows the same rule as EP0 IN on FSDEV.
348 LibXR::CH32EndpointDevFs::ClearEpCtrTx(EP_ID);
349 if (map[EP_ID][IN_IDX])
350 {
351 map[EP_ID][IN_IDX]->TransferComplete(0);
352 }
353 }
354 }
355 }
356}
357
358static void usb_irq_thunk() { usbdev_fs_irqhandler(); }
359
360// NOLINTNEXTLINE(readability-identifier-naming)
361extern "C" __attribute__((interrupt("WCH-Interrupt-fast"))) void USBWakeUp_IRQHandler(
362 void)
363{
364#if defined(EXTI_Line18)
365 EXTI_ClearITPendingBit(EXTI_Line18);
366#endif
367}
368
369CH32USBDeviceFS::CH32USBDeviceFS(
370 const std::initializer_list<EPConfig> EP_CFGS,
371 USB::DeviceDescriptor::PacketSize0 packet_size, uint16_t vid, uint16_t pid,
372 uint16_t bcd,
373 const std::initializer_list<const USB::DescriptorStrings::LanguagePack*> LANG_LIST,
374 const std::initializer_list<const std::initializer_list<USB::ConfigDescriptorItem*>>
375 CONFIGS,
376 ConstRawData uid)
377 : USB::EndpointPool(EP_CFGS.size() * 2),
378 USB::DeviceCore(*this, USB::USBSpec::USB_2_1, USB::Speed::FULL, packet_size, vid,
379 pid, bcd, LANG_LIST, CONFIGS, uid)
380{
381 self_ = this;
382
383 ASSERT(EP_CFGS.size() > 0 && EP_CFGS.size() <= CH32EndpointDevFs::EP_DEV_FS_MAX_SIZE);
384
385 auto cfgs_itr = EP_CFGS.begin();
386
387 auto ep0_out =
388 new CH32EndpointDevFs(USB::Endpoint::EPNumber::EP0, USB::Endpoint::Direction::OUT,
389 cfgs_itr->buffer, false);
390 auto ep0_in =
391 new CH32EndpointDevFs(USB::Endpoint::EPNumber::EP0, USB::Endpoint::Direction::IN,
392 cfgs_itr->buffer, false);
393
394 USB::EndpointPool::SetEndpoint0(ep0_in, ep0_out);
395
396 USB::Endpoint::EPNumber ep_index = USB::Endpoint::EPNumber::EP1;
397
398 for (++cfgs_itr, ep_index = USB::Endpoint::EPNumber::EP1; cfgs_itr != EP_CFGS.end();
399 ++cfgs_itr, ep_index = USB::Endpoint::NextEPNumber(ep_index))
400 {
401 if (cfgs_itr->is_in == -1)
402 {
403 auto ep_out = new CH32EndpointDevFs(
404 ep_index, USB::Endpoint::Direction::OUT,
405 select_buffer_dev_fs(ep_index, USB::Endpoint::Direction::OUT, cfgs_itr->buffer),
406 false);
407 USB::EndpointPool::Put(ep_out);
408
409 auto ep_in = new CH32EndpointDevFs(
410 ep_index, USB::Endpoint::Direction::IN,
411 select_buffer_dev_fs(ep_index, USB::Endpoint::Direction::IN, cfgs_itr->buffer),
412 false);
413 USB::EndpointPool::Put(ep_in);
414 }
415 else
416 {
417 auto ep = new CH32EndpointDevFs(
418 ep_index,
419 cfgs_itr->is_in ? USB::Endpoint::Direction::IN : USB::Endpoint::Direction::OUT,
420 cfgs_itr->buffer, true);
421 USB::EndpointPool::Put(ep);
422 }
423 }
424}
425
426LibXR::ErrorCode CH32USBDeviceFS::SetAddress(uint8_t address,
428{
429 if (context == USB::DeviceCore::Context::STATUS_IN_COMPLETE)
430 {
431 const uint8_t N_EP = static_cast<uint8_t>(CH32EndpointDevFs::EP_DEV_FS_MAX_SIZE);
432 for (uint8_t i = 0; i < N_EP; i++)
433 {
434 usbdev_set_ep_address(i, i);
435 }
436
437 *usbdev_daddr() = static_cast<uint16_t>(USB_DADDR_EF | address);
438
439 CH32EndpointDevFs::SetEpTxStatus(0, USB_EP_TX_NAK);
440 CH32EndpointDevFs::SetEpRxStatus(0, USB_EP_RX_VALID);
441 }
443}
444
445void CH32USBDeviceFS::Start(bool)
446{
447 LibXR::CH32UsbCanShared::usb_inited.store(true, std::memory_order_release);
448 LibXR::CH32UsbCanShared::register_usb_irq(&usb_irq_thunk);
449
450 // FSDEV 使用共享 USB 48 MHz 时钟;如果这个时钟来自 USBHS PHY PLL,
451 // 则必须先打开 USBHS 依赖时钟,再打开 USBDEV 本体时钟。
452 // FSDEV uses the shared USB 48 MHz clock; when that clock comes from the
453 // USBHS PHY PLL, keep the USBHS dependency clock enabled before USBDEV itself.
454 LibXR::CH32UsbRcc::ConfigureUsb48M();
455#if defined(RCC_USBCLK48MCLKSource_USBPHY) && defined(RCC_AHBPeriph_USBHS)
456 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_USBHS, ENABLE);
457#endif
458 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);
459
460#if defined(RCC_APB2Periph_GPIOA) && defined(GPIOA) && defined(GPIO_Pin_11) && \
461 defined(GPIO_Pin_12) && defined(GPIO_Mode_Out_PP) && defined(GPIO_Speed_50MHz) && \
462 defined(GPIO_Mode_IN_FLOATING)
463 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
464
465 GPIO_InitTypeDef gpio{};
466 gpio.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
467 gpio.GPIO_Speed = GPIO_Speed_50MHz;
468 gpio.GPIO_Mode = GPIO_Mode_Out_PP;
469 GPIO_Init(GPIOA, &gpio);
470 GPIO_ResetBits(GPIOA, GPIO_Pin_11 | GPIO_Pin_12);
471
472 gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
473 GPIO_Init(GPIOA, &gpio);
474#endif
475
476 *usbdev_cntr() = USB_CNTR_FRES;
477 *usbdev_cntr() = 0;
478
479 usbdev_clear_istr(0xFFFFu);
480 *usbdev_btable() = 0;
481
482 *usbdev_cntr() = static_cast<uint16_t>(USB_CNTR_RESETM | USB_CNTR_SUSPM |
483 USB_CNTR_WKUPM | USB_CNTR_CTRM);
484
485#if defined(EXTEN_USBD_LS)
486 EXTEN->EXTEN_CTR &= ~EXTEN_USBD_LS;
487#endif
488
489 NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
490 NVIC_EnableIRQ(USB_HP_CAN1_TX_IRQn);
491 NVIC_EnableIRQ(USBWakeUp_IRQn);
492
493#if defined(EXTEN_USBD_PU_EN)
494 EXTEN->EXTEN_CTR |= EXTEN_USBD_PU_EN;
495#endif
496
497 *usbdev_daddr() = USB_DADDR_EF;
498
499 CH32EndpointDevFs::SetEpTxStatus(0, USB_EP_TX_NAK);
500 CH32EndpointDevFs::SetEpRxStatus(0, USB_EP_RX_VALID);
501
502 // DeviceCore::Init() 可能早于 FSDEV reset/BTABLE 初始化就预挂起 OUT 端点;
503 // 因此这里在硬件初始化完成后补一次 non-EP0 OUT 端点重装填。
504 // DeviceCore::Init() may arm OUT endpoints before FSDEV reset/BTABLE
505 // initialization; re-arm non-EP0 OUT endpoints that remain BUSY afterwards.
506 auto& ep_map = LibXR::CH32EndpointDevFs::map_dev_fs_;
507 constexpr uint8_t OUT_IDX = static_cast<uint8_t>(LibXR::USB::Endpoint::Direction::OUT);
508 const uint8_t N_EP = static_cast<uint8_t>(LibXR::CH32EndpointDevFs::EP_DEV_FS_MAX_SIZE);
509 for (uint8_t ep = 1; ep < N_EP; ++ep)
510 {
511 auto* out = ep_map[ep][OUT_IDX];
512 if (out == nullptr)
513 {
514 continue;
515 }
516 if (out->GetState() != LibXR::USB::Endpoint::State::BUSY)
517 {
518 continue;
519 }
520 (void)out->Transfer(out->MaxTransferSize());
521 }
522}
523
524void CH32USBDeviceFS::Stop(bool)
525{
526 LibXR::CH32UsbCanShared::register_usb_irq(nullptr);
527 LibXR::CH32UsbCanShared::usb_inited.store(false, std::memory_order_release);
528
529#if defined(EXTEN_USBD_PU_EN)
530 EXTEN->EXTEN_CTR &= ~EXTEN_USBD_PU_EN;
531#endif
532
533 if (!LibXR::CH32UsbCanShared::can1_active())
534 {
535 NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn);
536 NVIC_DisableIRQ(USB_HP_CAN1_TX_IRQn);
537 }
538 NVIC_DisableIRQ(USBWakeUp_IRQn);
539
540 *usbdev_cntr() = USB_CNTR_FRES;
541}
542
543#endif // defined(RCC_APB1Periph_USB)
544
545// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast,performance-no-int-to-ptr)
常量原始数据封装类。 A class for encapsulating constant raw data.
原始数据封装类。 A class for encapsulating raw data.
size_t size_
数据大小(字节)。 The size of the data (in bytes).
void * addr_
数据存储地址。 The storage address of the data.
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:57