libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
ch32_usb_endpoint_devfs.cpp
1// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast,performance-no-int-to-ptr)
2// ch32_usb_endpoint_dev_fs.cpp
3#include <cstdint>
4#include <cstring>
5
6#include "ch32_usb_endpoint.hpp"
7#include "ch32_usbcan_shared.hpp"
8#include "ep.hpp"
9
10using namespace LibXR;
11
12#if defined(RCC_APB1Periph_USB)
13
14#ifdef USB_BASE
15static constexpr uintptr_t REG_BASE = USB_BASE;
16#else
17static constexpr uintptr_t REG_BASE = 0x40005C00UL;
18#endif
19
20#ifdef PMAAddr
21static constexpr uintptr_t PMA_BASE = PMAAddr;
22#else
23static constexpr uintptr_t PMA_BASE = 0x40006000UL;
24#endif
25
26static inline uintptr_t pma_phys(uint16_t pma_off_bytes)
27{
28 return PMA_BASE + (static_cast<uintptr_t>(pma_off_bytes) << 1);
29}
30
31static inline volatile uint16_t* btable()
32{
33 return reinterpret_cast<volatile uint16_t*>(REG_BASE + 0x50U);
34}
35
36static inline volatile uint16_t* ep_reg(uint8_t ep)
37{
38 return reinterpret_cast<volatile uint16_t*>(REG_BASE +
39 (static_cast<uintptr_t>(ep) * 4U));
40}
41
42#if !defined(USB_EP_CTR_RX) && defined(EP_CTR_RX)
43#define USB_EP_CTR_RX EP_CTR_RX
44#endif
45#if !defined(USB_EP_DTOG_RX) && defined(EP_DTOG_RX)
46#define USB_EP_DTOG_RX EP_DTOG_RX
47#endif
48#if !defined(USB_EPRX_STAT) && defined(EPRX_STAT)
49#define USB_EPRX_STAT EPRX_STAT
50#endif
51#if !defined(USB_EP_SETUP) && defined(EP_SETUP)
52#define USB_EP_SETUP EP_SETUP
53#endif
54#if !defined(USB_EP_T_FIELD) && defined(EP_T_FIELD)
55#define USB_EP_T_FIELD EP_T_FIELD
56#endif
57#if !defined(USB_EP_KIND) && defined(EP_KIND)
58#define USB_EP_KIND EP_KIND
59#endif
60#if !defined(USB_EP_CTR_TX) && defined(EP_CTR_TX)
61#define USB_EP_CTR_TX EP_CTR_TX
62#endif
63#if !defined(USB_EP_DTOG_TX) && defined(EP_DTOG_TX)
64#define USB_EP_DTOG_TX EP_DTOG_TX
65#endif
66#if !defined(USB_EPTX_STAT) && defined(EPTX_STAT)
67#define USB_EPTX_STAT EPTX_STAT
68#endif
69#if !defined(USB_EPADDR_FIELD) && defined(EPADDR_FIELD)
70#define USB_EPADDR_FIELD EPADDR_FIELD
71#endif
72
73#ifndef USB_EP_CTR_RX
74#define USB_EP_CTR_RX ((uint16_t)0x8000U)
75#endif
76#ifndef USB_EP_DTOG_RX
77#define USB_EP_DTOG_RX ((uint16_t)0x4000U)
78#endif
79#ifndef USB_EPRX_STAT
80#define USB_EPRX_STAT ((uint16_t)0x3000U)
81#endif
82#ifndef USB_EP_SETUP
83#define USB_EP_SETUP ((uint16_t)0x0800U)
84#endif
85#ifndef USB_EP_T_FIELD
86#define USB_EP_T_FIELD ((uint16_t)0x0600U)
87#endif
88#ifndef USB_EP_KIND
89#define USB_EP_KIND ((uint16_t)0x0100U)
90#endif
91#ifndef USB_EP_CTR_TX
92#define USB_EP_CTR_TX ((uint16_t)0x0080U)
93#endif
94#ifndef USB_EP_DTOG_TX
95#define USB_EP_DTOG_TX ((uint16_t)0x0040U)
96#endif
97#ifndef USB_EPTX_STAT
98#define USB_EPTX_STAT ((uint16_t)0x0030U)
99#endif
100#ifndef USB_EPADDR_FIELD
101#define USB_EPADDR_FIELD ((uint16_t)0x000FU)
102#endif
103
104#ifndef USB_EP_CONTROL
105#define USB_EP_CONTROL ((uint16_t)0x0200U)
106#endif
107#ifndef USB_EP_BULK
108#define USB_EP_BULK ((uint16_t)0x0000U)
109#endif
110#ifndef USB_EP_INTERRUPT
111#define USB_EP_INTERRUPT ((uint16_t)0x0600U)
112#endif
113#ifndef USB_EP_ISOCHRONOUS
114#define USB_EP_ISOCHRONOUS ((uint16_t)0x0400U)
115#endif
116
117#ifndef USB_EP_TX_DIS
118#define USB_EP_TX_DIS ((uint16_t)0x0000U)
119#endif
120#ifndef USB_EP_TX_STALL
121#define USB_EP_TX_STALL ((uint16_t)0x0010U)
122#endif
123#ifndef USB_EP_TX_NAK
124#define USB_EP_TX_NAK ((uint16_t)0x0020U)
125#endif
126#ifndef USB_EP_TX_VALID
127#define USB_EP_TX_VALID ((uint16_t)0x0030U)
128#endif
129
130#ifndef USB_EP_RX_DIS
131#define USB_EP_RX_DIS ((uint16_t)0x0000U)
132#endif
133#ifndef USB_EP_RX_STALL
134#define USB_EP_RX_STALL ((uint16_t)0x1000U)
135#endif
136#ifndef USB_EP_RX_NAK
137#define USB_EP_RX_NAK ((uint16_t)0x2000U)
138#endif
139#ifndef USB_EP_RX_VALID
140#define USB_EP_RX_VALID ((uint16_t)0x3000U)
141#endif
142
143#ifndef USB_EPREG_MASK
144#define USB_EPREG_MASK \
145 (USB_EP_CTR_RX | USB_EP_SETUP | USB_EP_T_FIELD | USB_EP_KIND | USB_EP_CTR_TX | \
146 USB_EPADDR_FIELD)
147#endif
148
149#ifndef USB_EPTX_DTOGMASK
150#define USB_EPTX_DTOGMASK (USB_EPTX_STAT | USB_EPREG_MASK)
151#endif
152#ifndef USB_EPRX_DTOGMASK
153#define USB_EPRX_DTOGMASK (USB_EPRX_STAT | USB_EPREG_MASK)
154#endif
155
156struct BTableEntry
157{
158 uint16_t addr_tx;
159 uint16_t _r0;
160 uint16_t count_tx;
161 uint16_t _r1;
162 uint16_t addr_rx;
163 uint16_t _r2;
164 uint16_t count_rx;
165 uint16_t _r3;
166};
167
168static inline volatile BTableEntry* btable_entries()
169{
170 const uint16_t BTABLE_OFF = static_cast<uint16_t>((*btable()) & 0xFFF8U);
171 return reinterpret_cast<volatile BTableEntry*>(pma_phys(BTABLE_OFF));
172}
173
174static inline void pma_write(uint16_t pma_offset, const void* src, size_t len)
175{
176 const uint8_t* s = reinterpret_cast<const uint8_t*>(src);
177 volatile uint16_t* p = reinterpret_cast<volatile uint16_t*>(pma_phys(pma_offset));
178
179 for (size_t i = 0; i < len; i += 2)
180 {
181 uint16_t w = s[i];
182 if (i + 1 < len)
183 {
184 w |= static_cast<uint16_t>(s[i + 1]) << 8;
185 }
186 *p = w;
187 p += 2; // stride=2 on CH32 FSDEV PMA
188 }
189}
190
191static inline void pma_read(void* dst, uint16_t pma_offset, size_t len)
192{
193 uint8_t* d = reinterpret_cast<uint8_t*>(dst);
194 const volatile uint16_t* p =
195 reinterpret_cast<const volatile uint16_t*>(pma_phys(pma_offset));
196
197 for (size_t i = 0; i < len; i += 2)
198 {
199 const uint16_t W = *p;
200 p += 2;
201
202 d[i] = static_cast<uint8_t>(W & 0xFFU);
203 if (i + 1 < len)
204 {
205 d[i + 1] = static_cast<uint8_t>((W >> 8) & 0xFFU);
206 }
207 }
208}
209
210static inline void set_tx_status(uint8_t ep, uint16_t desired_stat)
211{
212 const uint16_t CUR = *ep_reg(ep);
213 uint16_t reg = static_cast<uint16_t>(CUR & USB_EPREG_MASK);
214
215 // FSDEV EPxR STAT bits are write-1-to-toggle; write the delta to reach target.
216 const uint16_t TARGET = static_cast<uint16_t>(desired_stat & USB_EPTX_STAT);
217 reg |= static_cast<uint16_t>((CUR ^ TARGET) & USB_EPTX_STAT);
218 reg |= static_cast<uint16_t>(USB_EP_CTR_RX | USB_EP_CTR_TX);
219 *ep_reg(ep) = reg;
220}
221
222static inline void set_rx_status(uint8_t ep, uint16_t desired_stat)
223{
224 const uint16_t CUR = *ep_reg(ep);
225 uint16_t reg = static_cast<uint16_t>(CUR & USB_EPREG_MASK);
226
227 // FSDEV EPxR STAT bits are write-1-to-toggle; write the delta to reach target.
228 const uint16_t TARGET = static_cast<uint16_t>(desired_stat & USB_EPRX_STAT);
229 reg |= static_cast<uint16_t>((CUR ^ TARGET) & USB_EPRX_STAT);
230 reg |= static_cast<uint16_t>(USB_EP_CTR_RX | USB_EP_CTR_TX);
231 *ep_reg(ep) = reg;
232}
233
234static inline void clear_ctr_tx(uint8_t ep)
235{
236 uint16_t reg = static_cast<uint16_t>((*ep_reg(ep)) & USB_EPREG_MASK);
237 reg |= static_cast<uint16_t>(USB_EP_CTR_TX | USB_EP_CTR_RX);
238 reg = static_cast<uint16_t>(reg & ~USB_EP_CTR_TX);
239 *ep_reg(ep) = reg;
240}
241
242static inline void clear_ctr_rx(uint8_t ep)
243{
244 uint16_t reg = static_cast<uint16_t>((*ep_reg(ep)) & USB_EPREG_MASK);
245 reg |= static_cast<uint16_t>(USB_EP_CTR_TX | USB_EP_CTR_RX);
246 reg = static_cast<uint16_t>(reg & ~USB_EP_CTR_RX);
247 *ep_reg(ep) = reg;
248}
249
250static inline uint16_t get_rx_count_from_btable(uint8_t ep)
251{
252 return static_cast<uint16_t>(btable_entries()[ep].count_rx & 0x03FFU);
253}
254
255static inline uint16_t encode_rx_count(uint16_t mps)
256{
257 if (mps <= 62)
258 {
259 const uint16_t BLOCKS = static_cast<uint16_t>((mps + 1U) / 2U);
260 return static_cast<uint16_t>(BLOCKS << 10);
261 }
262
263 const uint16_t BLOCKS = static_cast<uint16_t>((mps + 31U) / 32U);
264 return static_cast<uint16_t>(0x8000U | ((BLOCKS - 1U) << 10));
265}
266
267static constexpr uint16_t PMA_ALLOC_BASE =
268 static_cast<uint16_t>(CH32EndpointDevFs::EP_DEV_FS_MAX_SIZE) * 8U;
269static uint16_t g_pma_next = PMA_ALLOC_BASE;
270static uint16_t g_pma_limit = LibXR::CH32UsbCanShared::USBD_PMA_BYTES_SOLO;
271
272void CH32EndpointDevFs::ResetPMAAllocator()
273{
274 const uint16_t LIMIT_BYTES = static_cast<uint16_t>(
275 LibXR::CH32UsbCanShared::usb_pma_limit_bytes() & static_cast<uint16_t>(~1U));
276 g_pma_limit = LIMIT_BYTES;
277
278 g_pma_next = PMA_ALLOC_BASE;
279 g_pma_next = static_cast<uint16_t>((g_pma_next + 1U) & ~1U);
280 ASSERT(g_pma_next <= g_pma_limit);
281}
282
283static inline uint16_t alloc_pma(size_t bytes)
284{
285 const uint16_t ADDR = g_pma_next;
286 const uint16_t INC = static_cast<uint16_t>((bytes + 1U) & ~1U);
287
288 const uint32_t END = static_cast<uint32_t>(ADDR) + static_cast<uint32_t>(INC);
289 ASSERT(END <= g_pma_limit);
290 if (END > g_pma_limit)
291 {
292 return 0;
293 }
294
295 g_pma_next = static_cast<uint16_t>(END);
296 return ADDR;
297}
298
299CH32EndpointDevFs::CH32EndpointDevFs(EPNumber ep_num, Direction dir,
300 LibXR::RawData buffer, bool is_isochronous)
301 : Endpoint(ep_num, dir, buffer), is_isochronous_(is_isochronous)
302{
303 const uint8_t EP_I = static_cast<uint8_t>(EPNumberToInt8(GetNumber()));
304 map_dev_fs_[EP_I][static_cast<uint8_t>(dir)] = this;
305}
306
307void CH32EndpointDevFs::Configure(const Config& cfg)
308{
309 ASSERT(cfg.direction == Direction::IN || cfg.direction == Direction::OUT);
310 ASSERT(cfg.direction == GetDirection());
311
312 auto& ep_cfg = GetConfig();
313 ep_cfg = cfg;
314
315 const uint8_t EP_I = static_cast<uint8_t>(EPNumberToInt8(GetNumber()));
316
317 size_t packet_size_limit = 64;
318 if (cfg.type == Type::ISOCHRONOUS)
319 {
320 packet_size_limit = 1023;
321 }
322
323 const auto BUF = GetBuffer();
324 if (packet_size_limit > BUF.size_)
325 {
326 packet_size_limit = BUF.size_;
327 }
328
329 size_t max_packet_size = cfg.max_packet_size;
330 if (max_packet_size > packet_size_limit)
331 {
332 max_packet_size = packet_size_limit;
333 }
334 if (max_packet_size < 8)
335 {
336 max_packet_size = 8;
337 }
338 if (max_packet_size > BUF.size_)
339 {
340 max_packet_size = BUF.size_;
341 }
342
343 ep_cfg.max_packet_size = static_cast<uint16_t>(max_packet_size);
344
345 if (pma_addr_ == 0 || pma_addr_ < PMA_ALLOC_BASE)
346 {
347 const uint16_t ADDR = alloc_pma(BUF.size_);
348 ASSERT(ADDR >= PMA_ALLOC_BASE);
349 if (ADDR < PMA_ALLOC_BASE)
350 {
351 return;
352 }
353 pma_addr_ = ADDR;
354 }
355
356 volatile BTableEntry* bt = btable_entries();
357
358 if (GetDirection() == Direction::IN)
359 {
360 bt[EP_I].addr_tx = pma_addr_;
361 bt[EP_I].count_tx = 0;
362 }
363 else
364 {
365 bt[EP_I].addr_rx = pma_addr_;
366 bt[EP_I].count_rx = encode_rx_count(ep_cfg.max_packet_size);
367 }
368
369 uint16_t epr = static_cast<uint16_t>((*ep_reg(EP_I)) & USB_EPREG_MASK);
370
371 epr = static_cast<uint16_t>((epr & ~USB_EPADDR_FIELD) | (EP_I & 0x0FU));
372 epr = static_cast<uint16_t>(epr & ~USB_EP_T_FIELD);
373
374 switch (ep_cfg.type)
375 {
376 case Type::CONTROL:
377 epr |= USB_EP_CONTROL;
378 break;
379 case Type::BULK:
380 epr |= USB_EP_BULK;
381 break;
382 case Type::INTERRUPT:
383 epr |= USB_EP_INTERRUPT;
384 break;
385 case Type::ISOCHRONOUS:
386 epr |= USB_EP_ISOCHRONOUS;
387 break;
388 default:
389 epr |= USB_EP_BULK;
390 break;
391 }
392
393 *ep_reg(EP_I) = epr;
394
395 if (GetDirection() == Direction::IN)
396 {
397 set_tx_status(EP_I, USB_EP_TX_NAK);
398 }
399 else
400 {
401 set_rx_status(EP_I, USB_EP_RX_NAK);
402 }
403
404 SetState(State::IDLE);
405}
406
407void CH32EndpointDevFs::Close()
408{
409 const uint8_t EP_I = static_cast<uint8_t>(EPNumberToInt8(GetNumber()));
410 if (GetDirection() == Direction::IN)
411 {
412 set_tx_status(EP_I, USB_EP_TX_DIS);
413 }
414 else
415 {
416 set_rx_status(EP_I, USB_EP_RX_DIS);
417 }
418}
419
420ErrorCode CH32EndpointDevFs::Transfer(size_t size)
421{
422 if (size > GetBuffer().size_)
423 {
424 return ErrorCode::OUT_OF_RANGE;
425 }
426
427 SetState(State::BUSY);
428
429 const uint8_t EP_I = static_cast<uint8_t>(EPNumberToInt8(GetNumber()));
430 last_transfer_size_ = size;
431
432 if (GetDirection() == Direction::IN)
433 {
434 auto buffer = GetBuffer();
435 pma_write(pma_addr_, buffer.addr_, size);
436
437 // Keep the current transfer on the old active block and switch to the next block
438 // for producer writes, matching STM32/HAL timing.
439 if (UseDoubleBuffer() && size > 0)
440 {
441 Endpoint::SwitchBuffer();
442 }
443
444 btable_entries()[EP_I].count_tx = static_cast<uint16_t>(size);
445 set_tx_status(EP_I, USB_EP_TX_VALID);
446 }
447 else
448 {
449 volatile BTableEntry* bt = btable_entries();
450 bt[EP_I].addr_rx = pma_addr_;
451 bt[EP_I].count_rx = encode_rx_count(GetConfig().max_packet_size);
452 set_rx_status(EP_I, USB_EP_RX_VALID);
453 }
454
455 return ErrorCode::OK;
456}
457
458void CH32EndpointDevFs::CopyRxDataToBuffer(size_t size)
459{
460 if (size > GetBuffer().size_)
461 {
462 size = GetBuffer().size_;
463 }
464 pma_read(GetBuffer().addr_, pma_addr_, size);
465}
466
467void CH32EndpointDevFs::TransferComplete(size_t size)
468{
469 const uint8_t EP_I = static_cast<uint8_t>(EPNumberToInt8(GetNumber()));
470
471 if (GetDirection() == Direction::OUT)
472 {
473 const uint16_t RX_CNT = get_rx_count_from_btable(EP_I);
474 size_t n = RX_CNT;
475 if (n > GetBuffer().size_)
476 {
477 n = GetBuffer().size_;
478 }
479 pma_read(GetBuffer().addr_, pma_addr_, n);
480 size = n;
481 set_rx_status(EP_I, USB_EP_RX_NAK);
482 }
483 else
484 {
485 set_tx_status(EP_I, USB_EP_TX_NAK);
486 size = last_transfer_size_;
487 }
488
489 OnTransferCompleteCallback(true, size);
490}
491
492ErrorCode CH32EndpointDevFs::Stall()
493{
494 const uint8_t EP_I = static_cast<uint8_t>(EPNumberToInt8(GetNumber()));
495 if (GetDirection() == Direction::IN)
496 {
497 set_tx_status(EP_I, USB_EP_TX_STALL);
498 }
499 else
500 {
501 set_rx_status(EP_I, USB_EP_RX_STALL);
502 }
503 return ErrorCode::OK;
504}
505
506ErrorCode CH32EndpointDevFs::ClearStall()
507{
508 const uint8_t EP_I = static_cast<uint8_t>(EPNumberToInt8(GetNumber()));
509 if (GetDirection() == Direction::IN)
510 {
511 set_tx_status(EP_I, USB_EP_TX_NAK);
512 }
513 else
514 {
515 set_rx_status(EP_I, USB_EP_RX_NAK);
516 }
517 return ErrorCode::OK;
518}
519
520void CH32EndpointDevFs::SwitchBuffer() { Endpoint::SwitchBuffer(); }
521
522void CH32EndpointDevFs::SetEpTxStatus(uint8_t ep, uint16_t status)
523{
524 set_tx_status(ep, status);
525}
526void CH32EndpointDevFs::SetEpRxStatus(uint8_t ep, uint16_t status)
527{
528 set_rx_status(ep, status);
529}
530void CH32EndpointDevFs::ClearEpCtrTx(uint8_t ep) { clear_ctr_tx(ep); }
531void CH32EndpointDevFs::ClearEpCtrRx(uint8_t ep) { clear_ctr_rx(ep); }
532uint16_t CH32EndpointDevFs::GetRxCount(uint8_t ep)
533{
534 return get_rx_count_from_btable(ep);
535}
536
537#endif // defined(RCC_APB1Periph_USB)
538
539// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast,performance-no-int-to-ptr)
原始数据封装类。 A class for encapsulating raw data.
void * addr_
数据存储地址。 The storage address of the data.
LibXR 命名空间
Definition ch32_can.hpp:14