Skip to content

Commit b1361d9

Browse files
committed
stm32: Add usbfs double buffer support for bulk rx messages
Implement the usbfs fast buffer switching mechanism on the "bulk out" endpoint. This can improve the overall USB throughput and bus utilization. Signed-off-by: Kevin O'Connor <[email protected]>
1 parent 01ac533 commit b1361d9

File tree

1 file changed

+49
-14
lines changed

1 file changed

+49
-14
lines changed

src/stm32/usbfs.c

+49-14
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@
4848
#define USB_CNTR_FRES USB_CNTR_USBRST
4949
#endif
5050

51+
// Some chip variants do not define these fields
52+
#ifndef USB_EP_DTOG_TX_Pos
53+
#define USB_EP_DTOG_TX_Pos 6
54+
#define USB_EP_DTOG_RX_Pos 14
55+
#endif
56+
5157

5258
/****************************************************************
5359
* USB transfer memory
@@ -110,8 +116,8 @@ btable_configure(void)
110116
epm_ep_desc_setup(0, BUFRX, USB_CDC_EP0_SIZE);
111117
epm_ep_desc_setup(USB_CDC_EP_ACM, BUFTX, 0);
112118
epm_ep_desc_setup(USB_CDC_EP_ACM, BUFRX, 0);
113-
epm_ep_desc_setup(USB_CDC_EP_BULK_OUT, BUFTX, 0);
114-
epm_ep_desc_setup(USB_CDC_EP_BULK_OUT, BUFRX, USB_CDC_EP_BULK_OUT_SIZE);
119+
epm_ep_desc_setup(USB_CDC_EP_BULK_OUT, 0, USB_CDC_EP_BULK_OUT_SIZE);
120+
epm_ep_desc_setup(USB_CDC_EP_BULK_OUT, 1, USB_CDC_EP_BULK_OUT_SIZE);
115121
epm_ep_desc_setup(USB_CDC_EP_BULK_IN, BUFTX, 0);
116122
epm_ep_desc_setup(USB_CDC_EP_BULK_IN, BUFRX, 0);
117123
}
@@ -192,20 +198,41 @@ calc_epr_bits(uint32_t epr, uint32_t mask, uint32_t value)
192198
return (((epr & (EPR_RWBITS | tmask)) ^ tvalue) & ~rwmask) | rwbits | cbits;
193199
}
194200

201+
// Check if double buffering endpoint hardware can no longer send/receive
202+
static int
203+
epr_is_dbuf_blocking(uint32_t epr)
204+
{
205+
return !(((epr >> (USB_EP_DTOG_RX_Pos - USB_EP_DTOG_TX_Pos)) ^ epr)
206+
& USB_EP_DTOG_TX);
207+
}
208+
195209

196210
/****************************************************************
197211
* USB interface
198212
****************************************************************/
199213

214+
static uint32_t bulk_out_pop_count, bulk_out_push_flag;
215+
200216
int_fast8_t
201217
usb_read_bulk_out(void *data, uint_fast8_t max_len)
202218
{
203-
uint32_t ep = USB_CDC_EP_BULK_OUT, epr = USB_EPR[ep];
204-
if ((epr & USB_EPRX_STAT) == USB_EP_RX_VALID)
219+
if (readl(&bulk_out_push_flag))
205220
// No data ready
206221
return -1;
207-
uint32_t count = btable_read_packet(ep, BUFRX, data, max_len);
208-
USB_EPR[ep] = calc_epr_bits(epr, USB_EPRX_STAT, USB_EP_RX_VALID);
222+
uint32_t ep = USB_CDC_EP_BULK_OUT;
223+
int bufnum = bulk_out_pop_count & 1;
224+
bulk_out_pop_count++;
225+
uint32_t count = btable_read_packet(ep, bufnum, data, max_len);
226+
writel(&bulk_out_push_flag, USB_EP_DTOG_TX);
227+
228+
// Check if irq handler pulled another packet before push flag update
229+
uint32_t epr = USB_EPR[ep];
230+
if (epr_is_dbuf_blocking(epr) && readl(&bulk_out_push_flag)) {
231+
// Second packet was already read - must notify hardware
232+
writel(&bulk_out_push_flag, 0);
233+
USB_EPR[ep] = calc_epr_bits(epr, 0, 0) | USB_EP_DTOG_TX;
234+
}
235+
209236
return count;
210237
}
211238

@@ -275,6 +302,9 @@ usb_set_address(uint_fast8_t addr)
275302
void
276303
usb_set_configure(void)
277304
{
305+
uint32_t ep = USB_CDC_EP_BULK_OUT;
306+
bulk_out_pop_count = 0;
307+
USB_EPR[ep] = calc_epr_bits(USB_EPR[ep], USB_EPRX_STAT, USB_EP_RX_VALID);
278308
}
279309

280310

@@ -294,8 +324,9 @@ usb_reset(void)
294324
| USB_EP_RX_NAK | USB_EP_TX_NAK);
295325

296326
ep = USB_CDC_EP_BULK_OUT;
297-
USB_EPR[ep] = (USB_CDC_EP_BULK_OUT | USB_EP_BULK
298-
| USB_EP_RX_VALID | USB_EP_TX_NAK);
327+
USB_EPR[ep] = (USB_CDC_EP_BULK_OUT | USB_EP_BULK | USB_EP_KIND
328+
| USB_EP_RX_VALID | USB_EP_TX_NAK | USB_EP_DTOG_TX);
329+
bulk_out_push_flag = USB_EP_DTOG_TX;
299330

300331
ep = USB_CDC_EP_BULK_IN;
301332
USB_EPR[ep] = (USB_CDC_EP_BULK_IN | USB_EP_BULK
@@ -313,18 +344,22 @@ USB_IRQHandler(void)
313344
if (istr & USB_ISTR_CTR) {
314345
// Endpoint activity
315346
uint32_t ep = istr & USB_ISTR_EP_ID, epr = USB_EPR[ep];
316-
USB_EPR[ep] = calc_epr_bits(epr, USB_EP_CTR_RX | USB_EP_CTR_TX, 0);
317-
if (ep == 0) {
347+
if (ep == USB_CDC_EP_BULK_OUT) {
348+
USB_EPR[ep] = (calc_epr_bits(epr, USB_EP_CTR_RX | USB_EP_CTR_TX, 0)
349+
| bulk_out_push_flag);
350+
bulk_out_push_flag = 0;
351+
usb_notify_bulk_out();
352+
} else if (ep == USB_CDC_EP_BULK_IN) {
353+
USB_EPR[ep] = calc_epr_bits(epr, USB_EP_CTR_RX | USB_EP_CTR_TX, 0);
354+
usb_notify_bulk_in();
355+
} else if (ep == 0) {
356+
USB_EPR[ep] = calc_epr_bits(epr, USB_EP_CTR_RX | USB_EP_CTR_TX, 0);
318357
usb_notify_ep0();
319358
if (epr & USB_EP_CTR_TX && set_address) {
320359
// Apply address after last "in" message transmitted
321360
USB->DADDR = set_address;
322361
set_address = 0;
323362
}
324-
} else if (ep == USB_CDC_EP_BULK_OUT) {
325-
usb_notify_bulk_out();
326-
} else if (ep == USB_CDC_EP_BULK_IN) {
327-
usb_notify_bulk_in();
328363
}
329364
}
330365
if (istr & USB_ISTR_RESET) {

0 commit comments

Comments
 (0)