summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorcopilot-swe-agent[bot] <[email protected]>2026-04-09 10:35:01 +0000
committerGitHub <[email protected]>2026-04-09 10:35:01 +0000
commitd32a6521256594b41e4c54d0dbf50470573ba995 (patch)
tree1471d74b7bbdf485e27321692f40f6d6c8ee1165 /src
parent7c3f5979ff9be05b7938f10dbaa6e55daaf8bdc1 (diff)
Refactor STM32 FSDEV PMA errata delay into common helper
Agent-Logs-Url: https://github.com/hathach/tinyusb/sessions/3ec0d5b6-cb8e-48ff-8606-3371beb1efcb Co-authored-by: HiFiPhile <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c20
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_common.c17
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_common.h23
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_stm32.h14
-rw-r--r--src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c45
5 files changed, 57 insertions, 62 deletions
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
index 8b4719b21..c8bb0e827 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
@@ -394,25 +394,7 @@ void dcd_int_handler(uint8_t rhport) {
if (ep_reg & U_EP_CTR_RX) {
#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
- * Description:
- * - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM
- * accesses have completed. If the software responds quickly to the interrupt, the full buffer contents may not be
- * correct. Workaround:
- * - Software should ensure that a small delay is included before accessing the SRAM contents. This delay
- * should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode
- * - Since H5 can run up to 250Mhz -> 1 cycle = 4ns. Per errata, we need to wait 200 cycles. Though executing code
- * also takes time, so we'll wait 60 cycles (count = 20).
- * - Since Low Speed mode is not supported/popular, we will ignore it for now.
- *
- * Note: this errata may also apply to G0, U5, H5 etc.
- */
- volatile uint32_t cycle_count = 20; // defined as PCD_RX_PMA_CNT in stm32 hal_driver
- while (cycle_count > 0U) {
- cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare)
- }
+ fsdev_btable_workaround_delay(false);
#endif
if (ep_reg & U_EP_SETUP) {
diff --git a/src/portable/st/stm32_fsdev/fsdev_common.c b/src/portable/st/stm32_fsdev/fsdev_common.c
index 003bcd069..3f3973a9d 100644
--- a/src/portable/st/stm32_fsdev/fsdev_common.c
+++ b/src/portable/st/stm32_fsdev/fsdev_common.c
@@ -113,4 +113,21 @@ void btable_set_rx_bufsize(uint32_t ep_id, uint8_t buf_id, uint16_t wCount) {
#endif
}
+/* STM32 FSDEV PMA Buffer Description Table errata workaround:
+ * - ES0561 (STM32H503), ES0587 (STM32U535/U545)
+ * - CTR may trigger before final PMA SRAM accesses complete on OUT transfers.
+ * - Insert delay before reading PMA count/data.
+ */
+void fsdev_btable_workaround_delay(bool low_speed) {
+#if defined(TUP_USBIP_FSDEV_STM32) && defined(CFG_TUSB_FSDEV_32BIT)
+ uint32_t cycle_count = low_speed ? CFG_TUSB_FSDEV_BTABLE_LS_DELAY_COUNT : CFG_TUSB_FSDEV_BTABLE_FS_DELAY_COUNT;
+ volatile uint32_t delay_count = cycle_count;
+ while (delay_count > 0U) {
+ delay_count--; // each count take 3 cycles (1 for sub, jump, and compare)
+ }
+#else
+ (void) low_speed;
+#endif
+}
+
#endif
diff --git a/src/portable/st/stm32_fsdev/fsdev_common.h b/src/portable/st/stm32_fsdev/fsdev_common.h
index 140ff1d61..bf4941794 100644
--- a/src/portable/st/stm32_fsdev/fsdev_common.h
+++ b/src/portable/st/stm32_fsdev/fsdev_common.h
@@ -307,6 +307,26 @@ typedef struct {
#error "Unknown USB IP"
#endif
+#if defined(TUP_USBIP_FSDEV_STM32) && defined(CFG_TUSB_FSDEV_32BIT)
+ #ifndef CFG_TUSB_FSDEV_BTABLE_FS_DELAY_COUNT
+ #if defined(FSDEV_STM32_CPU_MHZ)
+ #define CFG_TUSB_FSDEV_BTABLE_FS_DELAY_COUNT (FSDEV_STM32_CPU_MHZ / 4U)
+ #else
+ // Keep conservative default and allow board/application override.
+ #define CFG_TUSB_FSDEV_BTABLE_FS_DELAY_COUNT 20U
+ #endif
+ #endif
+
+ #ifndef CFG_TUSB_FSDEV_BTABLE_LS_DELAY_COUNT
+ #if defined(FSDEV_STM32_CPU_MHZ)
+ #define CFG_TUSB_FSDEV_BTABLE_LS_DELAY_COUNT (FSDEV_STM32_CPU_MHZ * 2U)
+ #else
+ // Keep conservative default and allow board/application override.
+ #define CFG_TUSB_FSDEV_BTABLE_LS_DELAY_COUNT 20U
+ #endif
+ #endif
+#endif
+
//--------------------------------------------------------------------+
// Endpoint Helper
// - CTR is write 0 to clear
@@ -449,6 +469,9 @@ uint16_t pma_align_buffer_size(uint16_t size, uint8_t *blsize, uint8_t *num_bloc
// Set RX buffer size
void btable_set_rx_bufsize(uint32_t ep_id, uint8_t buf_id, uint16_t wCount);
+// STM32 FSDEV PMA Buffer Description Table errata workaround delay.
+void fsdev_btable_workaround_delay(bool low_speed);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/portable/st/stm32_fsdev/fsdev_stm32.h b/src/portable/st/stm32_fsdev/fsdev_stm32.h
index a63592c5d..3f726c2ec 100644
--- a/src/portable/st/stm32_fsdev/fsdev_stm32.h
+++ b/src/portable/st/stm32_fsdev/fsdev_stm32.h
@@ -138,6 +138,20 @@
#error "FSDEV_HAS_SBUF_ISO not defined"
#endif
+#ifndef FSDEV_STM32_CPU_MHZ
+ #if CFG_TUSB_MCU == OPT_MCU_STM32H5
+ #define FSDEV_STM32_CPU_MHZ 250U
+ #elif CFG_TUSB_MCU == OPT_MCU_STM32U5
+ #define FSDEV_STM32_CPU_MHZ 160U
+ #elif CFG_TUSB_MCU == OPT_MCU_STM32U3
+ #define FSDEV_STM32_CPU_MHZ 96U
+ #elif CFG_TUSB_MCU == OPT_MCU_STM32G0
+ #define FSDEV_STM32_CPU_MHZ 64U
+ #elif CFG_TUSB_MCU == OPT_MCU_STM32C0
+ #define FSDEV_STM32_CPU_MHZ 48U
+ #endif
+#endif
+
#ifndef CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP
// Default configuration for double-buffered isochronous endpoints:
// - Enable double buffering on devices with >1KB Packet Memory Area (PMA)
diff --git a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c
index 18685dbdc..c41228919 100644
--- a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c
+++ b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c
@@ -58,20 +58,6 @@
TU_VERIFY_STATIC(CFG_TUH_FSDEV_ENDPOINT_MAX <= 255, "currently only use 8-bit for index");
-#if CFG_TUSB_MCU == OPT_MCU_STM32H5
- #define CPU_FREQUENCY_MHZ 250U
-#elif CFG_TUSB_MCU == OPT_MCU_STM32U5
- #define CPU_FREQUENCY_MHZ 160U
-#elif CFG_TUSB_MCU == OPT_MCU_STM32U3
- #define CPU_FREQUENCY_MHZ 96U
-#elif CFG_TUSB_MCU == OPT_MCU_STM32G0
- #define CPU_FREQUENCY_MHZ 64U
-#elif CFG_TUSB_MCU == OPT_MCU_STM32C0
- #define CPU_FREQUENCY_MHZ 48U
-#else
- #error "CPU_FREQUENCY_MHZ not defined for this STM32 MCU"
-#endif
-
enum {
HCD_XFER_ERROR_MAX = 3,
HCD_XFER_NAK_MAX = 15,
@@ -165,35 +151,8 @@ static inline void channel_write_status(uint8_t ch_id, uint32_t ch_reg, tusb_dir
}
static inline uint16_t channel_get_rx_count(uint8_t ch_id) {
- /* 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
- * Description:
- * - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses
- * have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct.
- * Workaround:
- * - Software should ensure that a small delay is included before accessing the SRAM contents. This delay
- * should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode
- *
- * Note: this errata may also apply to G0, U5, H5 etc.
- *
- * We choose the delay count based on max CPU frequency (in MHz) to ensure the delay is at least the required time.
- */
-
uint32_t ch_reg = ch_read(ch_id);
- if (FSDEV_REG->ISTR & U_ISTR_LS_DCONN || ch_reg & U_EP_LSEP) {
- // Low speed mode: 6.4 us delay -> about 2 cycles per MHz
- volatile uint32_t cycle_count = CPU_FREQUENCY_MHZ * 2U;
- while (cycle_count > 0U) {
- cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare)
- }
- } else {
- // Full speed mode: 800 ns delay -> about 0.25 cycles per MHz
- volatile uint32_t cycle_count = CPU_FREQUENCY_MHZ / 4U;
- while (cycle_count > 0U) {
- cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare)
- }
- }
+ fsdev_btable_workaround_delay((FSDEV_REG->ISTR & U_ISTR_LS_DCONN) || (ch_reg & U_EP_LSEP));
return btable_get_count(ch_id, BTABLE_BUF_RX);
}
@@ -238,7 +197,7 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
// If DCON_STAT is already set, the controller sometimes misses the initial connection interrupt
if (FSDEV_REG->ISTR & U_ISTR_DCON_STAT) {
// Wait DP/DM stabilize time
- volatile uint32_t cycle_count = CPU_FREQUENCY_MHZ / 4U;
+ volatile uint32_t cycle_count = CFG_TUSB_FSDEV_BTABLE_FS_DELAY_COUNT;
while (cycle_count > 0U) {
cycle_count--;
}