libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
ch32_usb_otgfs.cpp
1// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast,performance-no-int-to-ptr)
2// ch32_usb_otgfs.cpp (OTG FS)
3#include "ch32_usb_dev.hpp"
4#include "ch32_usb_endpoint.hpp"
5#include "ch32_usb_rcc.hpp"
6#include "ep.hpp"
7
8using namespace LibXR;
9using namespace LibXR::USB;
10
11#if defined(USBFSD)
12
13// NOLINTNEXTLINE(readability-identifier-naming)
14extern "C" __attribute__((interrupt("WCH-Interrupt-fast"))) void USBFS_IRQHandler(void)
15{
16 auto& map = LibXR::CH32EndpointOtgFs::map_otg_fs_;
17
18 constexpr uint8_t OUT_IDX = static_cast<uint8_t>(LibXR::USB::Endpoint::Direction::OUT);
19 constexpr uint8_t IN_IDX = static_cast<uint8_t>(LibXR::USB::Endpoint::Direction::IN);
20
21 constexpr uint8_t CLEARABLE_MASK = USBFS_UIF_FIFO_OV | USBFS_UIF_HST_SOF |
22 USBFS_UIF_SUSPEND | USBFS_UIF_TRANSFER |
23 USBFS_UIF_DETECT | USBFS_UIF_BUS_RST;
24 auto* out0 = map[0][OUT_IDX];
25 auto* in0 = map[0][IN_IDX];
26 ASSERT(out0 != nullptr);
27 ASSERT(in0 != nullptr);
28
29 // Handle order matches the control-transfer lifecycle:
30 // 1) bus-level recovery
31 // 2) token completion / setup dispatch
32 // 处理顺序与控制传输生命周期保持一致:
33 // 1) 总线级恢复
34 // 2) token 完成与 setup 分发
35 while (true)
36 {
37 const uint16_t INTFGST = *reinterpret_cast<volatile uint16_t*>(
38 reinterpret_cast<uintptr_t>(&USBFSD->INT_FG));
39
40 const uint8_t INTFLAG = static_cast<uint8_t>(INTFGST & 0x00FFu);
41 const uint8_t INTST = static_cast<uint8_t>((INTFGST >> 8) & 0x00FFu);
42
43 const uint8_t PENDING = static_cast<uint8_t>(INTFLAG & CLEARABLE_MASK);
44 if (PENDING == 0)
45 {
46 break;
47 }
48
49 uint8_t clear_mask = 0;
50
51 // Reset rebuilds EP0 state and returns the device to "waiting for setup".
52 // reset 会重建 EP0 状态,并把设备恢复到“等待 setup”的初始形态。
53 if (PENDING & USBFS_UIF_BUS_RST)
54 {
55 USBFSD->DEV_ADDR = 0;
56
57 LibXR::CH32USBOtgFS::self_->Deinit(true);
58 LibXR::CH32USBOtgFS::self_->Init(true);
59
62 out0->tog_ = true;
63 in0->tog_ = true;
64
65 USBFSD->UEP0_TX_CTRL = USBFS_UEP_T_RES_NAK;
66 USBFSD->UEP0_RX_CTRL = USBFS_UEP_R_RES_NAK;
67
68 clear_mask |= USBFS_UIF_BUS_RST;
69 }
70
71 // Suspend follows the same EP0 recovery path; resume is observed later by the host.
72 // suspend 走与 reset 相同的 EP0 恢复路径;resume 由后续主机时序体现。
73 if (PENDING & USBFS_UIF_SUSPEND)
74 {
75 LibXR::CH32USBOtgFS::self_->Deinit(true);
76 LibXR::CH32USBOtgFS::self_->Init(true);
77
80 out0->tog_ = true;
81 in0->tog_ = true;
82
83 USBFSD->UEP0_TX_CTRL = USBFS_UEP_T_RES_NAK;
84 USBFSD->UEP0_RX_CTRL = USBFS_UEP_R_RES_NAK;
85
86 clear_mask |= USBFS_UIF_SUSPEND;
87 }
88
89 if (PENDING & USBFS_UIF_TRANSFER)
90 {
91 const uint8_t TOKEN = INTST & USBFS_UIS_TOKEN_MASK;
92 const uint8_t EPNUM = INTST & USBFS_UIS_ENDP_MASK;
93
94 auto& ep = map[EPNUM];
95
96 switch (TOKEN)
97 {
98 case USBFS_UIS_TOKEN_SETUP:
99 {
100 // A fresh setup cancels the previous EP0 transaction, so both directions are
101 // reset to IDLE/TOG0 before handing the setup packet to DeviceCore.
102 // 新的 setup 会中断前一笔 EP0 事务,因此这里在把 setup 包交给 DeviceCore
103 // 之前,先把 EP0 的双向状态恢复到 IDLE/TOG0。
104 USBFSD->UEP0_TX_CTRL = USBFS_UEP_T_RES_NAK;
105 USBFSD->UEP0_RX_CTRL = USBFS_UEP_R_RES_NAK;
106
107 out0->SetState(LibXR::USB::Endpoint::State::IDLE);
109 out0->tog_ = true;
110 in0->tog_ = true;
111
112 LibXR::CH32USBOtgFS::self_->OnSetupPacket(
113 true, reinterpret_cast<const SetupPacket*>(out0->GetBuffer().addr_));
114 break;
115 }
116
117 case USBFS_UIS_TOKEN_OUT:
118 {
119 // OTGFS hardware already reports the completed RX length for this token.
120 // OTGFS 硬件已经给出了本次 token 的完成 RX 长度。
121 const uint16_t LEN = USBFSD->RX_LEN;
122 if (ep[OUT_IDX])
123 {
124 ep[OUT_IDX]->TransferComplete(LEN);
125 }
126 break;
127 }
128
129 case USBFS_UIS_TOKEN_IN:
130 {
131 // IN token completion has no payload length; completion itself is enough.
132 // IN token 完成不需要额外 payload 长度,事件本身就足够了。
133 if (ep[IN_IDX])
134 {
135 ep[IN_IDX]->TransferComplete(0);
136 }
137 break;
138 }
139
140 default:
141 break;
142 }
143
144 clear_mask |= USBFS_UIF_TRANSFER;
145 }
146
147 clear_mask |= static_cast<uint8_t>(PENDING & ~clear_mask);
148 USBFSD->INT_FG = clear_mask;
149 }
150}
151
152CH32USBOtgFS::CH32USBOtgFS(
153 const std::initializer_list<EPConfig> EP_CFGS,
154 USB::DeviceDescriptor::PacketSize0 packet_size, uint16_t vid, uint16_t pid,
155 uint16_t bcd,
156 const std::initializer_list<const USB::DescriptorStrings::LanguagePack*> LANG_LIST,
157 const std::initializer_list<const std::initializer_list<USB::ConfigDescriptorItem*>>
158 CONFIGS,
159 ConstRawData uid)
160 : USB::EndpointPool(EP_CFGS.size() * 2),
161 USB::DeviceCore(*this, USB::USBSpec::USB_2_1, USB::Speed::FULL, packet_size, vid,
162 pid, bcd, LANG_LIST, CONFIGS, uid)
163{
164 self_ = this;
165 ASSERT(EP_CFGS.size() > 0 && EP_CFGS.size() <= CH32EndpointOtgFs::EP_OTG_FS_MAX_SIZE);
166
167 auto cfgs_itr = EP_CFGS.begin();
168
169 auto ep0_out =
170 new CH32EndpointOtgFs(USB::Endpoint::EPNumber::EP0, USB::Endpoint::Direction::OUT,
171 cfgs_itr->buffer, false);
172 auto ep0_in =
173 new CH32EndpointOtgFs(USB::Endpoint::EPNumber::EP0, USB::Endpoint::Direction::IN,
174 cfgs_itr->buffer, false);
175
176 USB::EndpointPool::SetEndpoint0(ep0_in, ep0_out);
177
178 USB::Endpoint::EPNumber ep_index = USB::Endpoint::EPNumber::EP1;
179
180 for (++cfgs_itr, ep_index = USB::Endpoint::EPNumber::EP1; cfgs_itr != EP_CFGS.end();
181 ++cfgs_itr, ep_index = USB::Endpoint::NextEPNumber(ep_index))
182 {
183 if (cfgs_itr->is_in == -1)
184 {
185 auto ep_out = new CH32EndpointOtgFs(ep_index, USB::Endpoint::Direction::OUT,
186 cfgs_itr->buffer, false);
187 USB::EndpointPool::Put(ep_out);
188
189 auto ep_in = new CH32EndpointOtgFs(ep_index, USB::Endpoint::Direction::IN,
190 cfgs_itr->buffer, false);
191 USB::EndpointPool::Put(ep_in);
192 }
193 else
194 {
195 auto ep = new CH32EndpointOtgFs(
196 ep_index,
197 cfgs_itr->is_in ? USB::Endpoint::Direction::IN : USB::Endpoint::Direction::OUT,
198 cfgs_itr->buffer, true);
199 USB::EndpointPool::Put(ep);
200 }
201 }
202}
203
204LibXR::ErrorCode CH32USBOtgFS::SetAddress(uint8_t address,
206{
207 if (context == USB::DeviceCore::Context::STATUS_IN_COMPLETE)
208 {
209 USBFSD->DEV_ADDR = (USBFSD->DEV_ADDR & USBFS_UDA_GP_BIT) | address;
210 USBFSD->UEP0_TX_CTRL = USBFS_UEP_T_RES_NAK;
211 USBFSD->UEP0_RX_CTRL = USBFS_UEP_R_RES_ACK;
212 }
214}
215
216void CH32USBOtgFS::Start(bool)
217{
218 // OTGFS uses the same shared USB 48 MHz clock selection as FSDEV.
219 // OTGFS 与 FSDEV 共用同一套 USB 48 MHz 时钟选择规则。
220 LibXR::CH32UsbRcc::ConfigureUsb48M();
221#if defined(RCC_USBCLK48MCLKSource_USBPHY) && defined(RCC_AHBPeriph_USBHS)
222 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_USBHS, ENABLE);
223#endif
224#if defined(RCC_AHBPeriph_USBFS)
225 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_USBFS, ENABLE);
226#elif defined(RCC_AHBPeriph_USBOTGFS)
227 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_USBOTGFS, ENABLE);
228#endif
229 USBFSH->BASE_CTRL = USBFS_UC_RESET_SIE | USBFS_UC_CLR_ALL;
230 USBFSH->BASE_CTRL = 0x00;
231 USBFSD->INT_EN = USBFS_UIE_SUSPEND | USBFS_UIE_BUS_RST | USBFS_UIE_TRANSFER;
232 USBFSD->BASE_CTRL = USBFS_UC_DEV_PU_EN | USBFS_UC_INT_BUSY | USBFS_UC_DMA_EN;
233 USBFSD->UDEV_CTRL = USBFS_UD_PD_DIS | USBFS_UD_PORT_EN;
234 NVIC_EnableIRQ(USBFS_IRQn);
235}
236
237void CH32USBOtgFS::Stop(bool)
238{
239 USBFSH->BASE_CTRL = USBFS_UC_RESET_SIE | USBFS_UC_CLR_ALL;
240 USBFSD->BASE_CTRL = 0x00;
241 NVIC_DisableIRQ(USBFS_IRQn);
242}
243
244#endif // defined(USBFSD)
245
246// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast,performance-no-int-to-ptr)
常量原始数据封装类。 A class for encapsulating constant raw 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
@ 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
@ PENDING
等待中 | Pending
@ OK
操作成功 | Operation successful
USB 标准请求 SETUP 包(固定8字节) Standard USB setup packet (8 bytes)
Definition core.hpp:57