libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
ch32_usb_endpoint_otgfs.cpp
1#include <cstdint>
2
3#include "ch32_usb_endpoint.hpp"
4#include "ep.hpp"
5
6using namespace LibXR;
7
8#if defined(USBFSD)
9
10// NOLINTBEGIN
11
12static inline volatile uint8_t* get_tx_ctrl_addr(USB::Endpoint::EPNumber ep)
13{
14 return &USBFSD->UEP0_TX_CTRL + 4 * (USB::Endpoint::EPNumberToInt8(ep));
15}
16static inline volatile uint8_t* get_rx_ctrl_addr(USB::Endpoint::EPNumber ep)
17{
18 return &USBFSD->UEP0_RX_CTRL + 4 * (USB::Endpoint::EPNumberToInt8(ep));
19}
20static inline volatile uint16_t* get_tx_len_addr(USB::Endpoint::EPNumber ep)
21{
22 return &USBFSD->UEP0_TX_LEN + 2 * (USB::Endpoint::EPNumberToInt8(ep));
23}
24static inline volatile uint32_t* get_dma_addr(USB::Endpoint::EPNumber ep)
25{
26 return &USBFSD->UEP0_DMA + USB::Endpoint::EPNumberToInt8(ep);
27}
28
29static void set_dma_buffer(USB::Endpoint::EPNumber ep_num, void* value,
30 bool double_buffer)
31{
32 *get_dma_addr(ep_num) = (uint32_t)value;
33
34 if (!double_buffer)
35 {
36 return;
37 }
38
39 switch (ep_num)
40 {
41 case USB::Endpoint::EPNumber::EP1:
42 USBFSD->UEP4_1_MOD |= USBFS_UEP1_BUF_MOD;
43 break;
44 case USB::Endpoint::EPNumber::EP2:
45 USBFSD->UEP2_3_MOD |= USBFS_UEP2_BUF_MOD;
46 break;
47 case USB::Endpoint::EPNumber::EP3:
48 USBFSD->UEP2_3_MOD |= USBFS_UEP3_BUF_MOD;
49 break;
50 case USB::Endpoint::EPNumber::EP4:
51 USBFSD->UEP4_1_MOD |= USBFS_UEP4_BUF_MOD;
52 break;
53 case USB::Endpoint::EPNumber::EP5:
54 USBFSD->UEP5_6_MOD |= USBFS_UEP5_BUF_MOD;
55 break;
56 case USB::Endpoint::EPNumber::EP6:
57 USBFSD->UEP5_6_MOD |= USBFS_UEP6_BUF_MOD;
58 break;
59 case USB::Endpoint::EPNumber::EP7:
60 USBFSD->UEP7_MOD |= USBFS_UEP7_BUF_MOD;
61 break;
62 default:
63 break;
64 }
65}
66
67static void set_tx_len(USB::Endpoint::EPNumber ep_num, uint32_t value)
68{
69 *get_tx_len_addr(ep_num) = value;
70}
71
72static void enable_tx(USB::Endpoint::EPNumber ep_num)
73{
74 switch (ep_num)
75 {
76 case USB::Endpoint::EPNumber::EP1:
77 USBFSD->UEP4_1_MOD |= USBFS_UEP1_TX_EN;
78 break;
79 case USB::Endpoint::EPNumber::EP2:
80 USBFSD->UEP2_3_MOD |= USBFS_UEP2_TX_EN;
81 break;
82 case USB::Endpoint::EPNumber::EP3:
83 USBFSD->UEP2_3_MOD |= USBFS_UEP3_TX_EN;
84 break;
85 case USB::Endpoint::EPNumber::EP4:
86 USBFSD->UEP4_1_MOD |= USBFS_UEP4_TX_EN;
87 break;
88 case USB::Endpoint::EPNumber::EP5:
89 USBFSD->UEP5_6_MOD |= USBFS_UEP5_TX_EN;
90 break;
91 case USB::Endpoint::EPNumber::EP6:
92 USBFSD->UEP5_6_MOD |= USBFS_UEP6_TX_EN;
93 break;
94 case USB::Endpoint::EPNumber::EP7:
95 USBFSD->UEP7_MOD |= USBFS_UEP7_TX_EN;
96 break;
97 default:
98 break;
99 }
100}
101static void disable_tx(USB::Endpoint::EPNumber ep_num)
102{
103 switch (ep_num)
104 {
105 case USB::Endpoint::EPNumber::EP1:
106 USBFSD->UEP4_1_MOD &= ~USBFS_UEP1_TX_EN;
107 break;
108 case USB::Endpoint::EPNumber::EP2:
109 USBFSD->UEP2_3_MOD &= ~USBFS_UEP2_TX_EN;
110 break;
111 case USB::Endpoint::EPNumber::EP3:
112 USBFSD->UEP2_3_MOD &= ~USBFS_UEP3_TX_EN;
113 break;
114 case USB::Endpoint::EPNumber::EP4:
115 USBFSD->UEP4_1_MOD &= ~USBFS_UEP4_TX_EN;
116 break;
117 case USB::Endpoint::EPNumber::EP5:
118 USBFSD->UEP5_6_MOD &= ~USBFS_UEP5_TX_EN;
119 break;
120 case USB::Endpoint::EPNumber::EP6:
121 USBFSD->UEP5_6_MOD &= ~USBFS_UEP6_TX_EN;
122 break;
123 case USB::Endpoint::EPNumber::EP7:
124 USBFSD->UEP7_MOD &= ~USBFS_UEP7_TX_EN;
125 break;
126 default:
127 break;
128 }
129}
130static void enable_rx(USB::Endpoint::EPNumber ep_num)
131{
132 switch (ep_num)
133 {
134 case USB::Endpoint::EPNumber::EP1:
135 USBFSD->UEP4_1_MOD |= USBFS_UEP1_RX_EN;
136 break;
137 case USB::Endpoint::EPNumber::EP2:
138 USBFSD->UEP2_3_MOD |= USBFS_UEP2_RX_EN;
139 break;
140 case USB::Endpoint::EPNumber::EP3:
141 USBFSD->UEP2_3_MOD |= USBFS_UEP3_RX_EN;
142 break;
143 case USB::Endpoint::EPNumber::EP4:
144 USBFSD->UEP4_1_MOD |= USBFS_UEP4_RX_EN;
145 break;
146 case USB::Endpoint::EPNumber::EP5:
147 USBFSD->UEP5_6_MOD |= USBFS_UEP5_RX_EN;
148 break;
149 case USB::Endpoint::EPNumber::EP6:
150 USBFSD->UEP5_6_MOD |= USBFS_UEP6_RX_EN;
151 break;
152 case USB::Endpoint::EPNumber::EP7:
153 USBFSD->UEP7_MOD |= USBFS_UEP7_RX_EN;
154 break;
155 default:
156 break;
157 }
158}
159static void disable_rx(USB::Endpoint::EPNumber ep_num)
160{
161 switch (ep_num)
162 {
163 case USB::Endpoint::EPNumber::EP1:
164 USBFSD->UEP4_1_MOD &= ~USBFS_UEP1_RX_EN;
165 break;
166 case USB::Endpoint::EPNumber::EP2:
167 USBFSD->UEP2_3_MOD &= ~USBFS_UEP2_RX_EN;
168 break;
169 case USB::Endpoint::EPNumber::EP3:
170 USBFSD->UEP2_3_MOD &= ~USBFS_UEP3_RX_EN;
171 break;
172 case USB::Endpoint::EPNumber::EP4:
173 USBFSD->UEP4_1_MOD &= ~USBFS_UEP4_RX_EN;
174 break;
175 case USB::Endpoint::EPNumber::EP5:
176 USBFSD->UEP5_6_MOD &= ~USBFS_UEP5_RX_EN;
177 break;
178 case USB::Endpoint::EPNumber::EP6:
179 USBFSD->UEP5_6_MOD &= ~USBFS_UEP6_RX_EN;
180 break;
181 case USB::Endpoint::EPNumber::EP7:
182 USBFSD->UEP7_MOD &= ~USBFS_UEP7_RX_EN;
183 break;
184 default:
185 break;
186 }
187}
188// NOLINTEND
189
190// NOLINTNEXTLINE
191static LibXR::RawData select_buffer(USB::Endpoint::EPNumber ep_num,
193 const LibXR::RawData& buffer)
194{
195 if (ep_num == USB::Endpoint::EPNumber::EP0)
196 {
197 return buffer;
198 }
199
200 const size_t half = buffer.size_ / 2u;
201 ASSERT(half > 0u);
202
203 if (dir == USB::Endpoint::Direction::OUT)
204 {
205 return LibXR::RawData(buffer.addr_, half);
206 }
207
208 return LibXR::RawData(reinterpret_cast<uint8_t*>(buffer.addr_) + half, half);
209}
210
211CH32EndpointOtgFs::CH32EndpointOtgFs(EPNumber ep_num, Direction dir,
212 LibXR::RawData buffer, bool single_direction)
213 : Endpoint(ep_num, dir,
214 (single_direction || ep_num == EPNumber::EP0)
215 ? buffer
216 : select_buffer(ep_num, dir, buffer)),
217 single_direction_(single_direction),
218 dma_buffer_(buffer)
219{
220 map_otg_fs_[EPNumberToInt8(GetNumber())][static_cast<uint8_t>(dir)] = this;
221
222 set_dma_buffer(GetNumber(), dma_buffer_.addr_, false);
223
224 if (dir == Direction::IN)
225 {
226 set_tx_len(GetNumber(), 0);
227 *get_tx_ctrl_addr(GetNumber()) = USBFS_UEP_T_RES_NAK;
228 }
229 else
230 {
231 *get_rx_ctrl_addr(GetNumber()) = USBFS_UEP_R_RES_NAK;
232 }
233}
234
235void CH32EndpointOtgFs::Configure(const Config& cfg)
236{
237 auto& ep_cfg = GetConfig();
238 ep_cfg = cfg;
239 is_isochronous_ = (cfg.type == Type::ISOCHRONOUS);
240
241 const bool is_ep0 = (GetNumber() == EPNumber::EP0);
242 const bool is_bidir_noniso = !is_ep0 && !single_direction_ && !is_isochronous_;
243 const bool is_single_noniso = !is_ep0 && single_direction_ && !is_isochronous_;
244 const uint16_t type_limit = is_isochronous_ ? 1023u : 64u;
245 const uint16_t requested_mps = LibXR::min<uint16_t>(cfg.max_packet_size, type_limit);
246
247 if (is_bidir_noniso)
248 {
249 // Current shared bidirectional non-iso OTGFS path only splits raw memory by
250 // direction.
251 // 当前共享双向非等时 OTGFS 路径现在只按方向二分原始内存。
252 ASSERT(dma_buffer_.size_ >= static_cast<size_t>(requested_mps) * 2u);
253 }
254
255 ep_cfg.double_buffer = is_single_noniso;
256
257 // OTGFS MPS is clamped by request, effective buffer, and USB FS type limit.
258 // OTGFS 包长同时受请求值、当前有效缓冲区和 USB FS 类型上限约束。
259 ep_cfg.max_packet_size = LibXR::min<uint16_t>(
260 requested_mps,
261 LibXR::min<uint16_t>(static_cast<uint16_t>(GetBuffer().size_), type_limit));
262
263 set_tx_len(GetNumber(), 0);
264
265 if (!is_isochronous_)
266 {
267 *get_rx_ctrl_addr(GetNumber()) = USBFS_UEP_R_RES_NAK | USBFS_UEP_R_AUTO_TOG;
268 *get_tx_ctrl_addr(GetNumber()) = USBFS_UEP_T_RES_NAK | USBFS_UEP_T_AUTO_TOG;
269 enable_tx(GetNumber());
270 enable_rx(GetNumber());
271 }
272 else
273 {
274 *get_rx_ctrl_addr(GetNumber()) = USBFS_UEP_R_RES_NAK;
275 *get_tx_ctrl_addr(GetNumber()) = USBFS_UEP_T_RES_NAK;
276 if (GetDirection() == Direction::IN)
277 {
278 enable_tx(GetNumber());
279 }
280 else
281 {
282 enable_rx(GetNumber());
283 }
284 }
285
286 set_dma_buffer(GetNumber(), dma_buffer_.addr_, ep_cfg.double_buffer);
287
288 SetState(State::IDLE);
289}
290
291void CH32EndpointOtgFs::Close()
292{
293 disable_tx(GetNumber());
294 disable_rx(GetNumber());
295
296 *get_tx_ctrl_addr(GetNumber()) = USBFS_UEP_T_RES_NAK;
297 *get_rx_ctrl_addr(GetNumber()) = USBFS_UEP_R_RES_NAK;
298
299 SetState(State::DISABLED);
300}
301
302ErrorCode CH32EndpointOtgFs::Transfer(size_t size)
303{
304 if (GetState() == State::BUSY)
305 {
306 return ErrorCode::BUSY;
307 }
308
309 auto buffer = GetBuffer();
310 if (buffer.size_ < size)
311 {
312 return ErrorCode::NO_BUFF;
313 }
314
315 bool is_in = (GetDirection() == Direction::IN);
316
317 if (is_in && UseDoubleBuffer())
318 {
319 SwitchBuffer();
320 }
321
322 if (is_in)
323 {
324 set_tx_len(GetNumber(), size);
325 auto addr = get_tx_ctrl_addr(GetNumber());
326
327 if (GetNumber() != EPNumber::EP0)
328 {
329 *addr = (is_isochronous_ ? USBFS_UEP_T_RES_NONE : USBFS_UEP_T_RES_ACK) |
330 (*addr & (~USBFS_UEP_T_RES_MASK));
331 }
332 else
333 {
334 *addr = USBFS_UEP_T_RES_ACK | (tog_ ? USBFS_UEP_T_TOG : 0);
335 }
336 }
337 else
338 {
339 auto addr = get_rx_ctrl_addr(GetNumber());
340
341 if (GetNumber() != EPNumber::EP0)
342 {
343 *addr = (is_isochronous_ ? USBFS_UEP_R_RES_NONE : USBFS_UEP_R_RES_ACK) |
344 (*addr & (~USBFS_UEP_R_RES_MASK));
345 }
346 else
347 {
348 *addr = USBFS_UEP_R_RES_ACK | (tog_ ? USBFS_UEP_R_TOG : 0);
349 }
350 }
351
352 if (GetNumber() == EPNumber::EP0)
353 {
354 tog_ = !tog_;
355 }
356
357 last_transfer_size_ = size;
358 SetState(State::BUSY);
359 return ErrorCode::OK;
360}
361
362ErrorCode CH32EndpointOtgFs::Stall()
363{
364 const bool is_in = (GetDirection() == Direction::IN);
365 if (GetState() != State::IDLE && !(GetState() == State::BUSY && !is_in))
366 {
367 return ErrorCode::BUSY;
368 }
369
370 if (is_in)
371 {
372 *get_tx_ctrl_addr(GetNumber()) |= USBFS_UEP_T_RES_STALL;
373 }
374 else
375 {
376 *get_rx_ctrl_addr(GetNumber()) |= USBFS_UEP_R_RES_STALL;
377 }
378 SetState(State::STALLED);
379 return ErrorCode::OK;
380}
381
382ErrorCode CH32EndpointOtgFs::ClearStall()
383{
384 if (GetState() != State::STALLED)
385 {
386 return ErrorCode::FAILED;
387 }
388
389 bool is_in = (GetDirection() == Direction::IN);
390 if (is_in)
391 {
392 *get_tx_ctrl_addr(GetNumber()) &= ~USBFS_UEP_T_RES_STALL;
393 }
394 else
395 {
396 *get_rx_ctrl_addr(GetNumber()) &= ~USBFS_UEP_R_RES_STALL;
397 }
398 SetState(State::IDLE);
399 return ErrorCode::OK;
400}
401
402void CH32EndpointOtgFs::TransferComplete(size_t size)
403{
404 const bool IS_IN = (GetDirection() == Direction::IN);
405 const bool IS_OUT = !IS_IN;
406 const bool IS_EP0 = (GetNumber() == EPNumber::EP0);
407 const bool IS_ISO = (GetType() == Type::ISOCHRONOUS);
408
409 // UIF_TRANSFER/INT_FG 会在 IRQ handler 完成分发后统一清掉。
410 // UIF_TRANSFER/INT_FG are cleared by the IRQ handler after dispatch.
411
412 if (IS_IN)
413 {
414 // 完成后恢复到 NAK。
415 // Restore NAK on completion.
416 *get_tx_ctrl_addr(GetNumber()) =
417 (*get_tx_ctrl_addr(GetNumber()) & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_NAK;
418
419 size = last_transfer_size_;
420 }
421 else
422 {
423 // 对 non-EP0 OUT 端点,完成后恢复到 NAK。
424 // For non-EP0 OUT endpoints, restore NAK on completion.
425 if (!IS_EP0)
426 {
427 *get_rx_ctrl_addr(GetNumber()) =
428 (*get_rx_ctrl_addr(GetNumber()) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_NAK;
429 }
430 }
431
432 // TOG 不匹配表示数据同步失败。
433 // TOG mismatch indicates data synchronization failure.
434 if (IS_OUT)
435 {
436 const bool TOG_OK = ((USBFSD->INT_ST & USBFS_U_TOG_OK) == USBFS_U_TOG_OK); // NOLINT
437 if (!TOG_OK)
438 {
439 SetState(State::IDLE);
440 (void)Transfer(last_transfer_size_);
441 return;
442 }
443 }
444
445 // 对 non-EP0、non-ISO 端点推进软件侧 data toggle。
446 // Update the software data toggle for non-EP0 non-ISO endpoints.
447 if (GetState() == State::BUSY && !IS_EP0 && !IS_ISO)
448 {
449 tog_ = !tog_;
450 }
451
452 if (IS_EP0 && IS_OUT)
453 {
454 tog_ = true;
455 *get_rx_ctrl_addr(GetNumber()) = USBFS_UEP_R_RES_ACK;
456 }
457
458 OnTransferCompleteCallback(true, size);
459}
460
461void CH32EndpointOtgFs::SwitchBuffer()
462{
463 if (GetDirection() == Direction::IN)
464 {
465 tog_ = (*get_tx_ctrl_addr(GetNumber()) & USBFS_UEP_T_TOG) == USBFS_UEP_T_TOG;
466 SetActiveBlock(!tog_);
467 }
468 else
469 {
470 tog_ = (*get_rx_ctrl_addr(GetNumber()) & USBFS_UEP_R_TOG) == USBFS_UEP_R_TOG;
471 SetActiveBlock(tog_);
472 }
473}
474
475#endif
原始数据封装类。 A class for encapsulating raw data.
size_t size_
数据大小(字节)。 The size of the data (in bytes).
void * addr_
数据存储地址。 The storage address of the data.
EPNumber
端点号 Endpoint number
Definition ep.hpp:42
static constexpr uint8_t EPNumberToInt8(EPNumber ep)
端点号转换为 uint8_t / Convert endpoint number to uint8_t
Definition ep.hpp:94
Direction
端点方向 Endpoint direction
Definition ep.hpp:31
LibXR 命名空间
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举
constexpr auto min(LeftType a, RightType b) -> std::common_type_t< LeftType, RightType >
计算两个数的最小值