From c61dfc7c7a4744458b77caa4043af8b05a65fadc Mon Sep 17 00:00:00 2001 From: verylowfreq <60875431+verylowfreq@users.noreply.github.com> Date: Mon, 9 Sep 2024 18:04:00 +0900 Subject: [PATCH 01/10] Add ch32v20x usbfs hcd initial support. --- hw/bsp/ch32v20x/family.c | 3 + hw/bsp/ch32v20x/family.mk | 3 + src/portable/wch/hcd_ch32_usbfs.c | 618 ++++++++++++++++++++++++++++++ 3 files changed, 624 insertions(+) create mode 100644 src/portable/wch/hcd_ch32_usbfs.c diff --git a/hw/bsp/ch32v20x/family.c b/hw/bsp/ch32v20x/family.c index 5f52d9447..8a9ee6819 100644 --- a/hw/bsp/ch32v20x/family.c +++ b/hw/bsp/ch32v20x/family.c @@ -32,6 +32,9 @@ void USBHD_IRQHandler(void) { #if CFG_TUD_WCH_USBIP_USBFS tud_int_handler(0); #endif + #if CFG_TUH_WCH_USBIP_USBFS + tuh_int_handler(0); + #endif } __attribute__((interrupt)) __attribute__((used)) diff --git a/hw/bsp/ch32v20x/family.mk b/hw/bsp/ch32v20x/family.mk index 08761dc0d..16fc537ac 100644 --- a/hw/bsp/ch32v20x/family.mk +++ b/hw/bsp/ch32v20x/family.mk @@ -30,6 +30,8 @@ CFLAGS += -Wno-error=strict-prototypes ifeq ($(PORT),0) $(info "Using FSDEV driver") CFLAGS += -DCFG_TUD_WCH_USBIP_FSDEV=1 + $(info "Using USBFS Host driver") + CFLAGS += -DCFG_TUH_WCH_USBIP_USBFS=1 else $(info "Using USBFS driver") CFLAGS += -DCFG_TUD_WCH_USBIP_USBFS=1 @@ -43,6 +45,7 @@ LD_FILE = $(FAMILY_PATH)/linker/${CH32_FAMILY}.ld SRC_C += \ src/portable/wch/dcd_ch32_usbfs.c \ + src/portable/wch/hcd_ch32_usbfs.c \ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ $(SDK_SRC_DIR)/Core/core_riscv.c \ $(SDK_SRC_DIR)/Peripheral/src/${CH32_FAMILY}_gpio.c \ diff --git a/src/portable/wch/hcd_ch32_usbfs.c b/src/portable/wch/hcd_ch32_usbfs.c new file mode 100644 index 000000000..534edb22b --- /dev/null +++ b/src/portable/wch/hcd_ch32_usbfs.c @@ -0,0 +1,618 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Mitsumine Suzu (verylowfreq) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if CFG_TUH_ENABLED && defined(TUP_USBIP_WCH_USBFS) && CFG_TUH_WCH_USBIP_USBFS + +#include "host/hcd.h" +#include "host/usbh.h" +#include "host/usbh_pvt.h" + +#include "bsp/board_api.h" + +#include "ch32v20x.h" +#include "ch32v20x_usb.h" + + +#define USBFS_RX_BUF_LEN 64 +#define USBFS_TX_BUF_LEN 64 +__attribute__((aligned(4))) static uint8_t USBFS_RX_Buf[USBFS_RX_BUF_LEN]; +__attribute__((aligned(4))) static uint8_t USBFS_TX_Buf[USBFS_TX_BUF_LEN]; + +#define USB_XFER_TIMEOUT_MILLIS 500 + +#define PANIC(...) do { printf("\r\nPANIC: " __VA_ARGS__); while (true) { } } while (false) + +#define LOG_CH32_USBFSH(...) TU_LOG3(__VA_ARGS__) + +// Busywait for delay microseconds/nanoseconds +// static void loopdelay(uint32_t count) +// { +// volatile uint32_t c = count / 3; +// // while (c-- != 0); +// asm volatile( +// "1: \n" // loop label +// " addi %0, %0, -1 \n" // c-- +// " bne %0, zero, 1b \n" // if (c != 0) goto loop +// : "+r"(c) // c is input/output operand +// ); +// } + + +// Endpoint status +typedef struct usb_edpt +{ + // Is this a valid struct + bool configured; + + uint8_t dev_addr; + uint8_t ep_addr; + uint16_t max_packet_size; + + // Data toggle (0 or not 0) for DATA0/1 + uint8_t data_toggle; + + // Xfer started time in millis for timeout + uint32_t current_xfer_packet_start_millis; + uint8_t* current_xfer_buffer; + uint16_t current_xfer_bufferlen; + uint16_t current_xfer_xferred_len; + +} usb_edpt_t; + + +static usb_edpt_t usb_edpt_list[8] = { }; + + +static usb_edpt_t* get_edpt_record(uint8_t dev_addr, uint8_t ep_addr) +{ + for (size_t i = 0; i < TU_ARRAY_SIZE(usb_edpt_list); i++) + { + usb_edpt_t* cur = &usb_edpt_list[i]; + if (cur->configured && cur->dev_addr == dev_addr && cur->ep_addr == ep_addr) + { + return cur; + } + } + return NULL; +} + +static usb_edpt_t* get_empty_record_slot(void) +{ + for (size_t i = 0; i < TU_ARRAY_SIZE(usb_edpt_list); i++) + { + if (!usb_edpt_list[i].configured) + { + return &usb_edpt_list[i]; + } + } + return NULL; +} + +static usb_edpt_t* add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size) +{ + usb_edpt_t* slot = get_empty_record_slot(); + TU_ASSERT(slot != NULL, NULL); + + slot->dev_addr = dev_addr; + slot->ep_addr = ep_addr; + slot->max_packet_size = max_packet_size; + slot->data_toggle = 0; + slot->current_xfer_packet_start_millis = 0; + slot->current_xfer_buffer = NULL; + slot->current_xfer_bufferlen = 0; + slot->current_xfer_xferred_len = 0; + + slot->configured = true; + + return slot; +} + +static usb_edpt_t* get_or_add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size) +{ + usb_edpt_t* ret = get_edpt_record(dev_addr, ep_addr); + if (ret != NULL) + { + return ret; + } + else + { + return add_edpt_record(dev_addr, ep_addr, max_packet_size); + } +} + + +static void remove_edpt_record_for_device(uint8_t dev_addr) +{ + for (size_t i = 0; i < TU_ARRAY_SIZE(usb_edpt_list); i++) + { + if (usb_edpt_list[i].configured && usb_edpt_list[i].dev_addr == dev_addr) + { + usb_edpt_list[i].configured = false; + } + } +} + + +/** Enable or disable USBFS Host function */ +static void hardware_init_host(bool enabled) +{ + // Reset USBOTG module + USBOTG_H_FS->BASE_CTRL = USBFS_UC_RESET_SIE | USBFS_UC_CLR_ALL; + + osal_task_delay(1); + USBOTG_H_FS->BASE_CTRL = 0; + + if (!enabled) + { + // Disable all feature + USBOTG_H_FS->BASE_CTRL = 0; + } + else + { + // Enable USB Host features + NVIC_DisableIRQ(USBFS_IRQn); + USBOTG_H_FS->BASE_CTRL = USBFS_UC_HOST_MODE | USBFS_UC_INT_BUSY | USBFS_UC_DMA_EN; + USBOTG_H_FS->HOST_EP_MOD = USBFS_UH_EP_TX_EN | USBFS_UH_EP_RX_EN; + USBOTG_H_FS->HOST_RX_DMA = (uint32_t)USBFS_RX_Buf; + USBOTG_H_FS->HOST_TX_DMA = (uint32_t)USBFS_TX_Buf; + USBOTG_H_FS->INT_EN = USBFS_UIE_TRANSFER | USBFS_UIE_DETECT; + } +} + +static bool hardware_start_xfer(uint8_t pid, uint8_t ep_addr, uint8_t data_toggle) +{ + LOG_CH32_USBFSH("hardware_start_xfer(pid=%s(0x%02x), ep_addr=0x%02x, toggle=%d)\r\n", + pid == USB_PID_IN ? "IN" : pid == USB_PID_OUT ? "OUT" : pid == USB_PID_SETUP ? "SETUP" : "(other)", + pid, ep_addr, data_toggle); + + if (pid == USB_PID_IN) + { // FIXME: long delay needed (at release build) about 30msec + // loopdelay(SystemCoreClock / 1000 * 30); + } + + uint8_t pid_edpt = (pid << 4) | (tu_edpt_number(ep_addr) & 0x0f); + USBOTG_H_FS->HOST_TX_CTRL = (data_toggle != 0) ? USBFS_UH_T_TOG : 0; + USBOTG_H_FS->HOST_RX_CTRL = (data_toggle != 0) ? USBFS_UH_R_TOG : 0; + USBOTG_H_FS->HOST_EP_PID = pid_edpt; + USBOTG_H_FS->INT_FG = USBFS_UIF_TRANSFER; + return true; +} + + +/** Set device address to communicate */ +static void update_device_address(uint8_t dev_addr) +{ + // Keep the bit of GP_BIT. Other 7bits are actual device address. + USBOTG_H_FS->DEV_ADDR = (USBOTG_H_FS->DEV_ADDR & USBFS_UDA_GP_BIT) | (dev_addr & USBFS_USB_ADDR_MASK); +} + +/** Set port speed */ +static void update_port_speed(tusb_speed_t speed) +{ + LOG_CH32_USBFSH("update_port_speed(%s)\r\n", speed == TUSB_SPEED_FULL ? "Full" : speed == TUSB_SPEED_LOW ? "Low" : "(invalid)"); + switch (speed) { + case TUSB_SPEED_LOW: + USBOTG_H_FS->BASE_CTRL |= USBFS_UC_LOW_SPEED; + USBOTG_H_FS->HOST_CTRL |= USBFS_UH_LOW_SPEED; + USBOTG_H_FS->HOST_SETUP |= USBFS_UH_PRE_PID_EN; + return; + case TUSB_SPEED_FULL: + USBOTG_H_FS->BASE_CTRL &= ~USBFS_UC_LOW_SPEED; + USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_LOW_SPEED; + USBOTG_H_FS->HOST_SETUP &= ~USBFS_UH_PRE_PID_EN; + return; + default: + PANIC("update_port_speed(%d)\r\n", speed); + } +} + +static bool hardware_device_attached(void) +{ + return USBOTG_H_FS->MIS_ST & USBFS_UMS_DEV_ATTACH; +} + + +//--------------------------------------------------------------------+ +// HCD API +//--------------------------------------------------------------------+ +bool hcd_init(uint8_t rhport) +{ + (void)rhport; + hardware_init_host(true); + + return true; +} + +bool hcd_deinit(uint8_t rhport) +{ + (void)rhport; + hardware_init_host(false); + + return true; +} + +void hcd_port_reset(uint8_t rhport) +{ + (void)rhport; + LOG_CH32_USBFSH("hcd_port_reset()\r\n"); + NVIC_DisableIRQ(USBFS_IRQn); + update_device_address( 0x00 ); + + USBOTG_H_FS->HOST_CTRL |= USBFS_UH_BUS_RESET; + osal_task_delay(15); + USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_BUS_RESET; + osal_task_delay(2); + + if ((USBOTG_H_FS->HOST_CTRL & USBFS_UH_PORT_EN) == 0) + { + if (hcd_port_speed_get(0) == TUSB_SPEED_LOW) + { + update_port_speed(TUSB_SPEED_LOW); + } + } + + USBOTG_H_FS->HOST_CTRL |= USBFS_UH_PORT_EN; + USBOTG_H_FS->HOST_SETUP |= USBFS_UH_SOF_EN; + + return; +} + +void hcd_port_reset_end(uint8_t rhport) +{ + (void)rhport; + LOG_CH32_USBFSH("hcd_port_reset_end()\r\n"); + // Suppress the attached event + USBOTG_H_FS->INT_FG |= USBFS_UIF_DETECT; + NVIC_EnableIRQ(USBFS_IRQn); + + return; +} + +bool hcd_port_connect_status(uint8_t rhport) +{ + (void)rhport; + + return hardware_device_attached(); +} + +tusb_speed_t hcd_port_speed_get(uint8_t rhport) +{ + (void)rhport; + if (USBOTG_H_FS->MIS_ST & USBFS_UMS_DM_LEVEL) + { + return TUSB_SPEED_LOW; + } + else + { + return TUSB_SPEED_FULL; + } +} + +// Close all opened endpoint belong to this device +void hcd_device_close(uint8_t rhport, uint8_t dev_addr) +{ + (void)rhport; + LOG_CH32_USBFSH("hcd_device_close(%d, 0x%02x)\r\n", rhport, dev_addr); + remove_edpt_record_for_device(dev_addr); + + return; +} + +uint32_t hcd_frame_number(uint8_t rhport) +{ + (void)rhport; + + return board_millis(); +} + +void hcd_int_enable(uint8_t rhport) +{ + (void)rhport; + NVIC_EnableIRQ(USBFS_IRQn); + + return; +} + +void hcd_int_disable(uint8_t rhport) +{ + (void)rhport; + NVIC_DisableIRQ(USBFS_IRQn); + + return; +} + +void hcd_int_handler(uint8_t rhport, bool in_isr) +{ + (void)rhport; + (void)in_isr; + + if (USBOTG_H_FS->INT_FG & USBFS_UIF_DETECT) + { + // Clear the flag + USBOTG_H_FS->INT_FG = USBFS_UIF_DETECT; + // Read the detection state + bool attached = hardware_device_attached(); + LOG_CH32_USBFSH("hcd_int_handler() attached = %d\r\n", attached ? 1 : 0); + if (attached) + { + hcd_event_device_attach(rhport, true); + } + else + { + hcd_event_device_remove(rhport, true); + } + return; + } + + if (USBOTG_H_FS->INT_FG & USBFS_UIF_TRANSFER) + { + // Copy PID and Endpoint + uint8_t pid_edpt = USBOTG_H_FS->HOST_EP_PID; + uint8_t status = USBOTG_H_FS->INT_ST; + // Clear register to stop transfer + USBOTG_H_FS->HOST_EP_PID = 0; + // Clear the flag + USBOTG_H_FS->INT_FG = USBFS_UIF_TRANSFER; + + LOG_CH32_USBFSH("hcd_int_handler() pid_edpt=0x%02x\r\n", pid_edpt); + + uint8_t request_pid = pid_edpt >> 4; + uint8_t response_pid = USBOTG_H_FS->INT_ST & USBFS_UIS_H_RES_MASK; + uint8_t dev_addr = USBOTG_H_FS->DEV_ADDR; + uint8_t ep_addr = pid_edpt & 0x0f; + if (request_pid == USB_PID_IN) + { + ep_addr |= 0x80; + } + + usb_edpt_t* edpt_info = get_edpt_record(dev_addr, ep_addr); + if (edpt_info == NULL) + { + PANIC("\r\nget_edpt_record() returned NULL in USBHD_IRQHandler\r\n"); + } + + if (status & USBFS_UIS_TOG_OK) + { + edpt_info->data_toggle ^= 0x01; + + switch (request_pid) + { + case USB_PID_SETUP: + case USB_PID_OUT: + { + uint16_t xferred_len = edpt_info->current_xfer_bufferlen; + hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, XFER_RESULT_SUCCESS, true); + return; + } + case USB_PID_IN: + { + uint16_t received_len = USBOTG_H_FS->RX_LEN; + edpt_info->current_xfer_xferred_len += received_len; + uint16_t xferred_len = edpt_info->current_xfer_xferred_len; + LOG_CH32_USBFSH("Read %d bytes\r\n", received_len); + // if (received_len > 0 && (edpt_info->current_xfer_buffer == NULL || edpt_info->current_xfer_bufferlen == 0)) { + // PANIC("Data received but buffer not set\r\n"); + // } + memcpy(edpt_info->current_xfer_buffer, USBFS_RX_Buf, received_len); + edpt_info->current_xfer_buffer += received_len; + if ((received_len < edpt_info->max_packet_size) || (xferred_len == edpt_info->current_xfer_bufferlen)) + { + // USB device sent all data. + LOG_CH32_USBFSH("USB_PID_IN completed\r\n"); + hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, XFER_RESULT_SUCCESS, true); + return; + } + else + { + // USB device may send more data. + LOG_CH32_USBFSH("Read more data\r\n"); + hardware_start_xfer(USB_PID_IN, ep_addr, edpt_info->data_toggle); + return; + } + } + default: + { + PANIC("Unknown PID: 0x%02x\n", request_pid); + } + } + } + else + { + if (response_pid == USB_PID_STALL) + { + LOG_CH32_USBFSH("Data toggle mismatched and STALL\r\n"); + hcd_edpt_clear_stall(0, dev_addr, ep_addr); + edpt_info->data_toggle = 0; + hardware_start_xfer(request_pid, ep_addr, 0); + return; + } + else if (response_pid == USB_PID_NAK) + { + LOG_CH32_USBFSH("Data toggle mismatched and NAK\r\n"); + uint32_t elapsed_time = board_millis() - edpt_info->current_xfer_packet_start_millis; + if (elapsed_time > USB_XFER_TIMEOUT_MILLIS) + { + hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); + } + else + { + hardware_start_xfer(request_pid, ep_addr, edpt_info->data_toggle); + } + return; + } + else if (response_pid == USB_PID_DATA0 || response_pid == USB_PID_DATA1) + { + LOG_CH32_USBFSH("Data toggle mismatched and DATA0/1 (not STALL). RX_LEN=%d\r\n", USBOTG_H_FS->RX_LEN); + hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); + return; + } + else + { + LOG_CH32_USBFSH("\r\nIn USBHD_IRQHandler, unexpected response PID: 0x%02x\r\n", response_pid); + hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); + return; + } + } + } +} + +//--------------------------------------------------------------------+ +// Endpoint API +//--------------------------------------------------------------------+ + +bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) +{ + (void)rhport; + uint8_t ep_addr = ep_desc->bEndpointAddress; + uint8_t ep_num = tu_edpt_number(ep_addr); + uint16_t max_packet_size = ep_desc->wMaxPacketSize; + LOG_CH32_USBFSH("hcd_edpt_open(rhport=%d, dev_addr=0x%02x, %p) EndpointAdderss=0x%02x,maxPacketSize=%d\r\n", rhport, dev_addr, ep_desc, ep_addr, max_packet_size); + + if (ep_num == 0x00) + { + TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x00, max_packet_size) != NULL, false); + TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x80, max_packet_size) != NULL, false); + } + else + { + TU_ASSERT(get_or_add_edpt_record(dev_addr, ep_addr, max_packet_size) != NULL, false); + } + + update_device_address(dev_addr); + + if (dev_addr == 0x00 && ep_num == 0x00) + { + // It assumes first open for the device, so make the port enable + tusb_speed_t device_speed = hcd_port_speed_get(rhport); + update_port_speed(device_speed); + USBOTG_H_FS->HOST_CTRL |= USBFS_UH_PORT_EN; + USBOTG_H_FS->HOST_SETUP |= USBFS_UH_SOF_EN; + } + + return true; +} + +bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) +{ + (void)rhport; + + usb_edpt_t* edpt_info = get_edpt_record(dev_addr, ep_addr); + if (edpt_info == NULL) + { + PANIC("get_edpt_record() returned NULL in hcd_edpt_xfer()\r\n"); + } + + edpt_info->current_xfer_buffer = buffer; + edpt_info->current_xfer_bufferlen = buflen; + + edpt_info->current_xfer_packet_start_millis = board_millis(); + edpt_info->current_xfer_xferred_len = 0; + + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) + { + LOG_CH32_USBFSH("hcd_edpt_xfer(): READ, ep_addr=0x%02x, len=%d\r\n", ep_addr, buflen); + return hardware_start_xfer(USB_PID_IN, ep_addr, edpt_info->data_toggle); + } + else + { + LOG_CH32_USBFSH("hcd_edpt_xfer(): WRITE, ep_addr=0x%02x, len=%d\r\n", ep_addr, buflen); + USBOTG_H_FS->HOST_TX_LEN = buflen; + memcpy(USBFS_TX_Buf, buffer, buflen); + return hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle); + } +} + +bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) +{ + (void) rhport; + (void) dev_addr; + (void) ep_addr; + LOG_CH32_USBFSH("hcd_edpt_abort_xfer(%d, 0x%02x, 0x%02x)\r\n", rhport, dev_addr, ep_addr); + + return false; +} + +bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) +{ + (void)rhport; + LOG_CH32_USBFSH("hcd_setup_send(rhport=%d, dev_addr=0x%02x, %p)\r\n", rhport, dev_addr, setup_packet); + + + usb_edpt_t* edpt_info_tx = get_edpt_record(dev_addr, 0x00); + usb_edpt_t* edpt_info_rx = get_edpt_record(dev_addr, 0x80); + TU_ASSERT(edpt_info_tx != NULL, false); + TU_ASSERT(edpt_info_rx != NULL, false); + + // Initialize data toggle (SETUP always starts with DATA0) + // Data toggle for OUT is toggled in hcd_int_handler() + edpt_info_tx->data_toggle = 0; + // Data toggle for IN must be set 0x01 manually. + edpt_info_rx->data_toggle = 0x01; + const uint16_t setup_packet_datalen = 8; + memcpy(USBFS_TX_Buf, setup_packet, setup_packet_datalen); + USBOTG_H_FS->HOST_TX_LEN = setup_packet_datalen; + + edpt_info_tx->current_xfer_packet_start_millis = board_millis(); + edpt_info_tx->current_xfer_buffer = USBFS_TX_Buf; + edpt_info_tx->current_xfer_bufferlen = setup_packet_datalen; + edpt_info_tx->current_xfer_xferred_len = 0; + + hardware_start_xfer(USB_PID_SETUP, 0, 0); + + return true; +} + +bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) +{ + (void) rhport; + (void) dev_addr; + LOG_CH32_USBFSH("hcd_edpt_clear_stall(rhport=%d, dev_addr=0x%02x, ep_addr=0x%02x)\r\n", rhport, dev_addr, ep_addr); + // PANIC("\r\nstall\r\n"); + uint8_t edpt_num = tu_edpt_number(ep_addr); + uint8_t setup_request_clear_stall[8] = { + 0x02, 0x01, 0x00, 0x00, edpt_num, 0x00, 0x00, 0x00 + }; + memcpy(USBFS_TX_Buf, setup_request_clear_stall, 8); + USBOTG_H_FS->HOST_TX_LEN = 8; + + hcd_int_disable(0); + + USBOTG_H_FS->HOST_EP_PID = (USB_PID_SETUP << 4) | 0x00; + USBOTG_H_FS->INT_FG |= USBFS_UIF_TRANSFER; + while ((USBOTG_H_FS->INT_FG & USBFS_UIF_TRANSFER) == 0) { } + USBOTG_H_FS->HOST_EP_PID = 0; + uint8_t response_pid = USBOTG_H_FS->INT_ST & USBFS_UIS_H_RES_MASK; + (void)response_pid; + LOG_CH32_USBFSH("hcd_edpt_clear_stall() response pid=0x%02x\r\n", response_pid); + + hcd_int_enable(0); + + return true; +} + +#endif From dc3e6a59a9f50182c09e6301a4f8fcc9a4089722 Mon Sep 17 00:00:00 2001 From: verylowfreq <60875431+verylowfreq@users.noreply.github.com> Date: Mon, 9 Sep 2024 19:00:46 +0900 Subject: [PATCH 02/10] Repeat xfer on USB_PID_OUT if data is larger than MaxPacketSize --- src/portable/wch/hcd_ch32_usbfs.c | 34 ++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/portable/wch/hcd_ch32_usbfs.c b/src/portable/wch/hcd_ch32_usbfs.c index 534edb22b..93c5ce519 100644 --- a/src/portable/wch/hcd_ch32_usbfs.c +++ b/src/portable/wch/hcd_ch32_usbfs.c @@ -405,9 +405,28 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) case USB_PID_SETUP: case USB_PID_OUT: { - uint16_t xferred_len = edpt_info->current_xfer_bufferlen; - hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, XFER_RESULT_SUCCESS, true); - return; + uint16_t tx_len = USBOTG_H_FS->HOST_TX_LEN; + edpt_info->current_xfer_bufferlen -= tx_len; + edpt_info->current_xfer_xferred_len += tx_len; + if (edpt_info->current_xfer_bufferlen == 0) + { + LOG_CH32_USBFSH("USB_PID_OUT completed %d bytes\r\n", edpt_info->current_xfer_xferred_len); + hcd_event_xfer_complete(dev_addr, ep_addr, edpt_info->current_xfer_xferred_len, XFER_RESULT_SUCCESS, true); + return; + } + else + { + LOG_CH32_USBFSH("USB_PID_OUT continue...\r\n"); + edpt_info->current_xfer_buffer += tx_len; + uint16_t copylen = USBFS_TX_BUF_LEN; + if (copylen > edpt_info->current_xfer_bufferlen) + { + copylen = edpt_info->current_xfer_bufferlen; + } + memcpy(USBFS_TX_Buf, edpt_info->current_xfer_buffer, copylen); + hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle); + return; + } } case USB_PID_IN: { @@ -541,8 +560,13 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * else { LOG_CH32_USBFSH("hcd_edpt_xfer(): WRITE, ep_addr=0x%02x, len=%d\r\n", ep_addr, buflen); - USBOTG_H_FS->HOST_TX_LEN = buflen; - memcpy(USBFS_TX_Buf, buffer, buflen); + uint16_t copylen = USBFS_TX_BUF_LEN; + if (copylen > buflen) + { + copylen = buflen; + } + USBOTG_H_FS->HOST_TX_LEN = copylen; + memcpy(USBFS_TX_Buf, buffer, copylen); return hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle); } } From 879f78a91df08f0b3c6df7f56d6dd2293455dbcd Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 11 Sep 2024 18:34:48 +0700 Subject: [PATCH 03/10] fix pre-commmit --- src/portable/wch/hcd_ch32_usbfs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/portable/wch/hcd_ch32_usbfs.c b/src/portable/wch/hcd_ch32_usbfs.c index 93c5ce519..b775d6eee 100644 --- a/src/portable/wch/hcd_ch32_usbfs.c +++ b/src/portable/wch/hcd_ch32_usbfs.c @@ -186,7 +186,7 @@ static void hardware_init_host(bool enabled) static bool hardware_start_xfer(uint8_t pid, uint8_t ep_addr, uint8_t data_toggle) { - LOG_CH32_USBFSH("hardware_start_xfer(pid=%s(0x%02x), ep_addr=0x%02x, toggle=%d)\r\n", + LOG_CH32_USBFSH("hardware_start_xfer(pid=%s(0x%02x), ep_addr=0x%02x, toggle=%d)\r\n", pid == USB_PID_IN ? "IN" : pid == USB_PID_OUT ? "OUT" : pid == USB_PID_SETUP ? "SETUP" : "(other)", pid, ep_addr, data_toggle); @@ -342,7 +342,7 @@ void hcd_int_disable(uint8_t rhport) { (void)rhport; NVIC_DisableIRQ(USBFS_IRQn); - + return; } @@ -492,7 +492,7 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) } else { - LOG_CH32_USBFSH("\r\nIn USBHD_IRQHandler, unexpected response PID: 0x%02x\r\n", response_pid); + LOG_CH32_USBFSH("In USBHD_IRQHandler, unexpected response PID: 0x%02x\r\n", response_pid); hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); return; } @@ -616,7 +616,7 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) (void) rhport; (void) dev_addr; LOG_CH32_USBFSH("hcd_edpt_clear_stall(rhport=%d, dev_addr=0x%02x, ep_addr=0x%02x)\r\n", rhport, dev_addr, ep_addr); - // PANIC("\r\nstall\r\n"); + // PANIC("\r\install\r\n"); uint8_t edpt_num = tu_edpt_number(ep_addr); uint8_t setup_request_clear_stall[8] = { 0x02, 0x01, 0x00, 0x00, edpt_num, 0x00, 0x00, 0x00 From 7ed5503a5c2bc0b755d97303064614275e74ffb2 Mon Sep 17 00:00:00 2001 From: verylowfreq <60875431+verylowfreq@users.noreply.github.com> Date: Wed, 11 Sep 2024 23:25:49 +0900 Subject: [PATCH 04/10] Fix the condition related to CFG_TUH_WCH_USBIP_USBFS macro --- hw/bsp/ch32v20x/family.c | 2 +- src/portable/wch/hcd_ch32_usbfs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/bsp/ch32v20x/family.c b/hw/bsp/ch32v20x/family.c index 8a9ee6819..d674ccd6f 100644 --- a/hw/bsp/ch32v20x/family.c +++ b/hw/bsp/ch32v20x/family.c @@ -32,7 +32,7 @@ void USBHD_IRQHandler(void) { #if CFG_TUD_WCH_USBIP_USBFS tud_int_handler(0); #endif - #if CFG_TUH_WCH_USBIP_USBFS + #if defined(CFG_TUH_WCH_USBIP_USBFS) && CFG_TUH_WCH_USBIP_USBFS tuh_int_handler(0); #endif } diff --git a/src/portable/wch/hcd_ch32_usbfs.c b/src/portable/wch/hcd_ch32_usbfs.c index b775d6eee..7e73f686f 100644 --- a/src/portable/wch/hcd_ch32_usbfs.c +++ b/src/portable/wch/hcd_ch32_usbfs.c @@ -26,7 +26,7 @@ #include "tusb_option.h" -#if CFG_TUH_ENABLED && defined(TUP_USBIP_WCH_USBFS) && CFG_TUH_WCH_USBIP_USBFS +#if CFG_TUH_ENABLED && defined(TUP_USBIP_WCH_USBFS) && defined(CFG_TUH_WCH_USBIP_USBFS) && CFG_TUH_WCH_USBIP_USBFS #include "host/hcd.h" #include "host/usbh.h" From 382dcca5d63c9eff5ade0cf402fc113c68a57857 Mon Sep 17 00:00:00 2001 From: verylowfreq <60875431+verylowfreq@users.noreply.github.com> Date: Wed, 11 Sep 2024 23:33:19 +0900 Subject: [PATCH 05/10] Update ch32v20x family.cmake --- hw/bsp/ch32v20x/family.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/bsp/ch32v20x/family.cmake b/hw/bsp/ch32v20x/family.cmake index a5976e0ea..6092abc8d 100644 --- a/hw/bsp/ch32v20x/family.cmake +++ b/hw/bsp/ch32v20x/family.cmake @@ -61,6 +61,7 @@ function(add_board_target BOARD_TARGET) if (PORT EQUAL 0) target_compile_definitions(${BOARD_TARGET} PUBLIC CFG_TUD_WCH_USBIP_FSDEV=1 + CFG_TUH_WCH_USBIP_USBFS=1 ) elseif (PORT EQUAL 1) target_compile_definitions(${BOARD_TARGET} PUBLIC @@ -127,6 +128,7 @@ function(family_configure_example TARGET RTOS) target_sources(${TARGET} PUBLIC ${TOP}/src/portable/wch/dcd_ch32_usbfs.c + ${TOP}/src/portable/wch/hcd_ch32_usbfs.c ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c ) target_link_libraries(${TARGET} PUBLIC board_${BOARD}) From 426588d947b5c9ac789571019fc2b8da5d756669 Mon Sep 17 00:00:00 2001 From: verylowfreq <60875431+verylowfreq@users.noreply.github.com> Date: Mon, 28 Oct 2024 21:28:15 +0900 Subject: [PATCH 06/10] Fix for timing, timeout, and device switching issues --- src/portable/wch/hcd_ch32_usbfs.c | 193 ++++++++++++++++++++---------- 1 file changed, 127 insertions(+), 66 deletions(-) diff --git a/src/portable/wch/hcd_ch32_usbfs.c b/src/portable/wch/hcd_ch32_usbfs.c index 7e73f686f..ddd366b4f 100644 --- a/src/portable/wch/hcd_ch32_usbfs.c +++ b/src/portable/wch/hcd_ch32_usbfs.c @@ -43,24 +43,26 @@ __attribute__((aligned(4))) static uint8_t USBFS_RX_Buf[USBFS_RX_BUF_LEN]; __attribute__((aligned(4))) static uint8_t USBFS_TX_Buf[USBFS_TX_BUF_LEN]; -#define USB_XFER_TIMEOUT_MILLIS 500 +#define USB_XFER_TIMEOUT_MILLIS 100 +#define USB_INTERRUPT_XFER_TIMEOUT_MILLIS 1 #define PANIC(...) do { printf("\r\nPANIC: " __VA_ARGS__); while (true) { } } while (false) #define LOG_CH32_USBFSH(...) TU_LOG3(__VA_ARGS__) // Busywait for delay microseconds/nanoseconds -// static void loopdelay(uint32_t count) -// { -// volatile uint32_t c = count / 3; -// // while (c-- != 0); -// asm volatile( -// "1: \n" // loop label -// " addi %0, %0, -1 \n" // c-- -// " bne %0, zero, 1b \n" // if (c != 0) goto loop -// : "+r"(c) // c is input/output operand -// ); -// } +static void loopdelay(uint32_t count) +{ + volatile uint32_t c = count / 3; + if (c == 0) { return; } + // while (c-- != 0); + asm volatile( + "1: \n" // loop label + " addi %0, %0, -1 \n" // c-- + " bne %0, zero, 1b \n" // if (c != 0) goto loop + : "+r"(c) // c is input/output operand + ); +} // Endpoint status @@ -71,21 +73,30 @@ typedef struct usb_edpt uint8_t dev_addr; uint8_t ep_addr; - uint16_t max_packet_size; + uint8_t max_packet_size; + + uint8_t xfer_type; // Data toggle (0 or not 0) for DATA0/1 uint8_t data_toggle; +} usb_edpt_t; + +static usb_edpt_t usb_edpt_list[CFG_TUH_DEVICE_MAX * 6] = {}; + + +typedef struct usb_current_xfer_st { + bool is_busy; + uint8_t dev_addr; + uint8_t ep_addr; // Xfer started time in millis for timeout uint32_t current_xfer_packet_start_millis; uint8_t* current_xfer_buffer; uint16_t current_xfer_bufferlen; uint16_t current_xfer_xferred_len; +} usb_current_xfer_t; -} usb_edpt_t; - - -static usb_edpt_t usb_edpt_list[8] = { }; +static volatile usb_current_xfer_t usb_current_xfer_info = {}; static usb_edpt_t* get_edpt_record(uint8_t dev_addr, uint8_t ep_addr) @@ -113,26 +124,26 @@ static usb_edpt_t* get_empty_record_slot(void) return NULL; } -static usb_edpt_t* add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size) +static usb_edpt_t* add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size, uint8_t xfer_type) { usb_edpt_t* slot = get_empty_record_slot(); + if (slot == NULL) { + PANIC("add_edpt_record(0x%02x, 0x%02x, ...) no slot for new record\r\n", dev_addr, ep_addr); + } TU_ASSERT(slot != NULL, NULL); slot->dev_addr = dev_addr; slot->ep_addr = ep_addr; slot->max_packet_size = max_packet_size; + slot->xfer_type = xfer_type; slot->data_toggle = 0; - slot->current_xfer_packet_start_millis = 0; - slot->current_xfer_buffer = NULL; - slot->current_xfer_bufferlen = 0; - slot->current_xfer_xferred_len = 0; slot->configured = true; return slot; } -static usb_edpt_t* get_or_add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size) +static usb_edpt_t* get_or_add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size, uint8_t xfer_type) { usb_edpt_t* ret = get_edpt_record(dev_addr, ep_addr); if (ret != NULL) @@ -141,7 +152,7 @@ static usb_edpt_t* get_or_add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uin } else { - return add_edpt_record(dev_addr, ep_addr, max_packet_size); + return add_edpt_record(dev_addr, ep_addr, max_packet_size, xfer_type); } } @@ -157,6 +168,17 @@ static void remove_edpt_record_for_device(uint8_t dev_addr) } } +// static void dump_edpt_record_list() { +// for (size_t i = 0; i < TU_ARRAY_SIZE(usb_edpt_list); i++) { +// usb_edpt_t* cur = &usb_edpt_list[i]; +// if (cur->configured) { +// printf("[%2d] Device 0x%02x Endpoint 0x%02x\r\n", i, cur->dev_addr, cur->ep_addr); +// } else { +// printf("[%2d] not configured\r\n", i); +// } +// } +// } + /** Enable or disable USBFS Host function */ static void hardware_init_host(bool enabled) @@ -180,7 +202,8 @@ static void hardware_init_host(bool enabled) USBOTG_H_FS->HOST_EP_MOD = USBFS_UH_EP_TX_EN | USBFS_UH_EP_RX_EN; USBOTG_H_FS->HOST_RX_DMA = (uint32_t)USBFS_RX_Buf; USBOTG_H_FS->HOST_TX_DMA = (uint32_t)USBFS_TX_Buf; - USBOTG_H_FS->INT_EN = USBFS_UIE_TRANSFER | USBFS_UIE_DETECT; + // USBOTG_H_FS->INT_EN = USBFS_UIE_TRANSFER | USBFS_UIE_DETECT; + USBOTG_H_FS->INT_EN = USBFS_UIE_DETECT; } } @@ -199,6 +222,7 @@ static bool hardware_start_xfer(uint8_t pid, uint8_t ep_addr, uint8_t data_toggl USBOTG_H_FS->HOST_TX_CTRL = (data_toggle != 0) ? USBFS_UH_T_TOG : 0; USBOTG_H_FS->HOST_RX_CTRL = (data_toggle != 0) ? USBFS_UH_R_TOG : 0; USBOTG_H_FS->HOST_EP_PID = pid_edpt; + USBOTG_H_FS->INT_EN |= USBFS_UIE_TRANSFER; USBOTG_H_FS->INT_FG = USBFS_UIF_TRANSFER; return true; } @@ -371,19 +395,21 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) if (USBOTG_H_FS->INT_FG & USBFS_UIF_TRANSFER) { + // Disable transfer interrupt + USBOTG_H_FS->INT_EN &= ~USBFS_UIE_TRANSFER; + // Clear the flag + // USBOTG_H_FS->INT_FG = USBFS_UIF_TRANSFER; // Copy PID and Endpoint uint8_t pid_edpt = USBOTG_H_FS->HOST_EP_PID; uint8_t status = USBOTG_H_FS->INT_ST; + uint8_t dev_addr = USBOTG_H_FS->DEV_ADDR & USBFS_USB_ADDR_MASK; // Clear register to stop transfer - USBOTG_H_FS->HOST_EP_PID = 0; - // Clear the flag - USBOTG_H_FS->INT_FG = USBFS_UIF_TRANSFER; + // USBOTG_H_FS->HOST_EP_PID = 0x00; LOG_CH32_USBFSH("hcd_int_handler() pid_edpt=0x%02x\r\n", pid_edpt); uint8_t request_pid = pid_edpt >> 4; - uint8_t response_pid = USBOTG_H_FS->INT_ST & USBFS_UIS_H_RES_MASK; - uint8_t dev_addr = USBOTG_H_FS->DEV_ADDR; + uint8_t response_pid = status & USBFS_UIS_H_RES_MASK; uint8_t ep_addr = pid_edpt & 0x0f; if (request_pid == USB_PID_IN) { @@ -393,7 +419,7 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) usb_edpt_t* edpt_info = get_edpt_record(dev_addr, ep_addr); if (edpt_info == NULL) { - PANIC("\r\nget_edpt_record() returned NULL in USBHD_IRQHandler\r\n"); + PANIC("\r\nget_edpt_record(0x%02x, 0x%02x) returned NULL in USBHD_IRQHandler\r\n", dev_addr, ep_addr); } if (status & USBFS_UIS_TOG_OK) @@ -406,24 +432,25 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) case USB_PID_OUT: { uint16_t tx_len = USBOTG_H_FS->HOST_TX_LEN; - edpt_info->current_xfer_bufferlen -= tx_len; - edpt_info->current_xfer_xferred_len += tx_len; - if (edpt_info->current_xfer_bufferlen == 0) + usb_current_xfer_info.current_xfer_bufferlen -= tx_len; + usb_current_xfer_info.current_xfer_xferred_len += tx_len; + if (usb_current_xfer_info.current_xfer_bufferlen == 0) { - LOG_CH32_USBFSH("USB_PID_OUT completed %d bytes\r\n", edpt_info->current_xfer_xferred_len); - hcd_event_xfer_complete(dev_addr, ep_addr, edpt_info->current_xfer_xferred_len, XFER_RESULT_SUCCESS, true); + LOG_CH32_USBFSH("USB_PID_%s completed %d bytes\r\n", request_pid == USB_PID_OUT ? "OUT" : "SETUP", usb_current_xfer_info.current_xfer_xferred_len); + usb_current_xfer_info.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, usb_current_xfer_info.current_xfer_xferred_len, XFER_RESULT_SUCCESS, true); return; } else { LOG_CH32_USBFSH("USB_PID_OUT continue...\r\n"); - edpt_info->current_xfer_buffer += tx_len; + usb_current_xfer_info.current_xfer_buffer += tx_len; uint16_t copylen = USBFS_TX_BUF_LEN; - if (copylen > edpt_info->current_xfer_bufferlen) + if (copylen > usb_current_xfer_info.current_xfer_bufferlen) { - copylen = edpt_info->current_xfer_bufferlen; + copylen = usb_current_xfer_info.current_xfer_bufferlen; } - memcpy(USBFS_TX_Buf, edpt_info->current_xfer_buffer, copylen); + memcpy(USBFS_TX_Buf, usb_current_xfer_info.current_xfer_buffer, copylen); hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle); return; } @@ -431,18 +458,19 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) case USB_PID_IN: { uint16_t received_len = USBOTG_H_FS->RX_LEN; - edpt_info->current_xfer_xferred_len += received_len; - uint16_t xferred_len = edpt_info->current_xfer_xferred_len; + usb_current_xfer_info.current_xfer_xferred_len += received_len; + uint16_t xferred_len = usb_current_xfer_info.current_xfer_xferred_len; LOG_CH32_USBFSH("Read %d bytes\r\n", received_len); - // if (received_len > 0 && (edpt_info->current_xfer_buffer == NULL || edpt_info->current_xfer_bufferlen == 0)) { + // if (received_len > 0 && (usb_current_xfer_info.current_xfer_buffer == NULL || usb_current_xfer_info.current_xfer_bufferlen == 0)) { // PANIC("Data received but buffer not set\r\n"); // } - memcpy(edpt_info->current_xfer_buffer, USBFS_RX_Buf, received_len); - edpt_info->current_xfer_buffer += received_len; - if ((received_len < edpt_info->max_packet_size) || (xferred_len == edpt_info->current_xfer_bufferlen)) + memcpy(usb_current_xfer_info.current_xfer_buffer, USBFS_RX_Buf, received_len); + usb_current_xfer_info.current_xfer_buffer += received_len; + if ((received_len < edpt_info->max_packet_size) || (xferred_len == usb_current_xfer_info.current_xfer_bufferlen)) { // USB device sent all data. LOG_CH32_USBFSH("USB_PID_IN completed\r\n"); + usb_current_xfer_info.is_busy = false; hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, XFER_RESULT_SUCCESS, true); return; } @@ -464,7 +492,7 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { if (response_pid == USB_PID_STALL) { - LOG_CH32_USBFSH("Data toggle mismatched and STALL\r\n"); + LOG_CH32_USBFSH("STALL response\r\n"); hcd_edpt_clear_stall(0, dev_addr, ep_addr); edpt_info->data_toggle = 0; hardware_start_xfer(request_pid, ep_addr, 0); @@ -472,10 +500,16 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) } else if (response_pid == USB_PID_NAK) { - LOG_CH32_USBFSH("Data toggle mismatched and NAK\r\n"); - uint32_t elapsed_time = board_millis() - edpt_info->current_xfer_packet_start_millis; - if (elapsed_time > USB_XFER_TIMEOUT_MILLIS) + LOG_CH32_USBFSH("NAK reposense\r\n"); + uint32_t elapsed_time = board_millis() - usb_current_xfer_info.current_xfer_packet_start_millis; + if (edpt_info->xfer_type == TUSB_XFER_INTERRUPT && (elapsed_time > USB_INTERRUPT_XFER_TIMEOUT_MILLIS)) { + usb_current_xfer_info.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_SUCCESS, true); + } + else if (elapsed_time > USB_XFER_TIMEOUT_MILLIS) + { + usb_current_xfer_info.is_busy = false; hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); } else @@ -487,12 +521,14 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) else if (response_pid == USB_PID_DATA0 || response_pid == USB_PID_DATA1) { LOG_CH32_USBFSH("Data toggle mismatched and DATA0/1 (not STALL). RX_LEN=%d\r\n", USBOTG_H_FS->RX_LEN); + usb_current_xfer_info.is_busy = false; hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); return; } else { LOG_CH32_USBFSH("In USBHD_IRQHandler, unexpected response PID: 0x%02x\r\n", response_pid); + usb_current_xfer_info.is_busy = false; hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); return; } @@ -510,16 +546,17 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const uint8_t ep_addr = ep_desc->bEndpointAddress; uint8_t ep_num = tu_edpt_number(ep_addr); uint16_t max_packet_size = ep_desc->wMaxPacketSize; - LOG_CH32_USBFSH("hcd_edpt_open(rhport=%d, dev_addr=0x%02x, %p) EndpointAdderss=0x%02x,maxPacketSize=%d\r\n", rhport, dev_addr, ep_desc, ep_addr, max_packet_size); + uint8_t xfer_type = ep_desc->bmAttributes.xfer; + LOG_CH32_USBFSH("hcd_edpt_open(rhport=%d, dev_addr=0x%02x, %p) EndpointAdderss=0x%02x,maxPacketSize=%d,xfer_type=%d\r\n", rhport, dev_addr, ep_desc, ep_addr, max_packet_size, xfer_type); if (ep_num == 0x00) { - TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x00, max_packet_size) != NULL, false); - TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x80, max_packet_size) != NULL, false); + TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x00, max_packet_size, xfer_type) != NULL, false); + TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x80, max_packet_size, xfer_type) != NULL, false); } else { - TU_ASSERT(get_or_add_edpt_record(dev_addr, ep_addr, max_packet_size) != NULL, false); + TU_ASSERT(get_or_add_edpt_record(dev_addr, ep_addr, max_packet_size, xfer_type) != NULL, false); } update_device_address(dev_addr); @@ -540,26 +577,36 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * { (void)rhport; + while (usb_current_xfer_info.is_busy) { + osal_task_delay(1); + } + usb_current_xfer_info.is_busy = true; + usb_edpt_t* edpt_info = get_edpt_record(dev_addr, ep_addr); if (edpt_info == NULL) { PANIC("get_edpt_record() returned NULL in hcd_edpt_xfer()\r\n"); } + + update_device_address(dev_addr); + tusb_speed_t device_speed = hcd_port_speed_get(rhport); + update_port_speed(device_speed); - edpt_info->current_xfer_buffer = buffer; - edpt_info->current_xfer_bufferlen = buflen; - - edpt_info->current_xfer_packet_start_millis = board_millis(); - edpt_info->current_xfer_xferred_len = 0; + usb_current_xfer_info.dev_addr = dev_addr; + usb_current_xfer_info.ep_addr = ep_addr; + usb_current_xfer_info.current_xfer_buffer = buffer; + usb_current_xfer_info.current_xfer_bufferlen = buflen; + usb_current_xfer_info.current_xfer_packet_start_millis = board_millis(); + usb_current_xfer_info.current_xfer_xferred_len = 0; if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { - LOG_CH32_USBFSH("hcd_edpt_xfer(): READ, ep_addr=0x%02x, len=%d\r\n", ep_addr, buflen); + LOG_CH32_USBFSH("hcd_edpt_xfer(): READ, dev_addr=0x%02x, ep_addr=0x%02x, len=%d\r\n", dev_addr, ep_addr, buflen); return hardware_start_xfer(USB_PID_IN, ep_addr, edpt_info->data_toggle); } else { - LOG_CH32_USBFSH("hcd_edpt_xfer(): WRITE, ep_addr=0x%02x, len=%d\r\n", ep_addr, buflen); + LOG_CH32_USBFSH("hcd_edpt_xfer(): WRITE, dev_addr=0x%02x, ep_addr=0x%02x, len=%d\r\n", dev_addr, ep_addr, buflen); uint16_t copylen = USBFS_TX_BUF_LEN; if (copylen > buflen) { @@ -584,8 +631,20 @@ bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) { (void)rhport; + + if (usb_current_xfer_info.is_busy) { + osal_task_delay(1); + } + usb_current_xfer_info.is_busy = true; + LOG_CH32_USBFSH("hcd_setup_send(rhport=%d, dev_addr=0x%02x, %p)\r\n", rhport, dev_addr, setup_packet); + // loopdelay(SystemCoreClock / 1000000 * 100); + loopdelay(1); + + update_device_address(dev_addr); + tusb_speed_t device_speed = hcd_port_speed_get(rhport); + update_port_speed(device_speed); usb_edpt_t* edpt_info_tx = get_edpt_record(dev_addr, 0x00); usb_edpt_t* edpt_info_rx = get_edpt_record(dev_addr, 0x80); @@ -600,11 +659,13 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet const uint16_t setup_packet_datalen = 8; memcpy(USBFS_TX_Buf, setup_packet, setup_packet_datalen); USBOTG_H_FS->HOST_TX_LEN = setup_packet_datalen; - - edpt_info_tx->current_xfer_packet_start_millis = board_millis(); - edpt_info_tx->current_xfer_buffer = USBFS_TX_Buf; - edpt_info_tx->current_xfer_bufferlen = setup_packet_datalen; - edpt_info_tx->current_xfer_xferred_len = 0; + uint8_t ep_addr = (setup_packet[0] & 0x80) ? 0x80 : 0x00; + usb_current_xfer_info.dev_addr = dev_addr; + usb_current_xfer_info.ep_addr = ep_addr; + usb_current_xfer_info.current_xfer_packet_start_millis = board_millis(); + usb_current_xfer_info.current_xfer_buffer = USBFS_TX_Buf; + usb_current_xfer_info.current_xfer_bufferlen = setup_packet_datalen; + usb_current_xfer_info.current_xfer_xferred_len = 0; hardware_start_xfer(USB_PID_SETUP, 0, 0); From 9ca4bc89a7e285796e8102eb7a8fd1bbc6fb9938 Mon Sep 17 00:00:00 2001 From: verylowfreq <60875431+verylowfreq@users.noreply.github.com> Date: Thu, 12 Dec 2024 09:53:58 +0900 Subject: [PATCH 07/10] Update hcd_init() signature. Add osal_task_delay() implementation for none os. --- src/portable/wch/hcd_ch32_usbfs.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/portable/wch/hcd_ch32_usbfs.c b/src/portable/wch/hcd_ch32_usbfs.c index ddd366b4f..cbbf90da6 100644 --- a/src/portable/wch/hcd_ch32_usbfs.c +++ b/src/portable/wch/hcd_ch32_usbfs.c @@ -37,6 +37,10 @@ #include "ch32v20x.h" #include "ch32v20x_usb.h" +void osal_task_delay(uint32_t msec) { + unsigned long start = board_millis(); + while (board_millis() - start < msec) {} +} #define USBFS_RX_BUF_LEN 64 #define USBFS_TX_BUF_LEN 64 @@ -264,9 +268,10 @@ static bool hardware_device_attached(void) //--------------------------------------------------------------------+ // HCD API //--------------------------------------------------------------------+ -bool hcd_init(uint8_t rhport) +bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { (void)rhport; + (void)rh_init; hardware_init_host(true); return true; From cd2b3a53217857930bd8519d074b355ae8933982 Mon Sep 17 00:00:00 2001 From: verylowfreq <60875431+verylowfreq@users.noreply.github.com> Date: Sun, 16 Mar 2025 10:06:27 +0900 Subject: [PATCH 08/10] Fix interupt, LowSpeed switching and rename --- src/portable/wch/hcd_ch32_usbfs.c | 204 ++++++++++++++++-------------- 1 file changed, 111 insertions(+), 93 deletions(-) diff --git a/src/portable/wch/hcd_ch32_usbfs.c b/src/portable/wch/hcd_ch32_usbfs.c index cbbf90da6..800390989 100644 --- a/src/portable/wch/hcd_ch32_usbfs.c +++ b/src/portable/wch/hcd_ch32_usbfs.c @@ -38,7 +38,7 @@ #include "ch32v20x_usb.h" void osal_task_delay(uint32_t msec) { - unsigned long start = board_millis(); + uint32_t start = board_millis(); while (board_millis() - start < msec) {} } @@ -48,25 +48,25 @@ __attribute__((aligned(4))) static uint8_t USBFS_RX_Buf[USBFS_RX_BUF_LEN]; __attribute__((aligned(4))) static uint8_t USBFS_TX_Buf[USBFS_TX_BUF_LEN]; #define USB_XFER_TIMEOUT_MILLIS 100 -#define USB_INTERRUPT_XFER_TIMEOUT_MILLIS 1 +// #define USB_INTERRUPT_XFER_TIMEOUT_MILLIS 1 -#define PANIC(...) do { printf("\r\nPANIC: " __VA_ARGS__); while (true) { } } while (false) +#define PANIC(...) do { printf("%s() L%d: ", __func__, __LINE__); printf("\r\n[PANIC] " __VA_ARGS__); while (true) { } } while (false) #define LOG_CH32_USBFSH(...) TU_LOG3(__VA_ARGS__) // Busywait for delay microseconds/nanoseconds -static void loopdelay(uint32_t count) -{ - volatile uint32_t c = count / 3; - if (c == 0) { return; } - // while (c-- != 0); - asm volatile( - "1: \n" // loop label - " addi %0, %0, -1 \n" // c-- - " bne %0, zero, 1b \n" // if (c != 0) goto loop - : "+r"(c) // c is input/output operand - ); -} +// static void loopdelay(uint32_t count) +// { +// volatile uint32_t c = count / 3; +// if (c == 0) { return; } +// // while (c-- != 0); +// asm volatile( +// "1: \n" // loop label +// " addi %0, %0, -1 \n" // c-- +// " bne %0, zero, 1b \n" // if (c != 0) goto loop +// : "+r"(c) // c is input/output operand +// ); +// } // Endpoint status @@ -94,10 +94,10 @@ typedef struct usb_current_xfer_st { uint8_t dev_addr; uint8_t ep_addr; // Xfer started time in millis for timeout - uint32_t current_xfer_packet_start_millis; - uint8_t* current_xfer_buffer; - uint16_t current_xfer_bufferlen; - uint16_t current_xfer_xferred_len; + uint32_t start_ms; + uint8_t* buffer; + uint16_t bufferlen; + uint16_t xferred_len; } usb_current_xfer_t; static volatile usb_current_xfer_t usb_current_xfer_info = {}; @@ -184,6 +184,8 @@ static void remove_edpt_record_for_device(uint8_t dev_addr) // } +static bool interrupt_enabled = false; + /** Enable or disable USBFS Host function */ static void hardware_init_host(bool enabled) { @@ -201,7 +203,8 @@ static void hardware_init_host(bool enabled) else { // Enable USB Host features - NVIC_DisableIRQ(USBFS_IRQn); + // NVIC_DisableIRQ(USBFS_IRQn); + hcd_int_disable(0); USBOTG_H_FS->BASE_CTRL = USBFS_UC_HOST_MODE | USBFS_UC_INT_BUSY | USBFS_UC_DMA_EN; USBOTG_H_FS->HOST_EP_MOD = USBFS_UH_EP_TX_EN | USBFS_UH_EP_RX_EN; USBOTG_H_FS->HOST_RX_DMA = (uint32_t)USBFS_RX_Buf; @@ -217,10 +220,10 @@ static bool hardware_start_xfer(uint8_t pid, uint8_t ep_addr, uint8_t data_toggl pid == USB_PID_IN ? "IN" : pid == USB_PID_OUT ? "OUT" : pid == USB_PID_SETUP ? "SETUP" : "(other)", pid, ep_addr, data_toggle); - if (pid == USB_PID_IN) - { // FIXME: long delay needed (at release build) about 30msec - // loopdelay(SystemCoreClock / 1000 * 30); - } + // if (pid == USB_PID_IN) + // { // FIXME: long delay needed (at release build) about 30msec + // loopdelay(SystemCoreClock / 1000 * 30); + // } uint8_t pid_edpt = (pid << 4) | (tu_edpt_number(ep_addr) & 0x0f); USBOTG_H_FS->HOST_TX_CTRL = (data_toggle != 0) ? USBFS_UH_T_TOG : 0; @@ -233,16 +236,16 @@ static bool hardware_start_xfer(uint8_t pid, uint8_t ep_addr, uint8_t data_toggl /** Set device address to communicate */ -static void update_device_address(uint8_t dev_addr) +static void hardware_update_device_address(uint8_t dev_addr) { // Keep the bit of GP_BIT. Other 7bits are actual device address. USBOTG_H_FS->DEV_ADDR = (USBOTG_H_FS->DEV_ADDR & USBFS_UDA_GP_BIT) | (dev_addr & USBFS_USB_ADDR_MASK); } /** Set port speed */ -static void update_port_speed(tusb_speed_t speed) +static void hardware_update_port_speed(tusb_speed_t speed) { - LOG_CH32_USBFSH("update_port_speed(%s)\r\n", speed == TUSB_SPEED_FULL ? "Full" : speed == TUSB_SPEED_LOW ? "Low" : "(invalid)"); + LOG_CH32_USBFSH("hardware_update_port_speed(%s)\r\n", speed == TUSB_SPEED_FULL ? "Full" : speed == TUSB_SPEED_LOW ? "Low" : "(invalid)"); switch (speed) { case TUSB_SPEED_LOW: USBOTG_H_FS->BASE_CTRL |= USBFS_UC_LOW_SPEED; @@ -255,10 +258,22 @@ static void update_port_speed(tusb_speed_t speed) USBOTG_H_FS->HOST_SETUP &= ~USBFS_UH_PRE_PID_EN; return; default: - PANIC("update_port_speed(%d)\r\n", speed); + PANIC("hardware_update_port_speed(%d)\r\n", speed); } } + +static void hardware_set_port_address_speed(uint8_t dev_addr) { + hardware_update_device_address(dev_addr); + tusb_speed_t rhport_speed = hcd_port_speed_get(0); + tusb_speed_t dev_speed = tuh_speed_get(dev_addr); + hardware_update_port_speed(dev_speed); + if (rhport_speed == TUSB_SPEED_FULL && dev_speed == TUSB_SPEED_LOW) { + USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_LOW_SPEED; + } +} + + static bool hardware_device_attached(void) { return USBOTG_H_FS->MIS_ST & USBFS_UMS_DEV_ATTACH; @@ -285,28 +300,21 @@ bool hcd_deinit(uint8_t rhport) return true; } + +static bool int_state_for_portreset = false; + void hcd_port_reset(uint8_t rhport) { (void)rhport; LOG_CH32_USBFSH("hcd_port_reset()\r\n"); - NVIC_DisableIRQ(USBFS_IRQn); - update_device_address( 0x00 ); + int_state_for_portreset = interrupt_enabled; + // NVIC_DisableIRQ(USBFS_IRQn); + hcd_int_disable(rhport); + hardware_update_device_address(0x00); + + // USBOTG_H_FS->HOST_SETUP = 0x00; USBOTG_H_FS->HOST_CTRL |= USBFS_UH_BUS_RESET; - osal_task_delay(15); - USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_BUS_RESET; - osal_task_delay(2); - - if ((USBOTG_H_FS->HOST_CTRL & USBFS_UH_PORT_EN) == 0) - { - if (hcd_port_speed_get(0) == TUSB_SPEED_LOW) - { - update_port_speed(TUSB_SPEED_LOW); - } - } - - USBOTG_H_FS->HOST_CTRL |= USBFS_UH_PORT_EN; - USBOTG_H_FS->HOST_SETUP |= USBFS_UH_SOF_EN; return; } @@ -315,9 +323,27 @@ void hcd_port_reset_end(uint8_t rhport) { (void)rhport; LOG_CH32_USBFSH("hcd_port_reset_end()\r\n"); + + USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_BUS_RESET; + osal_task_delay(2); + + if ((USBOTG_H_FS->HOST_CTRL & USBFS_UH_PORT_EN) == 0) + { + if (hcd_port_speed_get(0) == TUSB_SPEED_LOW) + { + hardware_update_port_speed(TUSB_SPEED_LOW); + } + } + + USBOTG_H_FS->HOST_CTRL |= USBFS_UH_PORT_EN; + USBOTG_H_FS->HOST_SETUP |= USBFS_UH_SOF_EN; + // Suppress the attached event USBOTG_H_FS->INT_FG |= USBFS_UIF_DETECT; - NVIC_EnableIRQ(USBFS_IRQn); + + if (int_state_for_portreset) { + hcd_int_enable(rhport); + } return; } @@ -363,6 +389,7 @@ void hcd_int_enable(uint8_t rhport) { (void)rhport; NVIC_EnableIRQ(USBFS_IRQn); + interrupt_enabled = true; return; } @@ -371,6 +398,7 @@ void hcd_int_disable(uint8_t rhport) { (void)rhport; NVIC_DisableIRQ(USBFS_IRQn); + interrupt_enabled = false; return; } @@ -437,25 +465,25 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) case USB_PID_OUT: { uint16_t tx_len = USBOTG_H_FS->HOST_TX_LEN; - usb_current_xfer_info.current_xfer_bufferlen -= tx_len; - usb_current_xfer_info.current_xfer_xferred_len += tx_len; - if (usb_current_xfer_info.current_xfer_bufferlen == 0) + usb_current_xfer_info.bufferlen -= tx_len; + usb_current_xfer_info.xferred_len += tx_len; + if (usb_current_xfer_info.bufferlen == 0) { - LOG_CH32_USBFSH("USB_PID_%s completed %d bytes\r\n", request_pid == USB_PID_OUT ? "OUT" : "SETUP", usb_current_xfer_info.current_xfer_xferred_len); + LOG_CH32_USBFSH("USB_PID_%s completed %d bytes\r\n", request_pid == USB_PID_OUT ? "OUT" : "SETUP", usb_current_xfer_info.xferred_len); usb_current_xfer_info.is_busy = false; - hcd_event_xfer_complete(dev_addr, ep_addr, usb_current_xfer_info.current_xfer_xferred_len, XFER_RESULT_SUCCESS, true); + hcd_event_xfer_complete(dev_addr, ep_addr, usb_current_xfer_info.xferred_len, XFER_RESULT_SUCCESS, true); return; } else { LOG_CH32_USBFSH("USB_PID_OUT continue...\r\n"); - usb_current_xfer_info.current_xfer_buffer += tx_len; + usb_current_xfer_info.buffer += tx_len; uint16_t copylen = USBFS_TX_BUF_LEN; - if (copylen > usb_current_xfer_info.current_xfer_bufferlen) + if (copylen > usb_current_xfer_info.bufferlen) { - copylen = usb_current_xfer_info.current_xfer_bufferlen; + copylen = usb_current_xfer_info.bufferlen; } - memcpy(USBFS_TX_Buf, usb_current_xfer_info.current_xfer_buffer, copylen); + memcpy(USBFS_TX_Buf, usb_current_xfer_info.buffer, copylen); hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle); return; } @@ -463,15 +491,15 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) case USB_PID_IN: { uint16_t received_len = USBOTG_H_FS->RX_LEN; - usb_current_xfer_info.current_xfer_xferred_len += received_len; - uint16_t xferred_len = usb_current_xfer_info.current_xfer_xferred_len; + usb_current_xfer_info.xferred_len += received_len; + uint16_t xferred_len = usb_current_xfer_info.xferred_len; LOG_CH32_USBFSH("Read %d bytes\r\n", received_len); - // if (received_len > 0 && (usb_current_xfer_info.current_xfer_buffer == NULL || usb_current_xfer_info.current_xfer_bufferlen == 0)) { + // if (received_len > 0 && (usb_current_xfer_info.buffer == NULL || usb_current_xfer_info.bufferlen == 0)) { // PANIC("Data received but buffer not set\r\n"); // } - memcpy(usb_current_xfer_info.current_xfer_buffer, USBFS_RX_Buf, received_len); - usb_current_xfer_info.current_xfer_buffer += received_len; - if ((received_len < edpt_info->max_packet_size) || (xferred_len == usb_current_xfer_info.current_xfer_bufferlen)) + memcpy(usb_current_xfer_info.buffer, USBFS_RX_Buf, received_len); + usb_current_xfer_info.buffer += received_len; + if ((received_len < edpt_info->max_packet_size) || (xferred_len == usb_current_xfer_info.bufferlen)) { // USB device sent all data. LOG_CH32_USBFSH("USB_PID_IN completed\r\n"); @@ -506,8 +534,8 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) else if (response_pid == USB_PID_NAK) { LOG_CH32_USBFSH("NAK reposense\r\n"); - uint32_t elapsed_time = board_millis() - usb_current_xfer_info.current_xfer_packet_start_millis; - if (edpt_info->xfer_type == TUSB_XFER_INTERRUPT && (elapsed_time > USB_INTERRUPT_XFER_TIMEOUT_MILLIS)) + uint32_t elapsed_time = board_millis() - usb_current_xfer_info.start_ms; + if (edpt_info->xfer_type == TUSB_XFER_INTERRUPT) { usb_current_xfer_info.is_busy = false; hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_SUCCESS, true); @@ -564,16 +592,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const TU_ASSERT(get_or_add_edpt_record(dev_addr, ep_addr, max_packet_size, xfer_type) != NULL, false); } - update_device_address(dev_addr); - if (dev_addr == 0x00 && ep_num == 0x00) - { - // It assumes first open for the device, so make the port enable - tusb_speed_t device_speed = hcd_port_speed_get(rhport); - update_port_speed(device_speed); USBOTG_H_FS->HOST_CTRL |= USBFS_UH_PORT_EN; USBOTG_H_FS->HOST_SETUP |= USBFS_UH_SOF_EN; - } + + hardware_set_port_address_speed(dev_addr); return true; } @@ -582,9 +605,10 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * { (void)rhport; - while (usb_current_xfer_info.is_busy) { - osal_task_delay(1); - } + LOG_CH32_USBFSH("hcd_edpt_xfer(%d, 0x%02x, 0x%02x, ...)\r\n", rhport, dev_addr, ep_addr); + + while (usb_current_xfer_info.is_busy) { } + usb_current_xfer_info.is_busy = true; usb_edpt_t* edpt_info = get_edpt_record(dev_addr, ep_addr); @@ -593,16 +617,14 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * PANIC("get_edpt_record() returned NULL in hcd_edpt_xfer()\r\n"); } - update_device_address(dev_addr); - tusb_speed_t device_speed = hcd_port_speed_get(rhport); - update_port_speed(device_speed); + hardware_set_port_address_speed(dev_addr); usb_current_xfer_info.dev_addr = dev_addr; usb_current_xfer_info.ep_addr = ep_addr; - usb_current_xfer_info.current_xfer_buffer = buffer; - usb_current_xfer_info.current_xfer_bufferlen = buflen; - usb_current_xfer_info.current_xfer_packet_start_millis = board_millis(); - usb_current_xfer_info.current_xfer_xferred_len = 0; + usb_current_xfer_info.buffer = buffer; + usb_current_xfer_info.bufferlen = buflen; + usb_current_xfer_info.start_ms = board_millis(); + usb_current_xfer_info.xferred_len = 0; if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { @@ -628,7 +650,6 @@ bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) (void) rhport; (void) dev_addr; (void) ep_addr; - LOG_CH32_USBFSH("hcd_edpt_abort_xfer(%d, 0x%02x, 0x%02x)\r\n", rhport, dev_addr, ep_addr); return false; } @@ -637,19 +658,13 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet { (void)rhport; - if (usb_current_xfer_info.is_busy) { - osal_task_delay(1); - } + while (usb_current_xfer_info.is_busy) { } + usb_current_xfer_info.is_busy = true; LOG_CH32_USBFSH("hcd_setup_send(rhport=%d, dev_addr=0x%02x, %p)\r\n", rhport, dev_addr, setup_packet); - // loopdelay(SystemCoreClock / 1000000 * 100); - loopdelay(1); - - update_device_address(dev_addr); - tusb_speed_t device_speed = hcd_port_speed_get(rhport); - update_port_speed(device_speed); + hardware_set_port_address_speed(dev_addr); usb_edpt_t* edpt_info_tx = get_edpt_record(dev_addr, 0x00); usb_edpt_t* edpt_info_rx = get_edpt_record(dev_addr, 0x80); @@ -667,10 +682,10 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet uint8_t ep_addr = (setup_packet[0] & 0x80) ? 0x80 : 0x00; usb_current_xfer_info.dev_addr = dev_addr; usb_current_xfer_info.ep_addr = ep_addr; - usb_current_xfer_info.current_xfer_packet_start_millis = board_millis(); - usb_current_xfer_info.current_xfer_buffer = USBFS_TX_Buf; - usb_current_xfer_info.current_xfer_bufferlen = setup_packet_datalen; - usb_current_xfer_info.current_xfer_xferred_len = 0; + usb_current_xfer_info.start_ms = board_millis(); + usb_current_xfer_info.buffer = USBFS_TX_Buf; + usb_current_xfer_info.bufferlen = setup_packet_datalen; + usb_current_xfer_info.xferred_len = 0; hardware_start_xfer(USB_PID_SETUP, 0, 0); @@ -690,6 +705,7 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) memcpy(USBFS_TX_Buf, setup_request_clear_stall, 8); USBOTG_H_FS->HOST_TX_LEN = 8; + bool prev_int_state = interrupt_enabled; hcd_int_disable(0); USBOTG_H_FS->HOST_EP_PID = (USB_PID_SETUP << 4) | 0x00; @@ -700,7 +716,9 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) (void)response_pid; LOG_CH32_USBFSH("hcd_edpt_clear_stall() response pid=0x%02x\r\n", response_pid); + if (prev_int_state) { hcd_int_enable(0); + } return true; } From 6e88895dbc2b09e60b971f1587d19d3a2487c2f8 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 5 Jul 2025 11:26:48 +0700 Subject: [PATCH 09/10] always define CFG_TUH_WCH_USBIP_USBFS=1 for ch32v20x since only port1 support host mode reformat hcd usbfs add uart rx for ch32v20x bsp --- hw/bsp/ch32v20x/family.c | 91 +-- hw/bsp/ch32v20x/family.cmake | 28 +- src/common/tusb_mcu.h | 8 +- src/portable/wch/dcd_ch32_usbhs.c | 2 +- src/portable/wch/hcd_ch32_usbfs.c | 931 +++++++++++++----------------- 5 files changed, 483 insertions(+), 577 deletions(-) diff --git a/hw/bsp/ch32v20x/family.c b/hw/bsp/ch32v20x/family.c index 2c212a82b..510f82981 100644 --- a/hw/bsp/ch32v20x/family.c +++ b/hw/bsp/ch32v20x/family.c @@ -20,59 +20,56 @@ manufacturer: WCH #include "bsp/board_api.h" #include "board.h" -/* CH32v203 depending on variants can support 2 USB IPs: FSDEV and USBFS. +/* CH32v203 depending on variants can support 2 USB IPs: FSDEV (port0) and USBFS (port1). * By default, we use FSDEV, but you can explicitly select by define: * - CFG_TUD_WCH_USBIP_FSDEV * - CFG_TUD_WCH_USBIP_USBFS */ -// USBFS -__attribute__((interrupt)) __attribute__((used)) -void USBHD_IRQHandler(void) { - #if CFG_TUD_WCH_USBIP_USBFS +// Port0: USBD (fsdev) +__attribute__((interrupt)) __attribute__((used)) void USB_LP_CAN1_RX0_IRQHandler(void) { + #if CFG_TUD_WCH_USBIP_FSDEV tud_int_handler(0); #endif - #if defined(CFG_TUH_WCH_USBIP_USBFS) && CFG_TUH_WCH_USBIP_USBFS - tuh_int_handler(0); - #endif } -__attribute__((interrupt)) __attribute__((used)) -void USBHDWakeUp_IRQHandler(void) { +__attribute__((interrupt)) __attribute__((used)) void USB_HP_CAN1_TX_IRQHandler(void) { + #if CFG_TUD_WCH_USBIP_FSDEV + tud_int_handler(0); + #endif + +} + +__attribute__((interrupt)) __attribute__((used)) void USBWakeUp_IRQHandler(void) { + #if CFG_TUD_WCH_USBIP_FSDEV + tud_int_handler(0); + #endif +} + +// Port1: USBFS +__attribute__((interrupt)) __attribute__((used)) void USBHD_IRQHandler(void) { + #if CFG_TUD_ENABLED && CFG_TUD_WCH_USBIP_USBFS + tud_int_handler(1); + #endif + + #if CFG_TUH_ENABLED + tuh_int_handler(1); + #endif +} + +__attribute__((interrupt)) __attribute__((used)) void USBHDWakeUp_IRQHandler(void) { #if CFG_TUD_WCH_USBIP_USBFS tud_int_handler(0); #endif } -// USBD (fsdev) -__attribute__((interrupt)) __attribute__((used)) -void USB_LP_CAN1_RX0_IRQHandler(void) { - #if CFG_TUD_WCH_USBIP_FSDEV - tud_int_handler(0); - #endif -} - -__attribute__((interrupt)) __attribute__((used)) -void USB_HP_CAN1_TX_IRQHandler(void) { - #if CFG_TUD_WCH_USBIP_FSDEV - tud_int_handler(0); - #endif - -} - -__attribute__((interrupt)) __attribute__((used)) -void USBWakeUp_IRQHandler(void) { - #if CFG_TUD_WCH_USBIP_FSDEV - tud_int_handler(0); - #endif -} - - +//--------------------------------------------------------------------+ +// Board API +//--------------------------------------------------------------------+ #if CFG_TUSB_OS == OPT_OS_NONE volatile uint32_t system_ticks = 0; -__attribute__((interrupt)) -void SysTick_Handler(void) { +__attribute__((interrupt)) void SysTick_Handler(void) { SysTick->SR = 0; system_ticks++; } @@ -111,7 +108,7 @@ void board_init(void) { #ifdef UART_DEV UART_CLOCK_EN(); GPIO_InitTypeDef usart_init = { - .GPIO_Pin = UART_TX_PIN, + .GPIO_Pin = UART_TX_PIN | UART_RX_PIN, .GPIO_Speed = GPIO_Speed_50MHz, .GPIO_Mode = GPIO_Mode_AF_PP, }; @@ -122,7 +119,7 @@ void board_init(void) { .USART_WordLength = USART_WordLength_8b, .USART_StopBits = USART_StopBits_1, .USART_Parity = USART_Parity_No, - .USART_Mode = USART_Mode_Tx, + .USART_Mode = USART_Mode_Tx | USART_Mode_Rx, .USART_HardwareFlowControl = USART_HardwareFlowControl_None, }; USART_Init(UART_DEV, &usart); @@ -192,9 +189,19 @@ size_t board_get_unique_id(uint8_t id[], size_t max_len) { } int board_uart_read(uint8_t *buf, int len) { - (void) buf; - (void) len; +#ifdef UART_DEV + int count; + for (count = 0; count < len; count++) { + if (USART_GetFlagStatus(UART_DEV, USART_FLAG_RXNE) == RESET) { + break; + } + buf[count] = USART_ReceiveData(UART_DEV); + } + return count; +#else + (void) buf; (void) len; return 0; +#endif } int board_uart_write(void const *buf, int len) { @@ -210,7 +217,3 @@ int board_uart_write(void const *buf, int len) { return len; } - -//-------------------------------------------------------------------- -// Neopixel -//-------------------------------------------------------------------- diff --git a/hw/bsp/ch32v20x/family.cmake b/hw/bsp/ch32v20x/family.cmake index 6092abc8d..10044d5b3 100644 --- a/hw/bsp/ch32v20x/family.cmake +++ b/hw/bsp/ch32v20x/family.cmake @@ -16,9 +16,12 @@ set(FAMILY_MCUS CH32V20X CACHE INTERNAL "") set(OPENOCD_OPTION "-f ${CMAKE_CURRENT_LIST_DIR}/wch-riscv.cfg") # Port0 use FSDev, Port1 use USBFS -if (NOT DEFINED PORT) - set(PORT 0) -endif() +if (NOT DEFINED RHPORT_DEVICE) + set(RHPORT_DEVICE 0) +endif () + +# only port1 support host mode +set(RHPORT_HOST 1) #------------------------------------ # BOARD_TARGET @@ -56,19 +59,16 @@ function(add_board_target BOARD_TARGET) ) target_compile_definitions(${BOARD_TARGET} PUBLIC CH32V20x_${MCU_VARIANT} + BOARD_TUD_RHPORT=${RHPORT_DEVICE} + BOARD_TUH_RHPORT=${RHPORT_HOST} ) - if (PORT EQUAL 0) - target_compile_definitions(${BOARD_TARGET} PUBLIC - CFG_TUD_WCH_USBIP_FSDEV=1 - CFG_TUH_WCH_USBIP_USBFS=1 - ) - elseif (PORT EQUAL 1) - target_compile_definitions(${BOARD_TARGET} PUBLIC - CFG_TUD_WCH_USBIP_USBFS=1 - ) + if (RHPORT_DEVICE EQUAL 0) + target_compile_definitions(${BOARD_TARGET} PUBLIC CFG_TUD_WCH_USBIP_FSDEV=1) + elseif (RHPORT_DEVICE EQUAL 1) + target_compile_definitions(${BOARD_TARGET} PUBLIC CFG_TUH_WCH_USBIP_USBFS=1) else() - message(FATAL_ERROR "Invalid PORT ${PORT}") + message(FATAL_ERROR "Invalid RHPORT_DEVICE ${RHPORT_DEVICE}") endif() update_board(${BOARD_TARGET}) @@ -133,8 +133,6 @@ function(family_configure_example TARGET RTOS) ) target_link_libraries(${TARGET} PUBLIC board_${BOARD}) - - # Flashing family_add_bin_hex(${TARGET}) family_flash_openocd_wch(${TARGET}) diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 2ee2132bf..a08ed79c8 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -503,11 +503,17 @@ #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_CH32V20X) - // v20x support both FSDEV (USBD) and USBFS, default to FSDEV + // v20x support both port0 FSDEV (USBD) and port1 USBFS #define TUP_USBIP_WCH_USBFS + + #ifndef CFG_TUH_WCH_USBIP_USBFS + #define CFG_TUH_WCH_USBIP_USBFS 1 + #endif + #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_CH32 + // default to FSDEV for device #if !defined(CFG_TUD_WCH_USBIP_USBFS) #define CFG_TUD_WCH_USBIP_USBFS 0 #endif diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c index f8bf3c889..4a208b9df 100644 --- a/src/portable/wch/dcd_ch32_usbhs.c +++ b/src/portable/wch/dcd_ch32_usbhs.c @@ -27,7 +27,7 @@ #include "tusb_option.h" -#if CFG_TUD_ENABLED && defined(TUP_USBIP_WCH_USBHS) && CFG_TUD_WCH_USBIP_USBHS +#if CFG_TUD_ENABLED && defined(TUP_USBIP_WCH_USBHS) && defined(CFG_TUD_WCH_USBIP_USBHS) && CFG_TUD_WCH_USBIP_USBHS #include "ch32_usbhs_reg.h" #include "device/dcd.h" diff --git a/src/portable/wch/hcd_ch32_usbfs.c b/src/portable/wch/hcd_ch32_usbfs.c index 800390989..d176f40c5 100644 --- a/src/portable/wch/hcd_ch32_usbfs.c +++ b/src/portable/wch/hcd_ch32_usbfs.c @@ -37,20 +37,20 @@ #include "ch32v20x.h" #include "ch32v20x_usb.h" -void osal_task_delay(uint32_t msec) { - uint32_t start = board_millis(); - while (board_millis() - start < msec) {} -} - #define USBFS_RX_BUF_LEN 64 #define USBFS_TX_BUF_LEN 64 -__attribute__((aligned(4))) static uint8_t USBFS_RX_Buf[USBFS_RX_BUF_LEN]; -__attribute__((aligned(4))) static uint8_t USBFS_TX_Buf[USBFS_TX_BUF_LEN]; +TU_ATTR_ALIGNED(4) static uint8_t USBFS_RX_Buf[USBFS_RX_BUF_LEN]; +TU_ATTR_ALIGNED(4) static uint8_t USBFS_TX_Buf[USBFS_TX_BUF_LEN]; #define USB_XFER_TIMEOUT_MILLIS 100 // #define USB_INTERRUPT_XFER_TIMEOUT_MILLIS 1 -#define PANIC(...) do { printf("%s() L%d: ", __func__, __LINE__); printf("\r\n[PANIC] " __VA_ARGS__); while (true) { } } while (false) +#define PANIC(...) \ + do { \ + printf("%s() L%d: ", __func__, __LINE__); \ + printf("\r\n[PANIC] " __VA_ARGS__); \ + while (true) {} \ + } while (false) #define LOG_CH32_USBFSH(...) TU_LOG3(__VA_ARGS__) @@ -70,106 +70,87 @@ __attribute__((aligned(4))) static uint8_t USBFS_TX_Buf[USBFS_TX_BUF_LEN]; // Endpoint status -typedef struct usb_edpt -{ - // Is this a valid struct - bool configured; +typedef struct usb_edpt { + // Is this a valid struct + bool configured; - uint8_t dev_addr; - uint8_t ep_addr; - uint8_t max_packet_size; + uint8_t dev_addr; + uint8_t ep_addr; + uint8_t max_packet_size; - uint8_t xfer_type; + uint8_t xfer_type; - // Data toggle (0 or not 0) for DATA0/1 - uint8_t data_toggle; + // Data toggle (0 or not 0) for DATA0/1 + uint8_t data_toggle; } usb_edpt_t; - static usb_edpt_t usb_edpt_list[CFG_TUH_DEVICE_MAX * 6] = {}; - typedef struct usb_current_xfer_st { - bool is_busy; - uint8_t dev_addr; - uint8_t ep_addr; - // Xfer started time in millis for timeout - uint32_t start_ms; - uint8_t* buffer; - uint16_t bufferlen; - uint16_t xferred_len; + bool is_busy; + uint8_t dev_addr; + uint8_t ep_addr; + // Xfer started time in millis for timeout + uint32_t start_ms; + uint8_t *buffer; + uint16_t bufferlen; + uint16_t xferred_len; } usb_current_xfer_t; static volatile usb_current_xfer_t usb_current_xfer_info = {}; - -static usb_edpt_t* get_edpt_record(uint8_t dev_addr, uint8_t ep_addr) -{ - for (size_t i = 0; i < TU_ARRAY_SIZE(usb_edpt_list); i++) - { - usb_edpt_t* cur = &usb_edpt_list[i]; - if (cur->configured && cur->dev_addr == dev_addr && cur->ep_addr == ep_addr) - { - return cur; - } +static usb_edpt_t *get_edpt_record(uint8_t dev_addr, uint8_t ep_addr) { + for (size_t i = 0; i < TU_ARRAY_SIZE(usb_edpt_list); i++) { + usb_edpt_t *cur = &usb_edpt_list[i]; + if (cur->configured && cur->dev_addr == dev_addr && cur->ep_addr == ep_addr) { + return cur; } - return NULL; + } + return NULL; } -static usb_edpt_t* get_empty_record_slot(void) -{ - for (size_t i = 0; i < TU_ARRAY_SIZE(usb_edpt_list); i++) - { - if (!usb_edpt_list[i].configured) - { - return &usb_edpt_list[i]; - } +static usb_edpt_t *get_empty_record_slot(void) { + for (size_t i = 0; i < TU_ARRAY_SIZE(usb_edpt_list); i++) { + if (!usb_edpt_list[i].configured) { + return &usb_edpt_list[i]; } - return NULL; + } + return NULL; } -static usb_edpt_t* add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size, uint8_t xfer_type) -{ - usb_edpt_t* slot = get_empty_record_slot(); - if (slot == NULL) { - PANIC("add_edpt_record(0x%02x, 0x%02x, ...) no slot for new record\r\n", dev_addr, ep_addr); - } - TU_ASSERT(slot != NULL, NULL); +static usb_edpt_t *add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size, uint8_t xfer_type) { + usb_edpt_t *slot = get_empty_record_slot(); + if (slot == NULL) { + PANIC("add_edpt_record(0x%02x, 0x%02x, ...) no slot for new record\r\n", dev_addr, ep_addr); + } + TU_ASSERT(slot != NULL, NULL); - slot->dev_addr = dev_addr; - slot->ep_addr = ep_addr; - slot->max_packet_size = max_packet_size; - slot->xfer_type = xfer_type; - slot->data_toggle = 0; + slot->dev_addr = dev_addr; + slot->ep_addr = ep_addr; + slot->max_packet_size = max_packet_size; + slot->xfer_type = xfer_type; + slot->data_toggle = 0; - slot->configured = true; + slot->configured = true; - return slot; + return slot; } -static usb_edpt_t* get_or_add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size, uint8_t xfer_type) -{ - usb_edpt_t* ret = get_edpt_record(dev_addr, ep_addr); - if (ret != NULL) - { - return ret; - } - else - { - return add_edpt_record(dev_addr, ep_addr, max_packet_size, xfer_type); - } +static usb_edpt_t *get_or_add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size, uint8_t xfer_type) { + usb_edpt_t *ret = get_edpt_record(dev_addr, ep_addr); + if (ret != NULL) { + return ret; + } else { + return add_edpt_record(dev_addr, ep_addr, max_packet_size, xfer_type); + } } - -static void remove_edpt_record_for_device(uint8_t dev_addr) -{ - for (size_t i = 0; i < TU_ARRAY_SIZE(usb_edpt_list); i++) - { - if (usb_edpt_list[i].configured && usb_edpt_list[i].dev_addr == dev_addr) - { - usb_edpt_list[i].configured = false; - } +static void remove_edpt_record_for_device(uint8_t dev_addr) { + for (size_t i = 0; i < TU_ARRAY_SIZE(usb_edpt_list); i++) { + if (usb_edpt_list[i].configured && usb_edpt_list[i].dev_addr == dev_addr) { + usb_edpt_list[i].configured = false; } + } } // static void dump_edpt_record_list() { @@ -183,544 +164,462 @@ static void remove_edpt_record_for_device(uint8_t dev_addr) // } // } - static bool interrupt_enabled = false; /** Enable or disable USBFS Host function */ -static void hardware_init_host(bool enabled) -{ - // Reset USBOTG module - USBOTG_H_FS->BASE_CTRL = USBFS_UC_RESET_SIE | USBFS_UC_CLR_ALL; +static void hardware_init_host(bool enabled) { + // Reset USBOTG module + USBOTG_H_FS->BASE_CTRL = USBFS_UC_RESET_SIE | USBFS_UC_CLR_ALL; - osal_task_delay(1); + tusb_time_delay_ms_api(1); + USBOTG_H_FS->BASE_CTRL = 0; + + if (!enabled) { + // Disable all feature USBOTG_H_FS->BASE_CTRL = 0; - - if (!enabled) - { - // Disable all feature - USBOTG_H_FS->BASE_CTRL = 0; - } - else - { - // Enable USB Host features - // NVIC_DisableIRQ(USBFS_IRQn); - hcd_int_disable(0); - USBOTG_H_FS->BASE_CTRL = USBFS_UC_HOST_MODE | USBFS_UC_INT_BUSY | USBFS_UC_DMA_EN; - USBOTG_H_FS->HOST_EP_MOD = USBFS_UH_EP_TX_EN | USBFS_UH_EP_RX_EN; - USBOTG_H_FS->HOST_RX_DMA = (uint32_t)USBFS_RX_Buf; - USBOTG_H_FS->HOST_TX_DMA = (uint32_t)USBFS_TX_Buf; - // USBOTG_H_FS->INT_EN = USBFS_UIE_TRANSFER | USBFS_UIE_DETECT; - USBOTG_H_FS->INT_EN = USBFS_UIE_DETECT; - } + } else { + // Enable USB Host features + // NVIC_DisableIRQ(USBFS_IRQn); + hcd_int_disable(0); + USBOTG_H_FS->BASE_CTRL = USBFS_UC_HOST_MODE | USBFS_UC_INT_BUSY | USBFS_UC_DMA_EN; + USBOTG_H_FS->HOST_EP_MOD = USBFS_UH_EP_TX_EN | USBFS_UH_EP_RX_EN; + USBOTG_H_FS->HOST_RX_DMA = (uint32_t) USBFS_RX_Buf; + USBOTG_H_FS->HOST_TX_DMA = (uint32_t) USBFS_TX_Buf; + // USBOTG_H_FS->INT_EN = USBFS_UIE_TRANSFER | USBFS_UIE_DETECT; + USBOTG_H_FS->INT_EN = USBFS_UIE_DETECT; + } } -static bool hardware_start_xfer(uint8_t pid, uint8_t ep_addr, uint8_t data_toggle) -{ - LOG_CH32_USBFSH("hardware_start_xfer(pid=%s(0x%02x), ep_addr=0x%02x, toggle=%d)\r\n", - pid == USB_PID_IN ? "IN" : pid == USB_PID_OUT ? "OUT" : pid == USB_PID_SETUP ? "SETUP" : "(other)", - pid, ep_addr, data_toggle); +static bool hardware_start_xfer(uint8_t pid, uint8_t ep_addr, uint8_t data_toggle) { + LOG_CH32_USBFSH("hardware_start_xfer(pid=%s(0x%02x), ep_addr=0x%02x, toggle=%d)\r\n", + pid == USB_PID_IN ? "IN" : pid == USB_PID_OUT ? "OUT" + : pid == USB_PID_SETUP ? "SETUP" + : "(other)", + pid, ep_addr, data_toggle); - // if (pid == USB_PID_IN) - // { // FIXME: long delay needed (at release build) about 30msec - // loopdelay(SystemCoreClock / 1000 * 30); - // } + // if (pid == USB_PID_IN) + // { // FIXME: long delay needed (at release build) about 30msec + // loopdelay(SystemCoreClock / 1000 * 30); + // } - uint8_t pid_edpt = (pid << 4) | (tu_edpt_number(ep_addr) & 0x0f); - USBOTG_H_FS->HOST_TX_CTRL = (data_toggle != 0) ? USBFS_UH_T_TOG : 0; - USBOTG_H_FS->HOST_RX_CTRL = (data_toggle != 0) ? USBFS_UH_R_TOG : 0; - USBOTG_H_FS->HOST_EP_PID = pid_edpt; - USBOTG_H_FS->INT_EN |= USBFS_UIE_TRANSFER; - USBOTG_H_FS->INT_FG = USBFS_UIF_TRANSFER; - return true; + uint8_t pid_edpt = (pid << 4) | (tu_edpt_number(ep_addr) & 0x0f); + USBOTG_H_FS->HOST_TX_CTRL = (data_toggle != 0) ? USBFS_UH_T_TOG : 0; + USBOTG_H_FS->HOST_RX_CTRL = (data_toggle != 0) ? USBFS_UH_R_TOG : 0; + USBOTG_H_FS->HOST_EP_PID = pid_edpt; + USBOTG_H_FS->INT_EN |= USBFS_UIE_TRANSFER; + USBOTG_H_FS->INT_FG = USBFS_UIF_TRANSFER; + return true; } /** Set device address to communicate */ -static void hardware_update_device_address(uint8_t dev_addr) -{ - // Keep the bit of GP_BIT. Other 7bits are actual device address. - USBOTG_H_FS->DEV_ADDR = (USBOTG_H_FS->DEV_ADDR & USBFS_UDA_GP_BIT) | (dev_addr & USBFS_USB_ADDR_MASK); +static void hardware_update_device_address(uint8_t dev_addr) { + // Keep the bit of GP_BIT. Other 7bits are actual device address. + USBOTG_H_FS->DEV_ADDR = (USBOTG_H_FS->DEV_ADDR & USBFS_UDA_GP_BIT) | (dev_addr & USBFS_USB_ADDR_MASK); } /** Set port speed */ -static void hardware_update_port_speed(tusb_speed_t speed) -{ - LOG_CH32_USBFSH("hardware_update_port_speed(%s)\r\n", speed == TUSB_SPEED_FULL ? "Full" : speed == TUSB_SPEED_LOW ? "Low" : "(invalid)"); - switch (speed) { +static void hardware_update_port_speed(tusb_speed_t speed) { + LOG_CH32_USBFSH("hardware_update_port_speed(%s)\r\n", speed == TUSB_SPEED_FULL ? "Full" : speed == TUSB_SPEED_LOW ? "Low" + : "(invalid)"); + switch (speed) { case TUSB_SPEED_LOW: - USBOTG_H_FS->BASE_CTRL |= USBFS_UC_LOW_SPEED; - USBOTG_H_FS->HOST_CTRL |= USBFS_UH_LOW_SPEED; - USBOTG_H_FS->HOST_SETUP |= USBFS_UH_PRE_PID_EN; - return; + USBOTG_H_FS->BASE_CTRL |= USBFS_UC_LOW_SPEED; + USBOTG_H_FS->HOST_CTRL |= USBFS_UH_LOW_SPEED; + USBOTG_H_FS->HOST_SETUP |= USBFS_UH_PRE_PID_EN; + return; case TUSB_SPEED_FULL: - USBOTG_H_FS->BASE_CTRL &= ~USBFS_UC_LOW_SPEED; - USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_LOW_SPEED; - USBOTG_H_FS->HOST_SETUP &= ~USBFS_UH_PRE_PID_EN; - return; + USBOTG_H_FS->BASE_CTRL &= ~USBFS_UC_LOW_SPEED; + USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_LOW_SPEED; + USBOTG_H_FS->HOST_SETUP &= ~USBFS_UH_PRE_PID_EN; + return; default: - PANIC("hardware_update_port_speed(%d)\r\n", speed); - } + PANIC("hardware_update_port_speed(%d)\r\n", speed); + } } - static void hardware_set_port_address_speed(uint8_t dev_addr) { - hardware_update_device_address(dev_addr); - tusb_speed_t rhport_speed = hcd_port_speed_get(0); - tusb_speed_t dev_speed = tuh_speed_get(dev_addr); - hardware_update_port_speed(dev_speed); - if (rhport_speed == TUSB_SPEED_FULL && dev_speed == TUSB_SPEED_LOW) { - USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_LOW_SPEED; - } + hardware_update_device_address(dev_addr); + tusb_speed_t rhport_speed = hcd_port_speed_get(0); + tusb_speed_t dev_speed = tuh_speed_get(dev_addr); + hardware_update_port_speed(dev_speed); + if (rhport_speed == TUSB_SPEED_FULL && dev_speed == TUSB_SPEED_LOW) { + USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_LOW_SPEED; + } } - -static bool hardware_device_attached(void) -{ - return USBOTG_H_FS->MIS_ST & USBFS_UMS_DEV_ATTACH; +static bool hardware_device_attached(void) { + return USBOTG_H_FS->MIS_ST & USBFS_UMS_DEV_ATTACH; } - //--------------------------------------------------------------------+ // HCD API //--------------------------------------------------------------------+ -bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) -{ - (void)rhport; - (void)rh_init; - hardware_init_host(true); +bool hcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { + (void) rhport; + (void) rh_init; + hardware_init_host(true); - return true; + return true; } -bool hcd_deinit(uint8_t rhport) -{ - (void)rhport; - hardware_init_host(false); +bool hcd_deinit(uint8_t rhport) { + (void) rhport; + hardware_init_host(false); - return true; + return true; } - static bool int_state_for_portreset = false; -void hcd_port_reset(uint8_t rhport) -{ - (void)rhport; - LOG_CH32_USBFSH("hcd_port_reset()\r\n"); - int_state_for_portreset = interrupt_enabled; - // NVIC_DisableIRQ(USBFS_IRQn); - hcd_int_disable(rhport); - hardware_update_device_address(0x00); +void hcd_port_reset(uint8_t rhport) { + (void) rhport; + LOG_CH32_USBFSH("hcd_port_reset()\r\n"); + int_state_for_portreset = interrupt_enabled; + // NVIC_DisableIRQ(USBFS_IRQn); + hcd_int_disable(rhport); + hardware_update_device_address(0x00); - // USBOTG_H_FS->HOST_SETUP = 0x00; + // USBOTG_H_FS->HOST_SETUP = 0x00; - USBOTG_H_FS->HOST_CTRL |= USBFS_UH_BUS_RESET; + USBOTG_H_FS->HOST_CTRL |= USBFS_UH_BUS_RESET; - return; + return; } -void hcd_port_reset_end(uint8_t rhport) -{ - (void)rhport; - LOG_CH32_USBFSH("hcd_port_reset_end()\r\n"); +void hcd_port_reset_end(uint8_t rhport) { + (void) rhport; + LOG_CH32_USBFSH("hcd_port_reset_end()\r\n"); - USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_BUS_RESET; - osal_task_delay(2); + USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_BUS_RESET; + tusb_time_delay_ms_api(2); - if ((USBOTG_H_FS->HOST_CTRL & USBFS_UH_PORT_EN) == 0) - { - if (hcd_port_speed_get(0) == TUSB_SPEED_LOW) - { - hardware_update_port_speed(TUSB_SPEED_LOW); - } + if ((USBOTG_H_FS->HOST_CTRL & USBFS_UH_PORT_EN) == 0) { + if (hcd_port_speed_get(0) == TUSB_SPEED_LOW) { + hardware_update_port_speed(TUSB_SPEED_LOW); } + } - USBOTG_H_FS->HOST_CTRL |= USBFS_UH_PORT_EN; - USBOTG_H_FS->HOST_SETUP |= USBFS_UH_SOF_EN; + USBOTG_H_FS->HOST_CTRL |= USBFS_UH_PORT_EN; + USBOTG_H_FS->HOST_SETUP |= USBFS_UH_SOF_EN; - // Suppress the attached event - USBOTG_H_FS->INT_FG |= USBFS_UIF_DETECT; + // Suppress the attached event + USBOTG_H_FS->INT_FG |= USBFS_UIF_DETECT; - if (int_state_for_portreset) { - hcd_int_enable(rhport); - } - - return; + if (int_state_for_portreset) { + hcd_int_enable(rhport); + } } -bool hcd_port_connect_status(uint8_t rhport) -{ - (void)rhport; +bool hcd_port_connect_status(uint8_t rhport) { + (void) rhport; - return hardware_device_attached(); + return hardware_device_attached(); } -tusb_speed_t hcd_port_speed_get(uint8_t rhport) -{ - (void)rhport; - if (USBOTG_H_FS->MIS_ST & USBFS_UMS_DM_LEVEL) - { - return TUSB_SPEED_LOW; - } - else - { - return TUSB_SPEED_FULL; - } +tusb_speed_t hcd_port_speed_get(uint8_t rhport) { + (void) rhport; + if (USBOTG_H_FS->MIS_ST & USBFS_UMS_DM_LEVEL) { + return TUSB_SPEED_LOW; + } else { + return TUSB_SPEED_FULL; + } } // Close all opened endpoint belong to this device -void hcd_device_close(uint8_t rhport, uint8_t dev_addr) -{ - (void)rhport; - LOG_CH32_USBFSH("hcd_device_close(%d, 0x%02x)\r\n", rhport, dev_addr); - remove_edpt_record_for_device(dev_addr); +void hcd_device_close(uint8_t rhport, uint8_t dev_addr) { + (void) rhport; + LOG_CH32_USBFSH("hcd_device_close(%d, 0x%02x)\r\n", rhport, dev_addr); + remove_edpt_record_for_device(dev_addr); +} +uint32_t hcd_frame_number(uint8_t rhport) { + (void) rhport; + + return board_millis(); +} + +void hcd_int_enable(uint8_t rhport) { + (void) rhport; + NVIC_EnableIRQ(USBFS_IRQn); + interrupt_enabled = true; +} + +void hcd_int_disable(uint8_t rhport) { + (void) rhport; + NVIC_DisableIRQ(USBFS_IRQn); + interrupt_enabled = false; +} + +void hcd_int_handler(uint8_t rhport, bool in_isr) { + (void) rhport; + (void) in_isr; + + if (USBOTG_H_FS->INT_FG & USBFS_UIF_DETECT) { + // Clear the flag + USBOTG_H_FS->INT_FG = USBFS_UIF_DETECT; + // Read the detection state + bool attached = hardware_device_attached(); + LOG_CH32_USBFSH("hcd_int_handler() attached = %d\r\n", attached ? 1 : 0); + if (attached) { + hcd_event_device_attach(rhport, true); + } else { + hcd_event_device_remove(rhport, true); + } return; -} + } -uint32_t hcd_frame_number(uint8_t rhport) -{ - (void)rhport; + if (USBOTG_H_FS->INT_FG & USBFS_UIF_TRANSFER) { + // Disable transfer interrupt + USBOTG_H_FS->INT_EN &= ~USBFS_UIE_TRANSFER; + // Clear the flag + // USBOTG_H_FS->INT_FG = USBFS_UIF_TRANSFER; + // Copy PID and Endpoint + uint8_t pid_edpt = USBOTG_H_FS->HOST_EP_PID; + uint8_t status = USBOTG_H_FS->INT_ST; + uint8_t dev_addr = USBOTG_H_FS->DEV_ADDR & USBFS_USB_ADDR_MASK; + // Clear register to stop transfer + // USBOTG_H_FS->HOST_EP_PID = 0x00; - return board_millis(); -} + LOG_CH32_USBFSH("hcd_int_handler() pid_edpt=0x%02x\r\n", pid_edpt); -void hcd_int_enable(uint8_t rhport) -{ - (void)rhport; - NVIC_EnableIRQ(USBFS_IRQn); - interrupt_enabled = true; + uint8_t request_pid = pid_edpt >> 4; + uint8_t response_pid = status & USBFS_UIS_H_RES_MASK; + uint8_t ep_addr = pid_edpt & 0x0f; + if (request_pid == USB_PID_IN) { + ep_addr |= 0x80; + } - return; -} + usb_edpt_t *edpt_info = get_edpt_record(dev_addr, ep_addr); + if (edpt_info == NULL) { + PANIC("\r\nget_edpt_record(0x%02x, 0x%02x) returned NULL in USBHD_IRQHandler\r\n", dev_addr, ep_addr); + } -void hcd_int_disable(uint8_t rhport) -{ - (void)rhport; - NVIC_DisableIRQ(USBFS_IRQn); - interrupt_enabled = false; + if (status & USBFS_UIS_TOG_OK) { + edpt_info->data_toggle ^= 0x01; - return; -} - -void hcd_int_handler(uint8_t rhport, bool in_isr) -{ - (void)rhport; - (void)in_isr; - - if (USBOTG_H_FS->INT_FG & USBFS_UIF_DETECT) - { - // Clear the flag - USBOTG_H_FS->INT_FG = USBFS_UIF_DETECT; - // Read the detection state - bool attached = hardware_device_attached(); - LOG_CH32_USBFSH("hcd_int_handler() attached = %d\r\n", attached ? 1 : 0); - if (attached) - { - hcd_event_device_attach(rhport, true); + switch (request_pid) { + case USB_PID_SETUP: + case USB_PID_OUT: { + uint16_t tx_len = USBOTG_H_FS->HOST_TX_LEN; + usb_current_xfer_info.bufferlen -= tx_len; + usb_current_xfer_info.xferred_len += tx_len; + if (usb_current_xfer_info.bufferlen == 0) { + LOG_CH32_USBFSH("USB_PID_%s completed %d bytes\r\n", request_pid == USB_PID_OUT ? "OUT" : "SETUP", usb_current_xfer_info.xferred_len); + usb_current_xfer_info.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, usb_current_xfer_info.xferred_len, XFER_RESULT_SUCCESS, true); + return; + } else { + LOG_CH32_USBFSH("USB_PID_OUT continue...\r\n"); + usb_current_xfer_info.buffer += tx_len; + uint16_t copylen = USBFS_TX_BUF_LEN; + if (copylen > usb_current_xfer_info.bufferlen) { + copylen = usb_current_xfer_info.bufferlen; + } + memcpy(USBFS_TX_Buf, usb_current_xfer_info.buffer, copylen); + hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle); + return; + } } - else - { - hcd_event_device_remove(rhport, true); + case USB_PID_IN: { + uint16_t received_len = USBOTG_H_FS->RX_LEN; + usb_current_xfer_info.xferred_len += received_len; + uint16_t xferred_len = usb_current_xfer_info.xferred_len; + LOG_CH32_USBFSH("Read %d bytes\r\n", received_len); + // if (received_len > 0 && (usb_current_xfer_info.buffer == NULL || usb_current_xfer_info.bufferlen == 0)) { + // PANIC("Data received but buffer not set\r\n"); + // } + memcpy(usb_current_xfer_info.buffer, USBFS_RX_Buf, received_len); + usb_current_xfer_info.buffer += received_len; + if ((received_len < edpt_info->max_packet_size) || (xferred_len == usb_current_xfer_info.bufferlen)) { + // USB device sent all data. + LOG_CH32_USBFSH("USB_PID_IN completed\r\n"); + usb_current_xfer_info.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, XFER_RESULT_SUCCESS, true); + return; + } else { + // USB device may send more data. + LOG_CH32_USBFSH("Read more data\r\n"); + hardware_start_xfer(USB_PID_IN, ep_addr, edpt_info->data_toggle); + return; + } + } + default: { + PANIC("Unknown PID: 0x%02x\n", request_pid); + } + } + } else { + if (response_pid == USB_PID_STALL) { + LOG_CH32_USBFSH("STALL response\r\n"); + hcd_edpt_clear_stall(0, dev_addr, ep_addr); + edpt_info->data_toggle = 0; + hardware_start_xfer(request_pid, ep_addr, 0); + return; + } else if (response_pid == USB_PID_NAK) { + LOG_CH32_USBFSH("NAK reposense\r\n"); + uint32_t elapsed_time = board_millis() - usb_current_xfer_info.start_ms; + if (edpt_info->xfer_type == TUSB_XFER_INTERRUPT) { + usb_current_xfer_info.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_SUCCESS, true); + } else if (elapsed_time > USB_XFER_TIMEOUT_MILLIS) { + usb_current_xfer_info.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); + } else { + hardware_start_xfer(request_pid, ep_addr, edpt_info->data_toggle); } return; + } else if (response_pid == USB_PID_DATA0 || response_pid == USB_PID_DATA1) { + LOG_CH32_USBFSH("Data toggle mismatched and DATA0/1 (not STALL). RX_LEN=%d\r\n", USBOTG_H_FS->RX_LEN); + usb_current_xfer_info.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); + return; + } else { + LOG_CH32_USBFSH("In USBHD_IRQHandler, unexpected response PID: 0x%02x\r\n", response_pid); + usb_current_xfer_info.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); + return; + } } - - if (USBOTG_H_FS->INT_FG & USBFS_UIF_TRANSFER) - { - // Disable transfer interrupt - USBOTG_H_FS->INT_EN &= ~USBFS_UIE_TRANSFER; - // Clear the flag - // USBOTG_H_FS->INT_FG = USBFS_UIF_TRANSFER; - // Copy PID and Endpoint - uint8_t pid_edpt = USBOTG_H_FS->HOST_EP_PID; - uint8_t status = USBOTG_H_FS->INT_ST; - uint8_t dev_addr = USBOTG_H_FS->DEV_ADDR & USBFS_USB_ADDR_MASK; - // Clear register to stop transfer - // USBOTG_H_FS->HOST_EP_PID = 0x00; - - LOG_CH32_USBFSH("hcd_int_handler() pid_edpt=0x%02x\r\n", pid_edpt); - - uint8_t request_pid = pid_edpt >> 4; - uint8_t response_pid = status & USBFS_UIS_H_RES_MASK; - uint8_t ep_addr = pid_edpt & 0x0f; - if (request_pid == USB_PID_IN) - { - ep_addr |= 0x80; - } - - usb_edpt_t* edpt_info = get_edpt_record(dev_addr, ep_addr); - if (edpt_info == NULL) - { - PANIC("\r\nget_edpt_record(0x%02x, 0x%02x) returned NULL in USBHD_IRQHandler\r\n", dev_addr, ep_addr); - } - - if (status & USBFS_UIS_TOG_OK) - { - edpt_info->data_toggle ^= 0x01; - - switch (request_pid) - { - case USB_PID_SETUP: - case USB_PID_OUT: - { - uint16_t tx_len = USBOTG_H_FS->HOST_TX_LEN; - usb_current_xfer_info.bufferlen -= tx_len; - usb_current_xfer_info.xferred_len += tx_len; - if (usb_current_xfer_info.bufferlen == 0) - { - LOG_CH32_USBFSH("USB_PID_%s completed %d bytes\r\n", request_pid == USB_PID_OUT ? "OUT" : "SETUP", usb_current_xfer_info.xferred_len); - usb_current_xfer_info.is_busy = false; - hcd_event_xfer_complete(dev_addr, ep_addr, usb_current_xfer_info.xferred_len, XFER_RESULT_SUCCESS, true); - return; - } - else - { - LOG_CH32_USBFSH("USB_PID_OUT continue...\r\n"); - usb_current_xfer_info.buffer += tx_len; - uint16_t copylen = USBFS_TX_BUF_LEN; - if (copylen > usb_current_xfer_info.bufferlen) - { - copylen = usb_current_xfer_info.bufferlen; - } - memcpy(USBFS_TX_Buf, usb_current_xfer_info.buffer, copylen); - hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle); - return; - } - } - case USB_PID_IN: - { - uint16_t received_len = USBOTG_H_FS->RX_LEN; - usb_current_xfer_info.xferred_len += received_len; - uint16_t xferred_len = usb_current_xfer_info.xferred_len; - LOG_CH32_USBFSH("Read %d bytes\r\n", received_len); - // if (received_len > 0 && (usb_current_xfer_info.buffer == NULL || usb_current_xfer_info.bufferlen == 0)) { - // PANIC("Data received but buffer not set\r\n"); - // } - memcpy(usb_current_xfer_info.buffer, USBFS_RX_Buf, received_len); - usb_current_xfer_info.buffer += received_len; - if ((received_len < edpt_info->max_packet_size) || (xferred_len == usb_current_xfer_info.bufferlen)) - { - // USB device sent all data. - LOG_CH32_USBFSH("USB_PID_IN completed\r\n"); - usb_current_xfer_info.is_busy = false; - hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, XFER_RESULT_SUCCESS, true); - return; - } - else - { - // USB device may send more data. - LOG_CH32_USBFSH("Read more data\r\n"); - hardware_start_xfer(USB_PID_IN, ep_addr, edpt_info->data_toggle); - return; - } - } - default: - { - PANIC("Unknown PID: 0x%02x\n", request_pid); - } - } - } - else - { - if (response_pid == USB_PID_STALL) - { - LOG_CH32_USBFSH("STALL response\r\n"); - hcd_edpt_clear_stall(0, dev_addr, ep_addr); - edpt_info->data_toggle = 0; - hardware_start_xfer(request_pid, ep_addr, 0); - return; - } - else if (response_pid == USB_PID_NAK) - { - LOG_CH32_USBFSH("NAK reposense\r\n"); - uint32_t elapsed_time = board_millis() - usb_current_xfer_info.start_ms; - if (edpt_info->xfer_type == TUSB_XFER_INTERRUPT) - { - usb_current_xfer_info.is_busy = false; - hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_SUCCESS, true); - } - else if (elapsed_time > USB_XFER_TIMEOUT_MILLIS) - { - usb_current_xfer_info.is_busy = false; - hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); - } - else - { - hardware_start_xfer(request_pid, ep_addr, edpt_info->data_toggle); - } - return; - } - else if (response_pid == USB_PID_DATA0 || response_pid == USB_PID_DATA1) - { - LOG_CH32_USBFSH("Data toggle mismatched and DATA0/1 (not STALL). RX_LEN=%d\r\n", USBOTG_H_FS->RX_LEN); - usb_current_xfer_info.is_busy = false; - hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); - return; - } - else - { - LOG_CH32_USBFSH("In USBHD_IRQHandler, unexpected response PID: 0x%02x\r\n", response_pid); - usb_current_xfer_info.is_busy = false; - hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); - return; - } - } - } + } } //--------------------------------------------------------------------+ // Endpoint API //--------------------------------------------------------------------+ -bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) -{ - (void)rhport; - uint8_t ep_addr = ep_desc->bEndpointAddress; - uint8_t ep_num = tu_edpt_number(ep_addr); - uint16_t max_packet_size = ep_desc->wMaxPacketSize; - uint8_t xfer_type = ep_desc->bmAttributes.xfer; - LOG_CH32_USBFSH("hcd_edpt_open(rhport=%d, dev_addr=0x%02x, %p) EndpointAdderss=0x%02x,maxPacketSize=%d,xfer_type=%d\r\n", rhport, dev_addr, ep_desc, ep_addr, max_packet_size, xfer_type); +bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const *ep_desc) { + (void) rhport; + uint8_t ep_addr = ep_desc->bEndpointAddress; + uint8_t ep_num = tu_edpt_number(ep_addr); + uint16_t max_packet_size = ep_desc->wMaxPacketSize; + uint8_t xfer_type = ep_desc->bmAttributes.xfer; + LOG_CH32_USBFSH("hcd_edpt_open(rhport=%d, dev_addr=0x%02x, %p) EndpointAdderss=0x%02x,maxPacketSize=%d,xfer_type=%d\r\n", rhport, dev_addr, ep_desc, ep_addr, max_packet_size, xfer_type); - if (ep_num == 0x00) - { - TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x00, max_packet_size, xfer_type) != NULL, false); - TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x80, max_packet_size, xfer_type) != NULL, false); - } - else - { - TU_ASSERT(get_or_add_edpt_record(dev_addr, ep_addr, max_packet_size, xfer_type) != NULL, false); - } + if (ep_num == 0x00) { + TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x00, max_packet_size, xfer_type) != NULL, false); + TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x80, max_packet_size, xfer_type) != NULL, false); + } else { + TU_ASSERT(get_or_add_edpt_record(dev_addr, ep_addr, max_packet_size, xfer_type) != NULL, false); + } + USBOTG_H_FS->HOST_CTRL |= USBFS_UH_PORT_EN; + USBOTG_H_FS->HOST_SETUP |= USBFS_UH_SOF_EN; - USBOTG_H_FS->HOST_CTRL |= USBFS_UH_PORT_EN; - USBOTG_H_FS->HOST_SETUP |= USBFS_UH_SOF_EN; + hardware_set_port_address_speed(dev_addr); - hardware_set_port_address_speed(dev_addr); - - return true; + return true; } -bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) -{ - (void)rhport; +bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen) { + (void) rhport; - LOG_CH32_USBFSH("hcd_edpt_xfer(%d, 0x%02x, 0x%02x, ...)\r\n", rhport, dev_addr, ep_addr); + LOG_CH32_USBFSH("hcd_edpt_xfer(%d, 0x%02x, 0x%02x, ...)\r\n", rhport, dev_addr, ep_addr); - while (usb_current_xfer_info.is_busy) { } + while (usb_current_xfer_info.is_busy) {} + usb_current_xfer_info.is_busy = true; - usb_current_xfer_info.is_busy = true; + usb_edpt_t *edpt_info = get_edpt_record(dev_addr, ep_addr); + if (edpt_info == NULL) { + PANIC("get_edpt_record() returned NULL in hcd_edpt_xfer()\r\n"); + } - usb_edpt_t* edpt_info = get_edpt_record(dev_addr, ep_addr); - if (edpt_info == NULL) - { - PANIC("get_edpt_record() returned NULL in hcd_edpt_xfer()\r\n"); - } - - hardware_set_port_address_speed(dev_addr); - - usb_current_xfer_info.dev_addr = dev_addr; - usb_current_xfer_info.ep_addr = ep_addr; - usb_current_xfer_info.buffer = buffer; - usb_current_xfer_info.bufferlen = buflen; - usb_current_xfer_info.start_ms = board_millis(); - usb_current_xfer_info.xferred_len = 0; - - if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) - { - LOG_CH32_USBFSH("hcd_edpt_xfer(): READ, dev_addr=0x%02x, ep_addr=0x%02x, len=%d\r\n", dev_addr, ep_addr, buflen); - return hardware_start_xfer(USB_PID_IN, ep_addr, edpt_info->data_toggle); - } - else - { - LOG_CH32_USBFSH("hcd_edpt_xfer(): WRITE, dev_addr=0x%02x, ep_addr=0x%02x, len=%d\r\n", dev_addr, ep_addr, buflen); - uint16_t copylen = USBFS_TX_BUF_LEN; - if (copylen > buflen) - { - copylen = buflen; - } - USBOTG_H_FS->HOST_TX_LEN = copylen; - memcpy(USBFS_TX_Buf, buffer, copylen); - return hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle); + hardware_set_port_address_speed(dev_addr); + + usb_current_xfer_info.dev_addr = dev_addr; + usb_current_xfer_info.ep_addr = ep_addr; + usb_current_xfer_info.buffer = buffer; + usb_current_xfer_info.bufferlen = buflen; + usb_current_xfer_info.start_ms = board_millis(); + usb_current_xfer_info.xferred_len = 0; + + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { + LOG_CH32_USBFSH("hcd_edpt_xfer(): READ, dev_addr=0x%02x, ep_addr=0x%02x, len=%d\r\n", dev_addr, ep_addr, buflen); + return hardware_start_xfer(USB_PID_IN, ep_addr, edpt_info->data_toggle); + } else { + LOG_CH32_USBFSH("hcd_edpt_xfer(): WRITE, dev_addr=0x%02x, ep_addr=0x%02x, len=%d\r\n", dev_addr, ep_addr, buflen); + uint16_t copylen = USBFS_TX_BUF_LEN; + if (copylen > buflen) { + copylen = buflen; } + USBOTG_H_FS->HOST_TX_LEN = copylen; + memcpy(USBFS_TX_Buf, buffer, copylen); + return hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle); + } } -bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) -{ - (void) rhport; - (void) dev_addr; - (void) ep_addr; +bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { + (void) rhport; + (void) dev_addr; + (void) ep_addr; - return false; + return false; } -bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) -{ - (void)rhport; - - while (usb_current_xfer_info.is_busy) { } +bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) { + (void) rhport; - usb_current_xfer_info.is_busy = true; + while (usb_current_xfer_info.is_busy) {} - LOG_CH32_USBFSH("hcd_setup_send(rhport=%d, dev_addr=0x%02x, %p)\r\n", rhport, dev_addr, setup_packet); + usb_current_xfer_info.is_busy = true; - hardware_set_port_address_speed(dev_addr); + LOG_CH32_USBFSH("hcd_setup_send(rhport=%d, dev_addr=0x%02x, %p)\r\n", rhport, dev_addr, setup_packet); - usb_edpt_t* edpt_info_tx = get_edpt_record(dev_addr, 0x00); - usb_edpt_t* edpt_info_rx = get_edpt_record(dev_addr, 0x80); - TU_ASSERT(edpt_info_tx != NULL, false); - TU_ASSERT(edpt_info_rx != NULL, false); + hardware_set_port_address_speed(dev_addr); - // Initialize data toggle (SETUP always starts with DATA0) - // Data toggle for OUT is toggled in hcd_int_handler() - edpt_info_tx->data_toggle = 0; - // Data toggle for IN must be set 0x01 manually. - edpt_info_rx->data_toggle = 0x01; - const uint16_t setup_packet_datalen = 8; - memcpy(USBFS_TX_Buf, setup_packet, setup_packet_datalen); - USBOTG_H_FS->HOST_TX_LEN = setup_packet_datalen; - uint8_t ep_addr = (setup_packet[0] & 0x80) ? 0x80 : 0x00; - usb_current_xfer_info.dev_addr = dev_addr; - usb_current_xfer_info.ep_addr = ep_addr; - usb_current_xfer_info.start_ms = board_millis(); - usb_current_xfer_info.buffer = USBFS_TX_Buf; - usb_current_xfer_info.bufferlen = setup_packet_datalen; - usb_current_xfer_info.xferred_len = 0; + usb_edpt_t *edpt_info_tx = get_edpt_record(dev_addr, 0x00); + usb_edpt_t *edpt_info_rx = get_edpt_record(dev_addr, 0x80); + TU_ASSERT(edpt_info_tx != NULL, false); + TU_ASSERT(edpt_info_rx != NULL, false); - hardware_start_xfer(USB_PID_SETUP, 0, 0); + // Initialize data toggle (SETUP always starts with DATA0) + // Data toggle for OUT is toggled in hcd_int_handler() + edpt_info_tx->data_toggle = 0; + // Data toggle for IN must be set 0x01 manually. + edpt_info_rx->data_toggle = 0x01; + const uint16_t setup_packet_datalen = 8; + memcpy(USBFS_TX_Buf, setup_packet, setup_packet_datalen); + USBOTG_H_FS->HOST_TX_LEN = setup_packet_datalen; + uint8_t ep_addr = (setup_packet[0] & 0x80) ? 0x80 : 0x00; + usb_current_xfer_info.dev_addr = dev_addr; + usb_current_xfer_info.ep_addr = ep_addr; + usb_current_xfer_info.start_ms = board_millis(); + usb_current_xfer_info.buffer = USBFS_TX_Buf; + usb_current_xfer_info.bufferlen = setup_packet_datalen; + usb_current_xfer_info.xferred_len = 0; - return true; + hardware_start_xfer(USB_PID_SETUP, 0, 0); + + return true; } -bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) -{ - (void) rhport; - (void) dev_addr; - LOG_CH32_USBFSH("hcd_edpt_clear_stall(rhport=%d, dev_addr=0x%02x, ep_addr=0x%02x)\r\n", rhport, dev_addr, ep_addr); - // PANIC("\r\install\r\n"); - uint8_t edpt_num = tu_edpt_number(ep_addr); - uint8_t setup_request_clear_stall[8] = { - 0x02, 0x01, 0x00, 0x00, edpt_num, 0x00, 0x00, 0x00 - }; - memcpy(USBFS_TX_Buf, setup_request_clear_stall, 8); - USBOTG_H_FS->HOST_TX_LEN = 8; +bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { + (void) rhport; + (void) dev_addr; + LOG_CH32_USBFSH("hcd_edpt_clear_stall(rhport=%d, dev_addr=0x%02x, ep_addr=0x%02x)\r\n", rhport, dev_addr, ep_addr); + // PANIC("\r\install\r\n"); + uint8_t edpt_num = tu_edpt_number(ep_addr); + uint8_t setup_request_clear_stall[8] = { + 0x02, 0x01, 0x00, 0x00, edpt_num, 0x00, 0x00, 0x00 + }; + memcpy(USBFS_TX_Buf, setup_request_clear_stall, 8); + USBOTG_H_FS->HOST_TX_LEN = 8; - bool prev_int_state = interrupt_enabled; - hcd_int_disable(0); + bool prev_int_state = interrupt_enabled; + hcd_int_disable(0); - USBOTG_H_FS->HOST_EP_PID = (USB_PID_SETUP << 4) | 0x00; - USBOTG_H_FS->INT_FG |= USBFS_UIF_TRANSFER; - while ((USBOTG_H_FS->INT_FG & USBFS_UIF_TRANSFER) == 0) { } - USBOTG_H_FS->HOST_EP_PID = 0; - uint8_t response_pid = USBOTG_H_FS->INT_ST & USBFS_UIS_H_RES_MASK; - (void)response_pid; - LOG_CH32_USBFSH("hcd_edpt_clear_stall() response pid=0x%02x\r\n", response_pid); + USBOTG_H_FS->HOST_EP_PID = (USB_PID_SETUP << 4) | 0x00; + USBOTG_H_FS->INT_FG |= USBFS_UIF_TRANSFER; + while ((USBOTG_H_FS->INT_FG & USBFS_UIF_TRANSFER) == 0) {} + USBOTG_H_FS->HOST_EP_PID = 0; + uint8_t response_pid = USBOTG_H_FS->INT_ST & USBFS_UIS_H_RES_MASK; + (void) response_pid; + LOG_CH32_USBFSH("hcd_edpt_clear_stall() response pid=0x%02x\r\n", response_pid); - if (prev_int_state) { + if (prev_int_state) { hcd_int_enable(0); - } + } - return true; + return true; } #endif From 4b95a70bee078ad34bd916ed83b41cdaa4b00dbc Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 5 Jul 2025 11:37:19 +0700 Subject: [PATCH 10/10] enable ci host and dual build for ch32v20x --- examples/dual/host_hid_to_device_cdc/only.txt | 1 + examples/dual/host_info_to_device_cdc/only.txt | 1 + examples/host/bare_api/only.txt | 1 + examples/host/cdc_msc_hid/only.txt | 1 + examples/host/device_info/only.txt | 1 + examples/host/hid_controller/only.txt | 1 + examples/host/midi_rx/only.txt | 1 + examples/host/msc_file_explorer/only.txt | 1 + 8 files changed, 8 insertions(+) diff --git a/examples/dual/host_hid_to_device_cdc/only.txt b/examples/dual/host_hid_to_device_cdc/only.txt index 3f40b4e7c..35f896f1e 100644 --- a/examples/dual/host_hid_to_device_cdc/only.txt +++ b/examples/dual/host_hid_to_device_cdc/only.txt @@ -1,6 +1,7 @@ board:mimxrt1060_evk board:mimxrt1064_evk board:mcb1800 +mcu:CH32V20X mcu:RP2040 mcu:ra6m5 mcu:MAX3421 diff --git a/examples/dual/host_info_to_device_cdc/only.txt b/examples/dual/host_info_to_device_cdc/only.txt index 3f40b4e7c..35f896f1e 100644 --- a/examples/dual/host_info_to_device_cdc/only.txt +++ b/examples/dual/host_info_to_device_cdc/only.txt @@ -1,6 +1,7 @@ board:mimxrt1060_evk board:mimxrt1064_evk board:mcb1800 +mcu:CH32V20X mcu:RP2040 mcu:ra6m5 mcu:MAX3421 diff --git a/examples/host/bare_api/only.txt b/examples/host/bare_api/only.txt index dcdaf41c7..31dcb108c 100644 --- a/examples/host/bare_api/only.txt +++ b/examples/host/bare_api/only.txt @@ -1,3 +1,4 @@ +mcu:CH32V20X mcu:KINETIS_KL mcu:LPC175X_6X mcu:LPC177X_8X diff --git a/examples/host/cdc_msc_hid/only.txt b/examples/host/cdc_msc_hid/only.txt index dcdaf41c7..31dcb108c 100644 --- a/examples/host/cdc_msc_hid/only.txt +++ b/examples/host/cdc_msc_hid/only.txt @@ -1,3 +1,4 @@ +mcu:CH32V20X mcu:KINETIS_KL mcu:LPC175X_6X mcu:LPC177X_8X diff --git a/examples/host/device_info/only.txt b/examples/host/device_info/only.txt index b5a4b6739..94ddc73c3 100644 --- a/examples/host/device_info/only.txt +++ b/examples/host/device_info/only.txt @@ -1,3 +1,4 @@ +mcu:CH32V20X mcu:ESP32S2 mcu:ESP32S3 mcu:ESP32P4 diff --git a/examples/host/hid_controller/only.txt b/examples/host/hid_controller/only.txt index dcdaf41c7..31dcb108c 100644 --- a/examples/host/hid_controller/only.txt +++ b/examples/host/hid_controller/only.txt @@ -1,3 +1,4 @@ +mcu:CH32V20X mcu:KINETIS_KL mcu:LPC175X_6X mcu:LPC177X_8X diff --git a/examples/host/midi_rx/only.txt b/examples/host/midi_rx/only.txt index b5a4b6739..94ddc73c3 100644 --- a/examples/host/midi_rx/only.txt +++ b/examples/host/midi_rx/only.txt @@ -1,3 +1,4 @@ +mcu:CH32V20X mcu:ESP32S2 mcu:ESP32S3 mcu:ESP32P4 diff --git a/examples/host/msc_file_explorer/only.txt b/examples/host/msc_file_explorer/only.txt index dcdaf41c7..31dcb108c 100644 --- a/examples/host/msc_file_explorer/only.txt +++ b/examples/host/msc_file_explorer/only.txt @@ -1,3 +1,4 @@ +mcu:CH32V20X mcu:KINETIS_KL mcu:LPC175X_6X mcu:LPC177X_8X