summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralt-0191 <[email protected]>2026-02-27 01:30:39 +0800
committeralt-0191 <[email protected]>2026-03-18 15:23:28 +0800
commit2e913256073a07a993b3d3cb9abe8e1db97686db (patch)
tree3dee6fbc80c89ca8a3e80d46a21bcd491af91c28
parentc3e5fcadadcbefcfb884f2bf6ef9af87ae9b581c (diff)
ch58x: fix build flags and driver bugs
-rw-r--r--hw/bsp/ch58x/family.mk14
-rw-r--r--src/portable/wch/ch58x_usbfs_reg.h35
-rw-r--r--src/portable/wch/dcd_ch58x_usbfs.c70
-rw-r--r--src/portable/wch/hcd_ch58x_usbfs.c60
-rw-r--r--src/tusb_option.h6
5 files changed, 95 insertions, 90 deletions
diff --git a/hw/bsp/ch58x/family.mk b/hw/bsp/ch58x/family.mk
index 566842f93..7b62af646 100644
--- a/hw/bsp/ch58x/family.mk
+++ b/hw/bsp/ch58x/family.mk
@@ -1,3 +1,9 @@
+# https://www.embecosm.com/resources/tool-chain-downloads/#riscv-stable
+#CROSS_COMPILE ?= riscv32-unknown-elf-
+
+# Toolchain from https://nucleisys.com/download.php
+#CROSS_COMPILE ?= riscv-nuclei-elf-
+
# Toolchain from https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack
CROSS_COMPILE ?= riscv-none-elf-
@@ -9,17 +15,21 @@ CPU_CORE ?= rv32imac-ilp32
CFLAGS += \
-flto \
- -msmall-data-limit=8 \
+ -msmall-data-limit=16 \
-mno-save-restore \
-fmessage-length=0 \
-fsigned-char \
-DCFG_TUSB_MCU=OPT_MCU_CH58X \
-DCFG_TUD_WCH_USBIP_USBFS=1 \
-DFREQ_SYS=60000000 \
+ -DDISK_LIB_ENABLE=0 \
+ -DINT_SOFT \
+
+CFLAGS += -Wno-error=strict-prototypes
LDFLAGS_GCC += \
-nostdlib -nostartfiles \
- --specs=nosys.specs --specs=nano.specs \
+ --specs=nosys.specs \
SRC_C += \
src/portable/wch/dcd_ch58x_usbfs.c \
diff --git a/src/portable/wch/ch58x_usbfs_reg.h b/src/portable/wch/ch58x_usbfs_reg.h
index 11479a4f6..868589729 100644
--- a/src/portable/wch/ch58x_usbfs_reg.h
+++ b/src/portable/wch/ch58x_usbfs_reg.h
@@ -55,30 +55,23 @@
#define CH58X_UEP567_MOD(base) (*(volatile uint8_t *)((base) + 0x0E))
//--------------------------------------------------------------------+
-// Endpoint DMA / T_LEN / CTRL offset lookup tables
-// EP0-EP4 are at low offsets, EP5-EP7 jump to higher offsets
-// EP4 shares DMA with EP0 (no independent DMA register)
+// Endpoint DMA / T_LEN / CTRL register accessors
+//
+// EP0-EP3 DMA : base + 0x10 + ep*4 (EP4 shares EP0 DMA, no own register)
+// EP5-EP7 DMA : base + 0x54 + (ep-5)*4
+// EP0-EP4 TLEN: base + 0x20 + ep*4
+// EP5-EP7 TLEN: base + 0x64 + (ep-5)*4
+// EP0-EP4 CTRL: base + 0x22 + ep*4
+// EP5-EP7 CTRL: base + 0x66 + (ep-5)*4
+//
+// Using computed addresses avoids per-TU copies of static lookup tables.
+// EP4 DMA is not accessed directly (it shares EP0's DMA register).
//--------------------------------------------------------------------+
-static const uint8_t ch58x_ep_dma_offset[] = {
- 0x10, 0x14, 0x18, 0x1C, /* EP0, EP1, EP2, EP3 */
- 0xFF, /* EP4: shares with EP0, sentinel */
- 0x54, 0x58, 0x5C /* EP5, EP6, EP7 */
-};
-
-static const uint8_t ch58x_ep_tlen_offset[] = {
- 0x20, 0x24, 0x28, 0x2C, 0x30, /* EP0-EP4 */
- 0x64, 0x68, 0x6C /* EP5-EP7 */
-};
-
-static const uint8_t ch58x_ep_ctrl_offset[] = {
- 0x22, 0x26, 0x2A, 0x2E, 0x32, /* EP0-EP4 */
- 0x66, 0x6A, 0x6E /* EP5-EP7 */
-};
// EP DMA is 16-bit (only low 16 bits of RAM address, high bits implied 0x2000)
-#define CH58X_EP_DMA(base, ep) (*(volatile uint16_t *)((base) + ch58x_ep_dma_offset[ep]))
-#define CH58X_EP_TLEN(base, ep) (*(volatile uint8_t *)((base) + ch58x_ep_tlen_offset[ep]))
-#define CH58X_EP_CTRL(base, ep) (*(volatile uint8_t *)((base) + ch58x_ep_ctrl_offset[ep]))
+#define CH58X_EP_DMA(base, ep) (*(volatile uint16_t *)((base) + ((ep) <= 3 ? (0x10u + (ep)*4u) : (0x54u + ((ep)-5u)*4u))))
+#define CH58X_EP_TLEN(base, ep) (*(volatile uint8_t *)((base) + ((ep) <= 4 ? (0x20u + (ep)*4u) : (0x64u + ((ep)-5u)*4u))))
+#define CH58X_EP_CTRL(base, ep) (*(volatile uint8_t *)((base) + ((ep) <= 4 ? (0x22u + (ep)*4u) : (0x66u + ((ep)-5u)*4u))))
//--------------------------------------------------------------------+
// USB_CTRL (R8_USB_CTRL) bit definitions
diff --git a/src/portable/wch/dcd_ch58x_usbfs.c b/src/portable/wch/dcd_ch58x_usbfs.c
index 11ff2c7b1..ea4a5ac4a 100644
--- a/src/portable/wch/dcd_ch58x_usbfs.c
+++ b/src/portable/wch/dcd_ch58x_usbfs.c
@@ -165,16 +165,16 @@ static uint8_t* ep_dma_buffer(dcd_data_t* d, uint8_t ep) {
}
//--------------------------------------------------------------------+
-// EP has auto-toggle support?
+// AUTO_TOG supported on EP1/2/3/5/6/7 (no EP0 or EP4)
//--------------------------------------------------------------------+
static inline bool ep_has_auto_toggle(uint8_t ep) {
- return (ep >= 1 && ep <= 3);
+ return (ep >= 1 && ep <= 3) || (ep >= 5 && ep <= 7);
}
//--------------------------------------------------------------------+
// Private transfer helpers
//--------------------------------------------------------------------+
-static void update_in(uint8_t rhport, uint8_t ep, bool force) {
+static void update_in(uint8_t rhport, uint8_t ep, bool force, bool in_isr) {
dcd_data_t* d = &_dcd_data[rhport];
uint32_t base = d->usb_base;
struct usb_xfer* xfer = &d->xfer[ep][TUSB_DIR_IN];
@@ -213,12 +213,12 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force) {
xfer->valid = false;
ep_set_tx_response(base, ep, CH58X_EP_T_RES_NAK);
dcd_event_xfer_complete(rhport, ep | TUSB_DIR_IN_MASK,
- xfer->processed_len, XFER_RESULT_SUCCESS, true);
+ xfer->processed_len, XFER_RESULT_SUCCESS, in_isr);
}
}
}
-static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) {
+static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len, bool in_isr) {
dcd_data_t* d = &_dcd_data[rhport];
uint32_t base = d->usb_base;
struct usb_xfer* xfer = &d->xfer[ep][TUSB_DIR_OUT];
@@ -239,7 +239,7 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) {
if (xfer->len == 0 || len < xfer->max_size) {
xfer->valid = false;
dcd_event_xfer_complete(rhport, ep, xfer->processed_len,
- XFER_RESULT_SUCCESS, true);
+ XFER_RESULT_SUCCESS, in_isr);
}
if (ep == 0) {
@@ -297,11 +297,11 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
EP_TLEN(base, 4) = 0;
EP_CTRL(base, 4) = CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK;
- // EP5-7: DMA + no auto-toggle
+ // EP5-7: DMA + auto-toggle
for (uint8_t ep = 5; ep <= 7; ep++) {
EP_DMA(base, ep) = (uint16_t)(uint32_t) ep_dma_buffer(d, ep);
EP_TLEN(base, ep) = 0;
- EP_CTRL(base, ep) = CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK;
+ EP_CTRL(base, ep) = CH58X_EP_AUTO_TOG | CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK;
}
// Set EP0 max size
@@ -325,18 +325,27 @@ void dcd_int_handler(uint8_t rhport) {
// Check SETUP first via dedicated flag
if (int_st & CH58X_UIS_SETUP_ACT) {
// SETUP packet received on EP0
- ep_set_both_response(base, 0, CH58X_EP_T_RES_NAK, CH58X_EP_R_RES_ACK);
+ // After SETUP, both toggle bits must be set to DATA1 (SDK reference)
+ EP_CTRL(base, 0) = CH58X_EP_R_TOG | CH58X_EP_T_TOG |
+ CH58X_EP_R_RES_ACK | CH58X_EP_T_RES_NAK;
d->ep0_tog = true;
dcd_event_setup_received(rhport, ep_out_buffer(d, 0), true);
} else {
switch (token) {
case CH58X_PID_OUT: {
uint8_t rx_len = USB_RX_LEN(base);
- if (!ep_has_auto_toggle(ep) && ep != 0) {
- // Manual toggle for EP4-7
- EP_CTRL(base, ep) ^= CH58X_EP_R_TOG;
+ if (ep == 0) {
+ // EP0: always process (toggle managed via SETUP reset)
+ update_out(rhport, 0, rx_len, true);
+ } else if (int_st & CH58X_UIS_TOG_OK) {
+ // Toggle matched: data is valid
+ if (!ep_has_auto_toggle(ep)) {
+ // EP4: manual toggle
+ EP_CTRL(base, ep) ^= CH58X_EP_R_TOG;
+ }
+ update_out(rhport, ep, rx_len, true);
}
- update_out(rhport, ep, rx_len);
+ // else: toggle mismatch, discard packet per datasheet
break;
}
@@ -345,7 +354,7 @@ void dcd_int_handler(uint8_t rhport) {
// Manual toggle for EP4-7
EP_CTRL(base, ep) ^= CH58X_EP_T_TOG;
}
- update_in(rhport, ep, false);
+ update_in(rhport, ep, false, true);
break;
}
@@ -370,19 +379,14 @@ void dcd_int_handler(uint8_t rhport) {
USB_INT_FG(base) = CH58X_UIF_BUS_RST;
} else if (status & CH58X_UIF_SUSPEND) {
- if (USB_MIS_ST(base) & CH58X_UMS_SUSPEND) {
- dcd_event_t event = {.rhport = rhport, .event_id = DCD_EVENT_SUSPEND};
- dcd_event_handler(&event, true);
- } else {
- dcd_event_t event = {.rhport = rhport, .event_id = DCD_EVENT_RESUME};
- dcd_event_handler(&event, true);
- }
+ dcd_event_bus_signal(rhport,
+ (USB_MIS_ST(base) & CH58X_UMS_SUSPEND) ? DCD_EVENT_SUSPEND : DCD_EVENT_RESUME,
+ true);
USB_INT_FG(base) = CH58X_UIF_SUSPEND;
}
}
void dcd_int_enable(uint8_t rhport) {
- (void) rhport;
// PFIC enable: USB_IRQn=22, USB2_IRQn=23
volatile uint32_t* pfic_ienr = (volatile uint32_t*) 0xE000E100;
uint8_t irqn = (rhport == 0) ? 22 : 23;
@@ -390,7 +394,6 @@ void dcd_int_enable(uint8_t rhport) {
}
void dcd_int_disable(uint8_t rhport) {
- (void) rhport;
volatile uint32_t* pfic_irer = (volatile uint32_t*) 0xE000E180;
uint8_t irqn = (rhport == 0) ? 22 : 23;
pfic_irer[irqn / 32] = (1u << (irqn % 32));
@@ -406,7 +409,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
void dcd_remote_wakeup(uint8_t rhport) {
uint32_t base = get_usb_base(rhport);
USB_UDEV_CTRL(base) |= CH58X_UD_GP_BIT;
- for (volatile int i = 0; i < 60000; i++) { } // ~1ms resume signal
+ tusb_time_delay_ms_api(1); // 1ms resume signal per USB spec
USB_UDEV_CTRL(base) &= ~CH58X_UD_GP_BIT;
}
@@ -421,12 +424,10 @@ void dcd_disconnect(uint8_t rhport) {
}
void dcd_sof_enable(uint8_t rhport, bool en) {
- uint32_t base = get_usb_base(rhport);
- if (en) {
- USB_INT_EN(base) |= CH58X_UIE_HST_SOF;
- } else {
- USB_INT_EN(base) &= ~CH58X_UIE_HST_SOF;
- }
+ // CH58x has no device-mode SOF interrupt.
+ // RB_UIE_HST_SOF (0x08) is host-mode only and has no effect in device mode.
+ (void) rhport;
+ (void) en;
}
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) {
@@ -436,7 +437,9 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* req
if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
request->bRequest == TUSB_REQ_SET_ADDRESS) {
- USB_DEV_AD(base) = (uint8_t) request->wValue;
+ // Preserve GP_BIT (bit7) when setting device address
+ USB_DEV_AD(base) = (USB_DEV_AD(base) & CH58X_UDA_GP_BIT) |
+ ((uint8_t)request->wValue & CH58X_USB_ADDR_MASK);
}
ep_set_both_response(base, 0, CH58X_EP_T_RES_NAK, CH58X_EP_R_RES_ACK);
}
@@ -505,7 +508,6 @@ bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t* desc_ep)
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer,
uint16_t total_bytes, bool is_isr) {
- (void) is_isr;
uint8_t ep = tu_edpt_number(ep_addr);
uint8_t dir = tu_edpt_dir(ep_addr);
@@ -517,10 +519,9 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer,
xfer->buffer = buffer;
xfer->len = total_bytes;
xfer->processed_len = 0;
- dcd_int_enable(rhport);
if (dir == TUSB_DIR_IN) {
- update_in(rhport, ep, true);
+ update_in(rhport, ep, true, is_isr);
} else {
// For OUT direction, set endpoint to ACK to start receiving data
if (ep != 0) {
@@ -531,6 +532,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer,
}
}
}
+ dcd_int_enable(rhport);
return true;
}
diff --git a/src/portable/wch/hcd_ch58x_usbfs.c b/src/portable/wch/hcd_ch58x_usbfs.c
index 629c2a789..8a8da9f16 100644
--- a/src/portable/wch/hcd_ch58x_usbfs.c
+++ b/src/portable/wch/hcd_ch58x_usbfs.c
@@ -422,7 +422,13 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const*
dev_addr, ep_addr, max_packet_size, xfer_type);
// Wait for any pending transfer
- while (_current_xfer.is_busy) {}
+ uint32_t t0 = tusb_time_millis_api();
+ while (_current_xfer.is_busy) {
+ if (tusb_time_millis_api() - t0 > 200) {
+ _current_xfer.is_busy = false;
+ break;
+ }
+ }
if (ep_num == 0) {
TU_ASSERT(_get_or_add_edpt(dev_addr, 0x00, max_packet_size, xfer_type) != NULL, false);
@@ -447,8 +453,14 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr,
LOG_CH58X_HCD("hcd_edpt_xfer(dev=0x%02x, ep=0x%02x, len=%d)\r\n",
dev_addr, ep_addr, buflen);
- // Wait for any pending transfer
- while (_current_xfer.is_busy) {}
+ // Wait for any pending transfer (with 200ms timeout to avoid deadlock on disconnect)
+ uint32_t t0 = tusb_time_millis_api();
+ while (_current_xfer.is_busy) {
+ if (tusb_time_millis_api() - t0 > 200) {
+ _current_xfer.is_busy = false;
+ return false;
+ }
+ }
_current_xfer.is_busy = true;
hcd_edpt_t* edpt = _get_edpt(dev_addr, ep_addr);
@@ -490,7 +502,13 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
LOG_CH58X_HCD("hcd_setup_send(dev=0x%02x)\r\n", dev_addr);
// Wait for any pending transfer
- while (_current_xfer.is_busy) {}
+ uint32_t t0 = tusb_time_millis_api();
+ while (_current_xfer.is_busy) {
+ if (tusb_time_millis_api() - t0 > 200) {
+ _current_xfer.is_busy = false;
+ return false;
+ }
+ }
_current_xfer.is_busy = true;
_hw_set_addr_speed(rhport, dev_addr);
@@ -522,33 +540,12 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
}
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
- uint32_t base = _port_data[rhport].usb_base;
- uint8_t ep_num = tu_edpt_number(ep_addr);
+ (void) rhport;
LOG_CH58X_HCD("hcd_edpt_clear_stall(dev=0x%02x, ep=0x%02x)\r\n", dev_addr, ep_addr);
-
- // Send CLEAR_FEATURE(ENDPOINT_HALT) via blocking transfer
- uint8_t setup[8] = {
- 0x02, 0x01, 0x00, 0x00, ep_addr, 0x00, 0x00, 0x00
- };
- memcpy(_tx_buf[rhport], setup, 8);
- CH58X_UH_TX_LEN(base) = 8;
-
- bool prev_int = _port_data[rhport].int_enabled;
- hcd_int_disable(rhport);
-
- CH58X_UH_EP_PID(base) = (CH58X_USB_PID_SETUP << 4) | 0x00;
- CH58X_USB_INT_FG(base) = CH58X_UIF_TRANSFER;
- while ((CH58X_USB_INT_FG(base) & CH58X_UIF_TRANSFER) == 0) {}
- CH58X_UH_EP_PID(base) = 0;
-
- uint8_t response = CH58X_USB_INT_ST(base) & CH58X_UIS_H_RES_MASK;
- (void)response;
-
- LOG_CH58X_HCD("clear_stall response=0x%02x\r\n", response);
-
- if (prev_int) {
- hcd_int_enable(rhport);
+ hcd_edpt_t* edpt = _get_edpt(dev_addr, ep_addr);
+ if (edpt != NULL) {
+ edpt->data_toggle = 0;
}
return true;
@@ -570,6 +567,10 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
if (attached) {
hcd_event_device_attach(rhport, in_isr);
} else {
+ // Stop any ongoing hardware transfer before reporting removal
+ CH58X_UH_EP_PID(base) = 0x00;
+ _current_xfer.is_busy = false;
+ _current_xfer.nak_pending = false;
hcd_event_device_remove(rhport, in_isr);
}
return;
@@ -580,7 +581,6 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
// Read PID/endpoint before stopping (must read first!)
uint8_t pid_endp = CH58X_UH_EP_PID(base);
uint8_t int_st = CH58X_USB_INT_ST(base);
- uint8_t int_fg = CH58X_USB_INT_FG(base);
uint8_t dev_addr = CH58X_USB_DEV_AD(base) & CH58X_USB_ADDR_MASK;
// Stop USB transaction immediately (SDK: R8_UH_EP_PID = 0x00)
diff --git a/src/tusb_option.h b/src/tusb_option.h
index 699e3d44d..c75908e87 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -193,9 +193,9 @@
#define OPT_MCU_CH32F20X 2210 ///< WCH CH32F20x
#define OPT_MCU_CH32V20X 2220 ///< WCH CH32V20X
#define OPT_MCU_CH32V103 2230 ///< WCH CH32V103
-#define OPT_MCU_CH58X 2240 ///< WCH CH58x series (CH582/CH583)
-#define OPT_MCU_CH582 OPT_MCU_CH58X ///< alias
-#define OPT_MCU_CH583 OPT_MCU_CH58X ///< alias
+#define OPT_MCU_CH58X 2240 ///< WCH CH58x
+#define OPT_MCU_CH582 2240 ///< alias to CH58x series
+#define OPT_MCU_CH583 2240 ///< alias to CH58x series
// NXP LPC MCX
#define OPT_MCU_MCXN9 2300 ///< NXP MCX N9 Series