diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h index 22eddd913..fcdafb095 100644 --- a/src/common/tusb_common.h +++ b/src/common/tusb_common.h @@ -171,14 +171,14 @@ static inline uint16_t tu_u16_le2be(uint16_t u16) } // Min -static inline uint8_t tu_min8(uint8_t x, uint8_t y) { return (x < y) ? x : y; } -static inline uint16_t tu_min16(uint16_t x, uint16_t y) { return (x < y) ? x : y; } -static inline uint32_t tu_min32(uint32_t x, uint32_t y) { return (x < y) ? x : y; } +static inline uint8_t tu_min8 (uint8_t x, uint8_t y ) { return (x < y) ? x : y; } +static inline uint16_t tu_min16 (uint16_t x, uint16_t y) { return (x < y) ? x : y; } +static inline uint32_t tu_min32 (uint32_t x, uint32_t y) { return (x < y) ? x : y; } // Max -static inline uint8_t tu_max8(uint8_t x, uint8_t y) { return (x > y) ? x : y; } -static inline uint16_t tu_max16(uint16_t x, uint16_t y) { return (x > y) ? x : y; } -static inline uint32_t tu_max32(uint32_t x, uint32_t y) { return (x > y) ? x : y; } +static inline uint8_t tu_max8 (uint8_t x, uint8_t y ) { return (x > y) ? x : y; } +static inline uint16_t tu_max16 (uint16_t x, uint16_t y) { return (x > y) ? x : y; } +static inline uint32_t tu_max32 (uint32_t x, uint32_t y) { return (x > y) ? x : y; } // Align static inline uint32_t tu_align32 (uint32_t value) { return (value & 0xFFFFFFE0UL); } diff --git a/src/portable/st/stm32f4/dcd_stm32f4.c b/src/portable/st/stm32f4/dcd_stm32f4.c index dace9ed3e..086f33f1c 100644 --- a/src/portable/st/stm32f4/dcd_stm32f4.c +++ b/src/portable/st/stm32f4/dcd_stm32f4.c @@ -50,7 +50,7 @@ #define DEVICE_BASE (USB_OTG_DeviceTypeDef *) (USB_OTG_FS_PERIPH_BASE + USB_OTG_DEVICE_BASE) #define OUT_EP_BASE (USB_OTG_OUTEndpointTypeDef *) (USB_OTG_FS_PERIPH_BASE + USB_OTG_OUT_ENDPOINT_BASE) #define IN_EP_BASE (USB_OTG_INEndpointTypeDef *) (USB_OTG_FS_PERIPH_BASE + USB_OTG_IN_ENDPOINT_BASE) -#define FIFO_BASE(_x) (uint32_t *) (USB_OTG_FS_PERIPH_BASE + USB_OTG_FIFO_BASE + _x * USB_OTG_FIFO_SIZE) +#define FIFO_BASE(_x) (uint32_t *) (USB_OTG_FS_PERIPH_BASE + USB_OTG_FIFO_BASE + (_x) * USB_OTG_FIFO_SIZE) static ATTR_ALIGNED(4) uint32_t _setup_packet[6]; static uint8_t _setup_offs; // We store up to 3 setup packets. @@ -80,20 +80,39 @@ static void bus_reset(void) { dev->DOEPMSK |= USB_OTG_DOEPMSK_STUPM | USB_OTG_DOEPMSK_XFRCM; dev->DIEPMSK |= USB_OTG_DIEPMSK_TOM | USB_OTG_DIEPMSK_XFRCM; + // Peripheral FIFO architecture (Rev18 RM 29.11) + // + // --------------- 312.5 ( 1250 bytes ) + // | IN FIFO 3 | + // --------------- y + x + 16 + GRXFSIZ + // | IN FIFO 2 | + // --------------- x + 16 + GRXFSIZ + // | IN FIFO 1 | + // --------------- 16 + GRXFSIZ + // | IN FIFO 0 | + // --------------- GRXFSIZ + // | OUT FIFO | + // | ( Shared ) | + // --------------- 0 + // // FIFO sizes are set up by the following rules (each word 32-bits): - // OUT FIFO uses (based on page 1354 of Rev 17 of reference manual): + // All EP OUT shared a unique OUT FIFO which uses (based on page 1354 of Rev 17 of reference manual): // * 10 locations in hardware for setup packets + setup control words // (up to 3 setup packets). // * 2 locations for OUT endpoint control words. - // * 64 bytes for maximum control packet size. + // * 16 + 1 (data + info) for largest packet size of 64 bytes. // * 1 location for global NAK (not required/used here). - // IN FIFO uses 64 bytes for maximum control packet size. // // However, for OUT FIFO, 10 + 2 + 16 = 28 doesn't seem to work (TODO: why?). // Minimum that works in practice is 35, so allocate 40 32-bit locations // as a buffer. - USB_OTG_FS->GRXFSIZ = 40; - USB_OTG_FS->DIEPTXF0_HNPTXFSIZ |= (16 << USB_OTG_TX0FD_Pos); // 16 32-bit words = 64 bytes + // + // It is recommended to allocate 2 times the largest packet size, therefore + // Recommended value = 10 + 1 + 2 x (16+1) = 45 --> Let's make it 50 + USB_OTG_FS->GRXFSIZ = 50; + + // Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word ) + USB_OTG_FS->DIEPTXF0_HNPTXFSIZ = (16 << USB_OTG_TX0FD_Pos) | (USB_OTG_FS->GRXFSIZ & 0x0000ffffUL); out_ep[0].DOEPTSIZ |= (1 << USB_OTG_DOEPTSIZ_STUPCNT_Pos); @@ -194,6 +213,15 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num) // Nothing to do } +uint32_t dcd_get_frame_number(uint8_t rhport) +{ + (void) rhport; + + USB_OTG_DeviceTypeDef * dev = DEVICE_BASE; + + return (dev->DSTS & USB_OTG_DSTS_FNSOF_Msk) >> USB_OTG_DSTS_FNSOF_Pos; +} + /*------------------------------------------------------------------*/ /* DCD Endpoint port *------------------------------------------------------------------*/ @@ -222,13 +250,34 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) desc_edpt->wMaxPacketSize.size << USB_OTG_DOEPCTL_MPSIZ_Pos; dev->DAINTMSK |= (1 << (USB_OTG_DAINTMSK_OEPM_Pos + epnum)); } else { + // Peripheral FIFO architecture (Rev18 RM 29.11) + // + // --------------- 312.5 ( 1250 bytes ) + // | IN FIFO 3 | + // --------------- y + x + 16 + GRXFSIZ + // | IN FIFO 2 | + // --------------- x + 16 + GRXFSIZ + // | IN FIFO 1 | + // --------------- 16 + GRXFSIZ + // | IN FIFO 0 | + // --------------- GRXFSIZ + // | OUT FIFO | + // | ( Shared ) | + // --------------- 0 + // + // Since OUT FIFO = 50, FIFO0 = 16, average of FIFOx = (312-50-16) / 3 = 82 ~ 80 + in_ep[epnum].DIEPCTL |= (1 << USB_OTG_DIEPCTL_USBAEP_Pos) | \ (epnum - 1) << USB_OTG_DIEPCTL_TXFNUM_Pos | \ desc_edpt->bmAttributes.xfer << USB_OTG_DIEPCTL_EPTYP_Pos | \ + (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? USB_OTG_DOEPCTL_SD0PID_SEVNFRM : 0) | \ desc_edpt->wMaxPacketSize.size << USB_OTG_DIEPCTL_MPSIZ_Pos; dev->DAINTMSK |= (1 << (USB_OTG_DAINTMSK_IEPM_Pos + epnum)); - USB_OTG_FS->DIEPTXF[epnum - 1] = (40 << USB_OTG_DIEPTXF_INEPTXFD_Pos) | (epnum * 0x100); + // Both TXFD and TXSA are in unit of 32-bit words + uint16_t const fifo_size = 80; + uint32_t const fifo_offset = (USB_OTG_FS->GRXFSIZ & 0x0000ffff) + 16 + fifo_size*(epnum-1); + USB_OTG_FS->DIEPTXF[epnum - 1] = (80 << USB_OTG_DIEPTXF_INEPTXFD_Pos) | fifo_offset; } return true; @@ -587,7 +636,9 @@ static void handle_epout_ints(USB_OTG_DeviceTypeDef * dev, USB_OTG_OUTEndpointTy // on a packet-basis. The core can internally handle multiple OUT // packets; it would be more efficient to only trigger XFRC on a // completed transfer for non-0 endpoints. - if(xfer->short_packet) { + + // Transfer complete if short packet or total len is transferred + if(xfer->short_packet || (xfer->queued_len == xfer->total_len)) { xfer->short_packet = false; dcd_event_xfer_complete(0, n, xfer->queued_len, XFER_RESULT_SUCCESS, true); } else {