summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZixun LI <[email protected]>2026-05-30 13:03:32 +0200
committerGitHub <[email protected]>2026-05-30 13:03:32 +0200
commitd3ae3a02a9a01b2f2a1ed16a463074e044178945 (patch)
tree6bd843b73dd4ad8174bd546d5646665f195293d5
parent6f59b79a6cad1ade33f482e4db5246d65642699b (diff)
parent08381d44214135cc9ff9423de837cb466b6ad701 (diff)
Merge pull request #3634 from HKM-Messtechnik/fix/Dwc2Stm32U5
dwc2: preserve EP0 status completion before SETUP
-rw-r--r--examples/device/audio_4_channel_mic_freertos/CMakeLists.txt5
-rw-r--r--examples/device/audio_test_freertos/CMakeLists.txt5
-rw-r--r--examples/device/board_test/CMakeLists.txt5
-rw-r--r--examples/device/cdc_msc_freertos/CMakeLists.txt5
-rw-r--r--examples/device/hid_composite_freertos/CMakeLists.txt5
-rw-r--r--hw/bsp/stm32f4/family.c5
-rw-r--r--hw/bsp/stm32f7/boards/stm32f746disco/board.cmake2
-rw-r--r--src/portable/synopsys/dwc2/dcd_dwc2.c101
8 files changed, 79 insertions, 54 deletions
diff --git a/examples/device/audio_4_channel_mic_freertos/CMakeLists.txt b/examples/device/audio_4_channel_mic_freertos/CMakeLists.txt
index d43a72e58..66ef19fbc 100644
--- a/examples/device/audio_4_channel_mic_freertos/CMakeLists.txt
+++ b/examples/device/audio_4_channel_mic_freertos/CMakeLists.txt
@@ -2,6 +2,11 @@ cmake_minimum_required(VERSION 3.20)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
+# Need to set Espressif defaults before project() is called
+if(FAMILY STREQUAL "espressif")
+ list(APPEND SDKCONFIG_DEFAULTS "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults")
+endif()
+
project(audio_4_channel_mic_freertos C CXX ASM)
# Checks this example is valid for the family and initializes the project
diff --git a/examples/device/audio_test_freertos/CMakeLists.txt b/examples/device/audio_test_freertos/CMakeLists.txt
index 71d65eccc..a39e56822 100644
--- a/examples/device/audio_test_freertos/CMakeLists.txt
+++ b/examples/device/audio_test_freertos/CMakeLists.txt
@@ -2,6 +2,11 @@ cmake_minimum_required(VERSION 3.20)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
+# Need to set Espressif defaults before project() is called
+if(FAMILY STREQUAL "espressif")
+ list(APPEND SDKCONFIG_DEFAULTS "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults")
+endif()
+
project(audio_test_freertos C CXX ASM)
# Checks this example is valid for the family and initializes the project
diff --git a/examples/device/board_test/CMakeLists.txt b/examples/device/board_test/CMakeLists.txt
index bd7b8e0ca..f14d72c08 100644
--- a/examples/device/board_test/CMakeLists.txt
+++ b/examples/device/board_test/CMakeLists.txt
@@ -2,6 +2,11 @@ cmake_minimum_required(VERSION 3.20)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
+# Need to set Espressif defaults before project() is called
+if(FAMILY STREQUAL "espressif")
+ list(APPEND SDKCONFIG_DEFAULTS "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults")
+endif()
+
project(board_test C CXX ASM)
# Checks this example is valid for the family and initializes the project
diff --git a/examples/device/cdc_msc_freertos/CMakeLists.txt b/examples/device/cdc_msc_freertos/CMakeLists.txt
index 429000427..1eafd529a 100644
--- a/examples/device/cdc_msc_freertos/CMakeLists.txt
+++ b/examples/device/cdc_msc_freertos/CMakeLists.txt
@@ -2,6 +2,11 @@ cmake_minimum_required(VERSION 3.20)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
+# Need to set Espressif defaults before project() is called
+if(FAMILY STREQUAL "espressif")
+ list(APPEND SDKCONFIG_DEFAULTS "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults")
+endif()
+
project(cdc_msc_freertos C CXX ASM)
# Checks this example is valid for the family and initializes the project
diff --git a/examples/device/hid_composite_freertos/CMakeLists.txt b/examples/device/hid_composite_freertos/CMakeLists.txt
index b52373011..2081a7782 100644
--- a/examples/device/hid_composite_freertos/CMakeLists.txt
+++ b/examples/device/hid_composite_freertos/CMakeLists.txt
@@ -2,6 +2,11 @@ cmake_minimum_required(VERSION 3.20)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
+# Need to set Espressif defaults before project() is called
+if(FAMILY STREQUAL "espressif")
+ list(APPEND SDKCONFIG_DEFAULTS "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults")
+endif()
+
project(hid_composite_freertos C CXX ASM)
# Checks this example is valid for the family and initializes the project
diff --git a/hw/bsp/stm32f4/family.c b/hw/bsp/stm32f4/family.c
index 4eea5c7a8..3a323e673 100644
--- a/hw/bsp/stm32f4/family.c
+++ b/hw/bsp/stm32f4/family.c
@@ -109,6 +109,11 @@ void USARTn_IRQHandler(void) {
void board_init(void) {
board_clock_init();
+
+ __HAL_FLASH_INSTRUCTION_CACHE_ENABLE();
+ __HAL_FLASH_DATA_CACHE_ENABLE();
+ __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
+
//SystemCoreClockUpdate();
// Enable All GPIOs clocks
diff --git a/hw/bsp/stm32f7/boards/stm32f746disco/board.cmake b/hw/bsp/stm32f7/boards/stm32f746disco/board.cmake
index bc26c6ef4..5f46365f4 100644
--- a/hw/bsp/stm32f7/boards/stm32f746disco/board.cmake
+++ b/hw/bsp/stm32f7/boards/stm32f746disco/board.cmake
@@ -1,5 +1,5 @@
set(MCU_VARIANT stm32f746xx)
-set(JLINK_DEVICE stm32f746xx)
+set(JLINK_DEVICE stm32f746ng)
set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/STM32F746ZGTx_FLASH.ld)
diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c
index 1d0ef45d2..c90429a15 100644
--- a/src/portable/synopsys/dwc2/dcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/dcd_dwc2.c
@@ -73,8 +73,9 @@ typedef struct {
static dcd_data_t _dcd_data;
-CFG_TUD_MEM_SECTION static struct {
- TUD_EPBUF_DEF(setup_packet, 8);
+CFG_TUD_MEM_SECTION static union {
+ TUD_EPBUF_DEF(setup_buffer, 8);
+ tusb_control_request_t setup_packet;
} _dcd_usbbuf;
static tud_configure_dwc2_t _tud_cfg = CFG_TUD_CONFIGURE_DWC2_DEFAULT;
@@ -138,7 +139,7 @@ static void dma_setup_prepare(uint8_t rhport) {
// Receive only 1 packet
dwc2->epout[0].doeptsiz = (1 << DOEPTSIZ_STUPCNT_Pos) | (1 << DOEPTSIZ_PKTCNT_Pos) | (8 << DOEPTSIZ_XFRSIZ_Pos);
- dwc2->epout[0].doepdma = (uintptr_t) _dcd_usbbuf.setup_packet;
+ dwc2->epout[0].doepdma = (uintptr_t) _dcd_usbbuf.setup_buffer;
dwc2->epout[0].doepctl |= DOEPCTL_EPENA | DOEPCTL_USBAEP;
}
@@ -793,13 +794,15 @@ static void handle_bus_reset(uint8_t rhport) {
xfer_status[0][TUSB_DIR_OUT].max_size = CFG_TUD_ENDPOINT0_SIZE;
xfer_status[0][TUSB_DIR_IN].max_size = CFG_TUD_ENDPOINT0_SIZE;
+ uint32_t oepmsk = 0;
if(dma_device_enabled(dwc2)) {
+ oepmsk = GINTMSK_OEPINT;
dma_setup_prepare(rhport);
} else {
dwc2->epout[0].doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos);
}
- dwc2->gintmsk |= GINTMSK_OTGINT | GINTMSK_OEPINT | GINTMSK_IEPINT | GINTMSK_IISOIXFRM;
+ dwc2->gintmsk |= GINTMSK_OTGINT | oepmsk | GINTMSK_IEPINT | GINTMSK_IISOIXFRM;
}
static void handle_enum_done(uint8_t rhport) {
@@ -896,17 +899,31 @@ static void handle_rxflvl_irq(uint8_t rhport) {
case GRXSTS_PKTSTS_SETUP_RX: {
// Setup packet received
- uint32_t* setup = (uint32_t*)(uintptr_t) _dcd_usbbuf.setup_packet;
+ uint32_t* setup = (uint32_t*)(uintptr_t) _dcd_usbbuf.setup_buffer;
// We can receive up to three setup packets in succession, but only the last one is valid.
setup[0] = (*rx_fifo);
setup[1] = (*rx_fifo);
+
+ dwc2_dep_t* epin0 = &dwc2->epin[0];
+ if (edpt_is_enabled(epin0)) {
+ edpt_disable(rhport, 0x80, false);
+ }
+
+ // (GenID < 3.00a) Must wait SETUP_DONE before next OUT transfer, otherwise OUT data may be corrupted.
+ // (GenID >= 3.00a) On the other hand STUPCNT is auto reloaded and SETUP_DONE is only triggered once after bus reset.
+ if (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a) {
+ dcd_event_setup_received(rhport, _dcd_usbbuf.setup_buffer, true);
+ }
break;
}
case GRXSTS_PKTSTS_SETUP_DONE:
// Setup packet done:
- // After popping this out, dwc2 asserts a DOEPINT_SETUP interrupt which is handled by handle_epout_irq()
epout->doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos);
+
+ if (dwc2->gsnpsid < DWC2_CORE_REV_3_00a) {
+ dcd_event_setup_received(rhport, _dcd_usbbuf.setup_buffer, true);
+ }
break;
case GRXSTS_PKTSTS_RX_DATA: {
@@ -935,41 +952,19 @@ static void handle_rxflvl_irq(uint8_t rhport) {
break;
}
- case GRXSTS_PKTSTS_RX_COMPLETE:
+ case GRXSTS_PKTSTS_RX_COMPLETE: {
// Out packet done
- // After this entry is popped from the receive FIFO, dwc2 asserts a Transfer Completed interrupt on
- // the specified OUT endpoint which will be handled by handle_epout_irq()
- break;
-
- default: break; // nothing to do
- }
-}
-
-static void handle_epout_slave(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepint_bm) {
- if (doepint_bm.setup_phase_done) {
- // Cleanup previous pending EP0 IN transfer if any
- dwc2_dep_t* epin0 = &DWC2_REG(rhport)->epin[0];
- if (edpt_is_enabled(epin0)) {
- edpt_disable(rhport, 0x80, false);
- }
- dcd_event_setup_received(rhport, _dcd_usbbuf.setup_packet, true);
- return;
- }
-
- // Normal OUT transfer complete
- if (doepint_bm.xfer_complete) {
- // only handle data skip if it is setup or status related
- // Note: even though (xfer_complete + status_phase_rx) is for buffered DMA only, for STM32L47x (dwc2 v3.00a) they
- // can is set when GRXSTS_PKTSTS_SETUP_RX is popped therefore they can bet set before/together with setup_phase_done
- if (!doepint_bm.status_phase_rx && !doepint_bm.setup_packet_rx) {
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
- if ((epnum == 0) && _dcd_data.ep0_pending[TUSB_DIR_OUT]) {
- // EP0 can only handle one packet, Schedule another packet to be received.
- edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT);
+ if (epnum == 0 && _dcd_data.ep0_pending[TUSB_DIR_OUT] > 0) {
+ // EP0 can only handle one packet, schedule another packet to be received.
+ edpt_schedule_packets(rhport, 0, TUSB_DIR_OUT);
} else {
dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true);
}
+ break;
}
+
+ default: break; // nothing to do
}
}
@@ -1012,9 +1007,13 @@ static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepi
if (edpt_is_enabled(epin0)) {
edpt_disable(rhport, 0x80, false);
}
- dma_setup_prepare(rhport);
- dcd_dcache_invalidate(_dcd_usbbuf.setup_packet, 8);
- dcd_event_setup_received(rhport, _dcd_usbbuf.setup_packet, true);
+ dcd_dcache_invalidate(_dcd_usbbuf.setup_buffer, 8);
+ dcd_event_setup_received(rhport, _dcd_usbbuf.setup_buffer, true);
+
+ // Prepare EP0 for next setup if this setup has no data stage
+ if (_dcd_usbbuf.setup_packet.wLength == 0) {
+ dma_setup_prepare(rhport);
+ }
return;
}
@@ -1035,9 +1034,8 @@ static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepi
const uint16_t remain = tsiz.xfer_size;
xfer->total_len -= remain;
- // this is ZLP, so prepare EP0 for next setup
- // TODO use status phase rx
- if(epnum == 0 && xfer->total_len == 0) {
+ // prepare EP0 for next setup
+ if(epnum == 0) {
dma_setup_prepare(rhport);
}
@@ -1056,9 +1054,6 @@ static void handle_epin_dma(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diepin
// EP0 can only handle one packet. Schedule another packet to be transmitted.
edpt_schedule_packets(rhport, epnum, TUSB_DIR_IN);
} else {
- if(epnum == 0) {
- dma_setup_prepare(rhport);
- }
dcd_event_xfer_complete(rhport, epnum | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true);
}
}
@@ -1098,8 +1093,6 @@ static void handle_ep_irq(uint8_t rhport, uint8_t dir) {
#if CFG_TUD_DWC2_SLAVE_ENABLE
if (dir == TUSB_DIR_IN) {
handle_epin_slave(rhport, epnum, intr.diepint_bm);
- } else {
- handle_epout_slave(rhport, epnum, intr.doepint_bm);
}
#endif
}
@@ -1207,7 +1200,7 @@ void dcd_int_handler(uint8_t rhport) {
dwc2->gotgint = otg_int;
}
- if(gintsts & GINTSTS_SOF) {
+ if(gintsts & GINTSTS_SOF && dwc2->gintmsk & GINTMSK_SOFM) {
dwc2->gintsts = GINTSTS_SOF;
dwc2->gintmsk |= GINTMSK_USBSUSPM;
const uint32_t frame = (dwc2->dsts & DSTS_FNSOF) >> DSTS_FNSOF_Pos;
@@ -1220,6 +1213,12 @@ void dcd_int_handler(uint8_t rhport) {
dcd_event_sof(rhport, frame, true);
}
+ // IN endpoint interrupt handling.
+ if (gintsts & GINTSTS_IEPINT) {
+ // IEPINT bit read-only, clear using DIEPINTn
+ handle_ep_irq(rhport, TUSB_DIR_IN);
+ }
+
#if CFG_TUD_DWC2_SLAVE_ENABLE
// RxFIFO non-empty interrupt handling.
if (gintsts & GINTSTS_RXFLVL) {
@@ -1234,17 +1233,13 @@ void dcd_int_handler(uint8_t rhport) {
}
#endif
+#if CFG_TUD_DWC2_DMA_ENABLE
// OUT endpoint interrupt handling.
if (gintsts & GINTSTS_OEPINT) {
// OEPINT is read-only, clear using DOEPINTn
handle_ep_irq(rhport, TUSB_DIR_OUT);
}
-
- // IN endpoint interrupt handling.
- if (gintsts & GINTSTS_IEPINT) {
- // IEPINT bit read-only, clear using DIEPINTn
- handle_ep_irq(rhport, TUSB_DIR_IN);
- }
+#endif
// Incomplete isochronous IN transfer interrupt handling.
if (gintsts & GINTSTS_IISOIXFR) {