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 else
200 {
201 if (dir == USB::Endpoint::Direction::OUT)
202 {
203 return LibXR::RawData(buffer.addr_, 128);
204 }
205 else
206 {
207 return LibXR::RawData(reinterpret_cast<uint8_t*>(buffer.addr_) + 128, 128);
208 }
209 }
210}
211
212CH32EndpointOtgFs::CH32EndpointOtgFs(EPNumber ep_num, Direction dir,
213 LibXR::RawData buffer, bool is_isochronous)
214 : Endpoint(ep_num, dir, is_isochronous ? buffer : select_buffer(ep_num, dir, buffer)),
215 is_isochronous_(is_isochronous),
216 dma_buffer_(buffer)
217{
218 map_otg_fs_[EPNumberToInt8(GetNumber())][static_cast<uint8_t>(dir)] = this;
219
220 set_dma_buffer(GetNumber(), dma_buffer_.addr_, is_isochronous ? false : true);
221
222 if (dir == Direction::IN)
223 {
224 set_tx_len(GetNumber(), 0);
225 *get_tx_ctrl_addr(GetNumber()) = USBFS_UEP_T_RES_NAK;
226 }
227 else
228 {
229 *get_rx_ctrl_addr(GetNumber()) = USBFS_UEP_R_RES_NAK;
230 }
231}
232
233void CH32EndpointOtgFs::Configure(const Config& cfg)
234{
235 auto& ep_cfg = GetConfig();
236 ep_cfg = cfg;
237
238 if (GetNumber() != EPNumber::EP0 && !is_isochronous_)
239 {
240 ep_cfg.double_buffer = true;
241 }
242 else
243 {
244 ep_cfg.double_buffer = false;
245 }
246
247 ep_cfg.max_packet_size = GetBuffer().size_;
248
249 set_tx_len(GetNumber(), 0);
250
251 if (!is_isochronous_)
252 {
253 *get_rx_ctrl_addr(GetNumber()) = USBFS_UEP_R_RES_NAK | USBFS_UEP_R_AUTO_TOG;
254 *get_tx_ctrl_addr(GetNumber()) = USBFS_UEP_T_RES_NAK | USBFS_UEP_T_AUTO_TOG;
255 enable_tx(GetNumber());
256 enable_rx(GetNumber());
257 }
258 else
259 {
260 *get_rx_ctrl_addr(GetNumber()) = USBFS_UEP_R_RES_NAK;
261 *get_tx_ctrl_addr(GetNumber()) = USBFS_UEP_T_RES_NAK;
262 if (GetDirection() == Direction::IN)
263 {
264 enable_tx(GetNumber());
265 }
266 else
267 {
268 enable_rx(GetNumber());
269 }
270 }
271
272 set_dma_buffer(GetNumber(), dma_buffer_.addr_, is_isochronous_ ? false : true);
273
274 SetState(State::IDLE);
275}
276
277void CH32EndpointOtgFs::Close()
278{
279 disable_tx(GetNumber());
280 disable_rx(GetNumber());
281
282 *get_tx_ctrl_addr(GetNumber()) = USBFS_UEP_T_RES_NAK;
283 *get_rx_ctrl_addr(GetNumber()) = USBFS_UEP_R_RES_NAK;
284
285 SetState(State::DISABLED);
286}
287
288ErrorCode CH32EndpointOtgFs::Transfer(size_t size)
289{
290 if (GetState() == State::BUSY)
291 {
292 return ErrorCode::BUSY;
293 }
294
295 auto buffer = GetBuffer();
296 if (buffer.size_ < size)
297 {
298 return ErrorCode::NO_BUFF;
299 }
300
301 bool is_in = (GetDirection() == Direction::IN);
302
303 if (is_in && UseDoubleBuffer())
304 {
305 SwitchBuffer();
306 }
307
308 if (is_in)
309 {
310 set_tx_len(GetNumber(), size);
311 auto addr = get_tx_ctrl_addr(GetNumber());
312
313 if (GetNumber() != EPNumber::EP0)
314 {
315 *addr = (is_isochronous_ ? USBFS_UEP_T_RES_NONE : USBFS_UEP_T_RES_ACK) |
316 (*addr & (~USBFS_UEP_T_RES_MASK));
317 }
318 else
319 {
320 *addr = USBFS_UEP_T_RES_ACK | (tog_ ? USBFS_UEP_T_TOG : 0);
321 }
322 }
323 else
324 {
325 auto addr = get_rx_ctrl_addr(GetNumber());
326
327 if (GetNumber() != EPNumber::EP0)
328 {
329 *addr = (is_isochronous_ ? USBFS_UEP_R_RES_NONE : USBFS_UEP_R_RES_ACK) |
330 (*addr & (~USBFS_UEP_R_RES_MASK));
331 }
332 else
333 {
334 *addr = USBFS_UEP_R_RES_ACK | (tog_ ? USBFS_UEP_R_TOG : 0);
335 }
336 }
337
338 if (GetNumber() == EPNumber::EP0)
339 {
340 tog_ = !tog_;
341 }
342
343 last_transfer_size_ = size;
344 SetState(State::BUSY);
345 return ErrorCode::OK;
346}
347
348ErrorCode CH32EndpointOtgFs::Stall()
349{
350 if (GetState() != State::IDLE)
351 {
352 return ErrorCode::BUSY;
353 }
354
355 bool is_in = (GetDirection() == Direction::IN);
356 if (is_in)
357 {
358 *get_tx_ctrl_addr(GetNumber()) |= USBFS_UEP_T_RES_STALL;
359 }
360 else
361 {
362 *get_rx_ctrl_addr(GetNumber()) |= USBFS_UEP_R_RES_STALL;
363 }
364 SetState(State::STALLED);
365 return ErrorCode::OK;
366}
367
368ErrorCode CH32EndpointOtgFs::ClearStall()
369{
370 if (GetState() != State::STALLED)
371 {
372 return ErrorCode::FAILED;
373 }
374
375 bool is_in = (GetDirection() == Direction::IN);
376 if (is_in)
377 {
378 *get_tx_ctrl_addr(GetNumber()) &= ~USBFS_UEP_T_RES_STALL;
379 }
380 else
381 {
382 *get_rx_ctrl_addr(GetNumber()) &= ~USBFS_UEP_R_RES_STALL;
383 }
384 SetState(State::IDLE);
385 return ErrorCode::OK;
386}
387
388void CH32EndpointOtgFs::TransferComplete(size_t size)
389{
390 const bool IS_IN = (GetDirection() == Direction::IN);
391 const bool IS_OUT = !IS_IN;
392 const bool IS_EP0 = (GetNumber() == EPNumber::EP0);
393 const bool IS_ISO = (GetType() == Type::ISOCHRONOUS);
394
395 // UIF_TRANSFER/INT_FG are cleared by the IRQ handler after dispatch.
396
397 if (IS_IN)
398 {
399 // Restore NAK on completion.
400 *get_tx_ctrl_addr(GetNumber()) =
401 (*get_tx_ctrl_addr(GetNumber()) & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_NAK;
402
403 size = last_transfer_size_;
404 }
405 else
406 {
407 // For non-EP0 OUT endpoints, restore NAK on completion.
408 if (!IS_EP0)
409 {
410 *get_rx_ctrl_addr(GetNumber()) =
411 (*get_rx_ctrl_addr(GetNumber()) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_NAK;
412 }
413 }
414
415 // TOG mismatch indicates data synchronization failure.
416 if (IS_OUT)
417 {
418 const bool TOG_OK = ((USBFSD->INT_ST & USBFS_U_TOG_OK) == USBFS_U_TOG_OK); // NOLINT
419 if (!TOG_OK)
420 {
421 SetState(State::IDLE);
422 (void)Transfer(last_transfer_size_);
423 return;
424 }
425 }
426
427 // Update software data toggle for non-EP0 non-ISO endpoints.
428 if (GetState() == State::BUSY && !IS_EP0 && !IS_ISO)
429 {
430 tog_ = !tog_;
431 }
432
433 if (IS_EP0 && IS_OUT)
434 {
435 tog_ = true;
436 *get_rx_ctrl_addr(GetNumber()) = USBFS_UEP_R_RES_ACK;
437 }
438
439 OnTransferCompleteCallback(true, size);
440}
441
442void CH32EndpointOtgFs::SwitchBuffer()
443{
444 if (GetDirection() == Direction::IN)
445 {
446 tog_ = (*get_tx_ctrl_addr(GetNumber()) & USBFS_UEP_T_TOG) == USBFS_UEP_T_TOG;
447 SetActiveBlock(!tog_);
448 }
449 else
450 {
451 tog_ = (*get_rx_ctrl_addr(GetNumber()) & USBFS_UEP_R_TOG) == USBFS_UEP_R_TOG;
452 SetActiveBlock(tog_);
453 }
454}
455
456#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:41
static constexpr uint8_t EPNumberToInt8(EPNumber ep)
端点号转换为 uint8_t / Convert endpoint number to uint8_t
Definition ep.hpp:93
Direction
端点方向 Endpoint direction
Definition ep.hpp:30
LibXR 命名空间
Definition ch32_can.hpp:14