summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhathach <[email protected]>2019-09-09 00:53:05 +0700
committerGitHub <[email protected]>2019-09-09 00:53:05 +0700
commit4fe34c8f9b61ad85ce3bcd54466b03666c4578b8 (patch)
treec9d3008e9e728ca0f6589cb6f6c77083f0e78976 /src
parent6b7fe012f6c9e740160c183077f5780b58024268 (diff)
parentf8081536310e5ac7a1e8c8ba9295890429a2cb6f (diff)
Merge pull request #120 from hathach/develop
Ported STM32F412 Discovery board, close #102
Diffstat (limited to 'src')
-rw-r--r--src/portable/st/stm32f4/dcd_stm32f4.c93
1 files changed, 56 insertions, 37 deletions
diff --git a/src/portable/st/stm32f4/dcd_stm32f4.c b/src/portable/st/stm32f4/dcd_stm32f4.c
index 8bcb63068..7a778fb2b 100644
--- a/src/portable/st/stm32f4/dcd_stm32f4.c
+++ b/src/portable/st/stm32f4/dcd_stm32f4.c
@@ -2,6 +2,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2018 Scott Shawcroft, 2019 William D. Jones for Adafruit Industries
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -39,6 +40,11 @@
#define IN_EP_BASE (USB_OTG_INEndpointTypeDef *) (USB_OTG_FS_PERIPH_BASE + USB_OTG_IN_ENDPOINT_BASE)
#define FIFO_BASE(_x) (volatile uint32_t *) (USB_OTG_FS_PERIPH_BASE + USB_OTG_FIFO_BASE + (_x) * USB_OTG_FIFO_SIZE)
+// TODO Merge with OTG_HS
+// Max endpoints for each direction
+#define EP_MAX USB_OTG_FS_MAX_IN_ENDPOINTS
+#define EP_FIFO_SIZE USB_OTG_FS_TOTAL_FIFO_SIZE
+
static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[6];
static uint8_t _setup_offs; // We store up to 3 setup packets.
@@ -52,7 +58,7 @@ typedef struct {
typedef volatile uint32_t * usb_fifo_t;
-xfer_ctl_t xfer_status[4][2];
+xfer_ctl_t xfer_status[EP_MAX][2];
#define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir]
@@ -61,7 +67,7 @@ static void bus_reset(void) {
USB_OTG_DeviceTypeDef * dev = DEVICE_BASE;
USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE;
- for(int n = 0; n < 4; n++) {
+ for(uint8_t n = 0; n < EP_MAX; n++) {
out_ep[n].DOEPCTL |= USB_OTG_DOEPCTL_SNAK;
}
@@ -69,32 +75,35 @@ 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)
+ // "USB Data FIFOs" section in reference manual
+ // Peripheral FIFO architecture
//
- // --------------- 320 ( 1280 bytes )
- // | IN FIFO 3 |
+ // --------------- 320 or 1024 ( 1280 or 4096 bytes )
+ // | IN FIFO MAX |
+ // ---------------
+ // | ... |
// --------------- y + x + 16 + GRXFSIZ
- // | IN FIFO 2 |
+ // | IN FIFO 2 |
// --------------- x + 16 + GRXFSIZ
- // | IN FIFO 1 |
+ // | IN FIFO 1 |
// --------------- 16 + GRXFSIZ
- // | IN FIFO 0 |
+ // | IN FIFO 0 |
// --------------- GRXFSIZ
- // | OUT FIFO |
- // | ( Shared ) |
+ // | OUT FIFO |
+ // | ( Shared ) |
// --------------- 0
//
- // FIFO sizes are set up by the following rules (each word 32-bits):
- // 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.
- // * 16 for largest packet size of 64 bytes. ( TODO Highspeed is 512 bytes)
- // * 1 location for global NAK (not required/used here).
+ // According to "FIFO RAM allocation" section in RM, FIFO RAM are allocated as follows (each word 32-bits):
+ // - Each EP IN needs at least max packet size, 16 words is sufficient for EP0 IN
//
- // It is recommended to allocate 2 times the largest packet size, therefore
- // Recommended value = 10 + 1 + 2 x (16+2) = 47 --> Let's make it 50
- USB_OTG_FS->GRXFSIZ = 50;
+ // - All EP OUT shared a unique OUT FIFO which uses
+ // * 10 locations in hardware for setup packets + setup control words (up to 3 setup packets).
+ // * 2 locations for OUT endpoint control words.
+ // * 16 for largest packet size of 64 bytes. ( TODO Highspeed is 512 bytes)
+ // * 1 location for global NAK (not required/used here).
+ // * It is recommended to allocate 2 times the largest packet size, therefore
+ // Recommended value = 10 + 1 + 2 x (16+2) = 47 --> Let's make it 52
+ USB_OTG_FS->GRXFSIZ = 52;
// 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);
@@ -151,7 +160,7 @@ void dcd_init (uint8_t rhport)
// the core to stop working/require reset.
USB_OTG_FS->GINTMSK |= /* USB_OTG_GINTMSK_OTGINT | */ USB_OTG_GINTMSK_MMISM;
- USB_OTG_DeviceTypeDef * dev = ((USB_OTG_DeviceTypeDef *) (USB_OTG_FS_PERIPH_BASE + USB_OTG_DEVICE_BASE));
+ USB_OTG_DeviceTypeDef * dev = DEVICE_BASE;
// If USB host misbehaves during status portion of control xfer
// (non zero-length packet), send STALL back and discard. Full speed.
@@ -161,12 +170,15 @@ void dcd_init (uint8_t rhport)
USB_OTG_GINTMSK_SOFM | USB_OTG_GINTMSK_RXFLVLM /* SB_OTG_GINTMSK_ESUSPM | \
USB_OTG_GINTMSK_USBSUSPM */;
- // Enable pullup, enable peripheral.
+ // Enable VBus hardware sensing,
#ifdef USB_OTG_GCCFG_VBDEN
USB_OTG_FS->GCCFG |= USB_OTG_GCCFG_VBDEN | USB_OTG_GCCFG_PWRDWN;
#else
USB_OTG_FS->GCCFG |= USB_OTG_GCCFG_VBUSBSEN | USB_OTG_GCCFG_PWRDWN;
#endif
+
+ // Soft Connect -> Enable pullup on D+/D-
+ dev->DCTL &= ~USB_OTG_DCTL_SDIS;
}
void dcd_int_enable (uint8_t rhport)
@@ -220,7 +232,7 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
// Unsupported endpoint numbers/size.
- if((desc_edpt->wMaxPacketSize.size > 64) || (epnum > 3)) {
+ if((desc_edpt->wMaxPacketSize.size > 64) || (epnum > EP_MAX)) {
return false;
}
@@ -233,22 +245,27 @@ 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)
+ // "USB Data FIFOs" section in reference manual
+ // Peripheral FIFO architecture
//
- // --------------- 320 ( 1280 bytes )
- // | IN FIFO 3 |
+ // --------------- 320 or 1024 ( 1280 or 4096 bytes )
+ // | IN FIFO MAX |
+ // ---------------
+ // | ... |
// --------------- y + x + 16 + GRXFSIZ
- // | IN FIFO 2 |
+ // | IN FIFO 2 |
// --------------- x + 16 + GRXFSIZ
- // | IN FIFO 1 |
+ // | IN FIFO 1 |
// --------------- 16 + GRXFSIZ
- // | IN FIFO 0 |
+ // | IN FIFO 0 |
// --------------- GRXFSIZ
- // | OUT FIFO |
- // | ( Shared ) |
+ // | OUT FIFO |
+ // | ( Shared ) |
// --------------- 0
//
- // Since OUT FIFO = 50, FIFO 0 = 16, average of FIFOx = (312-50-16) / 3 = 82 ~ 80
+ // Since OUT FIFO = GRXFSIZ, FIFO 0 = 16, for simplicity, we equally allocated for the rest of endpoints
+ // - Size : (FIFO_SIZE/4 - GRXFSIZ - 16) / (EP_MAX-1)
+ // - Offset: GRXFSIZ + 16 + Size*(epnum-1)
in_ep[epnum].DIEPCTL |= (1 << USB_OTG_DIEPCTL_USBAEP_Pos) | \
(epnum - 1) << USB_OTG_DIEPCTL_TXFNUM_Pos | \
@@ -258,9 +275,10 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
dev->DAINTMSK |= (1 << (USB_OTG_DAINTMSK_IEPM_Pos + epnum));
// 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;
+ uint16_t const allocated_size = (USB_OTG_FS->GRXFSIZ & 0x0000ffff) + 16;
+ uint16_t const fifo_size = (EP_FIFO_SIZE/4 - allocated_size) / (EP_MAX-1);
+ uint32_t const fifo_offset = allocated_size + fifo_size*(epnum-1);
+ USB_OTG_FS->DIEPTXF[epnum - 1] = (fifo_size << USB_OTG_DIEPTXF_INEPTXFD_Pos) | fifo_offset;
}
return true;
@@ -551,8 +569,9 @@ static void read_rx_fifo(USB_OTG_OUTEndpointTypeDef * out_ep) {
static void handle_epout_ints(USB_OTG_DeviceTypeDef * dev, USB_OTG_OUTEndpointTypeDef * out_ep) {
// DAINT for a given EP clears when DOEPINTx is cleared.
// OEPINT will be cleared when DAINT's out bits are cleared.
- for(int n = 0; n < 4; n++) {
+ for(uint8_t n = 0; n < EP_MAX; n++) {
xfer_ctl_t * xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT);
+
if(dev->DAINT & (1 << (USB_OTG_DAINT_OEPINT_Pos + n))) {
// SETUP packet Setup Phase done.
if(out_ep[n].DOEPINT & USB_OTG_DOEPINT_STUP) {
@@ -588,7 +607,7 @@ static void handle_epout_ints(USB_OTG_DeviceTypeDef * dev, USB_OTG_OUTEndpointTy
static void handle_epin_ints(USB_OTG_DeviceTypeDef * dev, USB_OTG_INEndpointTypeDef * in_ep) {
// DAINT for a given EP clears when DIEPINTx is cleared.
// IEPINT will be cleared when DAINT's out bits are cleared.
- for(uint8_t n = 0; n < 4; n++) {
+ for(uint8_t n = 0; n < EP_MAX; n++) {
xfer_ctl_t * xfer = XFER_CTL_BASE(n, TUSB_DIR_IN);
if(dev->DAINT & (1 << (USB_OTG_DAINT_IEPINT_Pos + n))) {