summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhathach <[email protected]>2026-03-16 22:33:25 +0700
committerhathach <[email protected]>2026-03-16 22:33:25 +0700
commit741132948b10d2410692b46b227da194fefb7238 (patch)
treea81a86eaa97d9c37bc675a7a80020bf97da85e9e /src
parent8e8bb9a66fb4c822489f76bac434cdf10a45db93 (diff)
Unify USB FSDEV driver implementation for various microcontrollers. Replace `FSDEV_BUS_32BIT` with `CFG_TUSB_FSDEV_32BIT`, adjust data/address stride macros, and refactor register/PMU access for consistency across platforms.
Diffstat (limited to 'src')
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c4
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_common.c2
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_common.h180
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_stm32.h16
-rw-r--r--src/tusb_option.h4
5 files changed, 87 insertions, 119 deletions
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
index 965ebbbe5..c06911177 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
@@ -177,7 +177,7 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) {
FSDEV_REG->CNTR = 0; // Enable USB
- #if !defined(FSDEV_BUS_32BIT)
+ #if !defined( CFG_TUSB_FSDEV_32BIT)
// BTABLE register does not exist any more on 32-bit bus devices
FSDEV_REG->BTABLE = FSDEV_BTABLE_BASE;
#endif
@@ -407,7 +407,7 @@ void dcd_int_handler(uint8_t rhport) {
const uint32_t ep_reg = ep_read(ep_id);
if (ep_reg & U_EP_CTR_RX) {
- #ifdef FSDEV_BUS_32BIT
+ #ifdef CFG_TUSB_FSDEV_32BIT
/* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf
* https://www.st.com/resource/en/errata_sheet/es0587-stm32u535xx-and-stm32u545xx-device-errata-stmicroelectronics.pdf
* From H503/U535 errata: Buffer description table update completes after CTR interrupt triggers
diff --git a/src/portable/st/stm32_fsdev/fsdev_common.c b/src/portable/st/stm32_fsdev/fsdev_common.c
index f63b6755a..003bcd069 100644
--- a/src/portable/st/stm32_fsdev/fsdev_common.c
+++ b/src/portable/st/stm32_fsdev/fsdev_common.c
@@ -104,7 +104,7 @@ void btable_set_rx_bufsize(uint32_t ep_id, uint8_t buf_id, uint16_t wCount) {
bl_nb = 1 << 15;
}
-#ifdef FSDEV_BUS_32BIT
+#ifdef CFG_TUSB_FSDEV_32BIT
uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
count_addr = (bl_nb << 16) | (count_addr & 0x0000FFFFu);
FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr;
diff --git a/src/portable/st/stm32_fsdev/fsdev_common.h b/src/portable/st/stm32_fsdev/fsdev_common.h
index 36df4809d..140ff1d61 100644
--- a/src/portable/st/stm32_fsdev/fsdev_common.h
+++ b/src/portable/st/stm32_fsdev/fsdev_common.h
@@ -29,6 +29,10 @@
#ifndef TUSB_FSDEV_COMMON_H
#define TUSB_FSDEV_COMMON_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include "common/tusb_common.h"
#if CFG_TUD_ENABLED
@@ -88,7 +92,7 @@
#define U_EPREG_MASK_32 (U_EP_ERRRX | U_EP_ERRTX | U_EP_LSEP | U_EP_NAK | U_EP_DEVADDR | U_EPREG_MASK_16)
// EP register mask selection based on bus width
-#ifdef FSDEV_BUS_32BIT
+#ifdef CFG_TUSB_FSDEV_32BIT
#define U_EPREG_MASK U_EPREG_MASK_32
#else
#define U_EPREG_MASK U_EPREG_MASK_16
@@ -203,89 +207,74 @@
#define U_CH_RX_VALID 0x3000u
//--------------------------------------------------------------------+
-// Vendor-specific includes (after U_ definitions so they can use them)
+// Registers Typedef
//--------------------------------------------------------------------+
-#if defined(TUP_USBIP_FSDEV_STM32)
- #include "fsdev_stm32.h"
-#elif defined(TUP_USBIP_FSDEV_CH32)
- #include "fsdev_ch32.h"
-#elif defined(TUP_USBIP_FSDEV_AT32)
- #include "fsdev_at32.h"
-#else
- #error "Unknown USB IP"
-#endif
+// hardware limit endpoint
+#define FSDEV_EP_COUNT 8
-// LPM support - detect from vendor header (L1REQ bit position varies)
-#if defined(USB_ISTR_L1REQ)
- #define U_ISTR_L1REQ USB_ISTR_L1REQ
+// The fsdev_bus_t type can be used for both register and PMA access necessities
+#ifdef CFG_TUSB_FSDEV_32BIT
+typedef uint32_t fsdev_bus_t;
#else
- #define U_ISTR_L1REQ 0x0000u
+typedef uint16_t fsdev_bus_t;
#endif
-#define U_ISTR_ALL_EVENTS (U_ISTR_PMAOVR | U_ISTR_ERR | U_ISTR_WKUP | U_ISTR_SUSP | \
- U_ISTR_RESET | U_ISTR_SOF | U_ISTR_ESOF | U_ISTR_L1REQ)
+// volatile 32-bit aligned
+#define _va32 volatile TU_ATTR_ALIGNED(4)
-#ifdef __cplusplus
-extern "C" {
-#endif
+typedef struct {
+ struct {
+ _va32 fsdev_bus_t reg;
+ } ep[FSDEV_EP_COUNT];
+
+ _va32 uint32_t RESERVED7[8]; // Reserved
+ _va32 fsdev_bus_t CNTR; // 40: Control register
+ _va32 fsdev_bus_t ISTR; // 44: Interrupt status register
+ _va32 fsdev_bus_t FNR; // 48: Frame number register
+ _va32 fsdev_bus_t DADDR; // 4C: Device address register
+ _va32 fsdev_bus_t BTABLE; // 50: Buffer Table address register
+ _va32 fsdev_bus_t LPMCSR; // 54: LPM Control and Status (not on F1, F3, AT32, CH32)
+ _va32 fsdev_bus_t BCDR; // 58: Battery Charging Detector (not on F1, F3, AT32, CH32)
+} fsdev_regs_t;
+
+TU_VERIFY_STATIC(offsetof(fsdev_regs_t, CNTR) == 0x40, "Wrong offset");
+TU_VERIFY_STATIC(sizeof(fsdev_regs_t) == 0x5C, "Size is not correct");
+
+#define FSDEV_REG ((fsdev_regs_t *)FSDEV_REG_BASE)
+
+//--------------------------------------------------------------------+
+// BTable and PMA Access
+//--------------------------------------------------------------------+
// If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it
// Both of these MUST be a multiple of 2, and are in byte units.
#ifndef FSDEV_BTABLE_BASE
#define FSDEV_BTABLE_BASE 0U
#endif
+TU_VERIFY_STATIC((FSDEV_BTABLE_BASE & 0x7) == 0, "BTABLE base must be aligned to 8 bytes");
-TU_VERIFY_STATIC(FSDEV_BTABLE_BASE % 8 == 0, "BTABLE base must be aligned to 8 bytes");
-
-// CFG_TUSB_FSDEV_PMA_SIZE is PMA buffer size in bytes.
-// - 512-byte devices, access with a stride of two words (use every other 16-bit address)
-// - 1024-byte devices, access with a stride of one word (use every 16-bit address) or 32-bit address
-// - 2048-byte devices, access with 32-bit address
-#if CFG_TUSB_FSDEV_PMA_SIZE == 2048 || TU_CHECK_MCU(OPT_MCU_STM32U0)
- // 32 bit access scheme
- #define FSDEV_BUS_32BIT
- #define FSDEV_PMA_STRIDE 1
- #define pma_access_scheme
-#elif CFG_TUSB_FSDEV_PMA_SIZE == 1024
- // 2x16 bit / word access scheme
- #define FSDEV_PMA_STRIDE 1
- #define pma_access_scheme
-#elif CFG_TUSB_FSDEV_PMA_SIZE == 512
- // 1x16 bit / word access scheme
- #define FSDEV_PMA_STRIDE 2
- #define pma_access_scheme TU_ATTR_ALIGNED(4)
-#endif
+#define FSDEV_ADDR_DATA_RATIO (CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE/CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE)
-// The fsdev_bus_t type can be used for both register and PMA access necessities
-#ifdef FSDEV_BUS_32BIT
-typedef uint32_t fsdev_bus_t;
+// Need alignment when access address is 32 bit but data is only 16-bit
+#if FSDEV_ADDR_DATA_RATIO == 2
+ #define fsdev_addr_data_align TU_ATTR_ALIGNED(4)
#else
-typedef uint16_t fsdev_bus_t;
+ #define fsdev_addr_data_align
#endif
enum {
- FSDEV_BUS_SIZE = sizeof(fsdev_bus_t),
-};
-
-//--------------------------------------------------------------------+
-// BTable Typedef
-//--------------------------------------------------------------------+
-enum {
BTABLE_BUF_TX = 0,
BTABLE_BUF_RX = 1
};
-// hardware limit endpoint
-#define FSDEV_EP_COUNT 8
-
// Buffer Table is located in Packet Memory Area (PMA) and therefore its address access is forced to either
-// 16-bit or 32-bit depending on FSDEV_BUS_32BIT.
+// 16-bit or 32-bit depending on CFG_TUSB_FSDEV_32BIT.
// 0: TX (IN), 1: RX (OUT)
typedef union {
// data is strictly 16-bit access (address could be 32-bit aligned)
struct {
- volatile pma_access_scheme uint16_t addr;
- volatile pma_access_scheme uint16_t count;
+ volatile fsdev_addr_data_align uint16_t addr;
+ volatile fsdev_addr_data_align uint16_t count;
} ep16[FSDEV_EP_COUNT][2];
// strictly 32-bit access
@@ -294,45 +283,35 @@ typedef union {
} ep32[FSDEV_EP_COUNT][2];
} fsdev_btable_t;
-TU_VERIFY_STATIC(sizeof(fsdev_btable_t) == FSDEV_EP_COUNT * 8 * FSDEV_PMA_STRIDE, "size is not correct");
+TU_VERIFY_STATIC(sizeof(fsdev_btable_t) == FSDEV_EP_COUNT * 8 * FSDEV_ADDR_DATA_RATIO, "size is not correct");
TU_VERIFY_STATIC(FSDEV_BTABLE_BASE + FSDEV_EP_COUNT * 8 <= CFG_TUSB_FSDEV_PMA_SIZE, "BTABLE does not fit in PMA RAM");
-#define FSDEV_BTABLE ((volatile fsdev_btable_t *)(FSDEV_PMA_BASE + FSDEV_PMA_STRIDE * (FSDEV_BTABLE_BASE)))
+#define FSDEV_BTABLE ((volatile fsdev_btable_t *)(FSDEV_PMA_BASE + FSDEV_ADDR_DATA_RATIO * FSDEV_BTABLE_BASE))
typedef struct {
- volatile pma_access_scheme fsdev_bus_t value;
+ volatile fsdev_addr_data_align fsdev_bus_t value;
} fsdev_pma_buf_t;
-#define PMA_BUF_AT(_addr) ((fsdev_pma_buf_t *)(FSDEV_PMA_BASE + FSDEV_PMA_STRIDE * (_addr)))
+#define PMA_BUF_AT(_addr) ((fsdev_pma_buf_t *)(FSDEV_PMA_BASE + FSDEV_ADDR_DATA_RATIO * (_addr)))
//--------------------------------------------------------------------+
-// Registers Typedef
+// Vendor-specific includes
//--------------------------------------------------------------------+
+#if defined(TUP_USBIP_FSDEV_STM32)
+ #include "fsdev_stm32.h"
+#elif defined(TUP_USBIP_FSDEV_CH32)
+ #include "fsdev_ch32.h"
+#elif defined(TUP_USBIP_FSDEV_AT32)
+ #include "fsdev_at32.h"
+#else
+ #error "Unknown USB IP"
+#endif
-// volatile 32-bit aligned
-#define _va32 volatile TU_ATTR_ALIGNED(4)
-
-typedef struct {
- struct {
- _va32 fsdev_bus_t reg;
- } ep[FSDEV_EP_COUNT];
-
- _va32 uint32_t RESERVED7[8]; // Reserved
- _va32 fsdev_bus_t CNTR; // 40: Control register
- _va32 fsdev_bus_t ISTR; // 44: Interrupt status register
- _va32 fsdev_bus_t FNR; // 48: Frame number register
- _va32 fsdev_bus_t DADDR; // 4C: Device address register
- _va32 fsdev_bus_t BTABLE; // 50: Buffer Table address register
- _va32 fsdev_bus_t LPMCSR; // 54: LPM Control and Status (not on F1, F3, AT32, CH32)
- _va32 fsdev_bus_t BCDR; // 58: Battery Charging Detector (not on F1, F3, AT32, CH32)
-} fsdev_regs_t;
-
-TU_VERIFY_STATIC(offsetof(fsdev_regs_t, CNTR) == 0x40, "Wrong offset");
-TU_VERIFY_STATIC(sizeof(fsdev_regs_t) == 0x5C, "Size is not correct");
-
-#define FSDEV_REG ((fsdev_regs_t *)FSDEV_REG_BASE)
-
-
+//--------------------------------------------------------------------+
+// Endpoint Helper
+// - CTR is write 0 to clear
+// - DTOG and STAT are write 1 to toggle
+//--------------------------------------------------------------------+
typedef enum {
EP_STAT_DISABLED = 0,
EP_STAT_STALL = 1,
@@ -346,12 +325,6 @@ typedef enum {
#define CH_STAT_MASK(_dir) (3u << (U_EPTX_STAT_Pos + ((_dir) == TUSB_DIR_IN ? 8 : 0)))
#define CH_DTOG_MASK(_dir) (1u << (U_EP_DTOG_TX_Pos + ((_dir) == TUSB_DIR_IN ? 8 : 0)))
-//--------------------------------------------------------------------+
-// Endpoint Helper
-// - CTR is write 0 to clear
-// - DTOG and STAT are write 1 to toggle
-//--------------------------------------------------------------------+
-
TU_ATTR_ALWAYS_INLINE static inline uint32_t ep_read(uint32_t ep_id) {
return FSDEV_REG->ep[ep_id].reg;
}
@@ -422,7 +395,7 @@ TU_ATTR_ALWAYS_INLINE static inline void ch_change_dtog(uint32_t *reg, tusb_dir_
//--------------------------------------------------------------------+
TU_ATTR_ALWAYS_INLINE static inline uint32_t btable_get_addr(uint32_t ep_id, uint8_t buf_id) {
-#ifdef FSDEV_BUS_32BIT
+#ifdef CFG_TUSB_FSDEV_32BIT
return FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr & 0x0000FFFFu;
#else
return FSDEV_BTABLE->ep16[ep_id][buf_id].addr;
@@ -430,9 +403,10 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t btable_get_addr(uint32_t ep_id, uin
}
TU_ATTR_ALWAYS_INLINE static inline void btable_set_addr(uint32_t ep_id, uint8_t buf_id, uint16_t addr) {
-#ifdef FSDEV_BUS_32BIT
- uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
- count_addr = (count_addr & 0xFFFF0000u) | (addr & 0x0000FFFCu);
+#ifdef CFG_TUSB_FSDEV_32BIT
+ uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
+ count_addr = (count_addr & 0xFFFF0000u) | (addr & 0x0000FFFCu);
+
FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr;
#else
FSDEV_BTABLE->ep16[ep_id][buf_id].addr = addr;
@@ -441,7 +415,7 @@ TU_ATTR_ALWAYS_INLINE static inline void btable_set_addr(uint32_t ep_id, uint8_t
TU_ATTR_ALWAYS_INLINE static inline uint16_t btable_get_count(uint32_t ep_id, uint8_t buf_id) {
uint16_t count;
-#ifdef FSDEV_BUS_32BIT
+#ifdef CFG_TUSB_FSDEV_32BIT
count = (FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr >> 16);
#else
count = FSDEV_BTABLE->ep16[ep_id][buf_id].count;
@@ -450,13 +424,15 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t btable_get_count(uint32_t ep_id, ui
}
TU_ATTR_ALWAYS_INLINE static inline void btable_set_count(uint32_t ep_id, uint8_t buf_id, uint16_t byte_count) {
-#ifdef FSDEV_BUS_32BIT
- uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
- count_addr = (count_addr & ~0x03FF0000u) | ((byte_count & 0x3FFu) << 16);
+#ifdef CFG_TUSB_FSDEV_32BIT
+ uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
+ count_addr = (count_addr & ~0x03FF0000u) | ((byte_count & 0x3FFu) << 16);
+
FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr;
#else
- uint16_t cnt = FSDEV_BTABLE->ep16[ep_id][buf_id].count;
- cnt = (cnt & ~0x3FFU) | (byte_count & 0x3FFU);
+ uint16_t cnt = FSDEV_BTABLE->ep16[ep_id][buf_id].count;
+ cnt = (cnt & ~0x3FFU) | (byte_count & 0x3FFU);
+
FSDEV_BTABLE->ep16[ep_id][buf_id].count = cnt;
#endif
}
diff --git a/src/portable/st/stm32_fsdev/fsdev_stm32.h b/src/portable/st/stm32_fsdev/fsdev_stm32.h
index a1c5c9488..3bb137734 100644
--- a/src/portable/st/stm32_fsdev/fsdev_stm32.h
+++ b/src/portable/st/stm32_fsdev/fsdev_stm32.h
@@ -101,12 +101,10 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32U0
#include "stm32u0xx.h"
- #define FSDEV_BUS_32BIT
#define FSDEV_HAS_SBUF_ISO 1
#elif CFG_TUSB_MCU == OPT_MCU_STM32U3
#include "stm32u3xx.h"
- #define FSDEV_BUS_32BIT
#define FSDEV_HAS_SBUF_ISO 1 // This is assumed to work but has not been tested...
#elif CFG_TUSB_MCU == OPT_MCU_STM32U5
@@ -124,16 +122,6 @@
#endif
//--------------------------------------------------------------------+
-// USB DRD compatibility aliases
-// These MCUs use a newer USB_DRD peripheral that needs the USB macro
-// mapped to USB_DRD_FS for connect/disconnect register access.
-//--------------------------------------------------------------------+
-#if TU_CHECK_MCU(OPT_MCU_STM32C0, OPT_MCU_STM32G0, OPT_MCU_STM32H5, \
- OPT_MCU_STM32U0, OPT_MCU_STM32U3, OPT_MCU_STM32U5)
- #define USB USB_DRD_FS
-#endif
-
-//--------------------------------------------------------------------+
// Register and PMA Base Address
//--------------------------------------------------------------------+
#ifndef FSDEV_REG_BASE
@@ -292,12 +280,12 @@ TU_ATTR_ALWAYS_INLINE static inline void fsdev_int_disable(uint8_t rhport) {
TU_ATTR_ALWAYS_INLINE static inline void fsdev_disconnect(uint8_t rhport) {
(void)rhport;
- USB->BCDR &= ~U_BCDR_DPPU;
+ FSDEV_REG->BCDR &= ~U_BCDR_DPPU;
}
TU_ATTR_ALWAYS_INLINE static inline void fsdev_connect(uint8_t rhport) {
(void)rhport;
- USB->BCDR |= U_BCDR_DPPU;
+ FSDEV_REG->BCDR |= U_BCDR_DPPU;
}
#elif defined(SYSCFG_PMC_USB_PU) // works e.g. on STM32L151
diff --git a/src/tusb_option.h b/src/tusb_option.h
index 3814a4d71..9eb8ee533 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -340,12 +340,16 @@
#define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
#if CFG_TUSB_FSDEV_PMA_SIZE == 2048 || TU_CHECK_MCU(OPT_MCU_STM32U0)
+ // 32-bit access scheme
#define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 4 // 32-bit data
#define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 4 // 32-bit address increase
+ #define CFG_TUSB_FSDEV_32BIT
#elif CFG_TUSB_FSDEV_PMA_SIZE == 1024
+ // 2 x 16-bit access scheme
#define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 2 // 16-bit data
#define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 2 // 16-bit address increase
#elif CFG_TUSB_FSDEV_PMA_SIZE == 512
+ // 1 x 16-bit access scheme
#define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 2 // 16-bit data
#define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 4 // 32-bit address increase
#endif