libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
ch32_usb_otghs.cpp
1// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast,performance-no-int-to-ptr)
2// ch32_usb_otghs.cpp (OTG HS)
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(USBHSD)
11
12namespace
13{
14
15static void ch32_usb_clock48m_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_usbhs_rcc_enable()
76{
77 ch32_usb_clock48m_config();
78
79#if defined(RCC_HSBHSPLLCLKSource_HSE) && defined(RCC_USBPLL_Div2) && \
80 defined(RCC_USBHSPLLCKREFCLK_4M)
81 RCC_USBHSPLLCLKConfig(RCC_HSBHSPLLCLKSource_HSE);
82 RCC_USBHSConfig(RCC_USBPLL_Div2);
83 RCC_USBHSPLLCKREFCLKConfig(RCC_USBHSPLLCKREFCLK_4M);
84 RCC_USBHSPHYPLLALIVEcmd(ENABLE);
85#endif
86
87#if defined(RCC_AHBPeriph_USBHS)
88 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_USBHS, ENABLE);
89#endif
90#if defined(RCC_AHBPeriph_USBFS)
91 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_USBFS, ENABLE);
92#endif
93}
94
95} // namespace
96
97// NOLINTNEXTLINE(readability-identifier-naming)
98extern "C" __attribute__((interrupt)) void USBHS_IRQHandler(void)
99{
100 auto& map = LibXR::CH32EndpointOtgHs::map_otg_hs_;
101
102 constexpr uint8_t OUT_IDX = static_cast<uint8_t>(LibXR::USB::Endpoint::Direction::OUT);
103 constexpr uint8_t IN_IDX = static_cast<uint8_t>(LibXR::USB::Endpoint::Direction::IN);
104
105 while (true)
106 {
107 const uint16_t INTFGST = *reinterpret_cast<volatile uint16_t*>(
108 reinterpret_cast<uintptr_t>(&USBHSD->INT_FG));
109
110 const uint8_t INTFLAG = static_cast<uint8_t>(INTFGST & 0x00FFu);
111 const uint8_t INTST = static_cast<uint8_t>((INTFGST >> 8) & 0x00FFu);
112
113 if (INTFLAG == 0)
114 {
115 break;
116 }
117
118 uint8_t clear_mask = 0;
119
120 if (INTFLAG & USBHS_UIF_BUS_RST)
121 {
122 USBHSD->DEV_AD = 0;
123
124 LibXR::CH32USBOtgHS::self_->Deinit(true);
125 LibXR::CH32USBOtgHS::self_->Init(true);
126
127 if (map[0][OUT_IDX])
128 {
129 map[0][OUT_IDX]->SetState(LibXR::USB::Endpoint::State::IDLE);
130 }
131 if (map[0][IN_IDX])
132 {
133 map[0][IN_IDX]->SetState(LibXR::USB::Endpoint::State::IDLE);
134 }
135
136 if (map[0][OUT_IDX])
137 {
138 map[0][OUT_IDX]->tog0_ = true;
139 map[0][OUT_IDX]->tog1_ = false;
140 }
141 if (map[0][IN_IDX])
142 {
143 map[0][IN_IDX]->tog0_ = true;
144 map[0][IN_IDX]->tog1_ = false;
145 }
146
147 USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_NAK;
148 USBHSD->UEP0_RX_CTRL = USBHS_UEP_R_TOG_DATA1 | USBHS_UEP_R_RES_NAK;
149
150 clear_mask |= USBHS_UIF_BUS_RST;
151 }
152
153 if (INTFLAG & USBHS_UIF_SUSPEND)
154 {
155 LibXR::CH32USBOtgHS::self_->Deinit(true);
156 LibXR::CH32USBOtgHS::self_->Init(true);
157
158 if (map[0][OUT_IDX])
159 {
160 map[0][OUT_IDX]->SetState(LibXR::USB::Endpoint::State::IDLE);
161 }
162 if (map[0][IN_IDX])
163 {
164 map[0][IN_IDX]->SetState(LibXR::USB::Endpoint::State::IDLE);
165 }
166
167 if (map[0][OUT_IDX])
168 {
169 map[0][OUT_IDX]->tog0_ = true;
170 map[0][OUT_IDX]->tog1_ = false;
171 }
172 if (map[0][IN_IDX])
173 {
174 map[0][IN_IDX]->tog0_ = true;
175 map[0][IN_IDX]->tog1_ = false;
176 }
177
178 USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_NAK;
179 USBHSD->UEP0_RX_CTRL = USBHS_UEP_R_TOG_DATA1 | USBHS_UEP_R_RES_NAK;
180
181 clear_mask |= USBHS_UIF_SUSPEND;
182 }
183
184 if (INTFLAG & USBHS_UIF_SETUP_ACT)
185 {
186 USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_NAK;
187 USBHSD->UEP0_RX_CTRL = USBHS_UEP_R_TOG_DATA1 | USBHS_UEP_R_RES_NAK;
188
189 if (map[0][OUT_IDX])
190 {
191 map[0][OUT_IDX]->SetState(LibXR::USB::Endpoint::State::IDLE);
192 }
193 if (map[0][IN_IDX])
194 {
195 map[0][IN_IDX]->SetState(LibXR::USB::Endpoint::State::IDLE);
196 }
197
198 if (map[0][OUT_IDX])
199 {
200 map[0][OUT_IDX]->tog0_ = true;
201 map[0][OUT_IDX]->tog1_ = false;
202 }
203 if (map[0][IN_IDX])
204 {
205 map[0][IN_IDX]->tog0_ = true;
206 map[0][IN_IDX]->tog1_ = false;
207 }
208
209 LibXR::CH32USBOtgHS::self_->OnSetupPacket(
210 true, reinterpret_cast<const LibXR::USB::SetupPacket*>(
211 map[0][OUT_IDX]->GetBuffer().addr_));
212
213 clear_mask |= USBHS_UIF_SETUP_ACT;
214 }
215
216 if (INTFLAG & USBHS_UIF_TRANSFER)
217 {
218 const uint8_t TOKEN = INTST & USBHS_UIS_TOKEN_MASK;
219 const uint8_t EPNUM = INTST & USBHS_UIS_ENDP_MASK;
220
221 auto& ep = map[EPNUM];
222
223 switch (TOKEN)
224 {
225 case USBHS_UIS_TOKEN_SETUP:
226 {
227 USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_RES_NAK | USBHS_UEP_T_TOG_DATA1;
228 USBHSD->UEP0_RX_CTRL = USBHS_UEP_R_RES_NAK | USBHS_UEP_R_TOG_DATA1;
229
230 if (map[0][OUT_IDX])
231 {
232 map[0][OUT_IDX]->SetState(LibXR::USB::Endpoint::State::IDLE);
233 }
234 if (map[0][IN_IDX])
235 {
236 map[0][IN_IDX]->SetState(LibXR::USB::Endpoint::State::IDLE);
237 }
238
239 if (map[0][OUT_IDX])
240 {
241 map[0][OUT_IDX]->tog0_ = true;
242 map[0][OUT_IDX]->tog1_ = false;
243 }
244 if (map[0][IN_IDX])
245 {
246 map[0][IN_IDX]->tog0_ = true;
247 map[0][IN_IDX]->tog1_ = false;
248 }
249
250 LibXR::CH32USBOtgHS::self_->OnSetupPacket(
251 true, reinterpret_cast<const LibXR::USB::SetupPacket*>(
252 map[0][OUT_IDX]->GetBuffer().addr_));
253 break;
254 }
255
256 case USBHS_UIS_TOKEN_OUT:
257 {
258 // NAK is not a completed data OUT transaction.
259 if (((INTST & USBHS_UIS_IS_NAK) == 0) && ep[OUT_IDX])
260 {
261 const uint16_t LEN = USBHSD->RX_LEN;
262 ep[OUT_IDX]->TransferComplete(LEN);
263 }
264 break;
265 }
266
267 case USBHS_UIS_TOKEN_IN:
268 {
269 // NAK is not a completed data IN transaction.
270 if (((INTST & USBHS_UIS_IS_NAK) == 0) && ep[IN_IDX])
271 {
272 ep[IN_IDX]->TransferComplete(0);
273 }
274 break;
275 }
276
277 default:
278 break;
279 }
280
281 clear_mask |= USBHS_UIF_TRANSFER;
282 }
283
284 clear_mask |= static_cast<uint8_t>(INTFLAG & ~(clear_mask));
285 USBHSD->INT_FG = clear_mask;
286 }
287}
288
289CH32USBOtgHS::CH32USBOtgHS(
290 const std::initializer_list<CH32USBOtgHS::EPConfig> EP_CFGS, uint16_t vid,
291 uint16_t pid, uint16_t bcd,
292 const std::initializer_list<const USB::DescriptorStrings::LanguagePack*> LANG_LIST,
293 const std::initializer_list<const std::initializer_list<USB::ConfigDescriptorItem*>>
294 CONFIGS,
295 ConstRawData uid)
296 : USB::EndpointPool(EP_CFGS.size() * 2),
297 USB::DeviceCore(*this, USB::USBSpec::USB_2_1, USB::Speed::HIGH,
298 USB::DeviceDescriptor::PacketSize0::SIZE_64, vid, pid, bcd,
299 LANG_LIST, CONFIGS, uid)
300{
301 self_ = this;
302 ASSERT(EP_CFGS.size() > 0 && EP_CFGS.size() <= CH32EndpointOtgHs::EP_OTG_HS_MAX_SIZE);
303
304 auto cfgs_itr = EP_CFGS.begin();
305
306 ASSERT(cfgs_itr->buffer_tx.size_ == 64 && cfgs_itr->double_buffer == false);
307
308 auto ep0_out =
309 new CH32EndpointOtgHs(USB::Endpoint::EPNumber::EP0, USB::Endpoint::Direction::OUT,
310 cfgs_itr->buffer_rx, false);
311 auto ep0_in =
312 new CH32EndpointOtgHs(USB::Endpoint::EPNumber::EP0, USB::Endpoint::Direction::IN,
313 cfgs_itr->buffer_tx, false);
314
315 USB::EndpointPool::SetEndpoint0(ep0_in, ep0_out);
316
317 USB::Endpoint::EPNumber ep_index = USB::Endpoint::EPNumber::EP1;
318
319 for (++cfgs_itr, ep_index = USB::Endpoint::EPNumber::EP1; cfgs_itr != EP_CFGS.end();
320 ++cfgs_itr, ep_index = USB::Endpoint::NextEPNumber(ep_index))
321 {
322 if (!cfgs_itr->double_buffer)
323 {
324 auto ep_out = new CH32EndpointOtgHs(ep_index, USB::Endpoint::Direction::OUT,
325 cfgs_itr->buffer_rx, false);
326 USB::EndpointPool::Put(ep_out);
327
328 auto ep_in = new CH32EndpointOtgHs(ep_index, USB::Endpoint::Direction::IN,
329 cfgs_itr->buffer_tx, false);
330 USB::EndpointPool::Put(ep_in);
331 }
332 else
333 {
334 auto ep = new CH32EndpointOtgHs(
335 ep_index,
336 cfgs_itr->is_in ? USB::Endpoint::Direction::IN : USB::Endpoint::Direction::OUT,
337 cfgs_itr->buffer_tx, true);
338 USB::EndpointPool::Put(ep);
339 }
340 }
341}
342
343ErrorCode CH32USBOtgHS::SetAddress(uint8_t address, USB::DeviceCore::Context context)
344{
345 if (context == USB::DeviceCore::Context::STATUS_IN)
346 {
347 USBHSD->DEV_AD = address;
348 }
349 return ErrorCode::OK;
350}
351
352void CH32USBOtgHS::Start(bool)
353{
354 ch32_usbhs_rcc_enable();
355 USBHSD->CONTROL = USBHS_UC_CLR_ALL | USBHS_UC_RESET_SIE;
356 USBHSD->CONTROL &= ~USBHS_UC_RESET_SIE;
357 USBHSD->HOST_CTRL = USBHS_UH_PHY_SUSPENDM;
358 USBHSD->CONTROL = USBHS_UC_DMA_EN | USBHS_UC_INT_BUSY | USBHS_UC_SPEED_HIGH;
359 USBHSD->INT_EN = USBHS_UIE_SETUP_ACT | USBHS_UIE_TRANSFER | USBHS_UIE_DETECT |
360 USBHS_UIE_SUSPEND | USBHS_UIE_ISO_ACT;
361 USBHSD->CONTROL |= USBHS_UC_DEV_PU_EN;
362 NVIC_EnableIRQ(USBHS_IRQn);
363}
364
365void CH32USBOtgHS::Stop(bool)
366{
367 USBHSD->CONTROL = USBHS_UC_CLR_ALL | USBHS_UC_RESET_SIE;
368 USBHSD->CONTROL = 0;
369 NVIC_DisableIRQ(USBHS_IRQn);
370}
371
372#endif // defined(USBHSD)
373
374// 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
USB描述符基类 USB descriptor base class.
Definition desc_dev.hpp:40
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