diff options
| author | copilot-swe-agent[bot] <[email protected]> | 2026-04-09 10:35:01 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-04-09 10:35:01 +0000 |
| commit | d32a6521256594b41e4c54d0dbf50470573ba995 (patch) | |
| tree | 1471d74b7bbdf485e27321692f40f6d6c8ee1165 /src | |
| parent | 7c3f5979ff9be05b7938f10dbaa6e55daaf8bdc1 (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.c | 20 | ||||
| -rw-r--r-- | src/portable/st/stm32_fsdev/fsdev_common.c | 17 | ||||
| -rw-r--r-- | src/portable/st/stm32_fsdev/fsdev_common.h | 23 | ||||
| -rw-r--r-- | src/portable/st/stm32_fsdev/fsdev_stm32.h | 14 | ||||
| -rw-r--r-- | src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c | 45 |
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--; } |
