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 "ep.hpp"
6
7using namespace LibXR;
8using namespace LibXR::USB;
9
10#if defined(USBFSD)
11
12namespace
13{
14
15static void ch32_usb_clock48_m_config()
16{
17 RCC_ClocksTypeDef clk{};
18 RCC_GetClocksFreq(&clk);
19
20 const uint32_t SYSCLK_HZ = clk.SYSCLK_Frequency;
21
22#if defined(RCC_USBCLKSource_PLLCLK_Div1) && defined(RCC_USBCLKSource_PLLCLK_Div2) && \
23 defined(RCC_USBCLKSource_PLLCLK_Div3)
24 if (SYSCLK_HZ == 144000000u)
25 {
26 RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_Div3);
27 }
28 else if (SYSCLK_HZ == 96000000u)
29 {
30 RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_Div2);
31 }
32 else if (SYSCLK_HZ == 48000000u)
33 {
34 RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_Div1);
35 }
36#if defined(RCC_USB5PRE_JUDGE) && defined(RCC_USBCLKSource_PLLCLK_Div5)
37 else if (SYSCLK_HZ == 240000000u)
38 {
39 ASSERT(RCC_USB5PRE_JUDGE() == SET);
40 RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_Div5);
41 }
42#endif
43 else
44 {
45 ASSERT(false);
46 }
47
48#elif defined(RCC_USBCLK48MCLKSource_PLLCLK) && \
49 defined(RCC_USBFSCLKSource_PLLCLK_Div1) && \
50 defined(RCC_USBFSCLKSource_PLLCLK_Div2) && defined(RCC_USBFSCLKSource_PLLCLK_Div3)
51 RCC_USBCLK48MConfig(RCC_USBCLK48MCLKSource_PLLCLK);
52
53 if (SYSCLK_HZ == 144000000u)
54 {
55 RCC_USBFSCLKConfig(RCC_USBFSCLKSource_PLLCLK_Div3);
56 }
57 else if (SYSCLK_HZ == 96000000u)
58 {
59 RCC_USBFSCLKConfig(RCC_USBFSCLKSource_PLLCLK_Div2);
60 }
61 else if (SYSCLK_HZ == 48000000u)
62 {
63 RCC_USBFSCLKConfig(RCC_USBFSCLKSource_PLLCLK_Div1);
64 }
65 else
66 {
67 ASSERT(false);
68 }
69
70#else
71 (void)SYSCLK_HZ;
72#endif
73}
74
75static void ch32_usbfs_rcc_enable()
76{
77 ch32_usb_clock48_m_config();
78
79#if defined(RCC_AHBPeriph_USBFS)
80 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_USBFS, ENABLE);
81#elif defined(RCC_AHBPeriph_USBOTGFS)
82 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_USBOTGFS, ENABLE);
83#endif
84}
85
86} // namespace
87
88// NOLINTNEXTLINE(readability-identifier-naming)
89extern "C" __attribute__((interrupt)) void USBFS_IRQHandler(void)
90{
91 auto& map = LibXR::CH32EndpointOtgFs::map_otg_fs_;
92
93 constexpr uint8_t OUT_IDX = static_cast<uint8_t>(LibXR::USB::Endpoint::Direction::OUT);
94 constexpr uint8_t IN_IDX = static_cast<uint8_t>(LibXR::USB::Endpoint::Direction::IN);
95
96 constexpr uint8_t CLEARABLE_MASK = USBFS_UIF_FIFO_OV | USBFS_UIF_HST_SOF |
97 USBFS_UIF_SUSPEND | USBFS_UIF_TRANSFER |
98 USBFS_UIF_DETECT | USBFS_UIF_BUS_RST;
99
100 while (true)
101 {
102 const uint16_t INTFGST = *reinterpret_cast<volatile uint16_t*>(
103 reinterpret_cast<uintptr_t>(&USBFSD->INT_FG));
104
105 const uint8_t INTFLAG = static_cast<uint8_t>(INTFGST & 0x00FFu);
106 const uint8_t INTST = static_cast<uint8_t>((INTFGST >> 8) & 0x00FFu);
107
108 const uint8_t PENDING = static_cast<uint8_t>(INTFLAG & CLEARABLE_MASK);
109 if (PENDING == 0)
110 {
111 break;
112 }
113
114 uint8_t clear_mask = 0;
115
116 if (PENDING & USBFS_UIF_BUS_RST)
117 {
118 USBFSD->DEV_ADDR = 0;
119
120 LibXR::CH32USBOtgFS::self_->Deinit(true);
121 LibXR::CH32USBOtgFS::self_->Init(true);
122
123 if (map[0][OUT_IDX])
124 {
125 map[0][OUT_IDX]->SetState(LibXR::USB::Endpoint::State::IDLE);
126 }
127 if (map[0][IN_IDX])
128 {
129 map[0][IN_IDX]->SetState(LibXR::USB::Endpoint::State::IDLE);
130 }
131
132 if (map[0][OUT_IDX])
133 {
134 map[0][OUT_IDX]->tog_ = true;
135 }
136 if (map[0][IN_IDX])
137 {
138 map[0][IN_IDX]->tog_ = true;
139 }
140
141 USBFSD->UEP0_TX_CTRL = USBFS_UEP_T_RES_NAK;
142 USBFSD->UEP0_RX_CTRL = USBFS_UEP_R_RES_NAK;
143
144 clear_mask |= USBFS_UIF_BUS_RST;
145 }
146
147 if (PENDING & USBFS_UIF_SUSPEND)
148 {
149 LibXR::CH32USBOtgFS::self_->Deinit(true);
150 LibXR::CH32USBOtgFS::self_->Init(true);
151
152 if (map[0][OUT_IDX])
153 {
154 map[0][OUT_IDX]->SetState(LibXR::USB::Endpoint::State::IDLE);
155 }
156 if (map[0][IN_IDX])
157 {
158 map[0][IN_IDX]->SetState(LibXR::USB::Endpoint::State::IDLE);
159 }
160
161 if (map[0][OUT_IDX])
162 {
163 map[0][OUT_IDX]->tog_ = true;
164 }
165 if (map[0][IN_IDX])
166 {
167 map[0][IN_IDX]->tog_ = true;
168 }
169
170 USBFSD->UEP0_TX_CTRL = USBFS_UEP_T_RES_NAK;
171 USBFSD->UEP0_RX_CTRL = USBFS_UEP_R_RES_NAK;
172
173 clear_mask |= USBFS_UIF_SUSPEND;
174 }
175
176 if (PENDING & USBFS_UIF_TRANSFER)
177 {
178 const uint8_t TOKEN = INTST & USBFS_UIS_TOKEN_MASK;
179 const uint8_t EPNUM = INTST & USBFS_UIS_ENDP_MASK;
180
181 auto& ep = map[EPNUM];
182
183 switch (TOKEN)
184 {
185 case USBFS_UIS_TOKEN_SETUP:
186 {
187 USBFSD->UEP0_TX_CTRL = USBFS_UEP_T_RES_NAK;
188 USBFSD->UEP0_RX_CTRL = USBFS_UEP_R_RES_NAK;
189
190 if (map[0][OUT_IDX])
191 {
192 map[0][OUT_IDX]->SetState(LibXR::USB::Endpoint::State::IDLE);
193 }
194 if (map[0][IN_IDX])
195 {
196 map[0][IN_IDX]->SetState(LibXR::USB::Endpoint::State::IDLE);
197 }
198
199 if (map[0][OUT_IDX])
200 {
201 map[0][OUT_IDX]->tog_ = true;
202 }
203 if (map[0][IN_IDX])
204 {
205 map[0][IN_IDX]->tog_ = true;
206 }
207
208 LibXR::CH32USBOtgFS::self_->OnSetupPacket(
209 true,
210 reinterpret_cast<const SetupPacket*>(map[0][OUT_IDX]->GetBuffer().addr_));
211 break;
212 }
213
214 case USBFS_UIS_TOKEN_OUT:
215 {
216 const uint16_t LEN = USBFSD->RX_LEN;
217 if (ep[OUT_IDX])
218 {
219 ep[OUT_IDX]->TransferComplete(LEN);
220 }
221 break;
222 }
223
224 case USBFS_UIS_TOKEN_IN:
225 {
226 if (ep[IN_IDX])
227 {
228 ep[IN_IDX]->TransferComplete(0);
229 }
230 break;
231 }
232
233 default:
234 break;
235 }
236
237 clear_mask |= USBFS_UIF_TRANSFER;
238 }
239
240 clear_mask |= static_cast<uint8_t>(PENDING & ~clear_mask);
241 USBFSD->INT_FG = clear_mask;
242 }
243}
244
245CH32USBOtgFS::CH32USBOtgFS(
246 const std::initializer_list<EPConfig> EP_CFGS,
247 USB::DeviceDescriptor::PacketSize0 packet_size, uint16_t vid, uint16_t pid,
248 uint16_t bcd,
249 const std::initializer_list<const USB::DescriptorStrings::LanguagePack*> LANG_LIST,
250 const std::initializer_list<const std::initializer_list<USB::ConfigDescriptorItem*>>
251 CONFIGS,
252 ConstRawData uid)
253 : USB::EndpointPool(EP_CFGS.size() * 2),
254 USB::DeviceCore(*this, USB::USBSpec::USB_2_1, USB::Speed::FULL, packet_size, vid,
255 pid, bcd, LANG_LIST, CONFIGS, uid)
256{
257 self_ = this;
258 ASSERT(EP_CFGS.size() > 0 && EP_CFGS.size() <= CH32EndpointOtgFs::EP_OTG_FS_MAX_SIZE);
259
260 auto cfgs_itr = EP_CFGS.begin();
261
262 auto ep0_out =
263 new CH32EndpointOtgFs(USB::Endpoint::EPNumber::EP0, USB::Endpoint::Direction::OUT,
264 cfgs_itr->buffer, false);
265 auto ep0_in =
266 new CH32EndpointOtgFs(USB::Endpoint::EPNumber::EP0, USB::Endpoint::Direction::IN,
267 cfgs_itr->buffer, false);
268
269 USB::EndpointPool::SetEndpoint0(ep0_in, ep0_out);
270
271 USB::Endpoint::EPNumber ep_index = USB::Endpoint::EPNumber::EP1;
272
273 for (++cfgs_itr, ep_index = USB::Endpoint::EPNumber::EP1; cfgs_itr != EP_CFGS.end();
274 ++cfgs_itr, ep_index = USB::Endpoint::NextEPNumber(ep_index))
275 {
276 if (cfgs_itr->is_in == -1)
277 {
278 auto ep_out = new CH32EndpointOtgFs(ep_index, USB::Endpoint::Direction::OUT,
279 cfgs_itr->buffer, false);
280 USB::EndpointPool::Put(ep_out);
281
282 auto ep_in = new CH32EndpointOtgFs(ep_index, USB::Endpoint::Direction::IN,
283 cfgs_itr->buffer, false);
284 USB::EndpointPool::Put(ep_in);
285 }
286 else
287 {
288 auto ep = new CH32EndpointOtgFs(
289 ep_index,
290 cfgs_itr->is_in ? USB::Endpoint::Direction::IN : USB::Endpoint::Direction::OUT,
291 cfgs_itr->buffer, true);
292 USB::EndpointPool::Put(ep);
293 }
294 }
295}
296
297ErrorCode CH32USBOtgFS::SetAddress(uint8_t address, USB::DeviceCore::Context context)
298{
299 if (context == USB::DeviceCore::Context::STATUS_IN)
300 {
301 USBFSD->DEV_ADDR = (USBFSD->DEV_ADDR & USBFS_UDA_GP_BIT) | address;
302 USBFSD->UEP0_TX_CTRL = USBFS_UEP_T_RES_NAK;
303 USBFSD->UEP0_RX_CTRL = USBFS_UEP_R_RES_ACK;
304 }
305 return ErrorCode::OK;
306}
307
308void CH32USBOtgFS::Start(bool)
309{
310 ch32_usbfs_rcc_enable();
311 USBFSH->BASE_CTRL = USBFS_UC_RESET_SIE | USBFS_UC_CLR_ALL;
312 USBFSH->BASE_CTRL = 0x00;
313 USBFSD->INT_EN = USBFS_UIE_SUSPEND | USBFS_UIE_BUS_RST | USBFS_UIE_TRANSFER;
314 USBFSD->BASE_CTRL = USBFS_UC_DEV_PU_EN | USBFS_UC_INT_BUSY | USBFS_UC_DMA_EN;
315 USBFSD->UDEV_CTRL = USBFS_UD_PD_DIS | USBFS_UD_PORT_EN;
316 NVIC_EnableIRQ(USBFS_IRQn);
317}
318
319void CH32USBOtgFS::Stop(bool)
320{
321 USBFSH->BASE_CTRL = USBFS_UC_RESET_SIE | USBFS_UC_CLR_ALL;
322 USBFSD->BASE_CTRL = 0x00;
323 NVIC_DisableIRQ(USBFS_IRQn);
324}
325
326#endif // defined(USBFSD)
327
328// 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:179
Context
控制传输上下文 / Control transfer context
Definition dev_core.hpp:188
PacketSize0
控制端点0最大包长度枚举 Packet size for endpoint 0 (bMaxPacketSize0)
Definition desc_dev.hpp:75
EPNumber
端点号 Endpoint number
Definition ep.hpp:41
@ IN
输入方向 / IN direction
@ OUT
输出方向 / OUT direction
static constexpr EPNumber NextEPNumber(EPNumber ep)
获取下一个端点号 / Get the next endpoint number
Definition ep.hpp:127
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
USB 标准请求 SETUP 包(固定8字节) Standard USB setup packet (8 bytes)
Definition core.hpp:57