From 7258db344e99398a5e10f4c65b24d38c6b94b92b Mon Sep 17 00:00:00 2001 From: mickabrig7 Date: Tue, 28 Apr 2026 12:24:00 +0900 Subject: fix(dcd_ch32_usbfs): fix dropped bulk OUT packets by properly re-arming EP_RX_CTRL state --- src/portable/wch/dcd_ch32_usbfs.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 5cd25e33e..39c1cfb4a 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -118,6 +118,9 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { if (ep == 0) { EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; + } else { + EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | + (xfer->valid ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK); } } } @@ -312,6 +315,8 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t if (dir == TUSB_DIR_IN) { update_in(rhport, ep, true); + } else { + EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | USBFS_EP_R_RES_ACK; } return true; } -- cgit v1.3.1 From 2267046fadd8c40086c66c10abc99153b95d25bf Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 22 May 2026 15:30:51 +0200 Subject: ch32v20x: fix port1 IP selection Signed-off-by: HiFiPhile --- hw/bsp/ch32v20x/family.cmake | 3 ++- src/common/tusb_mcu.h | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/hw/bsp/ch32v20x/family.cmake b/hw/bsp/ch32v20x/family.cmake index 59a96f70d..785f5ee35 100644 --- a/hw/bsp/ch32v20x/family.cmake +++ b/hw/bsp/ch32v20x/family.cmake @@ -61,8 +61,9 @@ function(family_add_board BOARD_TARGET) if (RHPORT_DEVICE EQUAL 0) target_compile_definitions(${BOARD_TARGET} PUBLIC CFG_TUD_WCH_USBIP_FSDEV=1) + target_compile_definitions(${BOARD_TARGET} PUBLIC CFG_TUH_WCH_USBIP_FSDEV=1) elseif (RHPORT_DEVICE EQUAL 1) - target_compile_definitions(${BOARD_TARGET} PUBLIC CFG_TUH_WCH_USBIP_USBFS=1) + target_compile_definitions(${BOARD_TARGET} PUBLIC CFG_TUD_WCH_USBIP_USBFS=1) else() message(FATAL_ERROR "Invalid RHPORT_DEVICE ${RHPORT_DEVICE}") endif() diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index c85ade4d0..413ac4850 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -616,10 +616,6 @@ #define CFG_TUH_WCH_USBIP_USBFS 1 #endif - #define TUP_USBIP_FSDEV - #define TUP_USBIP_FSDEV_CH32 - #define CFG_TUSB_FSDEV_PMA_SIZE 512u - // default to FSDEV for device #if !defined(CFG_TUD_WCH_USBIP_USBFS) #define CFG_TUD_WCH_USBIP_USBFS 0 @@ -629,6 +625,12 @@ #define CFG_TUD_WCH_USBIP_FSDEV (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1) #endif + #if CFG_TUD_WCH_USBIP_FSDEV + #define TUP_USBIP_FSDEV + #define TUP_USBIP_FSDEV_CH32 + #define CFG_TUSB_FSDEV_PMA_SIZE 512u + #endif + #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_CH32V307) -- cgit v1.3.1 From d202477ebe0f8805bf88fcee4c0d5968d146dfbd Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 22 May 2026 18:02:23 +0200 Subject: dcd/ch32fs: reset EP regs on bus reset Signed-off-by: HiFiPhile --- src/portable/wch/dcd_ch32_usbfs.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 39c1cfb4a..0727664c9 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -125,6 +125,16 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { } } +static void reset_ep_ctrls(void) { + for (uint8_t ep = 1; ep < EP_MAX; ep++) { + EP_DMA(ep) = (uint32_t) &data.buffer[ep][0]; + EP_TX_LEN(ep) = 0; + EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NYET; + EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NYET; + } + EP_DMA(3) = (uint32_t) &data.ep3_buffer.out[0]; +} + /* public functions */ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { (void) rh_init; @@ -148,13 +158,7 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { USBOTG_FS->UEP5_6_MOD = 0xCC; USBOTG_FS->UEP7_MOD = 0x0C; - for (uint8_t ep = 1; ep < EP_MAX; ep++) { - EP_DMA(ep) = (uint32_t) &data.buffer[ep][0]; - EP_TX_LEN(ep) = 0; - EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK; - EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NAK; - } - EP_DMA(3) = (uint32_t) &data.ep3_buffer.out[0]; + reset_ep_ctrls(); dcd_connect(rhport); @@ -201,6 +205,8 @@ void dcd_int_handler(uint8_t rhport) { USBOTG_FS->DEV_ADDR = 0x00; EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; + reset_ep_ctrls(); + USBOTG_FS->INT_FG = USBFS_INT_FG_BUS_RST; } else if (status & USBFS_INT_FG_SUSPEND) { dcd_event_t event = {.rhport = rhport, .event_id = DCD_EVENT_SUSPEND}; -- cgit v1.3.1 From 66c5f6d45dc90f947261e2e4e62918c2ceb0ce11 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 22 May 2026 18:04:44 +0200 Subject: dcd/ch32fs: only enable EP0 ACK if no data stage, reduce race Signed-off-by: HiFiPhile --- src/portable/wch/dcd_ch32_usbfs.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 0727664c9..e4abbd824 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -186,9 +186,12 @@ void dcd_int_handler(uint8_t rhport) { case PID_SETUP: // setup clears stall EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK; - EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; - data.ep0_tog = true; + + tusb_control_request_t const* setup = + (tusb_control_request_t const*) &data.buffer[0][TUSB_DIR_OUT][0]; + EP_RX_CTRL(0) = (setup->wLength == 0) ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK; + dcd_event_setup_received(rhport, &data.buffer[0][TUSB_DIR_OUT][0], true); break; } -- cgit v1.3.1 From 61a8f688c800626962cfed4022f4672b35ceb3ae Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 22 May 2026 18:13:42 +0200 Subject: dcd/ch32fs: fix ISO IN transfer OUT is still buggy Signed-off-by: HiFiPhile --- src/portable/wch/dcd_ch32_usbfs.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index e4abbd824..f6c573b47 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -119,8 +119,10 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { if (ep == 0) { EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; } else { - EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | - (xfer->valid ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK); + uint8_t rx_res = data.isochronous[ep] + ? USBFS_EP_R_RES_NYET + : (xfer->valid ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK); + EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | rx_res; } } } @@ -272,18 +274,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) { uint8_t dir = tu_edpt_dir(desc_ep->bEndpointAddress); TU_ASSERT(ep < EP_MAX); - data.isochronous[ep] = desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS; data.xfer[ep][dir].max_size = tu_edpt_packet_size(desc_ep); if (ep != 0) { if (dir == TUSB_DIR_OUT) { - if (data.isochronous[ep]) { - EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NYET; - } else { - EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_ACK; - } + EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_T_RES_NAK; } else { - EP_TX_LEN(ep) = 0; EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK; } } @@ -299,13 +295,18 @@ bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet (void) rhport; (void) ep_addr; (void)largest_packet_size; - return false; + uint8_t ep = tu_edpt_number(ep_addr); + uint8_t dir = tu_edpt_dir(ep_addr); + + data.isochronous[ep] = true; + data.xfer[ep][dir].max_size = largest_packet_size; + return true; } bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { (void)rhport; (void)desc_ep; - return false; + return true; } bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { @@ -325,7 +326,8 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t if (dir == TUSB_DIR_IN) { update_in(rhport, ep, true); } else { - EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | USBFS_EP_R_RES_ACK; + uint8_t rx_res = data.isochronous[ep] ? USBFS_EP_R_RES_NYET : USBFS_EP_R_RES_ACK; + EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | rx_res; } return true; } -- cgit v1.3.1 From 28d4ec5723428cbdb085ecdaa70e7fd2bf7f893d Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 22 May 2026 18:14:58 +0200 Subject: dcd/ch32fs: reset EP on clear stall Signed-off-by: HiFiPhile --- src/portable/wch/dcd_ch32_usbfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index f6c573b47..8f583510c 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -362,9 +362,9 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { } } else { if (dir == TUSB_DIR_OUT) { - EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~(USBFS_EP_R_RES_MASK | USBFS_EP_R_TOG)) | USBFS_EP_R_RES_ACK; + EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NAK; } else { - EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK | USBFS_EP_T_TOG)) | USBFS_EP_T_RES_NAK; + EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK; } } } -- cgit v1.3.1 From e14b0e8514ace0043472d9cb0779152fccade1ee Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 23 May 2026 13:02:53 +0200 Subject: dcd/ch32fs: set EP to NAK earlier to reduce spuroius transfer Signed-off-by: HiFiPhile --- src/portable/wch/dcd_ch32_usbfs.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 8f583510c..3ba6eee87 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -66,6 +66,13 @@ static struct { static void update_in(uint8_t rhport, uint8_t ep, bool force) { struct usb_xfer* xfer = &data.xfer[ep][TUSB_DIR_IN]; if (xfer->valid) { + // Set EP to NAK to avoid spurious tramsfer + if (ep == 0) { + EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK | (data.ep0_tog ? USBFS_EP_T_TOG : 0); + } else if (!data.isochronous[ep]) { + EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NAK; + } + if (force || xfer->len) { size_t len = TU_MIN(xfer->max_size, xfer->len); if (ep == 0) { @@ -101,6 +108,13 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force) { static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { struct usb_xfer* xfer = &data.xfer[ep][TUSB_DIR_OUT]; if (xfer->valid) { + // Set EP to NAK to avoid spurious tramsfer + if (ep == 0) { + EP_RX_CTRL(0) = USBFS_EP_R_RES_NAK; + } else if (!data.isochronous[ep]) { + EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | USBFS_EP_R_RES_NAK; + } + size_t len = TU_MIN(xfer->max_size, TU_MIN(xfer->len, rx_len)); if (ep == 3) { memcpy(xfer->buffer, data.ep3_buffer.out, len); @@ -116,9 +130,7 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { dcd_event_xfer_complete(rhport, ep, xfer->processed_len, XFER_RESULT_SUCCESS, true); } - if (ep == 0) { - EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; - } else { + if (ep != 0) { uint8_t rx_res = data.isochronous[ep] ? USBFS_EP_R_RES_NYET : (xfer->valid ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK); @@ -173,10 +185,11 @@ void dcd_int_handler(uint8_t rhport) { if (status & USBFS_INT_FG_TRANSFER) { uint8_t ep = USBFS_INT_ST_MASK_UIS_ENDP(USBOTG_FS->INT_ST); uint8_t token = USBFS_INT_ST_MASK_UIS_TOKEN(USBOTG_FS->INT_ST); + uint16_t rx_len = USBOTG_FS->RX_LEN; + USBOTG_FS->INT_FG = USBFS_INT_FG_TRANSFER; switch (token) { case PID_OUT: { - uint16_t rx_len = USBOTG_FS->RX_LEN; update_out(rhport, ep, rx_len); break; } @@ -198,7 +211,6 @@ void dcd_int_handler(uint8_t rhport) { break; } - USBOTG_FS->INT_FG = USBFS_INT_FG_TRANSFER; } else if (status & USBFS_INT_FG_BUS_RST) { data.ep0_tog = true; data.xfer[0][TUSB_DIR_OUT].max_size = 64; -- cgit v1.3.1 From b66fc7e88400caf7748779c7dc0b9c90f90e626b Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 23 May 2026 13:10:47 +0200 Subject: dcd/ch32x : code reformat Signed-off-by: HiFiPhile --- src/portable/wch/dcd_ch32_usbfs.c | 159 ++++++++++++++++--------------- src/portable/wch/dcd_ch32_usbhs.c | 191 +++++++++++++++++++------------------- 2 files changed, 173 insertions(+), 177 deletions(-) (limited to 'src') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 3ba6eee87..37677276c 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -29,29 +29,29 @@ #if CFG_TUD_ENABLED && defined(TUP_USBIP_WCH_USBFS) && CFG_TUD_WCH_USBIP_USBFS -#include "device/dcd.h" -#include "ch32_usbfs_reg.h" + #include "device/dcd.h" + #include "ch32_usbfs_reg.h" -/* private defines */ -#define EP_MAX (8) + /* private defines */ + #define EP_MAX (8) -#define EP_DMA(ep) ((&USBOTG_FS->UEP0_DMA)[ep]) -#define EP_TX_LEN(ep) ((&USBOTG_FS->UEP0_TX_LEN)[2 * ep]) -#define EP_TX_CTRL(ep) ((&USBOTG_FS->UEP0_TX_CTRL)[4 * ep]) -#define EP_RX_CTRL(ep) ((&USBOTG_FS->UEP0_RX_CTRL)[4 * ep]) + #define EP_DMA(ep) ((&USBOTG_FS->UEP0_DMA)[ep]) + #define EP_TX_LEN(ep) ((&USBOTG_FS->UEP0_TX_LEN)[2 * ep]) + #define EP_TX_CTRL(ep) ((&USBOTG_FS->UEP0_TX_CTRL)[4 * ep]) + #define EP_RX_CTRL(ep) ((&USBOTG_FS->UEP0_RX_CTRL)[4 * ep]) /* private data */ struct usb_xfer { - bool valid; - uint8_t* buffer; - size_t len; - size_t processed_len; - size_t max_size; + bool valid; + uint8_t *buffer; + size_t len; + size_t processed_len; + size_t max_size; }; static struct { - bool ep0_tog; - bool isochronous[EP_MAX]; + bool ep0_tog; + bool isochronous[EP_MAX]; struct usb_xfer xfer[EP_MAX][2]; TU_ATTR_ALIGNED(4) uint8_t buffer[EP_MAX][2][64]; TU_ATTR_ALIGNED(4) struct { @@ -64,7 +64,7 @@ static struct { /* private helpers */ static void update_in(uint8_t rhport, uint8_t ep, bool force) { - struct usb_xfer* xfer = &data.xfer[ep][TUSB_DIR_IN]; + struct usb_xfer *xfer = &data.xfer[ep][TUSB_DIR_IN]; if (xfer->valid) { // Set EP to NAK to avoid spurious tramsfer if (ep == 0) { @@ -89,24 +89,22 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force) { EP_TX_LEN(ep) = len; if (ep == 0) { EP_TX_CTRL(0) = USBFS_EP_T_RES_ACK | (data.ep0_tog ? USBFS_EP_T_TOG : 0); - data.ep0_tog = !data.ep0_tog; + data.ep0_tog = !data.ep0_tog; } else if (data.isochronous[ep]) { EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NYET; } else { EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_ACK; } } else { - xfer->valid = false; + xfer->valid = false; EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NAK; - dcd_event_xfer_complete( - rhport, ep | TUSB_DIR_IN_MASK, xfer->processed_len, - XFER_RESULT_SUCCESS, true); + dcd_event_xfer_complete(rhport, ep | TUSB_DIR_IN_MASK, xfer->processed_len, XFER_RESULT_SUCCESS, true); } } } static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { - struct usb_xfer* xfer = &data.xfer[ep][TUSB_DIR_OUT]; + struct usb_xfer *xfer = &data.xfer[ep][TUSB_DIR_OUT]; if (xfer->valid) { // Set EP to NAK to avoid spurious tramsfer if (ep == 0) { @@ -131,9 +129,8 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { } if (ep != 0) { - uint8_t rx_res = data.isochronous[ep] - ? USBFS_EP_R_RES_NYET - : (xfer->valid ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK); + uint8_t rx_res = + data.isochronous[ep] ? USBFS_EP_R_RES_NYET : (xfer->valid ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK); EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | rx_res; } } @@ -141,28 +138,28 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { static void reset_ep_ctrls(void) { for (uint8_t ep = 1; ep < EP_MAX; ep++) { - EP_DMA(ep) = (uint32_t) &data.buffer[ep][0]; - EP_TX_LEN(ep) = 0; + EP_DMA(ep) = (uint32_t)&data.buffer[ep][0]; + EP_TX_LEN(ep) = 0; EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NYET; EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NYET; } - EP_DMA(3) = (uint32_t) &data.ep3_buffer.out[0]; + EP_DMA(3) = (uint32_t)&data.ep3_buffer.out[0]; } /* public functions */ -bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { - (void) rh_init; +bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { + (void)rh_init; // init registers USBOTG_FS->BASE_CTRL = USBFS_CTRL_SYS_CTRL | USBFS_CTRL_INT_BUSY | USBFS_CTRL_DMA_EN; USBOTG_FS->UDEV_CTRL = USBFS_UDEV_CTRL_PD_DIS | USBFS_UDEV_CTRL_PORT_EN; - USBOTG_FS->DEV_ADDR = 0x00; + USBOTG_FS->DEV_ADDR = 0x00; USBOTG_FS->INT_FG = 0xFF; USBOTG_FS->INT_EN = USBFS_INT_EN_BUS_RST | USBFS_INT_EN_TRANSFER | USBFS_INT_EN_SUSPEND; // setup endpoint 0 - EP_DMA(0) = (uint32_t) &data.buffer[0][0]; - EP_TX_LEN(0) = 0; + EP_DMA(0) = (uint32_t)&data.buffer[0][0]; + EP_TX_LEN(0) = 0; EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK; EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; @@ -170,7 +167,7 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { USBOTG_FS->UEP4_1_MOD = 0xCC; USBOTG_FS->UEP2_3_MOD = 0xCC; USBOTG_FS->UEP5_6_MOD = 0xCC; - USBOTG_FS->UEP7_MOD = 0x0C; + USBOTG_FS->UEP7_MOD = 0x0C; reset_ep_ctrls(); @@ -180,12 +177,12 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { } void dcd_int_handler(uint8_t rhport) { - (void) rhport; + (void)rhport; uint8_t status = USBOTG_FS->INT_FG; if (status & USBFS_INT_FG_TRANSFER) { - uint8_t ep = USBFS_INT_ST_MASK_UIS_ENDP(USBOTG_FS->INT_ST); - uint8_t token = USBFS_INT_ST_MASK_UIS_TOKEN(USBOTG_FS->INT_ST); - uint16_t rx_len = USBOTG_FS->RX_LEN; + uint8_t ep = USBFS_INT_ST_MASK_UIS_ENDP(USBOTG_FS->INT_ST); + uint8_t token = USBFS_INT_ST_MASK_UIS_TOKEN(USBOTG_FS->INT_ST); + uint16_t rx_len = USBOTG_FS->RX_LEN; USBOTG_FS->INT_FG = USBFS_INT_FG_TRANSFER; switch (token) { @@ -201,26 +198,27 @@ void dcd_int_handler(uint8_t rhport) { case PID_SETUP: // setup clears stall EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK; - data.ep0_tog = true; + data.ep0_tog = true; - tusb_control_request_t const* setup = - (tusb_control_request_t const*) &data.buffer[0][TUSB_DIR_OUT][0]; - EP_RX_CTRL(0) = (setup->wLength == 0) ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK; + const tusb_control_request_t *setup = (const tusb_control_request_t *)&data.buffer[0][TUSB_DIR_OUT][0]; + EP_RX_CTRL(0) = (setup->wLength == 0) ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK; dcd_event_setup_received(rhport, &data.buffer[0][TUSB_DIR_OUT][0], true); break; } } else if (status & USBFS_INT_FG_BUS_RST) { - data.ep0_tog = true; + data.ep0_tog = true; data.xfer[0][TUSB_DIR_OUT].max_size = 64; - data.xfer[0][TUSB_DIR_IN].max_size = 64; + data.xfer[0][TUSB_DIR_IN].max_size = 64; - //dcd_event_bus_reset(rhport, (USBOTG_FS->BASE_CTRL & USBFS_CTRL_LOW_SPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL, true); - dcd_event_bus_reset(rhport, (USBOTG_FS->UDEV_CTRL & USBFS_UDEV_CTRL_LOW_SPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL, true); + // dcd_event_bus_reset(rhport, (USBOTG_FS->BASE_CTRL & USBFS_CTRL_LOW_SPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL, + // true); + dcd_event_bus_reset(rhport, (USBOTG_FS->UDEV_CTRL & USBFS_UDEV_CTRL_LOW_SPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL, + true); USBOTG_FS->DEV_ADDR = 0x00; - EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; + EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; reset_ep_ctrls(); @@ -233,56 +231,55 @@ void dcd_int_handler(uint8_t rhport) { } void dcd_int_enable(uint8_t rhport) { - (void) rhport; + (void)rhport; NVIC_EnableIRQ(USBHD_IRQn); } void dcd_int_disable(uint8_t rhport) { - (void) rhport; + (void)rhport; NVIC_DisableIRQ(USBHD_IRQn); } void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { - (void) dev_addr; + (void)dev_addr; dcd_edpt_xfer(rhport, 0x80, NULL, 0, false); // zlp status response } void dcd_remote_wakeup(uint8_t rhport) { - (void) rhport; + (void)rhport; // TODO optional } void dcd_connect(uint8_t rhport) { - (void) rhport; + (void)rhport; USBOTG_FS->BASE_CTRL |= USBFS_CTRL_DEV_PUEN; } void dcd_disconnect(uint8_t rhport) { - (void) rhport; + (void)rhport; USBOTG_FS->BASE_CTRL &= ~USBFS_CTRL_DEV_PUEN; } void dcd_sof_enable(uint8_t rhport, bool en) { - (void) rhport; - (void) en; + (void)rhport; + (void)en; // TODO implement later } -void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) { - (void) rhport; +void dcd_edpt0_status_complete(uint8_t rhport, const tusb_control_request_t *request) { + (void)rhport; if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && - request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && - request->bRequest == TUSB_REQ_SET_ADDRESS) { - USBOTG_FS->DEV_ADDR = (uint8_t) request->wValue; + request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) { + USBOTG_FS->DEV_ADDR = (uint8_t)request->wValue; } EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK; EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; } -bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) { - (void) rhport; - uint8_t ep = tu_edpt_number(desc_ep->bEndpointAddress); +bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { + (void)rhport; + uint8_t ep = tu_edpt_number(desc_ep->bEndpointAddress); uint8_t dir = tu_edpt_dir(desc_ep->bEndpointAddress); TU_ASSERT(ep < EP_MAX); @@ -299,18 +296,18 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) { } void dcd_edpt_close_all(uint8_t rhport) { - (void) rhport; + (void)rhport; // TODO optional } bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { - (void) rhport; - (void) ep_addr; + (void)rhport; + (void)ep_addr; (void)largest_packet_size; - uint8_t ep = tu_edpt_number(ep_addr); + uint8_t ep = tu_edpt_number(ep_addr); uint8_t dir = tu_edpt_dir(ep_addr); - data.isochronous[ep] = true; + data.isochronous[ep] = true; data.xfer[ep][dir].max_size = largest_packet_size; return true; } @@ -321,17 +318,17 @@ bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) return true; } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { - (void) is_isr; - (void) rhport; - uint8_t ep = tu_edpt_number(ep_addr); +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool is_isr) { + (void)is_isr; + (void)rhport; + uint8_t ep = tu_edpt_number(ep_addr); uint8_t dir = tu_edpt_dir(ep_addr); - struct usb_xfer* xfer = &data.xfer[ep][dir]; + struct usb_xfer *xfer = &data.xfer[ep][dir]; dcd_int_disable(rhport); - xfer->valid = true; - xfer->buffer = buffer; - xfer->len = total_bytes; + xfer->valid = true; + xfer->buffer = buffer; + xfer->len = total_bytes; xfer->processed_len = 0; dcd_int_enable(rhport); @@ -345,14 +342,14 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t } void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { - (void) rhport; - uint8_t ep = tu_edpt_number(ep_addr); + (void)rhport; + uint8_t ep = tu_edpt_number(ep_addr); uint8_t dir = tu_edpt_dir(ep_addr); if (ep == 0) { if (dir == TUSB_DIR_OUT) { EP_RX_CTRL(0) = USBFS_EP_R_RES_STALL; } else { - EP_TX_LEN(0) = 0; + EP_TX_LEN(0) = 0; EP_TX_CTRL(0) = USBFS_EP_T_RES_STALL; } } else { @@ -365,8 +362,8 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { } void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { - (void) rhport; - uint8_t ep = tu_edpt_number(ep_addr); + (void)rhport; + uint8_t ep = tu_edpt_number(ep_addr); uint8_t dir = tu_edpt_dir(ep_addr); if (ep == 0) { if (dir == TUSB_DIR_OUT) { diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c index 11734de37..01ff6eba3 100644 --- a/src/portable/wch/dcd_ch32_usbhs.c +++ b/src/portable/wch/dcd_ch32_usbhs.c @@ -37,12 +37,12 @@ #define EP_MAX 16 typedef struct { - uint8_t* buffer; + uint8_t *buffer; uint16_t total_len; uint16_t queued_len; uint16_t max_size; - bool is_last_packet; - bool is_iso; + bool is_last_packet; + bool is_iso; } xfer_ctl_t; typedef enum { @@ -50,16 +50,16 @@ typedef enum { EP_RESPONSE_NAK, } ep_response_list_t; -#define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir] + #define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir] static xfer_ctl_t xfer_status[EP_MAX][2]; -#define EP_TX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_TX_LEN) + (ep) * 2) -#define EP_TX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_TX_CTRL) + (ep) * 4) -#define EP_RX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_RX_CTRL) + (ep) * 4) -#define EP_RX_MAX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_MAX_LEN) + (ep) * 2) + #define EP_TX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_TX_LEN) + (ep) * 2) + #define EP_TX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_TX_CTRL) + (ep) * 4) + #define EP_RX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_RX_CTRL) + (ep) * 4) + #define EP_RX_MAX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_MAX_LEN) + (ep) * 2) -#define EP_TX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_TX_DMA) + (ep - 1)) -#define EP_RX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_RX_DMA) + (ep - 1)) + #define EP_TX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_TX_DMA) + (ep - 1)) + #define EP_RX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_RX_DMA) + (ep - 1)) /* Endpoint Buffer */ TU_ATTR_ALIGNED(4) static uint8_t ep0_buffer[CFG_TUD_ENDPOINT0_SIZE]; @@ -96,15 +96,15 @@ static void ep_set_response_and_toggle(uint8_t ep_num, tusb_dir_t ep_dir, ep_res } } -static void xfer_data_packet(uint8_t ep_num, tusb_dir_t ep_dir, xfer_ctl_t* xfer) { +static void xfer_data_packet(uint8_t ep_num, tusb_dir_t ep_dir, xfer_ctl_t *xfer) { if (ep_dir == TUSB_DIR_IN) { - uint16_t remaining = xfer->total_len - xfer->queued_len; + uint16_t remaining = xfer->total_len - xfer->queued_len; uint16_t next_tx_size = TU_MIN(remaining, xfer->max_size); if (ep_num == 0) { memcpy(ep0_buffer, &xfer->buffer[xfer->queued_len], next_tx_size); } else { - EP_TX_DMA_ADDR(ep_num) = (uint32_t) &xfer->buffer[xfer->queued_len]; + EP_TX_DMA_ADDR(ep_num) = (uint32_t)&xfer->buffer[xfer->queued_len]; } EP_TX_LEN(ep_num) = next_tx_size; @@ -117,7 +117,7 @@ static void xfer_data_packet(uint8_t ep_num, tusb_dir_t ep_dir, xfer_ctl_t* xfer USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num); } } else { /* TUSB_DIR_OUT */ - uint16_t left_to_receive = xfer->total_len - xfer->queued_len; + uint16_t left_to_receive = xfer->total_len - xfer->queued_len; uint16_t max_possible_rx_size = TU_MIN(xfer->max_size, left_to_receive); if (max_possible_rx_size == left_to_receive) { @@ -125,16 +125,16 @@ static void xfer_data_packet(uint8_t ep_num, tusb_dir_t ep_dir, xfer_ctl_t* xfer } if (ep_num > 0) { - EP_RX_DMA_ADDR(ep_num) = (uint32_t) &xfer->buffer[xfer->queued_len]; - EP_RX_MAX_LEN(ep_num) = max_possible_rx_size; + EP_RX_DMA_ADDR(ep_num) = (uint32_t)&xfer->buffer[xfer->queued_len]; + EP_RX_MAX_LEN(ep_num) = max_possible_rx_size; } } ep_set_response_and_toggle(ep_num, ep_dir, USBHS_EP_R_RES_ACK); } -bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { - (void) rhport; - (void) rh_init; +bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { + (void)rhport; + (void)rh_init; memset(&xfer_status, 0, sizeof(xfer_status)); @@ -143,32 +143,32 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { USBHSD->CONTROL = 0; -#if TUD_OPT_HIGH_SPEED + #if TUD_OPT_HIGH_SPEED USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_HIGH_SPEED; -#else - #error OPT_MODE_FULL_SPEED not currently supported on CH32 + #else + #error OPT_MODE_FULL_SPEED not currently supported on CH32 USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_FULL_SPEED; -#endif + #endif USBHSD->INT_EN = 0; USBHSD->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_BUS_RST_EN | USBHS_SUSPEND_EN | USBHS_ISO_ACT_EN; USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN; - USBHSD->ENDP_TYPE = 0x00; - USBHSD->BUF_MODE = 0x00; + USBHSD->ENDP_TYPE = 0x00; + USBHSD->BUF_MODE = 0x00; for (int ep = 0; ep < EP_MAX; ep++) { - EP_TX_LEN(ep) = 0; + EP_TX_LEN(ep) = 0; EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK; EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; EP_RX_MAX_LEN(ep) = 0; } - USBHSD->UEP0_DMA = (uint32_t) ep0_buffer; - USBHSD->UEP0_MAX_LEN = CFG_TUD_ENDPOINT0_SIZE; + USBHSD->UEP0_DMA = (uint32_t)ep0_buffer; + USBHSD->UEP0_MAX_LEN = CFG_TUD_ENDPOINT0_SIZE; xfer_status[0][TUSB_DIR_OUT].max_size = CFG_TUD_ENDPOINT0_SIZE; - xfer_status[0][TUSB_DIR_IN].max_size = CFG_TUD_ENDPOINT0_SIZE; + xfer_status[0][TUSB_DIR_IN].max_size = CFG_TUD_ENDPOINT0_SIZE; USBHSD->DEV_AD = 0; USBHSD->CONTROL |= USBHS_DEV_PU_EN; @@ -177,20 +177,20 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { } void dcd_int_enable(uint8_t rhport) { - (void) rhport; + (void)rhport; NVIC_EnableIRQ(USBHS_IRQn); } void dcd_int_disable(uint8_t rhport) { - (void) rhport; + (void)rhport; NVIC_DisableIRQ(USBHS_IRQn); } void dcd_edpt_close_all(uint8_t rhport) { - (void) rhport; + (void)rhport; for (size_t ep = 1; ep < EP_MAX; ep++) { - EP_TX_LEN(ep) = 0; + EP_TX_LEN(ep) = 0; EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK; EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; @@ -201,18 +201,18 @@ void dcd_edpt_close_all(uint8_t rhport) { } void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { - (void) dev_addr; + (void)dev_addr; // Response with zlp status dcd_edpt_xfer(rhport, 0x80, NULL, 0, false); } void dcd_remote_wakeup(uint8_t rhport) { - (void) rhport; + (void)rhport; } void dcd_sof_enable(uint8_t rhport, bool en) { - (void) rhport; + (void)rhport; if (en) { USBHSD->INT_EN |= USBHS_SOF_ACT_EN; } else { @@ -220,24 +220,23 @@ void dcd_sof_enable(uint8_t rhport, bool en) { } } -void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) { - (void) rhport; +void dcd_edpt0_status_complete(uint8_t rhport, const tusb_control_request_t *request) { + (void)rhport; if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && - request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && - request->bRequest == TUSB_REQ_SET_ADDRESS) { - USBHSD->DEV_AD = (uint8_t) request->wValue; + request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) { + USBHSD->DEV_AD = (uint8_t)request->wValue; } EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; EP_RX_CTRL(0) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0; } -bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) { - (void) rhport; +bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_edpt) { + (void)rhport; - uint8_t const ep_num = tu_edpt_number(desc_edpt->bEndpointAddress); - tusb_dir_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress); + const uint8_t ep_num = tu_edpt_number(desc_edpt->bEndpointAddress); + const tusb_dir_t dir = tu_edpt_dir(desc_edpt->bEndpointAddress); TU_ASSERT(ep_num < EP_MAX); @@ -245,8 +244,8 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) { return true; } - xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, dir); - xfer->max_size = tu_edpt_packet_size(desc_edpt); + xfer_ctl_t *xfer = XFER_CTL_BASE(ep_num, dir); + xfer->max_size = tu_edpt_packet_size(desc_edpt); xfer->is_iso = (desc_edpt->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS); if (dir == TUSB_DIR_OUT) { @@ -263,7 +262,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) { /* Enable all types except Isochronous to avoid ISO_ACT interrupt generation */ USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num); } - EP_TX_LEN(ep_num) = 0; + EP_TX_LEN(ep_num) = 0; EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; } @@ -271,19 +270,19 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) { } void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { - (void) rhport; + (void)rhport; - uint8_t const ep_num = tu_edpt_number(ep_addr); - tusb_dir_t const dir = tu_edpt_dir(ep_addr); + const uint8_t ep_num = tu_edpt_number(ep_addr); + const tusb_dir_t dir = tu_edpt_dir(ep_addr); if (dir == TUSB_DIR_OUT) { - EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; + EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; EP_RX_MAX_LEN(ep_num) = 0; USBHSD->ENDP_TYPE &= ~(USBHS_EP0_R_TYP << ep_num); USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_R_EN << ep_num); - } else { // TUSB_DIR_IN + } else { // TUSB_DIR_IN EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; - EP_TX_LEN(ep_num) = 0; + EP_TX_LEN(ep_num) = 0; USBHSD->ENDP_TYPE &= ~(USBHS_EP0_T_TYP << ep_num); USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_T_EN << ep_num); } @@ -305,24 +304,24 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) #endif void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { - (void) rhport; + (void)rhport; - uint8_t const ep_num = tu_edpt_number(ep_addr); - tusb_dir_t const dir = tu_edpt_dir(ep_addr); + const uint8_t ep_num = tu_edpt_number(ep_addr); + const tusb_dir_t dir = tu_edpt_dir(ep_addr); if (dir == TUSB_DIR_OUT) { EP_RX_CTRL(ep_num) = USBHS_EP_R_RES_STALL; } else { - EP_TX_LEN(0) = 0; + EP_TX_LEN(0) = 0; EP_TX_CTRL(ep_num) = USBHS_EP_T_RES_STALL; } } void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { - (void) rhport; + (void)rhport; - uint8_t const ep_num = tu_edpt_number(ep_addr); - tusb_dir_t const dir = tu_edpt_dir(ep_addr); + const uint8_t ep_num = tu_edpt_number(ep_addr); + const tusb_dir_t dir = tu_edpt_dir(ep_addr); if (dir == TUSB_DIR_OUT) { EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; @@ -331,16 +330,16 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { } } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { - (void) is_isr; - (void) rhport; - uint8_t const ep_num = tu_edpt_number(ep_addr); - tusb_dir_t const dir = tu_edpt_dir(ep_addr); +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool is_isr) { + (void)is_isr; + (void)rhport; + const uint8_t ep_num = tu_edpt_number(ep_addr); + const tusb_dir_t dir = tu_edpt_dir(ep_addr); - xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, dir); - xfer->buffer = buffer; - xfer->total_len = total_bytes; - xfer->queued_len = 0; + xfer_ctl_t *xfer = XFER_CTL_BASE(ep_num, dir); + xfer->buffer = buffer; + xfer->total_len = total_bytes; + xfer->queued_len = 0; xfer->is_last_packet = false; xfer_data_packet(ep_num, dir, xfer); @@ -349,22 +348,22 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t } void dcd_int_handler(uint8_t rhport) { - (void) rhport; + (void)rhport; - uint8_t int_flag = USBHSD->INT_FG; + uint8_t int_flag = USBHSD->INT_FG; uint8_t int_status = USBHSD->INT_ST; if (int_flag & (USBHS_ISO_ACT_FLAG | USBHS_TRANSFER_FLAG)) { - uint8_t const token = int_status & MASK_UIS_TOKEN; + const uint8_t token = int_status & MASK_UIS_TOKEN; if (token == USBHS_TOKEN_PID_SOF) { uint32_t frame_count = USBHSD->FRAME_NO & USBHS_FRAME_NO_NUM_MASK; dcd_event_sof(rhport, frame_count, true); - }else { - uint8_t const ep_num = int_status & MASK_UIS_ENDP; - tusb_dir_t const ep_dir = (token == USBHS_TOKEN_PID_IN) ? TUSB_DIR_IN : TUSB_DIR_OUT; - uint8_t const ep_addr = tu_edpt_addr(ep_num, ep_dir); - xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, ep_dir); + } else { + const uint8_t ep_num = int_status & MASK_UIS_ENDP; + const tusb_dir_t ep_dir = (token == USBHS_TOKEN_PID_IN) ? TUSB_DIR_IN : TUSB_DIR_OUT; + const uint8_t ep_addr = tu_edpt_addr(ep_num, ep_dir); + xfer_ctl_t *xfer = XFER_CTL_BASE(ep_num, ep_dir); if (token == USBHS_TOKEN_PID_OUT) { uint16_t rx_len = USBHSD->RX_LEN; @@ -405,28 +404,28 @@ void dcd_int_handler(uint8_t rhport) { } else if (int_flag & USBHS_BUS_RST_FLAG) { // TODO CH32 does not detect actual speed at this time (should be known at end of reset) // This interrupt probably triggered at start of bus reset -// tusb_speed_t actual_speed; -// switch(USBHSD->SPEED_TYPE & USBHS_SPEED_TYPE_MASK){ -// case USBHS_SPEED_TYPE_HIGH: -// actual_speed = TUSB_SPEED_HIGH; -// break; -// case USBHS_SPEED_TYPE_FULL: -// actual_speed = TUSB_SPEED_FULL; -// break; -// case USBHS_SPEED_TYPE_LOW: -// actual_speed = TUSB_SPEED_LOW; -// break; -// default: -// TU_ASSERT(0,); -// break; -// } -// dcd_event_bus_reset(0, actual_speed, true); + // tusb_speed_t actual_speed; + // switch(USBHSD->SPEED_TYPE & USBHS_SPEED_TYPE_MASK){ + // case USBHS_SPEED_TYPE_HIGH: + // actual_speed = TUSB_SPEED_HIGH; + // break; + // case USBHS_SPEED_TYPE_FULL: + // actual_speed = TUSB_SPEED_FULL; + // break; + // case USBHS_SPEED_TYPE_LOW: + // actual_speed = TUSB_SPEED_LOW; + // break; + // default: + // TU_ASSERT(0,); + // break; + // } + // dcd_event_bus_reset(0, actual_speed, true); dcd_event_bus_reset(0, TUSB_SPEED_HIGH, true); USBHSD->DEV_AD = 0; - EP_RX_CTRL(0) = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0; - EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; + EP_RX_CTRL(0) = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0; + EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; USBHSD->INT_FG = USBHS_BUS_RST_FLAG; /* Clear flag */ } else if (int_flag & USBHS_SUSPEND_FLAG) { -- cgit v1.3.1 From 08cd5c3270e79ed2e63c8941c13c84027a5c003e Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 23 May 2026 17:45:16 +0200 Subject: dcd/ch32fs: clear INT flag after processing Signed-off-by: HiFiPhile --- src/portable/wch/dcd_ch32_usbfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 37677276c..4ecaf129e 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -183,7 +183,6 @@ void dcd_int_handler(uint8_t rhport) { uint8_t ep = USBFS_INT_ST_MASK_UIS_ENDP(USBOTG_FS->INT_ST); uint8_t token = USBFS_INT_ST_MASK_UIS_TOKEN(USBOTG_FS->INT_ST); uint16_t rx_len = USBOTG_FS->RX_LEN; - USBOTG_FS->INT_FG = USBFS_INT_FG_TRANSFER; switch (token) { case PID_OUT: { @@ -207,6 +206,7 @@ void dcd_int_handler(uint8_t rhport) { break; } + USBOTG_FS->INT_FG = USBFS_INT_FG_TRANSFER; } else if (status & USBFS_INT_FG_BUS_RST) { data.ep0_tog = true; data.xfer[0][TUSB_DIR_OUT].max_size = 64; -- cgit v1.3.1 From c6beac24ca280ce13e538f0b9459553abc825571 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 23 May 2026 19:21:59 +0200 Subject: dcd/ch32fs: do not set EP0 to ACK on status complete It would casue race condition, SETUP packet is always acked. Signed-off-by: HiFiPhile --- src/portable/wch/dcd_ch32_usbfs.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 4ecaf129e..ca3ce7ba8 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -273,8 +273,6 @@ void dcd_edpt0_status_complete(uint8_t rhport, const tusb_control_request_t *req request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) { USBOTG_FS->DEV_ADDR = (uint8_t)request->wValue; } - EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK; - EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; } bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { -- cgit v1.3.1 From 420de14b50dc2b9c1ed7ba587ef22eb227739eee Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 23 May 2026 19:30:22 +0200 Subject: dcd/ch32hs: refactor transfer flow Refactor the driver to follow USBFS style for easier maintenance. Replace the old packet/response helpers with explicit queue and update paths for IN and OUT transfers. Introduce transfer validity tracking and per-endpoint data toggle state. Reset toggle state on init, close-all, endpoint close, clear-stall, and bus reset. Initialize endpoint controls consistently in NAK + TOG_0 mode. Tighten EP0 setup/status handling and route transfer IRQ processing through the transfer-flag path. Stop enabling ISO_ACT in INT_EN and clear unhandled interrupt flags explicitly. Signed-off-by: HiFiPhile --- src/portable/wch/dcd_ch32_usbhs.c | 282 ++++++++++++++++++++++---------------- 1 file changed, 163 insertions(+), 119 deletions(-) (limited to 'src') diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c index 01ff6eba3..cfe5e646f 100644 --- a/src/portable/wch/dcd_ch32_usbhs.c +++ b/src/portable/wch/dcd_ch32_usbhs.c @@ -24,7 +24,6 @@ * * This file is part of the TinyUSB stack. */ - #include "tusb_option.h" #if CFG_TUD_ENABLED && defined(TUP_USBIP_WCH_USBHS) && defined(CFG_TUD_WCH_USBIP_USBHS) && \ @@ -41,15 +40,10 @@ typedef struct { uint16_t total_len; uint16_t queued_len; uint16_t max_size; - bool is_last_packet; bool is_iso; + bool valid; } xfer_ctl_t; -typedef enum { - EP_RESPONSE_ACK, - EP_RESPONSE_NAK, -} ep_response_list_t; - #define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir] static xfer_ctl_t xfer_status[EP_MAX][2]; @@ -63,73 +57,127 @@ static xfer_ctl_t xfer_status[EP_MAX][2]; /* Endpoint Buffer */ TU_ATTR_ALIGNED(4) static uint8_t ep0_buffer[CFG_TUD_ENDPOINT0_SIZE]; +static bool ep0_tog; +static bool ep_data_tog[EP_MAX][2]; -static void ep_set_response_and_toggle(uint8_t ep_num, tusb_dir_t ep_dir, ep_response_list_t response_type) { +static void set_ep_toggle(uint8_t ep_num, tusb_dir_t ep_dir, bool data1) { if (ep_dir == TUSB_DIR_IN) { - uint8_t response = (response_type == EP_RESPONSE_ACK) ? USBHS_EP_T_RES_ACK : USBHS_EP_T_RES_NAK; - if (ep_num == 0) { - if (response_type == EP_RESPONSE_ACK) { - if (EP_TX_LEN(ep_num) == 0) { - EP_TX_CTRL(ep_num) |= USBHS_EP_T_TOG_1; - } else { - EP_TX_CTRL(ep_num) ^= USBHS_EP_T_TOG_1; - } - } - } - if (xfer_status[ep_num][TUSB_DIR_IN].is_iso == true) { - EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG; - } else { - EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | response; - } + EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_TOG_MASK)) | + (data1 ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0); } else { - uint8_t response = (response_type == EP_RESPONSE_ACK) ? USBHS_EP_R_RES_ACK : USBHS_EP_R_RES_NAK; - if (ep_num == 0) { - if (response_type == EP_RESPONSE_ACK) { - if (xfer_status[ep_num][TUSB_DIR_OUT].queued_len == 0) { - EP_RX_CTRL(ep_num) |= USBHS_EP_R_TOG_1; - } - } else { - EP_RX_CTRL(ep_num) ^= USBHS_EP_R_TOG_1; - } - } - EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_RES_MASK)) | response; + EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_TOG_MASK)) | + (data1 ? USBHS_EP_R_TOG_1 : USBHS_EP_R_TOG_0); } } -static void xfer_data_packet(uint8_t ep_num, tusb_dir_t ep_dir, xfer_ctl_t *xfer) { - if (ep_dir == TUSB_DIR_IN) { - uint16_t remaining = xfer->total_len - xfer->queued_len; - uint16_t next_tx_size = TU_MIN(remaining, xfer->max_size); +static void queue_in_packet(uint8_t ep_num, xfer_ctl_t* xfer) { + uint16_t remaining = xfer->total_len - xfer->queued_len; + uint16_t tx_len = TU_MIN(remaining, xfer->max_size); - if (ep_num == 0) { - memcpy(ep0_buffer, &xfer->buffer[xfer->queued_len], next_tx_size); - } else { - EP_TX_DMA_ADDR(ep_num) = (uint32_t)&xfer->buffer[xfer->queued_len]; - } + if (ep_num == 0) { + memcpy(ep0_buffer, &xfer->buffer[xfer->queued_len], tx_len); + } else { + EP_TX_DMA_ADDR(ep_num) = (uint32_t) &xfer->buffer[xfer->queued_len]; + } - EP_TX_LEN(ep_num) = next_tx_size; - xfer->queued_len += next_tx_size; - if (xfer->queued_len == xfer->total_len) { - xfer->is_last_packet = true; - } - if (xfer->is_iso == true) { - /* Enable EP to generate ISA_ACT interrupt */ - USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num); - } - } else { /* TUSB_DIR_OUT */ - uint16_t left_to_receive = xfer->total_len - xfer->queued_len; - uint16_t max_possible_rx_size = TU_MIN(xfer->max_size, left_to_receive); + EP_TX_LEN(ep_num) = tx_len; + xfer->queued_len += tx_len; + + if (ep_num == 0) { + EP_TX_CTRL(0) = USBHS_EP_T_RES_ACK | (ep0_tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0); + ep0_tog = !ep0_tog; + } else if (xfer->is_iso) { + EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_NYET; + } else { + set_ep_toggle(ep_num, TUSB_DIR_IN, ep_data_tog[ep_num][TUSB_DIR_IN]); + EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_ACK; + } +} - if (max_possible_rx_size == left_to_receive) { - xfer->is_last_packet = true; +static void queue_out_packet(uint8_t ep_num, xfer_ctl_t* xfer) { + uint16_t remaining = xfer->total_len - xfer->queued_len; + uint16_t rx_len = TU_MIN(remaining, xfer->max_size); + + if (ep_num > 0) { + EP_RX_DMA_ADDR(ep_num) = (uint32_t) &xfer->buffer[xfer->queued_len]; + EP_RX_MAX_LEN(ep_num) = rx_len; + } + + if (ep_num == 0) { + EP_RX_CTRL(0) = (EP_RX_CTRL(0) & ~(USBHS_EP_R_RES_MASK)) | USBHS_EP_R_RES_ACK; + } else if (xfer->is_iso) { + EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_RES_MASK)) | USBHS_EP_R_RES_NYET; + } else { + set_ep_toggle(ep_num, TUSB_DIR_OUT, ep_data_tog[ep_num][TUSB_DIR_OUT]); + EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_RES_MASK)) | USBHS_EP_R_RES_ACK; + } +} + +static void update_in(uint8_t rhport, uint8_t ep_num, bool force) { + xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, TUSB_DIR_IN); + if (!xfer->valid) { + return; + } + + if (!force && ep_num != 0 && !xfer->is_iso) { + ep_data_tog[ep_num][TUSB_DIR_IN] = !ep_data_tog[ep_num][TUSB_DIR_IN]; + } + + if (ep_num == 0) { + EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | (ep0_tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0); + } else if (!xfer->is_iso) { + EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_NAK; + } + + if (force || (xfer->total_len > xfer->queued_len)) { + queue_in_packet(ep_num, xfer); + } else { + xfer->valid = false; + if (ep_num != 0) { + EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_NAK; } + dcd_event_xfer_complete(rhport, ep_num | TUSB_DIR_IN_MASK, xfer->queued_len, XFER_RESULT_SUCCESS, true); + } +} + +static void update_out(uint8_t rhport, uint8_t ep_num, uint16_t rx_len) { + xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, TUSB_DIR_OUT); + if (!xfer->valid) { + return; + } + + if (ep_num == 0) { + EP_RX_CTRL(0) = (EP_RX_CTRL(0) & ~(USBHS_EP_R_RES_MASK)) | USBHS_EP_R_RES_NAK; + } else if (!xfer->is_iso) { + EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_RES_MASK)) | USBHS_EP_R_RES_NAK; + } - if (ep_num > 0) { - EP_RX_DMA_ADDR(ep_num) = (uint32_t)&xfer->buffer[xfer->queued_len]; - EP_RX_MAX_LEN(ep_num) = max_possible_rx_size; + uint16_t remaining = xfer->total_len - xfer->queued_len; + uint16_t len = TU_MIN(rx_len, TU_MIN(remaining, xfer->max_size)); + + if (ep_num == 0) { + memcpy(&xfer->buffer[xfer->queued_len], ep0_buffer, len); + } + + xfer->queued_len += len; + + if (ep_num != 0 && !xfer->is_iso) { + ep_data_tog[ep_num][TUSB_DIR_OUT] = !ep_data_tog[ep_num][TUSB_DIR_OUT]; + } + + if ((xfer->queued_len == xfer->total_len) || (len < xfer->max_size)) { + xfer->valid = false; + dcd_event_xfer_complete(rhport, ep_num, xfer->queued_len, XFER_RESULT_SUCCESS, true); + } + + if (ep_num != 0) { + if (xfer->valid) { + queue_out_packet(ep_num, xfer); + } else { + uint8_t rx_res = xfer->is_iso ? USBHS_EP_R_RES_NYET : USBHS_EP_R_RES_NAK; + EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_RES_MASK)) | rx_res; } } - ep_set_response_and_toggle(ep_num, ep_dir, USBHS_EP_R_RES_ACK); } bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { @@ -137,6 +185,8 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { (void)rh_init; memset(&xfer_status, 0, sizeof(xfer_status)); + memset(ep_data_tog, 0, sizeof(ep_data_tog)); + ep0_tog = true; USBHSD->HOST_CTRL = 0x00; USBHSD->HOST_CTRL = USBHS_PHY_SUSPENDM; @@ -151,7 +201,7 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { #endif USBHSD->INT_EN = 0; - USBHSD->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_BUS_RST_EN | USBHS_SUSPEND_EN | USBHS_ISO_ACT_EN; + USBHSD->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_BUS_RST_EN | USBHS_SUSPEND_EN; USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN; USBHSD->ENDP_TYPE = 0x00; @@ -159,8 +209,8 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { for (int ep = 0; ep < EP_MAX; ep++) { EP_TX_LEN(ep) = 0; - EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK; - EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; + EP_TX_CTRL(ep) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; + EP_RX_CTRL(ep) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0; EP_RX_MAX_LEN(ep) = 0; } @@ -189,10 +239,12 @@ void dcd_int_disable(uint8_t rhport) { void dcd_edpt_close_all(uint8_t rhport) { (void)rhport; + memset(ep_data_tog, 0, sizeof(ep_data_tog)); + for (size_t ep = 1; ep < EP_MAX; ep++) { EP_TX_LEN(ep) = 0; - EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK; - EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; + EP_TX_CTRL(ep) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; + EP_RX_CTRL(ep) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0; EP_RX_MAX_LEN(ep) = 0; } @@ -222,14 +274,10 @@ void dcd_sof_enable(uint8_t rhport, bool en) { void dcd_edpt0_status_complete(uint8_t rhport, const tusb_control_request_t *request) { (void)rhport; - if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) { USBHSD->DEV_AD = (uint8_t)request->wValue; } - - EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; - EP_RX_CTRL(0) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0; } bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_edpt) { @@ -246,11 +294,12 @@ bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_edpt) { xfer_ctl_t *xfer = XFER_CTL_BASE(ep_num, dir); xfer->max_size = tu_edpt_packet_size(desc_edpt); + ep_data_tog[ep_num][dir] = false; xfer->is_iso = (desc_edpt->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS); if (dir == TUSB_DIR_OUT) { USBHSD->ENDP_CONFIG |= (USBHS_EP0_R_EN << ep_num); - EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; + EP_RX_CTRL(ep_num) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0; if (xfer->is_iso == true) { USBHSD->ENDP_TYPE |= (USBHS_EP0_R_TYP << ep_num); } @@ -258,12 +307,10 @@ bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_edpt) { } else { if (xfer->is_iso == true) { USBHSD->ENDP_TYPE |= (USBHS_EP0_T_TYP << ep_num); - } else { - /* Enable all types except Isochronous to avoid ISO_ACT interrupt generation */ - USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num); } + USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num); EP_TX_LEN(ep_num) = 0; - EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; + EP_TX_CTRL(ep_num) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; } return true; @@ -276,13 +323,15 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { const tusb_dir_t dir = tu_edpt_dir(ep_addr); if (dir == TUSB_DIR_OUT) { - EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; + EP_RX_CTRL(ep_num) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0; EP_RX_MAX_LEN(ep_num) = 0; + ep_data_tog[ep_num][TUSB_DIR_OUT] = false; USBHSD->ENDP_TYPE &= ~(USBHS_EP0_R_TYP << ep_num); USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_R_EN << ep_num); } else { // TUSB_DIR_IN - EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; + EP_TX_CTRL(ep_num) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; EP_TX_LEN(ep_num) = 0; + ep_data_tog[ep_num][TUSB_DIR_IN] = false; USBHSD->ENDP_TYPE &= ~(USBHS_EP0_T_TYP << ep_num); USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_T_EN << ep_num); } @@ -324,9 +373,11 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { const tusb_dir_t dir = tu_edpt_dir(ep_addr); if (dir == TUSB_DIR_OUT) { - EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; + EP_RX_CTRL(ep_num) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0; + ep_data_tog[ep_num][TUSB_DIR_OUT] = false; } else { - EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_R_RES_NAK; + EP_TX_CTRL(ep_num) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; + ep_data_tog[ep_num][TUSB_DIR_IN] = false; } } @@ -340,9 +391,21 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to xfer->buffer = buffer; xfer->total_len = total_bytes; xfer->queued_len = 0; - xfer->is_last_packet = false; + xfer->valid = true; + + if (ep_num == 0 && dir == TUSB_DIR_OUT) { + if (total_bytes == 0) { + EP_RX_CTRL(0) = (EP_RX_CTRL(0) & ~(USBHS_EP_R_TOG_MASK)) | USBHS_EP_R_TOG_1; + } else { + EP_RX_CTRL(0) ^= USBHS_EP_R_TOG_1; + } + } - xfer_data_packet(ep_num, dir, xfer); + if (dir == TUSB_DIR_IN) { + update_in(rhport, ep_num, true); + } else { + queue_out_packet(ep_num, xfer); + } return true; } @@ -353,51 +416,27 @@ void dcd_int_handler(uint8_t rhport) { uint8_t int_flag = USBHSD->INT_FG; uint8_t int_status = USBHSD->INT_ST; - if (int_flag & (USBHS_ISO_ACT_FLAG | USBHS_TRANSFER_FLAG)) { + if (int_flag & USBHS_TRANSFER_FLAG) { const uint8_t token = int_status & MASK_UIS_TOKEN; + const uint8_t ep_num = int_status & MASK_UIS_ENDP; + const uint16_t len = USBHSD->RX_LEN; if (token == USBHS_TOKEN_PID_SOF) { uint32_t frame_count = USBHSD->FRAME_NO & USBHS_FRAME_NO_NUM_MASK; dcd_event_sof(rhport, frame_count, true); - } else { - const uint8_t ep_num = int_status & MASK_UIS_ENDP; - const tusb_dir_t ep_dir = (token == USBHS_TOKEN_PID_IN) ? TUSB_DIR_IN : TUSB_DIR_OUT; - const uint8_t ep_addr = tu_edpt_addr(ep_num, ep_dir); - xfer_ctl_t *xfer = XFER_CTL_BASE(ep_num, ep_dir); - - if (token == USBHS_TOKEN_PID_OUT) { - uint16_t rx_len = USBHSD->RX_LEN; - - if (ep_num == 0) { - memcpy(&xfer->buffer[xfer->queued_len], ep0_buffer, rx_len); - } - - xfer->queued_len += rx_len; - if (rx_len < xfer->max_size) { - xfer->is_last_packet = true; - } - } else if (token == USBHS_TOKEN_PID_IN) { - if (xfer->is_iso && xfer->is_last_packet) { - /* Disable EP to avoid ISO_ACT interrupt generation */ - USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_T_EN << ep_num); - } else { - // Do nothing, no need to update xfer->is_last_packet, it is already updated in xfer_data_packet - } - } - - if (xfer->is_last_packet == true) { - ep_set_response_and_toggle(ep_num, ep_dir, EP_RESPONSE_NAK); - dcd_event_xfer_complete(0, ep_addr, xfer->queued_len, XFER_RESULT_SUCCESS, true); - } else { - /* prepare next part of packet to xref */ - xfer_data_packet(ep_num, ep_dir, xfer); - } + } else if (token == USBHS_TOKEN_PID_OUT) { + update_out(rhport, ep_num, len); + } else if (token == USBHS_TOKEN_PID_IN) { + update_in(rhport, ep_num, false); } - - USBHSD->INT_FG = (int_flag & (USBHS_ISO_ACT_FLAG | USBHS_TRANSFER_FLAG)); /* Clear flag */ + USBHSD->INT_FG = (int_flag & USBHS_TRANSFER_FLAG); /* Clear flag */ } else if (int_flag & USBHS_SETUP_FLAG) { - ep_set_response_and_toggle(0, TUSB_DIR_IN, EP_RESPONSE_NAK); - ep_set_response_and_toggle(0, TUSB_DIR_OUT, EP_RESPONSE_NAK); + tusb_control_request_t const* setup = + (tusb_control_request_t const*) ep0_buffer; + ep0_tog = true; + EP_RX_CTRL(0) = (setup->wLength == 0) ? USBHS_EP_R_RES_ACK : USBHS_EP_R_RES_NAK; + EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK; + dcd_event_setup_received(0, ep0_buffer, true); USBHSD->INT_FG = USBHS_SETUP_FLAG; /* Clear flag */ @@ -424,6 +463,8 @@ void dcd_int_handler(uint8_t rhport) { dcd_event_bus_reset(0, TUSB_SPEED_HIGH, true); USBHSD->DEV_AD = 0; + memset(ep_data_tog, 0, sizeof(ep_data_tog)); + ep0_tog = true; EP_RX_CTRL(0) = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0; EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; @@ -433,6 +474,9 @@ void dcd_int_handler(uint8_t rhport) { dcd_event_handler(&event, true); USBHSD->INT_FG = USBHS_SUSPEND_FLAG; /* Clear flag */ + } else { + // Unhandled interrupt + USBHSD->INT_FG = int_flag; /* Clear all flags */ } } #endif -- cgit v1.3.1 From 311fb46eb2f963254af6ab206b74828a0ba0273c Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 23 May 2026 20:06:50 +0200 Subject: dcd/ch32x: optmize CTRL reg writing, basically revert e14b0e85 Signed-off-by: HiFiPhile --- src/portable/wch/dcd_ch32_usbfs.c | 26 +++++++++----------------- src/portable/wch/dcd_ch32_usbhs.c | 19 ++++++------------- 2 files changed, 15 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index ca3ce7ba8..af0f17785 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -66,13 +66,6 @@ static struct { static void update_in(uint8_t rhport, uint8_t ep, bool force) { struct usb_xfer *xfer = &data.xfer[ep][TUSB_DIR_IN]; if (xfer->valid) { - // Set EP to NAK to avoid spurious tramsfer - if (ep == 0) { - EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK | (data.ep0_tog ? USBFS_EP_T_TOG : 0); - } else if (!data.isochronous[ep]) { - EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NAK; - } - if (force || xfer->len) { size_t len = TU_MIN(xfer->max_size, xfer->len); if (ep == 0) { @@ -96,8 +89,12 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force) { EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_ACK; } } else { - xfer->valid = false; - EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NAK; + xfer->valid = false; + if (ep == 0) { + EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK | (data.ep0_tog ? USBFS_EP_T_TOG : 0); + } else if (!data.isochronous[ep]) { + EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NAK; + } dcd_event_xfer_complete(rhport, ep | TUSB_DIR_IN_MASK, xfer->processed_len, XFER_RESULT_SUCCESS, true); } } @@ -106,13 +103,6 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force) { static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { struct usb_xfer *xfer = &data.xfer[ep][TUSB_DIR_OUT]; if (xfer->valid) { - // Set EP to NAK to avoid spurious tramsfer - if (ep == 0) { - EP_RX_CTRL(0) = USBFS_EP_R_RES_NAK; - } else if (!data.isochronous[ep]) { - EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | USBFS_EP_R_RES_NAK; - } - size_t len = TU_MIN(xfer->max_size, TU_MIN(xfer->len, rx_len)); if (ep == 3) { memcpy(xfer->buffer, data.ep3_buffer.out, len); @@ -128,7 +118,9 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { dcd_event_xfer_complete(rhport, ep, xfer->processed_len, XFER_RESULT_SUCCESS, true); } - if (ep != 0) { + if (ep == 0) { + EP_RX_CTRL(0) = USBFS_EP_R_RES_NAK; + } else { uint8_t rx_res = data.isochronous[ep] ? USBFS_EP_R_RES_NYET : (xfer->valid ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK); EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | rx_res; diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c index cfe5e646f..a6dd5bb79 100644 --- a/src/portable/wch/dcd_ch32_usbhs.c +++ b/src/portable/wch/dcd_ch32_usbhs.c @@ -123,17 +123,13 @@ static void update_in(uint8_t rhport, uint8_t ep_num, bool force) { ep_data_tog[ep_num][TUSB_DIR_IN] = !ep_data_tog[ep_num][TUSB_DIR_IN]; } - if (ep_num == 0) { - EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | (ep0_tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0); - } else if (!xfer->is_iso) { - EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_NAK; - } - if (force || (xfer->total_len > xfer->queued_len)) { queue_in_packet(ep_num, xfer); } else { xfer->valid = false; - if (ep_num != 0) { + if (ep_num == 0) { + EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | (ep0_tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0); + } else { EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_NAK; } dcd_event_xfer_complete(rhport, ep_num | TUSB_DIR_IN_MASK, xfer->queued_len, XFER_RESULT_SUCCESS, true); @@ -146,12 +142,6 @@ static void update_out(uint8_t rhport, uint8_t ep_num, uint16_t rx_len) { return; } - if (ep_num == 0) { - EP_RX_CTRL(0) = (EP_RX_CTRL(0) & ~(USBHS_EP_R_RES_MASK)) | USBHS_EP_R_RES_NAK; - } else if (!xfer->is_iso) { - EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_RES_MASK)) | USBHS_EP_R_RES_NAK; - } - uint16_t remaining = xfer->total_len - xfer->queued_len; uint16_t len = TU_MIN(rx_len, TU_MIN(remaining, xfer->max_size)); @@ -167,6 +157,9 @@ static void update_out(uint8_t rhport, uint8_t ep_num, uint16_t rx_len) { if ((xfer->queued_len == xfer->total_len) || (len < xfer->max_size)) { xfer->valid = false; + if (ep_num == 0) { + EP_RX_CTRL(0) = (EP_RX_CTRL(0) & ~(USBHS_EP_R_RES_MASK)) | USBHS_EP_R_RES_NAK; + } dcd_event_xfer_complete(rhport, ep_num, xfer->queued_len, XFER_RESULT_SUCCESS, true); } -- cgit v1.3.1