libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
stm32_usb_ep.cpp
1#include "stm32_usb_ep.hpp"
2
3#include "stm32_dcache.hpp"
4using namespace LibXR;
5
6#if defined(HAL_PCD_MODULE_ENABLED)
7
8static inline bool is_power_of_two(unsigned int n) { return n > 0 && (n & (n - 1)) == 0; }
9
10#if defined(USB_OTG_HS) || defined(USB_OTG_FS)
11
12STM32Endpoint::STM32Endpoint(EPNumber ep_num, stm32_usb_dev_id_t id,
13 PCD_HandleTypeDef* hpcd, Direction dir, size_t fifo_size,
14 LibXR::RawData buffer)
15 : Endpoint(ep_num, dir, buffer), hpcd_(hpcd), fifo_size_(fifo_size), id_(id)
16{
17 ASSERT(fifo_size >= 8);
18 ASSERT(is_power_of_two(fifo_size) || fifo_size % 4 == 0);
19 ASSERT(is_power_of_two(buffer.size_) || buffer.size_ % 4 == 0);
20
21#if defined(USB_OTG_HS)
22 if (id == STM32_USB_OTG_HS)
23 {
24 map_otg_hs_[EPNumberToInt8(GetNumber())][static_cast<uint8_t>(dir)] = this;
25 }
26#endif
27#if defined(USB_OTG_FS)
28 if (id == STM32_USB_OTG_FS)
29 {
30 map_otg_fs_[EPNumberToInt8(GetNumber())][static_cast<uint8_t>(dir)] = this;
31 }
32#endif
33
34 if (dir == Direction::IN)
35 {
36 HAL_PCDEx_SetTxFiFo(hpcd_, EPNumberToInt8(GetNumber()), fifo_size / 4);
37 }
38 else if (dir == Direction::OUT && ep_num == USB::Endpoint::EPNumber::EP0)
39 {
40 HAL_PCDEx_SetRxFiFo(hpcd_, fifo_size / 4);
41 }
42}
43#endif
44
45#if defined(USB_BASE) || defined(USB_DRD_FS)
46STM32Endpoint::STM32Endpoint(EPNumber ep_num, stm32_usb_dev_id_t id,
47 PCD_HandleTypeDef* hpcd, Direction dir,
48 size_t hw_buffer_offset, size_t hw_buffer_size,
49 LibXR::RawData buffer)
50 : Endpoint(ep_num, dir, buffer), hpcd_(hpcd), hw_buffer_size_(hw_buffer_size), id_(id)
51{
52 ASSERT(hw_buffer_size >= 8);
53
54 ASSERT(is_power_of_two(hw_buffer_size));
55 ASSERT(is_power_of_two(buffer.size_) || buffer.size_ % 4 == 0);
56
57 map_fs_[EPNumberToInt8(GetNumber())][static_cast<uint8_t>(dir)] = this;
58
59 size_t buffer_offset = hw_buffer_offset;
60
61 HAL_PCDEx_PMAConfig(hpcd_, EPNumberToAddr(GetNumber(), dir), PCD_SNG_BUF,
62 buffer_offset);
63}
64#endif
65
67{
68 ASSERT(cfg.direction == Direction::IN || cfg.direction == Direction::OUT);
69
70 uint8_t addr = EPNumberToAddr(GetNumber(), cfg.direction);
71 uint8_t type = static_cast<uint8_t>(cfg.type);
72 auto& ep_cfg = GetConfig();
73 size_t packet_size_limit = 0;
74
75 ep_cfg = cfg;
76
77 switch (cfg.type)
78 {
79 case Type::BULK:
80#if defined(PCD_SPEED_HIGH_IN_FULL)
81 if (hpcd_->Init.speed == PCD_SPEED_FULL ||
82 hpcd_->Init.speed == PCD_SPEED_HIGH_IN_FULL)
83#else
84 if (hpcd_->Init.speed == PCD_SPEED_FULL)
85#endif
86 {
87 packet_size_limit = 64;
88 }
89 else
90 {
91 packet_size_limit = 512;
92 }
93 break;
94 case Type::INTERRUPT:
95#if defined(PCD_SPEED_HIGH_IN_FULL)
96 if (hpcd_->Init.speed == PCD_SPEED_FULL ||
97 hpcd_->Init.speed == PCD_SPEED_HIGH_IN_FULL)
98#else
99 if (hpcd_->Init.speed == PCD_SPEED_FULL)
100#endif
101 {
102 packet_size_limit = 64;
103 }
104 else
105 {
106 packet_size_limit = 1024;
107 }
108 break;
110#if defined(PCD_SPEED_HIGH_IN_FULL)
111 if (hpcd_->Init.speed == PCD_SPEED_FULL ||
112 hpcd_->Init.speed == PCD_SPEED_HIGH_IN_FULL)
113#else
114 if (hpcd_->Init.speed == PCD_SPEED_FULL)
115#endif
116 {
117 packet_size_limit = 1023;
118 }
119 else
120 {
121 packet_size_limit = 1024;
122 }
123 break;
124 case Type::CONTROL:
125 packet_size_limit = 64;
126 break;
127 default:
128 break;
129 }
130
131#if defined(USB_OTG_FS) || defined(USB_OTG_HS)
132 if (packet_size_limit > fifo_size_)
133 {
134 packet_size_limit = fifo_size_;
135 }
136#endif
137
138#if defined(USB_BASE) || defined(USB_DRD_FS)
139 if (packet_size_limit > hw_buffer_size_)
140 {
141 packet_size_limit = hw_buffer_size_;
142 }
143#endif
144
145 auto buffer = GetBuffer();
146
147 if (packet_size_limit > buffer.size_)
148 {
149 packet_size_limit = buffer.size_;
150 }
151
152 size_t max_packet_size = cfg.max_packet_size;
153
154 if (max_packet_size > packet_size_limit)
155 {
156 max_packet_size = packet_size_limit;
157 }
158
159 ep_cfg.max_packet_size = max_packet_size;
160
161 if (max_packet_size < 8)
162 {
163 max_packet_size = 8;
164 }
165
166 if (HAL_PCD_EP_Open(hpcd_, addr, max_packet_size, type) == HAL_OK)
167 {
169 }
170 else
171 {
173 }
174}
175
176#if defined(USB_OTG_FS) || defined(USB_OTG_HS)
177static bool wait_otg_in_ep_flag(USB_OTG_INEndpointTypeDef* in_ep, uint32_t flag)
178{
179 // 正常情况下几个 PHY 时钟内置位;上限只防止 PHY 时钟停止时卡死。
180 // Normally set within a few PHY clocks; the bound only guards a stopped PHY clock.
181 constexpr uint32_t MAX_POLLS = 10000U;
182 for (uint32_t i = 0U; i < MAX_POLLS; ++i)
183 {
184 if ((in_ep->DIEPINT & flag) != 0U)
185 {
186 return true;
187 }
188 }
189 return false;
190}
191
192static void disable_otg_in_ep(PCD_HandleTypeDef* hpcd, uint8_t ep_num)
193{
194 const uintptr_t base = reinterpret_cast<uintptr_t>(hpcd->Instance);
195 auto* in_ep = reinterpret_cast<USB_OTG_INEndpointTypeDef*>(
196 base + USB_OTG_IN_ENDPOINT_BASE + ep_num * USB_OTG_EP_REG_SIZE);
197 auto* device = reinterpret_cast<USB_OTG_DeviceTypeDef*>(base + USB_OTG_DEVICE_BASE);
198
199 if ((in_ep->DIEPCTL & USB_OTG_DIEPCTL_EPENA) == 0U)
200 {
201 return;
202 }
203
204 // HAL_PCD_EP_Close 只请求禁用;HAL 稍后在 EPDISD 中断里清空该 TxFIFO,
205 // 会清掉关闭后重新开始的传输已写入的数据。这里按参考手册的禁用流程等禁用完成,
206 // 清掉 EPDISD 并立即清空 FIFO。
207 // HAL_PCD_EP_Close only requests the disable; HAL later flushes this TxFIFO in the
208 // EPDISD interrupt, which would discard data already written for a transfer
209 // restarted after the close. Follow the reference-manual disable sequence, wait
210 // for completion, clear EPDISD and flush the FIFO now.
211 device->DIEPEMPMSK &= ~(1UL << ep_num);
212 in_ep->DIEPCTL |= USB_OTG_DIEPCTL_SNAK;
213 (void)wait_otg_in_ep_flag(in_ep, USB_OTG_DIEPINT_INEPNE);
214 in_ep->DIEPCTL |= USB_OTG_DIEPCTL_EPDIS | USB_OTG_DIEPCTL_SNAK;
215 (void)wait_otg_in_ep_flag(in_ep, USB_OTG_DIEPINT_EPDISD);
216 in_ep->DIEPINT = USB_OTG_DIEPINT_INEPNE | USB_OTG_DIEPINT_EPDISD;
217 (void)USB_FlushTxFifo(hpcd->Instance, ep_num);
218}
219#endif
220
222{
223 uint8_t addr = EPNumberToAddr(GetNumber(), GetDirection());
224#if defined(USB_OTG_FS) || defined(USB_OTG_HS)
225 bool is_otg = false;
226#if defined(USB_OTG_FS)
227 is_otg = is_otg || id_ == STM32_USB_OTG_FS;
228#endif
229#if defined(USB_OTG_HS)
230 is_otg = is_otg || id_ == STM32_USB_OTG_HS;
231#endif
232 if (is_otg && GetDirection() == Direction::IN)
233 {
234 disable_otg_in_ep(hpcd_, EPNumberToInt8(GetNumber()));
235 }
236#endif
237 HAL_PCD_EP_Close(hpcd_, addr);
239}
240
242{
243 if (GetState() == State::BUSY)
244 {
245 return ErrorCode::BUSY;
246 }
247
248 bool is_in = GetDirection() == Direction::IN;
249 auto ep_addr = EPNumberToAddr(GetNumber(), GetDirection());
250
251 PCD_EPTypeDef* ep = is_in ? &hpcd_->IN_ep[ep_addr & EP_ADDR_MSK]
252 : &hpcd_->OUT_ep[ep_addr & EP_ADDR_MSK];
253
254 auto buffer = GetBuffer();
255
256 if (buffer.size_ < size)
257 {
258 return ErrorCode::NO_BUFF;
259 }
260
261 ep->xfer_buff = reinterpret_cast<uint8_t*>(buffer.addr_);
262
263 if (UseDoubleBuffer() && GetDirection() == Direction::IN && size > 0)
264 {
265 SwitchBuffer();
266 }
267
268 ep->xfer_len = size;
269 ep->xfer_count = 0U;
270 ep->is_in = is_in ? 1U : 0U;
271 ep->num = ep_addr & EP_ADDR_MSK;
272 last_transfer_size_ = size;
273
274#if defined(USB_OTG_FS) || defined(USB_OTG_HS)
275 if (hpcd_->Init.dma_enable == 1U)
276 {
277 ep->dma_addr = reinterpret_cast<uint32_t>(ep->xfer_buff);
278
279 if (is_in == true)
280 {
281 STM32_CleanDCacheByAddr(buffer.addr_, size);
282 }
283 }
284#endif
285
286#if defined(USB_BASE) || defined(USB_DRD_FS)
287 if (is_in)
288 {
289 ep->xfer_fill_db = 0U;
290 ep->xfer_len_db = 0U;
291 }
292#endif
293
295
296#if defined(USB_OTG_FS) || defined(USB_OTG_HS)
297 auto ans = USB_EPStartXfer(hpcd_->Instance, ep, hpcd_->Init.dma_enable);
298#else
299 auto ans = USB_EPStartXfer(hpcd_->Instance, ep);
300 if (size == 0 && GetNumber() == USB::Endpoint::EPNumber::EP0 &&
302 {
304 }
305#endif
306
307 if (ans == HAL_OK)
308 {
309 return ErrorCode::OK;
310 }
311 else
312 {
314 return ErrorCode::FAILED;
315 }
316}
317
319{
320 const bool is_in = (GetDirection() == Direction::IN);
321 if (GetState() != State::IDLE && !(GetState() == State::BUSY && !is_in))
322 {
323 return ErrorCode::BUSY;
324 }
325
326 uint8_t addr = EPNumberToAddr(GetNumber(), GetDirection());
327 if (HAL_PCD_EP_SetStall(hpcd_, addr) == HAL_OK)
328 {
330 return ErrorCode::OK;
331 }
332 else
333 {
335 return ErrorCode::FAILED;
336 }
337}
338
340{
341 if (GetState() != State::STALLED)
342 {
343 return ErrorCode::FAILED;
344 }
345
346 uint8_t addr = EPNumberToAddr(GetNumber(), GetDirection());
347
349 {
351 return ErrorCode::OK;
352 }
353
354 if (HAL_PCD_EP_ClrStall(hpcd_, addr) == HAL_OK)
355 {
357 return ErrorCode::OK;
358 }
359 else
360 {
362 return ErrorCode::FAILED;
363 }
364}
365
367{
369 {
370 return MaxPacketSize();
371 }
372 else
373 {
374 return GetBuffer().size_;
375 }
376}
377
378// --- HAL C 回调桥接 ---
379// NOLINTNEXTLINE
380static STM32Endpoint* GetEndpoint(PCD_HandleTypeDef* hpcd, uint8_t epnum, bool is_in)
381{
382 auto id = STM32USBDeviceGetID(hpcd);
383#if defined(USB_OTG_HS)
384 if (id == STM32_USB_OTG_HS)
385 {
386 return STM32Endpoint::map_otg_hs_[epnum & 0x7F][static_cast<uint8_t>(is_in)];
387 }
388#endif
389#if defined(USB_OTG_FS)
390 if (id == STM32_USB_OTG_FS)
391 {
392 return STM32Endpoint::map_otg_fs_[epnum & 0x7F][static_cast<uint8_t>(is_in)];
393 }
394#endif
395#if defined(USB_BASE) || defined(USB_DRD_FS)
396 if (id == STM32_USB_FS_DEV)
397 {
398 return STM32Endpoint::map_fs_[epnum & 0x7F][static_cast<uint8_t>(is_in)];
399 }
400#endif
401 return nullptr;
402}
403
404extern "C" void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef* hpcd, uint8_t epnum)
405{
406 auto id = STM32USBDeviceGetID(hpcd);
407
408 if (id >= STM32_USB_DEV_ID_NUM || STM32USBDevice::map_[id] == nullptr)
409 {
410 return;
411 }
412
413 auto ep = GetEndpoint(hpcd, epnum, true);
414
415 if (!ep || ep->hpcd_ != hpcd)
416 {
417 return;
418 }
419
420 ep->OnTransferCompleteCallback(true, ep->last_transfer_size_);
421}
422
423extern "C" void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef* hpcd, uint8_t epnum)
424{
425 auto id = STM32USBDeviceGetID(hpcd);
426
427 if (id >= STM32_USB_DEV_ID_NUM || STM32USBDevice::map_[id] == nullptr)
428 {
429 return;
430 }
431
432 auto ep = GetEndpoint(hpcd, epnum, false);
433
434 if (!ep || ep->hpcd_ != hpcd)
435 {
436 return;
437 }
438
439 PCD_EPTypeDef* ep_handle = &hpcd->OUT_ep[epnum & EP_ADDR_MSK];
440
441 size_t actual_transfer_size = ep_handle->xfer_count;
442
443 if (STM32USBUsesDma(hpcd))
444 {
445 STM32_InvalidateDCacheByAddr(ep->GetBuffer().addr_, actual_transfer_size);
446 }
447
448 ep->OnTransferCompleteCallback(true, actual_transfer_size);
449}
450
451extern "C" void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef* hpcd, uint8_t epnum)
452{
453 auto id = STM32USBDeviceGetID(hpcd);
454
455 if (id >= STM32_USB_DEV_ID_NUM || STM32USBDevice::map_[id] == nullptr)
456 {
457 return;
458 }
459
460 auto ep = GetEndpoint(hpcd, epnum, true);
461
462 if (!ep || ep->hpcd_ != hpcd)
463 {
464 return;
465 }
466
467 ep->OnTransferCompleteCallback(true, 0);
468}
469
470extern "C" void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef* hpcd, uint8_t epnum)
471{
472 auto id = STM32USBDeviceGetID(hpcd);
473
474 if (id >= STM32_USB_DEV_ID_NUM || STM32USBDevice::map_[id] == nullptr)
475 {
476 return;
477 }
478
479 auto ep = GetEndpoint(hpcd, epnum, false);
480
481 if (!ep || ep->hpcd_ != hpcd)
482 {
483 return;
484 }
485
486 ep->OnTransferCompleteCallback(true, 0);
487}
488#endif
可写原始数据视图 / Mutable raw data view
size_t size_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
STM32 USB 端点实现 / STM32 USB endpoint implementation.
ErrorCode Transfer(size_t size) override
启动一次传输 / Start a transfer
ErrorCode ClearStall() override
清除 STALL / Clear stall
void Configure(const Config &cfg) override
配置端点协议参数 / Configure endpoint protocol parameters
void Close() override
关闭端点 / Close endpoint
ErrorCode Stall() override
置 STALL / Stall endpoint
size_t MaxTransferSize() const override
返回当前最大可传输字节数 / Return maximum transferable size at this time
@ EP0
端点 0 / Endpoint 0
static constexpr uint8_t EPNumberToInt8(EPNumber ep)
端点号转换为 uint8_t / Convert endpoint number to uint8_t
Definition ep.hpp:93
@ IN
输入方向 / IN direction
@ OUT
输出方向 / OUT direction
static constexpr uint8_t EPNumberToAddr(EPNumber ep, Direction dir)
端点号转换为端点地址 / Convert endpoint number to endpoint address
Definition ep.hpp:104
Direction GetDirection() const
获取当前端点方向 / Get current endpoint direction
Definition ep.hpp:181
bool UseDoubleBuffer() const
是否启用双缓冲 / Whether double buffer is enabled
Definition ep.hpp:239
virtual void SwitchBuffer()
切换双缓冲 / Switch double buffer
Definition ep.hpp:520
Config & GetConfig()
获取当前配置引用 / Get endpoint config reference
Definition ep.hpp:515
void OnTransferCompleteCallback(bool in_isr, size_t actual_transfer_size)
由底层在传输完成时调用 / Called by low-level driver when transfer completes
Definition ep.hpp:392
@ ISOCHRONOUS
等时端点 / Isochronous
@ BULK
批量端点 / Bulk
@ INTERRUPT
中断端点 / Interrupt
@ CONTROL
控制端点 / Control
EPNumber GetNumber() const
获取端点号 / Get endpoint number
Definition ep.hpp:169
uint16_t MaxPacketSize() const
获取最大包长 / Get max packet size
Definition ep.hpp:225
@ DISABLED
禁用 / Disabled
@ STALLED
停止/挂起 / Stalled
void SetState(State state)
设置端点状态 / Set endpoint state
Definition ep.hpp:213
State GetState() const
获取端点状态 / Get endpoint state
Definition ep.hpp:207
RawData GetBuffer() const
获取当前可用于传输的缓冲区 / Get current transfer buffer
Definition ep.hpp:245
LibXR 命名空间 / LibXR namespace.
Definition ch32_can.hpp:14
void STM32_InvalidateDCacheByAddr(const void *addr, size_t size)
失效指定内存范围覆盖的 D-Cache cache line Invalidates D-Cache lines covering the specified memory range
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ BUSY
忙碌 / Busy
@ NO_BUFF
缓冲区不足 / Insufficient buffer
@ FAILED
操作失败 / Operation failed
@ OK
操作成功 / Operation successful
void STM32_CleanDCacheByAddr(const void *addr, size_t size)
清理指定内存范围覆盖的 D-Cache cache line Cleans D-Cache lines covering the specified memory range
端点配置参数 / Endpoint configuration parameters
Definition ep.hpp:138
Type type
端点类型 / Endpoint type
Definition ep.hpp:140
uint16_t max_packet_size
最大包长 / Max packet size
Definition ep.hpp:141
Direction direction
端点方向 / Endpoint direction
Definition ep.hpp:139