diff options
| author | alt-0191 <[email protected]> | 2026-02-27 01:30:39 +0800 |
|---|---|---|
| committer | alt-0191 <[email protected]> | 2026-03-18 15:23:28 +0800 |
| commit | 2e913256073a07a993b3d3cb9abe8e1db97686db (patch) | |
| tree | 3dee6fbc80c89ca8a3e80d46a21bcd491af91c28 | |
| parent | c3e5fcadadcbefcfb884f2bf6ef9af87ae9b581c (diff) | |
ch58x: fix build flags and driver bugs
| -rw-r--r-- | hw/bsp/ch58x/family.mk | 14 | ||||
| -rw-r--r-- | src/portable/wch/ch58x_usbfs_reg.h | 35 | ||||
| -rw-r--r-- | src/portable/wch/dcd_ch58x_usbfs.c | 70 | ||||
| -rw-r--r-- | src/portable/wch/hcd_ch58x_usbfs.c | 60 | ||||
| -rw-r--r-- | src/tusb_option.h | 6 |
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 |
