From 367044e4873fc9ca9cdac918cee684e1e08216e0 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 14 Oct 2025 20:51:49 +0700 Subject: fix lots of warnings for missing-prototypes for irqhandler --- src/portable/wch/hcd_ch32_usbfs.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/portable/wch') diff --git a/src/portable/wch/hcd_ch32_usbfs.c b/src/portable/wch/hcd_ch32_usbfs.c index 200136906..7bbf122dd 100644 --- a/src/portable/wch/hcd_ch32_usbfs.c +++ b/src/portable/wch/hcd_ch32_usbfs.c @@ -36,7 +36,17 @@ #include "bsp/board_api.h" +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-prototypes" +#endif + #include "ch32v20x.h" + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + #include "ch32v20x_usb.h" #define USBFS_RX_BUF_LEN 64 -- cgit v1.3.1 From 31bd4fc169eb002ded3f23e8a6a0b95f3f591efb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Oct 2025 05:28:31 +0000 Subject: Add is_isr parameter to dcd_edpt_xfer and dcd_edpt_xfer_fifo Co-authored-by: HiFiPhile <4375114+HiFiPhile@users.noreply.github.com> --- src/device/dcd.h | 4 ++-- src/device/usbd.c | 8 ++++---- src/portable/bridgetek/ft9xx/dcd_ft9xx.c | 9 ++++++--- src/portable/chipidea/ci_fs/dcd_ci_fs.c | 6 ++++-- src/portable/chipidea/ci_hs/dcd_ci_hs.c | 9 ++++++--- src/portable/dialog/da146xx/dcd_da146xx.c | 6 ++++-- src/portable/mentor/musb/dcd_musb.c | 7 +++++-- src/portable/microchip/pic/dcd_pic.c | 6 ++++-- src/portable/microchip/pic32mz/dcd_pic32mz.c | 4 +++- src/portable/microchip/samd/dcd_samd.c | 6 ++++-- src/portable/microchip/samg/dcd_samg.c | 9 ++++++--- src/portable/microchip/samx7x/dcd_samx7x.c | 9 ++++++--- src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c | 6 ++++-- src/portable/nordic/nrf5x/dcd_nrf5x.c | 4 +++- src/portable/nuvoton/nuc120/dcd_nuc120.c | 7 +++++-- src/portable/nuvoton/nuc121/dcd_nuc121.c | 7 +++++-- src/portable/nuvoton/nuc505/dcd_nuc505.c | 7 +++++-- src/portable/nxp/khci/dcd_khci.c | 6 ++++-- src/portable/nxp/lpc17_40/dcd_lpc17_40.c | 6 ++++-- src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c | 7 +++++-- src/portable/raspberrypi/pio_usb/dcd_pio_usb.c | 8 +++++--- src/portable/raspberrypi/rp2040/dcd_rp2040.c | 4 +++- src/portable/renesas/rusb2/dcd_rusb2.c | 7 +++++-- src/portable/sony/cxd56/dcd_cxd56.c | 4 +++- src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 9 ++++++--- src/portable/sunxi/dcd_sunxi_musb.c | 7 +++++-- src/portable/synopsys/dwc2/dcd_dwc2.c | 17 ++++++++++------- src/portable/template/dcd_template.c | 7 +++++-- src/portable/ti/msp430x5xx/dcd_msp430x5xx.c | 9 ++++++--- src/portable/valentyusb/eptri/dcd_eptri.c | 6 ++++-- src/portable/wch/dcd_ch32_usbfs.c | 6 ++++-- src/portable/wch/dcd_ch32_usbhs.c | 6 ++++-- test/unit-test/test/device/msc/test_msc_device.c | 10 +++++----- test/unit-test/test/device/usbd/test_usbd.c | 16 ++++++++-------- 34 files changed, 162 insertions(+), 87 deletions(-) (limited to 'src/portable/wch') diff --git a/src/device/dcd.h b/src/device/dcd.h index 400f62bff..f90156235 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -158,11 +158,11 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc void dcd_edpt_close_all (uint8_t rhport); // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack -bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); +bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr); // Submit an transfer using fifo, When complete dcd_event_xfer_complete() is invoked to notify the stack // This API is optional, may be useful for register-based for transferring data. -bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes); +bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr); // Stall endpoint, any queuing transfer should be removed from endpoint void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr); diff --git a/src/device/usbd.c b/src/device/usbd.c index 339ccf4b4..d5ebcc66b 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -415,8 +415,8 @@ TU_ATTR_WEAK usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_c return NULL; } -TU_ATTR_WEAK bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { - (void) rhport; (void) ep_addr; (void) ff; (void) total_bytes; +TU_ATTR_WEAK bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) { + (void) rhport; (void) ep_addr; (void) ff; (void) total_bytes; (void) is_isr; return false; } @@ -1433,7 +1433,7 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t // could return and USBD task can preempt and clear the busy _usbd_dev.ep_status[epnum][dir].busy = 1; - if (dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes)) { + if (dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes, false)) { return true; } else { // DCD error, mark endpoint as ready to allow next transfer @@ -1464,7 +1464,7 @@ bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_ // and usbd task can preempt and clear the busy _usbd_dev.ep_status[epnum][dir].busy = 1; - if (dcd_edpt_xfer_fifo(rhport, ep_addr, ff, total_bytes)) { + if (dcd_edpt_xfer_fifo(rhport, ep_addr, ff, total_bytes, false)) { TU_LOG_USBD("OK\r\n"); return true; } else { diff --git a/src/portable/bridgetek/ft9xx/dcd_ft9xx.c b/src/portable/bridgetek/ft9xx/dcd_ft9xx.c index 34a8be3b6..f6def44ab 100644 --- a/src/portable/bridgetek/ft9xx/dcd_ft9xx.c +++ b/src/portable/bridgetek/ft9xx/dcd_ft9xx.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -556,7 +557,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) (void)dev_addr; // Respond with status. There is no checking that the address is in range. - dcd_edpt_xfer(rhport, tu_edpt_addr(USBD_EP_0, TUSB_DIR_IN), NULL, 0); + dcd_edpt_xfer(rhport, tu_edpt_addr(USBD_EP_0, TUSB_DIR_IN), NULL, 0, false); // Set the update bit for the address register. dev_addr |= 0x80; @@ -807,8 +808,9 @@ void dcd_edpt_close_all(uint8_t rhport) } // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void)rhport; uint8_t ep_number = tu_edpt_number(ep_addr); uint8_t ep_dir = tu_edpt_dir(ep_addr); @@ -891,8 +893,9 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to } // Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack - optional, however, must be listed in usbd.c -bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes) +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void)rhport; (void)ep_addr; (void)ff; diff --git a/src/portable/chipidea/ci_fs/dcd_ci_fs.c b/src/portable/chipidea/ci_fs/dcd_ci_fs.c index 11ddb683f..6bf3450ed 100644 --- a/src/portable/chipidea/ci_fs/dcd_ci_fs.c +++ b/src/portable/chipidea/ci_fs/dcd_ci_fs.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -303,7 +304,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { _dcd.addr = dev_addr & 0x7F; /* Response with status first before changing device address */ - dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0, false); } void dcd_remote_wakeup(uint8_t rhport) @@ -419,8 +420,9 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) dcd_int_enable(rhport); } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; const unsigned epn = tu_edpt_number(ep_addr); const unsigned dir = tu_edpt_dir(ep_addr); endpoint_state_t *ep = &_dcd.endpoint[epn][dir]; diff --git a/src/portable/chipidea/ci_hs/dcd_ci_hs.c b/src/portable/chipidea/ci_hs/dcd_ci_hs.c index 244f5a2d4..a11d2bbd1 100644 --- a/src/portable/chipidea/ci_hs/dcd_ci_hs.c +++ b/src/portable/chipidea/ci_hs/dcd_ci_hs.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -277,7 +278,7 @@ void dcd_int_disable(uint8_t rhport) void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { // Response with status first before changing device address - dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0, false); ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport); dcd_reg->DEVICEADDR = (dev_addr << 25) | TU_BIT(24); @@ -465,8 +466,9 @@ static void qhd_start_xfer(uint8_t rhport, uint8_t epnum, uint8_t dir) dcd_reg->ENDPTPRIME = TU_BIT(epnum + (dir ? 16 : 0)); } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); @@ -486,8 +488,9 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t #if !CFG_TUD_MEM_DCACHE_ENABLE // fifo has to be aligned to 4k boundary // It's incompatible with dcache enabled transfer, since neither address nor size is aligned to cache line -bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) { + (void) is_isr; uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); diff --git a/src/portable/dialog/da146xx/dcd_da146xx.c b/src/portable/dialog/da146xx/dcd_da146xx.c index 56ecb7575..8666992aa 100644 --- a/src/portable/dialog/da146xx/dcd_da146xx.c +++ b/src/portable/dialog/da146xx/dcd_da146xx.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -837,7 +838,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) // Set default address for one ZLP USB->USB_EPC0_REG = USB_USB_EPC0_REG_USB_DEF_Msk; USB->USB_FAR_REG = (dev_addr & USB_USB_FAR_REG_USB_AD_Msk) | USB_USB_FAR_REG_USB_AD_EN_Msk; - dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0, false); } void dcd_remote_wakeup(uint8_t rhport) @@ -1025,8 +1026,9 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) tu_memclr(xfer, sizeof(*xfer)); } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); diff --git a/src/portable/mentor/musb/dcd_musb.c b/src/portable/mentor/musb/dcd_musb.c index 4fce08dd9..acb35fcee 100644 --- a/src/portable/mentor/musb/dcd_musb.c +++ b/src/portable/mentor/musb/dcd_musb.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -772,8 +773,9 @@ void dcd_edpt_close_all(uint8_t rhport) } // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void)rhport; bool ret; // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); @@ -794,8 +796,9 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t // Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack // - optional, however, must be listed in usbd.c -bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void)rhport; bool ret; // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); diff --git a/src/portable/microchip/pic/dcd_pic.c b/src/portable/microchip/pic/dcd_pic.c index b4a698199..7d92056e8 100644 --- a/src/portable/microchip/pic/dcd_pic.c +++ b/src/portable/microchip/pic/dcd_pic.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -545,7 +546,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { _dcd.addr = dev_addr & 0x7F; /* Response with status first before changing device address */ - dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0, false); } void dcd_remote_wakeup(uint8_t rhport) @@ -687,8 +688,9 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) if (ie) intr_enable(rhport); } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; const unsigned epn = tu_edpt_number(ep_addr); const unsigned dir = tu_edpt_dir(ep_addr); diff --git a/src/portable/microchip/pic32mz/dcd_pic32mz.c b/src/portable/microchip/pic32mz/dcd_pic32mz.c index cbd157d6b..ce53893ec 100644 --- a/src/portable/microchip/pic32mz/dcd_pic32mz.c +++ b/src/portable/microchip/pic32mz/dcd_pic32mz.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -444,8 +445,9 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) (void) ep_addr; } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); diff --git a/src/portable/microchip/samd/dcd_samd.c b/src/portable/microchip/samd/dcd_samd.c index e43439f2a..1ff314d39 100644 --- a/src/portable/microchip/samd/dcd_samd.c +++ b/src/portable/microchip/samd/dcd_samd.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -142,7 +143,7 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr) (void) dev_addr; // Response with zlp status - dcd_edpt_xfer(rhport, 0x80, NULL, 0); + dcd_edpt_xfer(rhport, 0x80, NULL, 0, false); // DCD can only set address after status for this request is complete // do it at dcd_edpt0_status_complete() @@ -258,8 +259,9 @@ void dcd_edpt_close_all (uint8_t rhport) // TODO implement dcd_edpt_close_all() } -bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; uint8_t const epnum = tu_edpt_number(ep_addr); diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c index a5c768839..3ba538639 100644 --- a/src/portable/microchip/samg/dcd_samg.c +++ b/src/portable/microchip/samg/dcd_samg.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -175,7 +176,7 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr) (void) dev_addr; // Response with zlp status - dcd_edpt_xfer(rhport, 0x80, NULL, 0); + dcd_edpt_xfer(rhport, 0x80, NULL, 0, false); // DCD can only set address after status for this request is complete. // do it at dcd_edpt0_status_complete() @@ -282,8 +283,9 @@ void dcd_edpt_close_all (uint8_t rhport) } // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack -bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; uint8_t const epnum = tu_edpt_number(ep_addr); @@ -309,8 +311,9 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t } #if 0 // TODO support dcd_edpt_xfer_fifo API -bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; return true; } diff --git a/src/portable/microchip/samx7x/dcd_samx7x.c b/src/portable/microchip/samx7x/dcd_samx7x.c index 8aec1568d..494c83fde 100644 --- a/src/portable/microchip/samx7x/dcd_samx7x.c +++ b/src/portable/microchip/samx7x/dcd_samx7x.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -132,7 +133,7 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr) // do it at dcd_edpt0_status_complete() // Response with zlp status - dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0, false); } // Wake up host @@ -605,8 +606,9 @@ static void dcd_transmit_packet(xfer_ctl_t * xfer, uint8_t ep_ix) } // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack -bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); @@ -666,8 +668,9 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t // bytes should be written and second to keep the return value free to give back a boolean // success message. If total_bytes is too big, the FIFO will copy only what is available // into the USB buffer! -bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); diff --git a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c index 1ce3da27e..5cec4defb 100644 --- a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c +++ b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -282,7 +283,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) (void) rhport; _dcd.addr = dev_addr & 0x7F; /* Response with status first before changing device address */ - dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0, false); } #ifdef __GNUC__ // caused by extra declaration of SystemCoreClock in freeRTOSConfig.h @@ -381,8 +382,9 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) bd->head = 0; } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; NVIC_DisableIRQ(USB_FS_IRQn); const unsigned epn = ep_addr & 0xFu; diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index 9e5f5117f..a2d634fe6 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -426,7 +427,8 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { __DSB(); } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; uint8_t const epnum = tu_edpt_number(ep_addr); diff --git a/src/portable/nuvoton/nuc120/dcd_nuc120.c b/src/portable/nuvoton/nuc120/dcd_nuc120.c index 0edebf159..bb1d11355 100644 --- a/src/portable/nuvoton/nuc120/dcd_nuc120.c +++ b/src/portable/nuvoton/nuc120/dcd_nuc120.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -294,8 +295,9 @@ void dcd_edpt_close_all (uint8_t rhport) // TODO implement dcd_edpt_close_all() } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; /* mine the data for the information we need */ @@ -326,8 +328,9 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to } #if 0 // TODO support dcd_edpt_xfer_fifo API -bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; /* mine the data for the information we need */ diff --git a/src/portable/nuvoton/nuc121/dcd_nuc121.c b/src/portable/nuvoton/nuc121/dcd_nuc121.c index 37210ea34..067d455c6 100644 --- a/src/portable/nuvoton/nuc121/dcd_nuc121.c +++ b/src/portable/nuvoton/nuc121/dcd_nuc121.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -323,8 +324,9 @@ void dcd_edpt_close_all (uint8_t rhport) // TODO implement dcd_edpt_close_all() } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; /* mine the data for the information we need */ @@ -355,8 +357,9 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to } #if 0 // TODO support dcd_edpt_xfer_fifo API -bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; /* mine the data for the information we need */ diff --git a/src/portable/nuvoton/nuc505/dcd_nuc505.c b/src/portable/nuvoton/nuc505/dcd_nuc505.c index fa457d861..f7593cf25 100644 --- a/src/portable/nuvoton/nuc505/dcd_nuc505.c +++ b/src/portable/nuvoton/nuc505/dcd_nuc505.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -376,8 +377,9 @@ void dcd_edpt_close_all (uint8_t rhport) // TODO implement dcd_edpt_close_all() } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; if (0x80 == ep_addr) /* control EP0 IN */ @@ -437,8 +439,9 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to } #if 0 // TODO support dcd_edpt_xfer_fifo API -bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; TU_ASSERT(0x80 != ep_addr && 0x00 != ep_addr); // Must not be used for control stuff diff --git a/src/portable/nxp/khci/dcd_khci.c b/src/portable/nxp/khci/dcd_khci.c index 3d5e195a9..395bf0d3d 100644 --- a/src/portable/nxp/khci/dcd_khci.c +++ b/src/portable/nxp/khci/dcd_khci.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -314,7 +315,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { _dcd.addr = dev_addr & 0x7F; /* Response with status first before changing device address */ - dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0, false); } void dcd_remote_wakeup(uint8_t rhport) @@ -428,8 +429,9 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) if (ie) NVIC_EnableIRQ(USB0_IRQn); } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; const unsigned epn = tu_edpt_number(ep_addr); const unsigned dir = tu_edpt_dir(ep_addr); diff --git a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c index 855c59cd1..81220e850 100644 --- a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c +++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -205,7 +206,7 @@ void dcd_int_disable(uint8_t rhport) void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { // Response with status first before changing device address - dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0, false); sie_write(SIE_CMDCODE_SET_ADDRESS, 1, 0x80 | dev_addr); // 7th bit is : device_enable @@ -399,8 +400,9 @@ static bool control_xact(uint8_t rhport, uint8_t dir, uint8_t * buffer, uint8_t return true; } -bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; // Control transfer is not DMA support, and must be done in slave mode if ( tu_edpt_number(ep_addr) == 0 ) { diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c index 7c637ce0c..6e889b473 100644 --- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c +++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -322,7 +323,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; // Response with status first before changing device address - dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0, false); dcd_reg->DEVCMDSTAT &= ~DEVCMDSTAT_DEVICE_ADDR_MASK; dcd_reg->DEVCMDSTAT |= dev_addr; @@ -464,7 +465,8 @@ static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset, ep_cs[0].cmd_sts.active = 1; } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; uint8_t const ep_id = ep_addr2id(ep_addr); if (!buffer || total_bytes == 0) { @@ -486,6 +488,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to //--------------------------------------------------------------------+ static void bus_reset(uint8_t rhport) { + (void) is_isr; tu_memclr(&_dcd, sizeof(dcd_data_t)); edpt_reset_all(rhport); diff --git a/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c index 60afbd435..3653544d9 100644 --- a/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c +++ b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -76,7 +77,7 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr) { // must be called before queuing status pio_usb_device_set_address(dev_addr); - dcd_edpt_xfer(rhport, 0x80, NULL, 0); + dcd_edpt_xfer(rhport, 0x80, NULL, 0, false); } // Wake up host @@ -114,15 +115,16 @@ void dcd_edpt_close_all (uint8_t rhport) } // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack -bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; endpoint_t *ep = pio_usb_device_get_endpoint_by_address(ep_addr); return pio_usb_ll_transfer_start(ep, buffer, total_bytes); } // Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack - optional, however, must be listed in usbd.c -//bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +//bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) //{ // (void) rhport; // (void) ep_addr; diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c index a89c2f42b..0a7c250c2 100644 --- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -526,7 +527,8 @@ void dcd_edpt_close_all(uint8_t rhport) { reset_non_control_endpoints(); } -bool dcd_edpt_xfer(__unused uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { +bool dcd_edpt_xfer(__unused uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; assert(rhport == 0); hw_endpoint_xfer(ep_addr, buffer, total_bytes); return true; diff --git a/src/portable/renesas/rusb2/dcd_rusb2.c b/src/portable/renesas/rusb2/dcd_rusb2.c index ecd28973c..9b875f0d1 100644 --- a/src/portable/renesas/rusb2/dcd_rusb2.c +++ b/src/portable/renesas/rusb2/dcd_rusb2.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -859,8 +860,9 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) _dcd.ep[dir][epn] = 0; } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; rusb2_reg_t* rusb = RUSB2_REG(rhport); dcd_int_disable(rhport); @@ -870,8 +872,9 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to return r; } -bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) { + (void) is_isr; // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1 TU_ASSERT(ff->item_size == 1); rusb2_reg_t* rusb = RUSB2_REG(rhport); diff --git a/src/portable/sony/cxd56/dcd_cxd56.c b/src/portable/sony/cxd56/dcd_cxd56.c index a13cd152c..664952b83 100644 --- a/src/portable/sony/cxd56/dcd_cxd56.c +++ b/src/portable/sony/cxd56/dcd_cxd56.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -358,8 +359,9 @@ void dcd_edpt_close_all (uint8_t rhport) // TODO implement dcd_edpt_close_all() } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; bool ret = true; diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index ed823a832..640481442 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -246,7 +247,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { (void)dev_addr; // Respond with status - dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK | 0x00, NULL, 0); + dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK | 0x00, NULL, 0, false); // DCD can only set address after status for this request is complete. // do it at dcd_edpt0_status_complete() @@ -788,7 +789,8 @@ static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir) { return true; } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) { +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; uint8_t const ep_num = tu_edpt_number(ep_addr); tusb_dir_t const dir = tu_edpt_dir(ep_addr); xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); @@ -801,7 +803,8 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to return edpt_xfer(rhport, ep_num, dir); } -bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes) { +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) { + (void) is_isr; uint8_t const ep_num = tu_edpt_number(ep_addr); tusb_dir_t const dir = tu_edpt_dir(ep_addr); xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); diff --git a/src/portable/sunxi/dcd_sunxi_musb.c b/src/portable/sunxi/dcd_sunxi_musb.c index f1f4897cb..52d69ad01 100644 --- a/src/portable/sunxi/dcd_sunxi_musb.c +++ b/src/portable/sunxi/dcd_sunxi_musb.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -1083,8 +1084,9 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) } // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void)rhport; bool ret; // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); @@ -1102,8 +1104,9 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t } // Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack - optional, however, must be listed in usbd.c -bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void)rhport; bool ret; // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index f1e4dbd77..f3a0ee7fc 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -456,7 +457,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { dwc2->dcfg = (dwc2->dcfg & ~DCFG_DAD_Msk) | (dev_addr << DCFG_DAD_Pos); // Response with status after changing device address - dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0, false, false); } void dcd_remote_wakeup(uint8_t rhport) { @@ -577,13 +578,14 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpo return true; } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir); bool ret; - usbd_spin_lock(false); + usbd_spin_lock(is_isr); if (xfer->max_size == 0) { ret = false; // Endpoint is closed @@ -602,7 +604,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to ret = true; } - usbd_spin_unlock(false); + usbd_spin_unlock(is_isr); return ret; } @@ -611,7 +613,8 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to // bytes should be written and second to keep the return value free to give back a boolean // success message. If total_bytes is too big, the FIFO will copy only what is available // into the USB buffer! -bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t total_bytes) { +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t total_bytes, bool is_isr) { + (void) is_isr; // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1 TU_ASSERT(ff->item_size == 1); @@ -620,7 +623,7 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir); bool ret; - usbd_spin_lock(false); + usbd_spin_lock(is_isr); if (xfer->max_size == 0) { ret = false; // Endpoint is closed @@ -635,7 +638,7 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t ret = true; } - usbd_spin_unlock(false); + usbd_spin_unlock(is_isr); return ret; } diff --git a/src/portable/template/dcd_template.c b/src/portable/template/dcd_template.c index 3738ac0cb..ff7995c11 100644 --- a/src/portable/template/dcd_template.c +++ b/src/portable/template/dcd_template.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -113,7 +114,8 @@ void dcd_edpt_close_all (uint8_t rhport) { } // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack -bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) { +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; (void) ep_addr; (void) buffer; @@ -122,7 +124,8 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t } // Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack - optional, however, must be listed in usbd.c -bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; (void) ep_addr; (void) ff; diff --git a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c index 64cbc5087..def55b59b 100644 --- a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c +++ b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -219,7 +220,7 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr) USBFUNADR = dev_addr; // Response with status after changing device address - dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0, false); } void dcd_remote_wakeup(uint8_t rhport) @@ -344,8 +345,9 @@ void dcd_edpt_close_all (uint8_t rhport) // TODO implement dcd_edpt_close_all() } -bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; uint8_t const epnum = tu_edpt_number(ep_addr); @@ -393,8 +395,9 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t } #if 0 // TODO support dcd_edpt_xfer_fifo API -bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; uint8_t const epnum = tu_edpt_number(ep_addr); diff --git a/src/portable/valentyusb/eptri/dcd_eptri.c b/src/portable/valentyusb/eptri/dcd_eptri.c index a03c94558..a389aa761 100644 --- a/src/portable/valentyusb/eptri/dcd_eptri.c +++ b/src/portable/valentyusb/eptri/dcd_eptri.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -375,7 +376,7 @@ void dcd_int_disable(uint8_t rhport) void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { // Respond with ACK status first before changing device address - dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0, false); // Wait for the response packet to get sent while (tx_active) @@ -475,8 +476,9 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) // IN endpoints will get un-stalled when more data is written. } -bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void)rhport; uint8_t ep_num = tu_edpt_number(ep_addr); uint8_t ep_dir = tu_edpt_dir(ep_addr); diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index c248ba14e..c5b610b82 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -218,7 +219,7 @@ void dcd_int_disable(uint8_t rhport) { void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { (void) dev_addr; - dcd_edpt_xfer(rhport, 0x80, NULL, 0); // zlp status response + dcd_edpt_xfer(rhport, 0x80, NULL, 0, false); // zlp status response } void dcd_remote_wakeup(uint8_t rhport) { @@ -289,7 +290,8 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { // TODO optional } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; uint8_t ep = tu_edpt_number(ep_addr); uint8_t dir = tu_edpt_dir(ep_addr); diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c index 4a208b9df..cf2deab78 100644 --- a/src/portable/wch/dcd_ch32_usbhs.c +++ b/src/portable/wch/dcd_ch32_usbhs.c @@ -1,3 +1,4 @@ + /* * The MIT License (MIT) * @@ -203,7 +204,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { (void) dev_addr; // Response with zlp status - dcd_edpt_xfer(rhport, 0x80, NULL, 0); + dcd_edpt_xfer(rhport, 0x80, NULL, 0, false); } void dcd_remote_wakeup(uint8_t rhport) { @@ -315,7 +316,8 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { } } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { + (void) is_isr; (void) rhport; uint8_t const ep_num = tu_edpt_number(ep_addr); tusb_dir_t const dir = tu_edpt_dir(ep_addr); diff --git a/test/unit-test/test/device/msc/test_msc_device.c b/test/unit-test/test/device/msc/test_msc_device.c index 49843a921..ea02b7050 100644 --- a/test/unit-test/test/device/msc/test_msc_device.c +++ b/test/unit-test/test/device/msc/test_msc_device.c @@ -256,7 +256,7 @@ void test_msc(void) dcd_edpt_open_ExpectAndReturn(rhport, (tusb_desc_endpoint_t const *) tu_desc_next(desc_ep), true); // Prepare SCSI command - dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_MSC_OUT, NULL, sizeof(msc_cbw_t), true); + dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_MSC_OUT, NULL, sizeof(msc_cbw_t), false, true); dcd_edpt_xfer_IgnoreArg_buffer(); dcd_edpt_xfer_ReturnMemThruPtr_buffer( (uint8_t*) &cbw_read10, sizeof(msc_cbw_t)); @@ -264,20 +264,20 @@ void test_msc(void) dcd_event_xfer_complete(rhport, EDPT_MSC_OUT, sizeof(msc_cbw_t), 0, true); // control status - dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_CTRL_IN, NULL, 0, true); + dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_CTRL_IN, NULL, 0, false, true); // SCSI Data transfer - dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_MSC_IN, NULL, 512, true); + dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_MSC_IN, NULL, 512, false, true); dcd_edpt_xfer_IgnoreArg_buffer(); dcd_event_xfer_complete(rhport, EDPT_MSC_IN, 512, 0, true); // complete // SCSI Status - dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_MSC_IN, NULL, 13, true); + dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_MSC_IN, NULL, 13, false, true); dcd_edpt_xfer_IgnoreArg_buffer(); dcd_event_xfer_complete(rhport, EDPT_MSC_IN, 13, 0, true); // Prepare for next command - dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_MSC_OUT, NULL, sizeof(msc_cbw_t), true); + dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_MSC_OUT, NULL, sizeof(msc_cbw_t), false, true); dcd_edpt_xfer_IgnoreArg_buffer(); tud_task(); diff --git a/test/unit-test/test/device/usbd/test_usbd.c b/test/unit-test/test/device/usbd/test_usbd.c index f0153da3f..3a2cf3217 100644 --- a/test/unit-test/test/device/usbd/test_usbd.c +++ b/test/unit-test/test/device/usbd/test_usbd.c @@ -151,11 +151,11 @@ void test_usbd_get_device_descriptor(void) dcd_event_setup_received(rhport, (uint8_t*) &req_get_desc_device, false); // data - dcd_edpt_xfer_ExpectWithArrayAndReturn(rhport, 0x80, (uint8_t*)&data_desc_device, sizeof(tusb_desc_device_t), sizeof(tusb_desc_device_t), true); + dcd_edpt_xfer_ExpectWithArrayAndReturn(rhport, 0x80, (uint8_t*)&data_desc_device, sizeof(tusb_desc_device_t), sizeof(tusb_desc_device_t), false, true); dcd_event_xfer_complete(rhport, EDPT_CTRL_IN, sizeof(tusb_desc_device_t), 0, false); // status - dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_CTRL_OUT, NULL, 0, true); + dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_CTRL_OUT, NULL, 0, false, true); dcd_event_xfer_complete(rhport, EDPT_CTRL_OUT, 0, 0, false); dcd_edpt0_status_complete_ExpectWithArray(rhport, &req_get_desc_device, 1); @@ -184,11 +184,11 @@ void test_usbd_get_configuration_descriptor(void) dcd_event_setup_received(rhport, (uint8_t*) &req_get_desc_configuration, false); // data - dcd_edpt_xfer_ExpectWithArrayAndReturn(rhport, 0x80, (uint8_t*) data_desc_configuration, total_len, total_len, true); + dcd_edpt_xfer_ExpectWithArrayAndReturn(rhport, 0x80, (uint8_t*) data_desc_configuration, total_len, total_len, false, true); dcd_event_xfer_complete(rhport, EDPT_CTRL_IN, total_len, 0, false); // status - dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_CTRL_OUT, NULL, 0, true); + dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_CTRL_OUT, NULL, 0, false, true); dcd_event_xfer_complete(rhport, EDPT_CTRL_OUT, 0, 0, false); dcd_edpt0_status_complete_ExpectWithArray(rhport, &req_get_desc_configuration, 1); @@ -227,20 +227,20 @@ void test_usbd_control_in_zlp(void) // 1st transaction dcd_edpt_xfer_ExpectWithArrayAndReturn(rhport, EDPT_CTRL_IN, - zlp_desc_configuration, CFG_TUD_ENDPOINT0_SIZE, CFG_TUD_ENDPOINT0_SIZE, true); + zlp_desc_configuration, CFG_TUD_ENDPOINT0_SIZE, CFG_TUD_ENDPOINT0_SIZE, false, true); dcd_event_xfer_complete(rhport, EDPT_CTRL_IN, CFG_TUD_ENDPOINT0_SIZE, 0, false); // 2nd transaction dcd_edpt_xfer_ExpectWithArrayAndReturn(rhport, EDPT_CTRL_IN, - zlp_desc_configuration + CFG_TUD_ENDPOINT0_SIZE, CFG_TUD_ENDPOINT0_SIZE, CFG_TUD_ENDPOINT0_SIZE, true); + zlp_desc_configuration + CFG_TUD_ENDPOINT0_SIZE, CFG_TUD_ENDPOINT0_SIZE, CFG_TUD_ENDPOINT0_SIZE, false, true); dcd_event_xfer_complete(rhport, EDPT_CTRL_IN, CFG_TUD_ENDPOINT0_SIZE, 0, false); // Expect Zero length Packet - dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_CTRL_IN, NULL, 0, true); + dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_CTRL_IN, NULL, 0, false, true); dcd_event_xfer_complete(rhport, EDPT_CTRL_IN, 0, 0, false); // Status - dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_CTRL_OUT, NULL, 0, true); + dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_CTRL_OUT, NULL, 0, false, true); dcd_event_xfer_complete(rhport, EDPT_CTRL_OUT, 0, 0, false); dcd_edpt0_status_complete_ExpectWithArray(rhport, &req_get_desc_configuration, 1); -- cgit v1.3.1 From 925ba123dac77b1675abeb2455762b52fffdc29b Mon Sep 17 00:00:00 2001 From: Zixun LI Date: Wed, 22 Oct 2025 21:08:09 +0200 Subject: Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/portable/bridgetek/ft9xx/dcd_ft9xx.c | 1 - src/portable/chipidea/ci_fs/dcd_ci_fs.c | 1 - src/portable/chipidea/ci_hs/dcd_ci_hs.c | 1 - src/portable/dialog/da146xx/dcd_da146xx.c | 1 - src/portable/mentor/musb/dcd_musb.c | 1 - src/portable/microchip/pic/dcd_pic.c | 1 - src/portable/microchip/pic32mz/dcd_pic32mz.c | 1 - src/portable/microchip/samd/dcd_samd.c | 1 - src/portable/microchip/samg/dcd_samg.c | 1 - src/portable/microchip/samx7x/dcd_samx7x.c | 1 - src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c | 1 - src/portable/nordic/nrf5x/dcd_nrf5x.c | 1 - src/portable/nuvoton/nuc120/dcd_nuc120.c | 1 - src/portable/nuvoton/nuc121/dcd_nuc121.c | 1 - src/portable/nuvoton/nuc505/dcd_nuc505.c | 1 - src/portable/nxp/khci/dcd_khci.c | 1 - src/portable/nxp/lpc17_40/dcd_lpc17_40.c | 1 - src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c | 1 - src/portable/raspberrypi/pio_usb/dcd_pio_usb.c | 1 - src/portable/raspberrypi/rp2040/dcd_rp2040.c | 1 - src/portable/renesas/rusb2/dcd_rusb2.c | 1 - src/portable/sony/cxd56/dcd_cxd56.c | 1 - src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 1 - src/portable/sunxi/dcd_sunxi_musb.c | 1 - src/portable/synopsys/dwc2/dcd_dwc2.c | 1 - src/portable/template/dcd_template.c | 1 - src/portable/ti/msp430x5xx/dcd_msp430x5xx.c | 1 - src/portable/valentyusb/eptri/dcd_eptri.c | 1 - src/portable/wch/dcd_ch32_usbfs.c | 1 - src/portable/wch/dcd_ch32_usbhs.c | 1 - 30 files changed, 30 deletions(-) (limited to 'src/portable/wch') diff --git a/src/portable/bridgetek/ft9xx/dcd_ft9xx.c b/src/portable/bridgetek/ft9xx/dcd_ft9xx.c index f6def44ab..76a54e62e 100644 --- a/src/portable/bridgetek/ft9xx/dcd_ft9xx.c +++ b/src/portable/bridgetek/ft9xx/dcd_ft9xx.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/chipidea/ci_fs/dcd_ci_fs.c b/src/portable/chipidea/ci_fs/dcd_ci_fs.c index 283baf645..558d64b57 100644 --- a/src/portable/chipidea/ci_fs/dcd_ci_fs.c +++ b/src/portable/chipidea/ci_fs/dcd_ci_fs.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/chipidea/ci_hs/dcd_ci_hs.c b/src/portable/chipidea/ci_hs/dcd_ci_hs.c index a11d2bbd1..808c293a5 100644 --- a/src/portable/chipidea/ci_hs/dcd_ci_hs.c +++ b/src/portable/chipidea/ci_hs/dcd_ci_hs.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/dialog/da146xx/dcd_da146xx.c b/src/portable/dialog/da146xx/dcd_da146xx.c index 8666992aa..5beb62b4d 100644 --- a/src/portable/dialog/da146xx/dcd_da146xx.c +++ b/src/portable/dialog/da146xx/dcd_da146xx.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/mentor/musb/dcd_musb.c b/src/portable/mentor/musb/dcd_musb.c index acb35fcee..1e4ec0015 100644 --- a/src/portable/mentor/musb/dcd_musb.c +++ b/src/portable/mentor/musb/dcd_musb.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/microchip/pic/dcd_pic.c b/src/portable/microchip/pic/dcd_pic.c index 7d92056e8..3114295de 100644 --- a/src/portable/microchip/pic/dcd_pic.c +++ b/src/portable/microchip/pic/dcd_pic.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/microchip/pic32mz/dcd_pic32mz.c b/src/portable/microchip/pic32mz/dcd_pic32mz.c index ce53893ec..a903c3ae2 100644 --- a/src/portable/microchip/pic32mz/dcd_pic32mz.c +++ b/src/portable/microchip/pic32mz/dcd_pic32mz.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/microchip/samd/dcd_samd.c b/src/portable/microchip/samd/dcd_samd.c index 1ff314d39..8293273e5 100644 --- a/src/portable/microchip/samd/dcd_samd.c +++ b/src/portable/microchip/samd/dcd_samd.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c index 3ba538639..c6c7f15d1 100644 --- a/src/portable/microchip/samg/dcd_samg.c +++ b/src/portable/microchip/samg/dcd_samg.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/microchip/samx7x/dcd_samx7x.c b/src/portable/microchip/samx7x/dcd_samx7x.c index 494c83fde..57c0fcb4d 100644 --- a/src/portable/microchip/samx7x/dcd_samx7x.c +++ b/src/portable/microchip/samx7x/dcd_samx7x.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c index 6c0302031..929cb40c4 100644 --- a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c +++ b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index a2d634fe6..89dff4995 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/nuvoton/nuc120/dcd_nuc120.c b/src/portable/nuvoton/nuc120/dcd_nuc120.c index bb1d11355..d9a0e3fa8 100644 --- a/src/portable/nuvoton/nuc120/dcd_nuc120.c +++ b/src/portable/nuvoton/nuc120/dcd_nuc120.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/nuvoton/nuc121/dcd_nuc121.c b/src/portable/nuvoton/nuc121/dcd_nuc121.c index 067d455c6..a4dfe24fa 100644 --- a/src/portable/nuvoton/nuc121/dcd_nuc121.c +++ b/src/portable/nuvoton/nuc121/dcd_nuc121.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/nuvoton/nuc505/dcd_nuc505.c b/src/portable/nuvoton/nuc505/dcd_nuc505.c index f7593cf25..25e3f2203 100644 --- a/src/portable/nuvoton/nuc505/dcd_nuc505.c +++ b/src/portable/nuvoton/nuc505/dcd_nuc505.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/nxp/khci/dcd_khci.c b/src/portable/nxp/khci/dcd_khci.c index 3b0de47f4..8941ca766 100644 --- a/src/portable/nxp/khci/dcd_khci.c +++ b/src/portable/nxp/khci/dcd_khci.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c index 81220e850..364cf8de4 100644 --- a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c +++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c index 2257d0368..143b0277c 100644 --- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c +++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c index 3653544d9..5e3dd7faf 100644 --- a/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c +++ b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c index 0a7c250c2..15852f29f 100644 --- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/renesas/rusb2/dcd_rusb2.c b/src/portable/renesas/rusb2/dcd_rusb2.c index 9b875f0d1..6ac1c5ee4 100644 --- a/src/portable/renesas/rusb2/dcd_rusb2.c +++ b/src/portable/renesas/rusb2/dcd_rusb2.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/sony/cxd56/dcd_cxd56.c b/src/portable/sony/cxd56/dcd_cxd56.c index 664952b83..be694edfa 100644 --- a/src/portable/sony/cxd56/dcd_cxd56.c +++ b/src/portable/sony/cxd56/dcd_cxd56.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index 640481442..381aa0b40 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/sunxi/dcd_sunxi_musb.c b/src/portable/sunxi/dcd_sunxi_musb.c index 52d69ad01..46d05e3e6 100644 --- a/src/portable/sunxi/dcd_sunxi_musb.c +++ b/src/portable/sunxi/dcd_sunxi_musb.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index ab30a06e8..ad78708b6 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/template/dcd_template.c b/src/portable/template/dcd_template.c index ff7995c11..90c672d19 100644 --- a/src/portable/template/dcd_template.c +++ b/src/portable/template/dcd_template.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c index def55b59b..10c7d78c5 100644 --- a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c +++ b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/valentyusb/eptri/dcd_eptri.c b/src/portable/valentyusb/eptri/dcd_eptri.c index a389aa761..760f3c90a 100644 --- a/src/portable/valentyusb/eptri/dcd_eptri.c +++ b/src/portable/valentyusb/eptri/dcd_eptri.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index c5b610b82..eb2ebd868 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c index cf2deab78..a18eb3e81 100644 --- a/src/portable/wch/dcd_ch32_usbhs.c +++ b/src/portable/wch/dcd_ch32_usbhs.c @@ -1,4 +1,3 @@ - /* * The MIT License (MIT) * -- cgit v1.3.1 From 6b28a4478c9f8fa3993d593360eb5574bbdeda22 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 15 Nov 2025 19:46:14 +0700 Subject: make TUP_DCD_EDPT_ISO_ALLOC i.e dcd_edpt_iso_alloc()/dcd_edpt_iso_activate() as default driver implementation. dcd_edpt_close() is deprecated and will be removed from all driver in the future. --- docs/porting.rst | 10 + src/common/tusb_mcu.h | 335 ++++++++++++----------- src/device/dcd.h | 11 +- src/portable/bridgetek/ft9xx/dcd_ft9xx.c | 15 +- src/portable/chipidea/ci_fs/dcd_ci_fs.c | 18 +- src/portable/chipidea/ci_hs/dcd_ci_hs.c | 196 +++++++------ src/portable/dialog/da146xx/dcd_da146xx.c | 16 +- src/portable/microchip/pic/dcd_pic.c | 16 +- src/portable/microchip/pic32mz/dcd_pic32mz.c | 13 +- src/portable/microchip/samd/dcd_samd.c | 11 +- src/portable/microchip/samg/dcd_samg.c | 15 +- src/portable/microchip/samx7x/dcd_samx7x.c | 17 +- src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c | 299 ++++++++++---------- src/portable/nordic/nrf5x/dcd_nrf5x.c | 16 +- src/portable/nxp/khci/dcd_khci.c | 16 +- src/portable/nxp/lpc17_40/dcd_lpc17_40.c | 15 +- src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c | 16 +- src/portable/raspberrypi/pio_usb/dcd_pio_usb.c | 14 +- src/portable/renesas/rusb2/dcd_rusb2.c | 16 +- src/portable/sunxi/dcd_sunxi_musb.c | 16 +- src/portable/ti/msp430x5xx/dcd_msp430x5xx.c | 16 +- src/portable/valentyusb/eptri/dcd_eptri.c | 15 +- src/portable/wch/dcd_ch32_usbfs.c | 13 +- src/portable/wch/dcd_ch32_usbhs.c | 27 +- 24 files changed, 702 insertions(+), 450 deletions(-) (limited to 'src/portable/wch') diff --git a/docs/porting.rst b/docs/porting.rst index c3076354c..9b60ec5a2 100644 --- a/docs/porting.rst +++ b/docs/porting.rst @@ -173,12 +173,22 @@ Also make sure to enable endpoint specific interrupts. ``dcd_edpt_close()`` """""""""""""""""""" +.. warning:: + This function is deprecated, ISO transfer should implement dcd_edpt_iso_alloc() and dcd_edpt_iso_activate() instead. + Close an endpoint. his function is used for implementing alternate settings. After calling this, the device should not respond to any packets directed towards this endpoint. When called, this function must abort any transfers in progress through this endpoint, before returning. Implementation is optional. Must be called from the USB task. Interrupts could be disabled or enabled during the call. +``dcd_edpt_iso_alloc() / dcd_edpt_iso_activate()`` +"""""""""""""""""""""""""""""""""""""""""""""""""" + +dcd_edpt_iso_alloc() is used to allocate largest buffer (for all alternative interfaces) for ISO endpoints when device is enumerated. This allows DCD to allocate necessary resources for ISO endpoints in the future. + +dcd_edpt_iso_activate() is used to activate or deactivate ISO endpoint when alternate setting is set with active max packet size. + ``dcd_edpt_xfer()`` """"""""""""""""""" diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index fd922ee56..05ae6929c 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -37,14 +37,14 @@ #ifdef __ARM_ARCH // ARM Architecture set __ARM_FEATURE_UNALIGNED to 1 for mcu supports unaligned access #if defined(__ARM_FEATURE_UNALIGNED) && __ARM_FEATURE_UNALIGNED == 1 - #define TUP_ARCH_STRICT_ALIGN 0 + #define TUP_ARCH_STRICT_ALIGN 0 #else - #define TUP_ARCH_STRICT_ALIGN 1 + #define TUP_ARCH_STRICT_ALIGN 1 #endif #else // TODO default to strict align for others // Should investigate other architecture such as risv, xtensa, mips for optimal setting - #define TUP_ARCH_STRICT_ALIGN 1 + #define TUP_ARCH_STRICT_ALIGN 1 #endif /* USB Controller Attributes for Device, Host or MCU (both) @@ -57,41 +57,41 @@ //--------------------------------------------------------------------+ // NXP //--------------------------------------------------------------------+ -#if TU_CHECK_MCU(OPT_MCU_LPC11UXX, OPT_MCU_LPC13XX, OPT_MCU_LPC15XX) +#if TU_CHECK_MCU(OPT_MCU_LPC11UXX, OPT_MCU_LPC13XX, OPT_MCU_LPC15XX) #define TUP_USBIP_IP3511 - #define TUP_DCD_ENDPOINT_MAX 5 + #define TUP_DCD_ENDPOINT_MAX 5 #elif TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX) - #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_DCD_ENDPOINT_MAX 16 #define TUP_USBIP_OHCI #define TUP_USBIP_OHCI_NXP - #define TUP_OHCI_RHPORTS 2 + #define TUP_OHCI_RHPORTS 2 #elif TU_CHECK_MCU(OPT_MCU_LPC51UXX) - #define TUP_USBIP_IP3511 - #define TUP_DCD_ENDPOINT_MAX 5 + #define TUP_USBIP_IP3511 + #define TUP_DCD_ENDPOINT_MAX 5 #elif TU_CHECK_MCU(OPT_MCU_LPC54) // TODO USB0 has 5, USB1 has 6 #define TUP_USBIP_IP3511 - #define TUP_DCD_ENDPOINT_MAX 6 + #define TUP_DCD_ENDPOINT_MAX 6 #elif TU_CHECK_MCU(OPT_MCU_LPC55) // TODO USB0 has 5, USB1 has 6 #define TUP_USBIP_IP3511 #define TUP_USBIP_OHCI #define TUP_USBIP_OHCI_NXP - #define TUP_OHCI_RHPORTS 1 // 1 downstream port + #define TUP_OHCI_RHPORTS 1 // 1 downstream port - #define TUP_DCD_ENDPOINT_MAX 6 + #define TUP_DCD_ENDPOINT_MAX 6 #elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX) // USB0 has 6 with HS PHY, USB1 has 4 only FS #define TUP_USBIP_CHIPIDEA_HS #define TUP_USBIP_EHCI - #define TUP_DCD_ENDPOINT_MAX 6 - #define TUP_RHPORT_HIGHSPEED 1 + #define TUP_DCD_ENDPOINT_MAX 6 + #define TUP_RHPORT_HIGHSPEED 1 #elif TU_CHECK_MCU(OPT_MCU_MCXN9) // USB0 is chipidea FS @@ -102,15 +102,15 @@ #define TUP_USBIP_CHIPIDEA_HS #define TUP_USBIP_EHCI - #define TUP_DCD_ENDPOINT_MAX 8 - #define TUP_RHPORT_HIGHSPEED 1 + #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_RHPORT_HIGHSPEED 1 #elif TU_CHECK_MCU(OPT_MCU_MCXA15) // USB0 is chipidea FS #define TUP_USBIP_CHIPIDEA_FS #define TUP_USBIP_CHIPIDEA_FS_MCX - #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_DCD_ENDPOINT_MAX 16 #elif TU_CHECK_MCU(OPT_MCU_MIMXRT1XXX) #include "fsl_device_registers.h" @@ -118,60 +118,61 @@ #define TUP_USBIP_CHIPIDEA_HS #define TUP_USBIP_EHCI - #define TUP_DCD_ENDPOINT_MAX 8 - #define TUP_RHPORT_HIGHSPEED 1 + #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_RHPORT_HIGHSPEED 1 #if __CORTEX_M == 7 - #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT 1 - #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT 1 - #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32 + #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT 1 + #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT 1 + #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32 #endif #elif TU_CHECK_MCU(OPT_MCU_KINETIS_KL, OPT_MCU_KINETIS_K32L, OPT_MCU_KINETIS_K) #define TUP_USBIP_CHIPIDEA_FS #define TUP_USBIP_CHIPIDEA_FS_KINETIS - #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_DCD_ENDPOINT_MAX 16 #elif TU_CHECK_MCU(OPT_MCU_MM32F327X) - #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_DCD_EDPT_CLOSE_API //--------------------------------------------------------------------+ // Nordic //--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_NRF5X) // 8 CBI + 1 ISO - #define TUP_DCD_ENDPOINT_MAX 9 + #define TUP_DCD_ENDPOINT_MAX 9 + #define TUP_DCD_EDPT_CLOSE_API #elif TU_CHECK_MCU(OPT_MCU_NRF54) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_NRF - #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_DCD_ENDPOINT_MAX 16 #define CFG_TUH_DWC2_DMA_ENABLE_DEFAULT 0 //--------------------------------------------------------------------+ // Microchip //--------------------------------------------------------------------+ -#elif TU_CHECK_MCU(OPT_MCU_SAMD11, OPT_MCU_SAML2X, OPT_MCU_SAMD21) || \ - TU_CHECK_MCU(OPT_MCU_SAMD51, OPT_MCU_SAME5X) - #define TUP_DCD_ENDPOINT_MAX 8 +#elif TU_CHECK_MCU(OPT_MCU_SAMD11, OPT_MCU_SAML2X, OPT_MCU_SAMD21) || TU_CHECK_MCU(OPT_MCU_SAMD51, OPT_MCU_SAME5X) + #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_SAMG) - #define TUP_DCD_ENDPOINT_MAX 6 + #define TUP_DCD_ENDPOINT_MAX 6 #define TUD_ENDPOINT_ONE_DIRECTION_ONLY #elif TU_CHECK_MCU(OPT_MCU_SAMX7X) - #define TUP_DCD_ENDPOINT_MAX 10 - #define TUP_RHPORT_HIGHSPEED 1 + #define TUP_DCD_ENDPOINT_MAX 10 + #define TUP_RHPORT_HIGHSPEED 1 #define TUD_ENDPOINT_ONE_DIRECTION_ONLY #elif TU_CHECK_MCU(OPT_MCU_PIC32MZ) - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #define TUD_ENDPOINT_ONE_DIRECTION_ONLY -#elif TU_CHECK_MCU(OPT_MCU_PIC32MX, OPT_MCU_PIC32MM, OPT_MCU_PIC32MK) || \ - TU_CHECK_MCU(OPT_MCU_PIC24, OPT_MCU_DSPIC33) - #define TUP_DCD_ENDPOINT_MAX 16 +#elif TU_CHECK_MCU(OPT_MCU_PIC32MX, OPT_MCU_PIC32MM, OPT_MCU_PIC32MK) || TU_CHECK_MCU(OPT_MCU_PIC24, OPT_MCU_DSPIC33) + #define TUP_DCD_ENDPOINT_MAX 16 #define TUD_ENDPOINT_ONE_DIRECTION_ONLY + #define TUP_DCD_EDPT_CLOSE_API //--------------------------------------------------------------------+ // ST @@ -179,23 +180,23 @@ #elif TU_CHECK_MCU(OPT_MCU_STM32F0) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_STM32F1) // - F102, F103 use fsdev // - F105, F107 use dwc2 - #if defined (STM32F105x8) || defined (STM32F105xB) || defined (STM32F105xC) || \ - defined (STM32F107xB) || defined (STM32F107xC) + #if defined(STM32F105x8) || defined(STM32F105xB) || defined(STM32F105xC) || defined(STM32F107xB) || \ + defined(STM32F107xC) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_STM32 #define CFG_TUH_DWC2_DMA_ENABLE_DEFAULT 0 - #define TUP_DCD_ENDPOINT_MAX 4 - #elif defined(STM32F102x6) || defined(STM32F102xB) || \ - defined(STM32F103x6) || defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F103xG) + #define TUP_DCD_ENDPOINT_MAX 4 + #elif defined(STM32F102x6) || defined(STM32F102xB) || defined(STM32F103x6) || defined(STM32F103xB) || \ + defined(STM32F103xE) || defined(STM32F103xG) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #else #error "Unsupported STM32F1 mcu" #endif @@ -205,55 +206,55 @@ #define TUP_USBIP_DWC2_STM32 // FS has 4 ep, HS has 5 ep - #define TUP_DCD_ENDPOINT_MAX 6 + #define TUP_DCD_ENDPOINT_MAX 6 #elif TU_CHECK_MCU(OPT_MCU_STM32F3) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_STM32F4) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_STM32 // For most mcu, FS has 4, HS has 6. TODO 446/469/479 HS has 9 - #define TUP_DCD_ENDPOINT_MAX 6 + #define TUP_DCD_ENDPOINT_MAX 6 #elif TU_CHECK_MCU(OPT_MCU_STM32F7) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_STM32 // FS has 6, HS has 9 - #define TUP_DCD_ENDPOINT_MAX 9 + #define TUP_DCD_ENDPOINT_MAX 9 // MCU with on-chip HS Phy #if defined(STM32F723xx) || defined(STM32F730xx) || defined(STM32F733xx) - #define TUP_RHPORT_HIGHSPEED 1 // Port0: FS, Port1: HS + #define TUP_RHPORT_HIGHSPEED 1 // Port0: FS, Port1: HS #endif // Enable dcache if DMA is enabled - #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE - #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE - #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32 + #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE + #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE + #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32 #elif TU_CHECK_MCU(OPT_MCU_STM32H7) #include "stm32h7xx.h" #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_STM32 - #define TUP_DCD_ENDPOINT_MAX 9 + #define TUP_DCD_ENDPOINT_MAX 9 #if __CORTEX_M == 7 // Enable dcache if DMA is enabled - #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE - #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE - #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32 + #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE + #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE + #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32 #endif #elif TU_CHECK_MCU(OPT_MCU_STM32H5) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_STM32G4) // Device controller @@ -262,41 +263,40 @@ // TypeC controller #define TUP_USBIP_TYPEC_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #define TUP_TYPEC_RHPORTS_NUM 1 #elif TU_CHECK_MCU(OPT_MCU_STM32G0) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_STM32C0) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_STM32L0, OPT_MCU_STM32L1) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_STM32L4) // - L4x2, L4x3 use fsdev // - L4x4, L4x6, L4x7, L4x9 use dwc2 - #if defined (STM32L475xx) || defined (STM32L476xx) || \ - defined (STM32L485xx) || defined (STM32L486xx) || defined (STM32L496xx) || \ - defined (STM32L4A6xx) || defined (STM32L4P5xx) || defined (STM32L4Q5xx) || \ - defined (STM32L4R5xx) || defined (STM32L4R7xx) || defined (STM32L4R9xx) || \ - defined (STM32L4S5xx) || defined (STM32L4S7xx) || defined (STM32L4S9xx) + #if defined(STM32L475xx) || defined(STM32L476xx) || defined(STM32L485xx) || defined(STM32L486xx) || \ + defined(STM32L496xx) || defined(STM32L4A6xx) || defined(STM32L4P5xx) || defined(STM32L4Q5xx) || \ + defined(STM32L4R5xx) || defined(STM32L4R7xx) || defined(STM32L4R9xx) || defined(STM32L4S5xx) || \ + defined(STM32L4S7xx) || defined(STM32L4S9xx) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_STM32 - #define TUP_DCD_ENDPOINT_MAX 6 + #define TUP_DCD_ENDPOINT_MAX 6 #elif defined(STM32L412xx) || defined(STM32L422xx) || defined(STM32L432xx) || defined(STM32L433xx) || \ - defined(STM32L442xx) || defined(STM32L443xx) || defined(STM32L452xx) || defined(STM32L462xx) + defined(STM32L442xx) || defined(STM32L443xx) || defined(STM32L452xx) || defined(STM32L462xx) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #else #error "Unsupported STM32L4 mcu" #endif @@ -304,19 +304,19 @@ #elif TU_CHECK_MCU(OPT_MCU_STM32WB) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_STM32WBA) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_STM32 - #define TUP_DCD_ENDPOINT_MAX 9 - #define TUP_RHPORT_HIGHSPEED 1 + #define TUP_DCD_ENDPOINT_MAX 9 + #define TUP_RHPORT_HIGHSPEED 1 #elif TU_CHECK_MCU(OPT_MCU_STM32U5) - #if defined (STM32U535xx) || defined (STM32U545xx) + #if defined(STM32U535xx) || defined(STM32U545xx) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #else #define TUP_USBIP_DWC2 @@ -324,38 +324,38 @@ // U59x/5Ax/5Fx/5Gx are highspeed with built-in HS PHY #if defined(STM32U595xx) || defined(STM32U599xx) || defined(STM32U5A5xx) || defined(STM32U5A9xx) || \ - defined(STM32U5F7xx) || defined(STM32U5F9xx) || defined(STM32U5G7xx) || defined(STM32U5G9xx) - #define TUP_DCD_ENDPOINT_MAX 9 - #define TUP_RHPORT_HIGHSPEED 1 + defined(STM32U5F7xx) || defined(STM32U5F9xx) || defined(STM32U5G7xx) || defined(STM32U5G9xx) + #define TUP_DCD_ENDPOINT_MAX 9 + #define TUP_RHPORT_HIGHSPEED 1 #else - #define TUP_DCD_ENDPOINT_MAX 6 + #define TUP_DCD_ENDPOINT_MAX 6 #endif #endif #elif TU_CHECK_MCU(OPT_MCU_STM32L5) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_STM32U0) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_STM32U3) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_STM32H7RS, OPT_MCU_STM32N6) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_STM32 // FS has 6, HS has 9 - #define TUP_DCD_ENDPOINT_MAX 9 + #define TUP_DCD_ENDPOINT_MAX 9 // MCU with on-chip HS Phy - #define TUP_RHPORT_HIGHSPEED 1 + #define TUP_RHPORT_HIGHSPEED 1 // Enable dcache if DMA is enabled #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE @@ -366,43 +366,39 @@ // Sony //--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_CXD56) - #define TUP_DCD_ENDPOINT_MAX 7 - #define TUP_RHPORT_HIGHSPEED 1 + #define TUP_DCD_ENDPOINT_MAX 7 + #define TUP_RHPORT_HIGHSPEED 1 #define TUD_ENDPOINT_ONE_DIRECTION_ONLY - #define TUP_DCD_EDPT_ISO_ALLOC //--------------------------------------------------------------------+ // TI //--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_MSP430x5xx) - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129) #define TUP_USBIP_MUSB #define TUP_USBIP_MUSB_TI - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 //--------------------------------------------------------------------+ // ValentyUSB (Litex) //--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_VALENTYUSB_EPTRI) - #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_DCD_ENDPOINT_MAX 16 //--------------------------------------------------------------------+ // Nuvoton //--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_NUC121, OPT_MCU_NUC126) - #define TUP_DCD_ENDPOINT_MAX 8 - #define TUP_DCD_EDPT_ISO_ALLOC + #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_NUC120) - #define TUP_DCD_ENDPOINT_MAX 6 - #define TUP_DCD_EDPT_ISO_ALLOC + #define TUP_DCD_ENDPOINT_MAX 6 #elif TU_CHECK_MCU(OPT_MCU_NUC505) - #define TUP_DCD_ENDPOINT_MAX 12 - #define TUP_RHPORT_HIGHSPEED 1 - #define TUP_DCD_EDPT_ISO_ALLOC + #define TUP_DCD_ENDPOINT_MAX 12 + #define TUP_RHPORT_HIGHSPEED 1 //--------------------------------------------------------------------+ // Espressif @@ -410,114 +406,124 @@ #elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3, OPT_MCU_ESP32H4) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_ESP32 - #define TUP_DCD_ENDPOINT_MAX 7 // only 5 TX FIFO for endpoint IN - #define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/ + #define TUP_DCD_ENDPOINT_MAX 7 // only 5 TX FIFO for endpoint IN + + // clang-format off + #define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/ + // clang-format on #if CFG_TUSB_MCU == OPT_MCU_ESP32S3 #define TUP_MCU_MULTIPLE_CORE 1 #endif // Disable slave if DMA is enabled - #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE - #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE + #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE + #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE #elif TU_CHECK_MCU(OPT_MCU_ESP32P4) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_ESP32 - #define TUP_RHPORT_HIGHSPEED 1 // port0 FS, port1 HS - #define TUP_DCD_ENDPOINT_MAX 16 // FS 7 ep, HS 16 ep + #define TUP_RHPORT_HIGHSPEED 1 // port0 FS, port1 HS + #define TUP_DCD_ENDPOINT_MAX 16 // FS 7 ep, HS 16 ep - #define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/ + // clang-format off + #define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/ + // clang-format on - #define TUP_MCU_MULTIPLE_CORE 1 + #define TUP_MCU_MULTIPLE_CORE 1 // Disable slave if DMA is enabled - #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE - #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE + #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE + #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE // Enable dcache if DMA is enabled - #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE - #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE - #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 64 + #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE + #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE + #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 64 -#elif TU_CHECK_MCU(OPT_MCU_ESP32, OPT_MCU_ESP32C2, OPT_MCU_ESP32C3, OPT_MCU_ESP32C5, OPT_MCU_ESP32C6, OPT_MCU_ESP32C61, OPT_MCU_ESP32H2) +#elif TU_CHECK_MCU(OPT_MCU_ESP32, OPT_MCU_ESP32C2, OPT_MCU_ESP32C3, OPT_MCU_ESP32C5, OPT_MCU_ESP32C6, \ + OPT_MCU_ESP32C61, OPT_MCU_ESP32H2) #if (CFG_TUD_ENABLED || !(defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421)) - #error "MCUs are only supported with CFG_TUH_MAX3421 enabled" + #error "MCUs are only supported with CFG_TUH_MAX3421 enabled" #endif - #define TUP_DCD_ENDPOINT_MAX 0 - #define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/ + #define TUP_DCD_ENDPOINT_MAX 0 + + // clang-format off + #define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/ + // clang-format on + //--------------------------------------------------------------------+ // Dialog //--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_DA1469X) - #define TUP_DCD_ENDPOINT_MAX 4 + #define TUP_DCD_ENDPOINT_MAX 4 + #define TUP_DCD_EDPT_CLOSE_API //--------------------------------------------------------------------+ // Raspberry Pi //--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_RP2040) - #define TUP_DCD_EDPT_ISO_ALLOC - #define TUP_DCD_ENDPOINT_MAX 16 - #define TUP_MCU_MULTIPLE_CORE 1 + #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_MCU_MULTIPLE_CORE 1 - #define TU_ATTR_FAST_FUNC __not_in_flash("tinyusb") + #define TU_ATTR_FAST_FUNC __not_in_flash("tinyusb") //--------------------------------------------------------------------+ // Silabs //--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_EFM32GG) #define TUP_USBIP_DWC2 - #define TUP_DCD_ENDPOINT_MAX 7 + #define TUP_DCD_ENDPOINT_MAX 7 //--------------------------------------------------------------------+ // Renesas //--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N, OPT_MCU_RAXXX) #define TUP_USBIP_RUSB2 - #define TUP_DCD_ENDPOINT_MAX 10 + #define TUP_DCD_ENDPOINT_MAX 10 //--------------------------------------------------------------------+ // GigaDevice //--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_GD32VF103) #define TUP_USBIP_DWC2 - #define TUP_DCD_ENDPOINT_MAX 4 + #define TUP_DCD_ENDPOINT_MAX 4 //--------------------------------------------------------------------+ // Broadcom //--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_BCM2711, OPT_MCU_BCM2835, OPT_MCU_BCM2837) #define TUP_USBIP_DWC2 - #define TUP_DCD_ENDPOINT_MAX 8 - #define TUP_RHPORT_HIGHSPEED 1 + #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_RHPORT_HIGHSPEED 1 //--------------------------------------------------------------------+ // Infineon //--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_XMC4000) #define TUP_USBIP_DWC2 - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 //--------------------------------------------------------------------+ // BridgeTek //--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_FT90X) - #define TUP_DCD_ENDPOINT_MAX 8 - #define TUP_RHPORT_HIGHSPEED 1 + #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_RHPORT_HIGHSPEED 1 #define TUD_ENDPOINT_ONE_DIRECTION_ONLY #elif TU_CHECK_MCU(OPT_MCU_FT93X) - #define TUP_DCD_ENDPOINT_MAX 16 - #define TUP_RHPORT_HIGHSPEED 1 + #define TUP_DCD_ENDPOINT_MAX 16 + #define TUP_RHPORT_HIGHSPEED 1 #define TUD_ENDPOINT_ONE_DIRECTION_ONLY //--------------------------------------------------------------------+ // Allwinner //--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_F1C100S) - #define TUP_DCD_ENDPOINT_MAX 4 + #define TUP_DCD_ENDPOINT_MAX 4 //--------------------------------------------------------------------+ // WCH @@ -527,31 +533,31 @@ #define TUP_USBIP_WCH_USBFS #if !defined(CFG_TUD_WCH_USBIP_USBFS) - #define CFG_TUD_WCH_USBIP_USBFS 0 + #define CFG_TUD_WCH_USBIP_USBFS 0 #endif #if !defined(CFG_TUD_WCH_USBIP_USBHS) - #define CFG_TUD_WCH_USBIP_USBHS (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1) + #define CFG_TUD_WCH_USBIP_USBHS (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1) #endif - #define TUP_RHPORT_HIGHSPEED CFG_TUD_WCH_USBIP_USBHS - #define TUP_DCD_ENDPOINT_MAX (CFG_TUD_WCH_USBIP_USBHS ? 16 : 8) + #define TUP_RHPORT_HIGHSPEED CFG_TUD_WCH_USBIP_USBHS + #define TUP_DCD_ENDPOINT_MAX (CFG_TUD_WCH_USBIP_USBHS ? 16 : 8) #elif TU_CHECK_MCU(OPT_MCU_CH32V103) #define TUP_USBIP_WCH_USBFS #if !defined(CFG_TUD_WCH_USBIP_USBFS) - #define CFG_TUD_WCH_USBIP_USBFS 1 + #define CFG_TUD_WCH_USBIP_USBFS 1 #endif - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_CH32V20X) // 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 + #define CFG_TUH_WCH_USBIP_USBFS 1 #endif #define TUP_USBIP_FSDEV @@ -559,14 +565,14 @@ // default to FSDEV for device #if !defined(CFG_TUD_WCH_USBIP_USBFS) - #define CFG_TUD_WCH_USBIP_USBFS 0 + #define CFG_TUD_WCH_USBIP_USBFS 0 #endif #if !defined(CFG_TUD_WCH_USBIP_FSDEV) - #define CFG_TUD_WCH_USBIP_FSDEV (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1) + #define CFG_TUD_WCH_USBIP_FSDEV (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1) #endif - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_CH32V307) // v307 support both FS and HS, default to HS @@ -574,15 +580,15 @@ #define TUP_USBIP_WCH_USBFS #if !defined(CFG_TUD_WCH_USBIP_USBFS) - #define CFG_TUD_WCH_USBIP_USBFS 0 + #define CFG_TUD_WCH_USBIP_USBFS 0 #endif #if !defined(CFG_TUD_WCH_USBIP_USBHS) - #define CFG_TUD_WCH_USBIP_USBHS (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1) + #define CFG_TUD_WCH_USBIP_USBHS (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1) #endif - #define TUP_RHPORT_HIGHSPEED CFG_TUD_WCH_USBIP_USBHS - #define TUP_DCD_ENDPOINT_MAX (CFG_TUD_WCH_USBIP_USBHS ? 16 : 8) + #define TUP_RHPORT_HIGHSPEED CFG_TUD_WCH_USBIP_USBHS + #define TUP_DCD_ENDPOINT_MAX (CFG_TUD_WCH_USBIP_USBHS ? 16 : 8) //--------------------------------------------------------------------+ // Analog Devices @@ -590,8 +596,8 @@ #elif TU_CHECK_MCU(OPT_MCU_MAX32650, OPT_MCU_MAX32666, OPT_MCU_MAX32690, OPT_MCU_MAX78002) #define TUP_USBIP_MUSB #define TUP_USBIP_MUSB_ADI - #define TUP_DCD_ENDPOINT_MAX 12 - #define TUP_RHPORT_HIGHSPEED 1 + #define TUP_DCD_ENDPOINT_MAX 12 + #define TUP_RHPORT_HIGHSPEED 1 #define TUD_ENDPOINT_ONE_DIRECTION_ONLY //--------------------------------------------------------------------+ @@ -600,46 +606,44 @@ #elif TU_CHECK_MCU(OPT_MCU_AT32F403A_407) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_AT32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_AT32F413) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_AT32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_AT32F415) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_AT32 - #define TUP_DCD_ENDPOINT_MAX 4 + #define TUP_DCD_ENDPOINT_MAX 4 #elif TU_CHECK_MCU(OPT_MCU_AT32F435_437) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_AT32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_AT32F423) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_AT32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_AT32F402_405) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_AT32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 // AT32F405xx has on-chip HS PHY - #if defined(AT32F405CBT7) || defined(AT32F405CBU7) || \ - defined(AT32F405CCT7) || defined(AT32F405CCU7) || \ - defined(AT32F405KBU7_4) || defined(AT32F405KCU7_4) || \ - defined(AT32F405RBT7_7) || defined(AT32F405RBT7) || \ - defined(AT32F405RCT7_7) || defined(AT32F405RCT7) - #define TUP_RHPORT_HIGHSPEED 1 // Port0: FS, Port1: HS + #if defined(AT32F405CBT7) || defined(AT32F405CBU7) || defined(AT32F405CCT7) || defined(AT32F405CCU7) || \ + defined(AT32F405KBU7_4) || defined(AT32F405KCU7_4) || defined(AT32F405RBT7_7) || defined(AT32F405RBT7) || \ + defined(AT32F405RCT7_7) || defined(AT32F405RCT7) + #define TUP_RHPORT_HIGHSPEED 1 // Port0: FS, Port1: HS #endif #elif TU_CHECK_MCU(OPT_MCU_AT32F425) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_AT32 - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #endif @@ -649,7 +653,7 @@ #if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421 #ifndef CFG_TUH_MAX3421_ENDPOINT_TOTAL - #define CFG_TUH_MAX3421_ENDPOINT_TOTAL (8 + 4*(CFG_TUH_DEVICE_MAX-1)) + #define CFG_TUH_MAX3421_ENDPOINT_TOTAL (8 + 4 * (CFG_TUH_DEVICE_MAX - 1)) #endif #endif @@ -659,17 +663,17 @@ //--------------------------------------------------------------------+ #ifndef TUP_MCU_MULTIPLE_CORE -#define TUP_MCU_MULTIPLE_CORE 0 + #define TUP_MCU_MULTIPLE_CORE 0 #endif #if !defined(TUP_DCD_ENDPOINT_MAX) && defined(CFG_TUD_ENABLED) && CFG_TUD_ENABLED #warning "TUP_DCD_ENDPOINT_MAX is not defined for this MCU, default to 8" - #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_ENDPOINT_MAX 8 #endif // Default to fullspeed if not defined #ifndef TUP_RHPORT_HIGHSPEED - #define TUP_RHPORT_HIGHSPEED 0 + #define TUP_RHPORT_HIGHSPEED 0 #endif // fast function, normally mean placing function in SRAM @@ -677,8 +681,13 @@ #define TU_ATTR_FAST_FUNC #endif -// USBIP that support ISO alloc & activate API -#if defined(TUP_USBIP_DWC2) || defined(TUP_USBIP_FSDEV) || defined(TUP_USBIP_MUSB) +#if defined(TUP_USBIP_CHIPIDEA_FS) || defined(TUP_USBIP_IP3511) || defined(TUP_USBIP_RUSB2) || \ + (defined(TUP_USBIP_WCH_USBFS) && CFG_TUD_WCH_USBIP_USBFS) + #define TUP_DCD_EDPT_CLOSE_API +#endif + +// USBIP implement dcd_edpt_close() and does not support ISO alloc & activate API +#ifndef TUP_DCD_EDPT_CLOSE_API #define TUP_DCD_EDPT_ISO_ALLOC #endif diff --git a/src/device/dcd.h b/src/device/dcd.h index 1b0289280..353f836ee 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -171,7 +171,12 @@ void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr); // This API never calls with control endpoints, since it is auto cleared when receiving setup packet void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr); -#ifdef TUP_DCD_EDPT_ISO_ALLOC +#ifdef TUP_DCD_EDPT_CLOSE_API +// Close an endpoint. +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr); + +#else + // Allocate packet buffer used by ISO endpoints // Some MCU need manual packet buffer allocation, we allocate the largest size to avoid clustering bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size); @@ -179,10 +184,6 @@ bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet // Configure and enable an ISO endpoint according to descriptor bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep); -#else -// Close an endpoint. -void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr); - #endif //--------------------------------------------------------------------+ diff --git a/src/portable/bridgetek/ft9xx/dcd_ft9xx.c b/src/portable/bridgetek/ft9xx/dcd_ft9xx.c index 34a8be3b6..6ed4be410 100644 --- a/src/portable/bridgetek/ft9xx/dcd_ft9xx.c +++ b/src/portable/bridgetek/ft9xx/dcd_ft9xx.c @@ -806,6 +806,20 @@ void dcd_edpt_close_all(uint8_t rhport) _ft9xx_reset_edpts(); } +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void)rhport; + (void)ep_addr; + (void)largest_packet_size; + return false; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { + (void)rhport; + (void)desc_ep; + return false; +} + + // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) { @@ -1200,5 +1214,4 @@ void ft9xx_usbd_pm_ISR(void) } } } - #endif diff --git a/src/portable/chipidea/ci_fs/dcd_ci_fs.c b/src/portable/chipidea/ci_fs/dcd_ci_fs.c index 11ddb683f..8b5c42aa2 100644 --- a/src/portable/chipidea/ci_fs/dcd_ci_fs.c +++ b/src/portable/chipidea/ci_fs/dcd_ci_fs.c @@ -399,6 +399,7 @@ void dcd_edpt_close_all(uint8_t rhport) } } +#ifdef TUP_DCD_EDPT_CLOSE_API void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { const unsigned epn = tu_edpt_number(ep_addr); @@ -419,6 +420,22 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) dcd_int_enable(rhport); } +#else + +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void) rhport; + (void) ep_addr; + (void) largest_packet_size; + return false; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) { + (void) rhport; + (void) desc_ep; + return false; +} +#endif + bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { const unsigned epn = tu_edpt_number(ep_addr); @@ -564,5 +581,4 @@ void dcd_int_handler(uint8_t rhport) process_tokdne(rhport); } } - #endif diff --git a/src/portable/chipidea/ci_hs/dcd_ci_hs.c b/src/portable/chipidea/ci_hs/dcd_ci_hs.c index 244f5a2d4..8c5253eb9 100644 --- a/src/portable/chipidea/ci_hs/dcd_ci_hs.c +++ b/src/portable/chipidea/ci_hs/dcd_ci_hs.c @@ -64,16 +64,19 @@ bool dcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) { //--------------------------------------------------------------------+ // ENDPTCTRL +enum { + ENDPTCTRL_TYPE_POS = 2, // Endpoint type is 2-bit field +}; + enum { ENDPTCTRL_STALL = TU_BIT(0), ENDPTCTRL_TOGGLE_INHIBIT = TU_BIT(5), // used for test only ENDPTCTRL_TOGGLE_RESET = TU_BIT(6), - ENDPTCTRL_ENABLE = TU_BIT(7) + ENDPTCTRL_ENABLE = TU_BIT(7), }; -enum { - ENDPTCTRL_TYPE_POS = 2, // Endpoint type is 2-bit field -}; +#define ENDPTCTRL_TYPE(_type) ((_type) << ENDPTCTRL_TYPE_POS) + #define ENDPTCTRL_RESET_MASK (ENDPTCTRL_TYPE(TUSB_XFER_BULK) | (ENDPTCTRL_TYPE(TUSB_XFER_BULK) << 16u)) // USBSTS, USBINTR enum { @@ -170,9 +173,7 @@ static dcd_data_t _dcd_data; // Prototypes and Helper Functions //--------------------------------------------------------------------+ -TU_ATTR_ALWAYS_INLINE -static inline uint8_t ci_ep_count(ci_hs_regs_t const* dcd_reg) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t ci_ep_count(const ci_hs_regs_t *dcd_reg) { return dcd_reg->DCCPARAMS & DCCPARAMS_DEN_MASK; } @@ -191,9 +192,8 @@ static void bus_reset(uint8_t rhport) // type (e.g. bulk). Leaving an un-configured endpoint control will cause undefined behavior // for the data PID tracking on the active endpoint. uint8_t const ep_count = ci_ep_count(dcd_reg); - for( uint8_t i=1; i < ep_count; i++) - { - dcd_reg->ENDPTCTRL[i] = (TUSB_XFER_BULK << ENDPTCTRL_TYPE_POS) | (TUSB_XFER_BULK << (16+ENDPTCTRL_TYPE_POS)); + for (uint8_t i = 1; i < ep_count; i++) { + dcd_reg->ENDPTCTRL[i] = ENDPTCTRL_RESET_MASK; } //------------- Clear All Registers -------------// @@ -315,26 +315,25 @@ void dcd_sof_enable(uint8_t rhport, bool en) // HELPER //--------------------------------------------------------------------+ -static void qtd_init(dcd_qtd_t* p_qtd, void * data_ptr, uint16_t total_bytes) -{ - dcd_dcache_clean_invalidate((uint32_t*) tu_align((uint32_t) data_ptr, 4), total_bytes); +static void qtd_init(dcd_qtd_t *p_qtd, void *data_ptr, uint16_t total_bytes) { + dcd_dcache_clean_invalidate((uint32_t *)tu_align((uint32_t)data_ptr, 4), total_bytes); tu_memclr(p_qtd, sizeof(dcd_qtd_t)); - p_qtd->next = QTD_NEXT_INVALID; - p_qtd->active = 1; - p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes; - p_qtd->int_on_complete = true; + p_qtd->next = QTD_NEXT_INVALID; + p_qtd->active = 1; + p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes; + p_qtd->int_on_complete = true; - if (data_ptr != NULL) - { - p_qtd->buffer[0] = (uint32_t) data_ptr; + if (data_ptr != NULL) { + p_qtd->buffer[0] = (uint32_t)data_ptr; - uint32_t const bufend = p_qtd->buffer[0] + total_bytes; - for(uint8_t i=1; i<5; i++) - { - uint32_t const next_page = tu_align4k( p_qtd->buffer[i-1] ) + 4096; - if ( bufend <= next_page ) break; + const uint32_t bufend = p_qtd->buffer[0] + total_bytes; + for (uint8_t i = 1; i < 5; i++) { + const uint32_t next_page = tu_align4k(p_qtd->buffer[i - 1]) + 4096; + if (bufend <= next_page) { + break; + } p_qtd->buffer[i] = next_page; @@ -346,6 +345,35 @@ static void qtd_init(dcd_qtd_t* p_qtd, void * data_ptr, uint16_t total_bytes) //--------------------------------------------------------------------+ // DCD Endpoint Port //--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline void ep_ctrl_write(volatile uint32_t *epctrl, uint8_t dir, uint32_t value) { + if (dir == TUSB_DIR_OUT) { + *epctrl = (*epctrl & 0xFFFF0000u) | value; + } else { + *epctrl = (*epctrl & 0x0000FFFFu) | (value << 16); + } +} + +TU_ATTR_ALWAYS_INLINE static inline void ep_ctrl_mask(volatile uint32_t *epctrl, uint8_t dir, uint32_t and_mask, + uint32_t or_mask) { + uint32_t value = *epctrl; + if (and_mask != 0) { + value &= (dir == TUSB_DIR_OUT) ? and_mask : (and_mask << 16u); + } + if (or_mask != 0) { + value |= (dir == TUSB_DIR_OUT) ? or_mask : (or_mask << 16u); + } + + *epctrl = value; +} + +TU_ATTR_ALWAYS_INLINE static inline void ep_ctrl_set(volatile uint32_t *epctrl, uint8_t dir, uint32_t mask) { + ep_ctrl_mask(epctrl, dir, 0, mask); +} + +TU_ATTR_ALWAYS_INLINE static inline void ep_ctrl_clear(volatile uint32_t *epctrl, uint8_t dir, uint32_t mask) { + ep_ctrl_mask(epctrl, dir, ~mask, 0); +} + void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { uint8_t const epnum = tu_edpt_number(ep_addr); @@ -366,80 +394,91 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) // data toggle also need to be reset ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport); dcd_reg->ENDPTCTRL[epnum] |= ENDPTCTRL_TOGGLE_RESET << ( dir ? 16 : 0 ); - dcd_reg->ENDPTCTRL[epnum] &= ~(ENDPTCTRL_STALL << ( dir ? 16 : 0)); + dcd_reg->ENDPTCTRL[epnum] &= ~(ENDPTCTRL_STALL << (dir ? 16 : 0)); } -bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) -{ - uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress); - uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); - - ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport); - - // Must not exceed max endpoint number - TU_ASSERT(epnum < ci_ep_count(dcd_reg)); - - //------------- Prepare Queue Head -------------// - dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir]; +static void qhd_init(dcd_qhd_t *p_qhd, uint16_t max_packet_size, uint8_t iso_mult) { tu_memclr(p_qhd, sizeof(dcd_qhd_t)); - p_qhd->zero_length_termination = 1; - p_qhd->max_packet_size = tu_edpt_packet_size(p_endpoint_desc); - if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) - { - p_qhd->iso_mult = 1; - } - + p_qhd->max_packet_size = max_packet_size; + p_qhd->iso_mult = iso_mult; p_qhd->qtd_overlay.next = QTD_NEXT_INVALID; - dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t)); +} - // Enable EP Control - uint32_t const epctrl = (p_endpoint_desc->bmAttributes.xfer << ENDPTCTRL_TYPE_POS) | ENDPTCTRL_ENABLE | ENDPTCTRL_TOGGLE_RESET; +bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *endpoint_desc) { + ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); + const uint8_t epnum = tu_edpt_number(endpoint_desc->bEndpointAddress); + const uint8_t dir = tu_edpt_dir(endpoint_desc->bEndpointAddress); + const uint8_t xfer_type = endpoint_desc->bmAttributes.xfer; + TU_ASSERT(epnum < ci_ep_count(dcd_reg)); - if ( dir == TUSB_DIR_OUT ) - { - dcd_reg->ENDPTCTRL[epnum] = (dcd_reg->ENDPTCTRL[epnum] & 0xFFFF0000u) | epctrl; - }else - { - dcd_reg->ENDPTCTRL[epnum] = (dcd_reg->ENDPTCTRL[epnum] & 0x0000FFFFu) | (epctrl << 16); - } + dcd_qhd_t *p_qhd = &_dcd_data.qhd[epnum][dir]; + qhd_init(p_qhd, tu_edpt_packet_size(endpoint_desc), 0u); + + // EP Control + const uint32_t epctrl = ENDPTCTRL_TYPE(xfer_type) | ENDPTCTRL_ENABLE | ENDPTCTRL_TOGGLE_RESET; + ep_ctrl_write(&dcd_reg->ENDPTCTRL[epnum], dir, epctrl); return true; } -void dcd_edpt_close_all (uint8_t rhport) -{ - ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport); +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void)rhport; + (void)ep_addr; + (void)largest_packet_size; - // Disable all non-control endpoints - uint8_t const ep_count = ci_ep_count(dcd_reg); - for (uint8_t epnum = 1; epnum < ep_count; epnum++) - { - _dcd_data.qhd[epnum][TUSB_DIR_OUT].qtd_overlay.halted = 1; - _dcd_data.qhd[epnum][TUSB_DIR_IN ].qtd_overlay.halted = 1; + ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); + const uint8_t epnum = tu_edpt_number(ep_addr); + const uint8_t dir = tu_edpt_dir(ep_addr); + TU_ASSERT(epnum < ci_ep_count(dcd_reg)); - dcd_reg->ENDPTFLUSH = TU_BIT(epnum) | TU_BIT(epnum+16); - dcd_reg->ENDPTCTRL[epnum] = (TUSB_XFER_BULK << ENDPTCTRL_TYPE_POS) | (TUSB_XFER_BULK << (16+ENDPTCTRL_TYPE_POS)); - } + // EP Control: set type but not enabled yet + const uint32_t epctrl = ENDPTCTRL_TYPE(TUSB_XFER_ISOCHRONOUS) | ENDPTCTRL_TOGGLE_RESET; + ep_ctrl_write(&dcd_reg->ENDPTCTRL[epnum], dir, epctrl); + + return true; } -void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) -{ - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); +bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { + const uint8_t epnum = tu_edpt_number(desc_ep->bEndpointAddress); + const uint8_t dir = tu_edpt_dir(desc_ep->bEndpointAddress); + ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); + TU_ASSERT(epnum < ci_ep_count(dcd_reg)); - ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport); + dcd_qhd_t *p_qhd = &_dcd_data.qhd[epnum][dir]; + volatile uint32_t *endptctrl = &dcd_reg->ENDPTCTRL[epnum]; - _dcd_data.qhd[epnum][dir].qtd_overlay.halted = 1; + // _dcd_data.qhd[epnum][dir].qtd_overlay.halted = 1; + // dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t)); // Flush EP - uint32_t const flush_mask = TU_BIT(epnum + (dir ? 16 : 0)); - dcd_reg->ENDPTFLUSH = flush_mask; - while(dcd_reg->ENDPTFLUSH & flush_mask); + const uint32_t flush_mask = TU_BIT(epnum + (dir ? 16 : 0)); + dcd_reg->ENDPTFLUSH = flush_mask; + while (dcd_reg->ENDPTFLUSH & flush_mask) {} + + // disable to change max packet size + ep_ctrl_clear(endptctrl, dir, ENDPTCTRL_ENABLE); - // Clear EP enable - dcd_reg->ENDPTCTRL[epnum] &=~(ENDPTCTRL_ENABLE << (dir ? 16 : 0)); + qhd_init(p_qhd, tu_edpt_packet_size(desc_ep), 1u); + + ep_ctrl_set(endptctrl, dir, ENDPTCTRL_ENABLE); + + return true; +} + +void dcd_edpt_close_all(uint8_t rhport) { + ci_hs_regs_t *dcd_reg = CI_HS_REG(rhport); + + // Disable all non-control endpoints + uint8_t const ep_count = ci_ep_count(dcd_reg); + for (uint8_t epnum = 1; epnum < ep_count; epnum++) { + _dcd_data.qhd[epnum][TUSB_DIR_OUT].qtd_overlay.halted = 1; + _dcd_data.qhd[epnum][TUSB_DIR_IN].qtd_overlay.halted = 1; + + dcd_reg->ENDPTFLUSH = TU_BIT(epnum) | TU_BIT(epnum + 16); + dcd_reg->ENDPTCTRL[epnum] = ENDPTCTRL_RESET_MASK; + } } static void qhd_start_xfer(uint8_t rhport, uint8_t epnum, uint8_t dir) @@ -678,5 +717,4 @@ void dcd_int_handler(uint8_t rhport) dcd_event_sof(rhport, frame, true); } } - #endif diff --git a/src/portable/dialog/da146xx/dcd_da146xx.c b/src/portable/dialog/da146xx/dcd_da146xx.c index 56ecb7575..868a10dd9 100644 --- a/src/portable/dialog/da146xx/dcd_da146xx.c +++ b/src/portable/dialog/da146xx/dcd_da146xx.c @@ -1025,6 +1025,21 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) tu_memclr(xfer, sizeof(*xfer)); } +#if 0 +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void) rhport; + (void) ep_addr; + (void) largest_packet_size; + return false; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) { + (void) rhport; + (void) desc_ep; + return false; +} +#endif + bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) { uint8_t const epnum = tu_edpt_number(ep_addr); @@ -1218,5 +1233,4 @@ void dcd_int_handler(uint8_t rhport) handle_alt_ev(); } } - #endif diff --git a/src/portable/microchip/pic/dcd_pic.c b/src/portable/microchip/pic/dcd_pic.c index b4a698199..8413a7ddd 100644 --- a/src/portable/microchip/pic/dcd_pic.c +++ b/src/portable/microchip/pic/dcd_pic.c @@ -687,6 +687,21 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) if (ie) intr_enable(rhport); } +#if 0 +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void) rhport; + (void) ep_addr; + (void) largest_packet_size; + return false; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) { + (void) rhport; + (void) desc_ep; + return false; +} +#endif + bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { @@ -866,5 +881,4 @@ void dcd_int_handler(uint8_t rhport) intr_clear(rhport); } - #endif diff --git a/src/portable/microchip/pic32mz/dcd_pic32mz.c b/src/portable/microchip/pic32mz/dcd_pic32mz.c index cbd157d6b..b039bb505 100644 --- a/src/portable/microchip/pic32mz/dcd_pic32mz.c +++ b/src/portable/microchip/pic32mz/dcd_pic32mz.c @@ -438,12 +438,20 @@ void dcd_edpt_close_all (uint8_t rhport) } } -void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) -{ +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { (void) rhport; (void) ep_addr; + (void)largest_packet_size; + return false; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { + (void)rhport; + (void)desc_ep; + return false; } + bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) { uint8_t const epnum = tu_edpt_number(ep_addr); @@ -744,5 +752,4 @@ void dcd_int_handler(uint8_t rhport) } } } - #endif diff --git a/src/portable/microchip/samd/dcd_samd.c b/src/portable/microchip/samd/dcd_samd.c index e43439f2a..383cf60e5 100644 --- a/src/portable/microchip/samd/dcd_samd.c +++ b/src/portable/microchip/samd/dcd_samd.c @@ -245,11 +245,17 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) return true; } -void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) { +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { (void) rhport; (void) ep_addr; + (void)largest_packet_size; + return false; +} - // TODO: implement if necessary? +bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { + (void)rhport; + (void)desc_ep; + return false; } void dcd_edpt_close_all (uint8_t rhport) @@ -427,5 +433,4 @@ void dcd_int_handler (uint8_t rhport) // Handle complete transfer maybe_transfer_complete(); } - #endif diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c index a5c768839..879b2eb2b 100644 --- a/src/portable/microchip/samg/dcd_samg.c +++ b/src/portable/microchip/samg/dcd_samg.c @@ -270,9 +270,17 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) return true; } -void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { - (void) rhport; (void) ep_addr; - // TODO implement dcd_edpt_close() +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void)rhport; + (void)ep_addr; + (void)largest_packet_size; + return false; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { + (void)rhport; + (void)desc_ep; + return false; } void dcd_edpt_close_all (uint8_t rhport) @@ -494,5 +502,4 @@ void dcd_int_handler(uint8_t rhport) } } } - #endif diff --git a/src/portable/microchip/samx7x/dcd_samx7x.c b/src/portable/microchip/samx7x/dcd_samx7x.c index 8aec1568d..51308f7a2 100644 --- a/src/portable/microchip/samx7x/dcd_samx7x.c +++ b/src/portable/microchip/samx7x/dcd_samx7x.c @@ -559,15 +559,17 @@ void dcd_edpt_close_all (uint8_t rhport) // TODO implement dcd_edpt_close_all() } -void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) -{ +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { (void) rhport; - uint8_t const epnum = tu_edpt_number(ep_addr); + (void) ep_addr; + (void) largest_packet_size; + return false; +} - // Disable endpoint interrupt - USB_REG->DEVIDR = 1 << (DEVIDR_PEP_0_Pos + epnum); - // Disable EP - USB_REG->DEVEPT &=~(1 << (DEVEPT_EPEN0_Pos + epnum)); +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) { + (void) rhport; + (void) desc_ep; + return false; } static void dcd_transmit_packet(xfer_ctl_t * xfer, uint8_t ep_ix) @@ -773,5 +775,4 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) USB_REG->DEVEPTIDR[epnum] = DEVEPTIDR_CTRL_STALLRQC; USB_REG->DEVEPTIER[epnum] = HSTPIPIER_RSTDTS; } - #endif diff --git a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c index 1ce3da27e..a232810a2 100644 --- a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c +++ b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c @@ -26,7 +26,7 @@ #include "tusb_option.h" -#if CFG_TUD_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_MM32F327X ) +#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_MM32F327X) #include "reg_usb_otg_fs.h" #include "mm32_device.h" @@ -43,56 +43,53 @@ enum { TOK_PID_SETUP = 0xDu, }; -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { union { uint32_t head; struct { union { struct { - uint16_t : 2; - uint16_t tok_pid : 4; - uint16_t data : 1; - uint16_t own : 1; - uint16_t : 8; + uint16_t : 2; + uint16_t tok_pid : 4; + uint16_t data : 1; + uint16_t own : 1; + uint16_t : 8; }; struct { - uint16_t : 2; - uint16_t bdt_stall: 1; - uint16_t dts : 1; - uint16_t ninc : 1; - uint16_t keep : 1; - uint16_t : 10; + uint16_t : 2; + uint16_t bdt_stall : 1; + uint16_t dts : 1; + uint16_t ninc : 1; + uint16_t keep : 1; + uint16_t : 10; }; }; - uint16_t bc : 10; - uint16_t : 6; + uint16_t bc : 10; + uint16_t : 6; }; }; uint8_t *addr; -}buffer_descriptor_t; +} buffer_descriptor_t; -TU_VERIFY_STATIC( sizeof(buffer_descriptor_t) == 8, "size is not correct" ); +TU_VERIFY_STATIC(sizeof(buffer_descriptor_t) == 8, "size is not correct"); -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { union { uint32_t state; struct { - uint32_t max_packet_size :11; + uint32_t max_packet_size : 11; uint32_t : 5; uint32_t odd : 1; - uint32_t :15; + uint32_t : 15; }; }; uint16_t length; uint16_t remaining; -}endpoint_state_t; +} endpoint_state_t; -TU_VERIFY_STATIC( sizeof(endpoint_state_t) == 8, "size is not correct" ); +TU_VERIFY_STATIC(sizeof(endpoint_state_t) == 8, "size is not correct"); -typedef struct -{ +typedef struct { union { /* [#EP][OUT,IN][EVEN,ODD] */ buffer_descriptor_t bdt[16][2][2]; @@ -104,7 +101,7 @@ typedef struct }; uint8_t setup_packet[8]; uint8_t addr; -}dcd_data_t; +} dcd_data_t; //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION @@ -112,10 +109,9 @@ typedef struct // BDT(Buffer Descriptor Table) must be 256-byte aligned CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(512) static dcd_data_t _dcd; -TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 512, "size is not correct" ); +TU_VERIFY_STATIC(sizeof(_dcd.bdt) == 512, "size is not correct"); -static void prepare_next_setup_packet(uint8_t rhport) -{ +static void prepare_next_setup_packet(uint8_t rhport) { const unsigned out_odd = _dcd.endpoint[0][0].odd; const unsigned in_odd = _dcd.endpoint[0][1].odd; if (_dcd.bdt[0][0][out_odd].own) { @@ -126,12 +122,10 @@ static void prepare_next_setup_packet(uint8_t rhport) _dcd.bdt[0][0][out_odd ^ 1].data = 1; _dcd.bdt[0][1][in_odd].data = 1; _dcd.bdt[0][1][in_odd ^ 1].data = 0; - dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_OUT), - _dcd.setup_packet, sizeof(_dcd.setup_packet)); + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_OUT), _dcd.setup_packet, sizeof(_dcd.setup_packet)); } -static void process_stall(uint8_t rhport) -{ +static void process_stall(uint8_t rhport) { if (USB_OTG_FS->EP_CTL[0] & USB_ENDPT_EPSTALL_MASK) { /* clear stall condition of the control pipe */ prepare_next_setup_packet(rhport); @@ -139,13 +133,12 @@ static void process_stall(uint8_t rhport) } } -static void process_tokdne(uint8_t rhport) -{ - const unsigned s = USB_OTG_FS->STAT; - USB_OTG_FS->INT_STAT = USB_ISTAT_TOKDNE_MASK; /* fetch the next token if received */ - buffer_descriptor_t *bd = (buffer_descriptor_t *)&_dcd.bda[s]; - endpoint_state_t *ep = &_dcd.endpoint_unified[s >> 3]; - unsigned odd = (s & USB_STAT_ODD_MASK) ? 1 : 0; +static void process_tokdne(uint8_t rhport) { + const unsigned s = USB_OTG_FS->STAT; + USB_OTG_FS->INT_STAT = USB_ISTAT_TOKDNE_MASK; /* fetch the next token if received */ + buffer_descriptor_t *bd = (buffer_descriptor_t *)&_dcd.bda[s]; + endpoint_state_t *ep = &_dcd.endpoint_unified[s >> 3]; + unsigned odd = (s & USB_STAT_ODD_MASK) ? 1 : 0; /* fetch pid before discarded by the next steps */ const unsigned pid = bd->tok_pid; @@ -155,7 +148,7 @@ static void process_tokdne(uint8_t rhport) bd->ninc = 0; bd->keep = 0; /* update the odd variable to prepare for the next transfer */ - ep->odd = odd ^ 1; + ep->odd = odd ^ 1; if (pid == TOK_PID_SETUP) { dcd_event_setup_received(rhport, bd->addr, true); USB_OTG_FS->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK; @@ -165,25 +158,24 @@ static void process_tokdne(uint8_t rhport) TU_LOG1("TKDNE %x\r\n", s); } - const unsigned bc = bd->bc; + const unsigned bc = bd->bc; const unsigned remaining = ep->remaining - bc; if (remaining && bc == ep->max_packet_size) { /* continue the transferring consecutive data */ - ep->remaining = remaining; + ep->remaining = remaining; const int next_remaining = remaining - ep->max_packet_size; if (next_remaining > 0) { /* prepare to the after next transfer */ bd->addr += ep->max_packet_size * 2; - bd->bc = next_remaining > ep->max_packet_size ? ep->max_packet_size: next_remaining; + bd->bc = next_remaining > ep->max_packet_size ? ep->max_packet_size : next_remaining; __DSB(); - bd->own = 1; /* the own bit must set after addr */ + bd->own = 1; /* the own bit must set after addr */ } return; } const unsigned length = ep->length; - dcd_event_xfer_complete(rhport, - ((s & USB_STAT_TX_MASK) << 4) | (s >> USB_STAT_ENDP_SHIFT), - length - remaining, XFER_RESULT_SUCCESS, true); + dcd_event_xfer_complete(rhport, ((s & USB_STAT_TX_MASK) << 4) | (s >> USB_STAT_ENDP_SHIFT), length - remaining, + XFER_RESULT_SUCCESS, true); if (0 == (s & USB_STAT_ENDP_MASK) && 0 == length) { /* After completion a ZLP of control transfer, * it prepares for the next steup transfer. */ @@ -191,24 +183,23 @@ static void process_tokdne(uint8_t rhport) /* When the transfer was the SetAddress, * the device address should be updated here. */ USB_OTG_FS->ADDR = _dcd.addr; - _dcd.addr = 0; + _dcd.addr = 0; } prepare_next_setup_packet(rhport); } } -static void process_bus_reset(uint8_t rhport) -{ - USB_OTG_FS->CTL |= USB_CTL_ODDRST_MASK; - USB_OTG_FS->ADDR = 0; - USB_OTG_FS->INT_ENB = (USB_OTG_FS->INT_ENB & ~USB_INTEN_RESUMEEN_MASK) | USB_INTEN_SLEEPEN_MASK; +static void process_bus_reset(uint8_t rhport) { + USB_OTG_FS->CTL |= USB_CTL_ODDRST_MASK; + USB_OTG_FS->ADDR = 0; + USB_OTG_FS->INT_ENB = (USB_OTG_FS->INT_ENB & ~USB_INTEN_RESUMEEN_MASK) | USB_INTEN_SLEEPEN_MASK; USB_OTG_FS->EP_CTL[0] = USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK; for (unsigned i = 1; i < 16; ++i) { USB_OTG_FS->EP_CTL[i] = 0; } buffer_descriptor_t *bd = _dcd.bdt[0][0]; - for (unsigned i = 0; i < sizeof(_dcd.bdt)/sizeof(*bd); ++i, ++bd) { + for (unsigned i = 0; i < sizeof(_dcd.bdt) / sizeof(*bd); ++i, ++bd) { bd->head = 0; } const endpoint_state_t ep0 = { @@ -226,31 +217,29 @@ static void process_bus_reset(uint8_t rhport) dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true); } -static void process_bus_inactive(uint8_t rhport) -{ - (void) rhport; +static void process_bus_inactive(uint8_t rhport) { + (void)rhport; const unsigned inten = USB_OTG_FS->INT_ENB; - USB_OTG_FS->INT_ENB = (inten & ~USB_INTEN_SLEEPEN_MASK) | USB_INTEN_RESUMEEN_MASK; + USB_OTG_FS->INT_ENB = (inten & ~USB_INTEN_SLEEPEN_MASK) | USB_INTEN_RESUMEEN_MASK; dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); } -static void process_bus_active(uint8_t rhport) -{ - (void) rhport; +static void process_bus_active(uint8_t rhport) { + (void)rhport; const unsigned inten = USB_OTG_FS->INT_ENB; - USB_OTG_FS->INT_ENB = (inten & ~USB_INTEN_RESUMEEN_MASK) | USB_INTEN_SLEEPEN_MASK; + USB_OTG_FS->INT_ENB = (inten & ~USB_INTEN_RESUMEEN_MASK) | USB_INTEN_SLEEPEN_MASK; dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true); } /*------------------------------------------------------------------*/ /* Device API *------------------------------------------------------------------*/ -bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { - (void) rhport; - (void) rh_init; +bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { + (void)rhport; + (void)rh_init; tu_memclr(&_dcd, sizeof(_dcd)); - USB_OTG_FS->BDT_PAGE_01 = (uint8_t)((uintptr_t)_dcd.bdt >> 8); + USB_OTG_FS->BDT_PAGE_01 = (uint8_t)((uintptr_t)_dcd.bdt >> 8); USB_OTG_FS->BDT_PAGE_02 = (uint8_t)((uintptr_t)_dcd.bdt >> 16); USB_OTG_FS->BDT_PAGE_03 = (uint8_t)((uintptr_t)_dcd.bdt >> 24); @@ -259,27 +248,24 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { return true; } #define USB_DEVICE_INTERRUPT_PRIORITY (3U) -void dcd_int_enable(uint8_t rhport) -{ +void dcd_int_enable(uint8_t rhport) { uint8_t irqNumber; irqNumber = USB_FS_IRQn; - (void) rhport; - USB_OTG_FS->INT_ENB = USB_INTEN_USBRSTEN_MASK | USB_INTEN_TOKDNEEN_MASK | - USB_INTEN_SLEEPEN_MASK | USB_INTEN_ERROREN_MASK | USB_INTEN_STALLEN_MASK; + (void)rhport; + USB_OTG_FS->INT_ENB = USB_INTEN_USBRSTEN_MASK | USB_INTEN_TOKDNEEN_MASK | USB_INTEN_SLEEPEN_MASK | + USB_INTEN_ERROREN_MASK | USB_INTEN_STALLEN_MASK; NVIC_SetPriority((IRQn_Type)irqNumber, USB_DEVICE_INTERRUPT_PRIORITY); NVIC_EnableIRQ(USB_FS_IRQn); } -void dcd_int_disable(uint8_t rhport) -{ - (void) rhport; +void dcd_int_disable(uint8_t rhport) { + (void)rhport; NVIC_DisableIRQ(USB_FS_IRQn); USB_OTG_FS->INT_ENB = 0; } -void dcd_set_address(uint8_t rhport, uint8_t dev_addr) -{ - (void) rhport; +void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { + (void)rhport; _dcd.addr = dev_addr & 0x7F; /* Response with status first before changing device address */ dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); @@ -296,31 +282,29 @@ extern u32 SystemCoreClock; #pragma GCC diagnostic pop #endif -void dcd_remote_wakeup(uint8_t rhport) -{ - (void) rhport; +void dcd_remote_wakeup(uint8_t rhport) { + (void)rhport; unsigned cnt = SystemCoreClock / 100; USB_OTG_FS->CTL |= USB_CTL_RESUME_MASK; - while (cnt--) __NOP(); + while (cnt--) { + __NOP(); + } USB_OTG_FS->CTL &= ~USB_CTL_RESUME_MASK; } -void dcd_connect(uint8_t rhport) -{ - (void) rhport; - USB_OTG_FS->CTL |= USB_CTL_USBENSOFEN_MASK; +void dcd_connect(uint8_t rhport) { + (void)rhport; + USB_OTG_FS->CTL |= USB_CTL_USBENSOFEN_MASK; } -void dcd_disconnect(uint8_t rhport) -{ - (void) rhport; - USB_OTG_FS->CTL = 0; +void dcd_disconnect(uint8_t rhport) { + (void)rhport; + USB_OTG_FS->CTL = 0; } -void dcd_sof_enable(uint8_t rhport, bool en) -{ - (void) rhport; - (void) en; +void dcd_sof_enable(uint8_t rhport, bool en) { + (void)rhport; + (void)en; // TODO implement later } @@ -328,24 +312,23 @@ void dcd_sof_enable(uint8_t rhport, bool en) //--------------------------------------------------------------------+ // Endpoint API //--------------------------------------------------------------------+ -bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) -{ - (void) rhport; - - const unsigned ep_addr = ep_desc->bEndpointAddress; - const unsigned epn = ep_addr & 0xFu; - const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; - const unsigned xfer = ep_desc->bmAttributes.xfer; - endpoint_state_t *ep = &_dcd.endpoint[epn][dir]; - const unsigned odd = ep->odd; - buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][0]; +bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *ep_desc) { + (void)rhport; + + const unsigned ep_addr = ep_desc->bEndpointAddress; + const unsigned epn = ep_addr & 0xFu; + const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; + const unsigned xfer = ep_desc->bmAttributes.xfer; + endpoint_state_t *ep = &_dcd.endpoint[epn][dir]; + const unsigned odd = ep->odd; + buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][0]; /* No support for control transfer */ TU_ASSERT(epn && (xfer != TUSB_XFER_CONTROL)); ep->max_packet_size = tu_edpt_packet_size(ep_desc); - unsigned val = USB_ENDPT_EPCTLDIS_MASK; - val |= (xfer != TUSB_XFER_ISOCHRONOUS) ? USB_ENDPT_EPHSHK_MASK: 0; + unsigned val = USB_ENDPT_EPCTLDIS_MASK; + val |= (xfer != TUSB_XFER_ISOCHRONOUS) ? USB_ENDPT_EPHSHK_MASK : 0; val |= dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK; USB_OTG_FS->EP_CTL[epn] |= val; @@ -359,21 +342,19 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) return true; } -void dcd_edpt_close_all (uint8_t rhport) -{ - (void) rhport; +void dcd_edpt_close_all(uint8_t rhport) { + (void)rhport; // TODO implement dcd_edpt_close_all() } -void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) -{ - (void) rhport; +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { + (void)rhport; - const unsigned epn = ep_addr & 0xFu; - const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; - endpoint_state_t *ep = &_dcd.endpoint[epn][dir]; - buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][0]; - const unsigned msk = dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK; + const unsigned epn = ep_addr & 0xFu; + const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; + endpoint_state_t *ep = &_dcd.endpoint[epn][dir]; + buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][0]; + const unsigned msk = dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK; USB_OTG_FS->EP_CTL[epn] &= ~msk; ep->max_packet_size = 0; ep->length = 0; @@ -381,14 +362,28 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) bd->head = 0; } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) -{ - (void) rhport; + #if 0 +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void)rhport; + (void)ep_addr; + (void)largest_packet_size; + return false; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { + (void)rhport; + (void)desc_ep; + return false; +} + #endif + +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) { + (void)rhport; NVIC_DisableIRQ(USB_FS_IRQn); - const unsigned epn = ep_addr & 0xFu; - const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; - endpoint_state_t *ep = &_dcd.endpoint[epn][dir]; - buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][ep->odd]; + const unsigned epn = ep_addr & 0xFu; + const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; + endpoint_state_t *ep = &_dcd.endpoint[epn][dir]; + buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][ep->odd]; if (bd->own) { TU_LOG1("DCD XFER fail %x %d %lx %lx\r\n", ep_addr, total_bytes, ep->state, bd->head); @@ -399,42 +394,40 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to const unsigned mps = ep->max_packet_size; if (total_bytes > mps) { - buffer_descriptor_t *next = ep->odd ? bd - 1: bd + 1; + buffer_descriptor_t *next = ep->odd ? bd - 1 : bd + 1; /* When total_bytes is greater than the max packet size, * it prepares to the next transfer to avoid NAK in advance. */ - next->bc = total_bytes >= 2 * mps ? mps: total_bytes - mps; + next->bc = total_bytes >= 2 * mps ? mps : total_bytes - mps; next->addr = buffer + mps; next->own = 1; } - bd->bc = total_bytes >= mps ? mps: total_bytes; - bd->addr = buffer; + bd->bc = total_bytes >= mps ? mps : total_bytes; + bd->addr = buffer; __DSB(); - bd->own = 1; /* the own bit must set after addr */ + bd->own = 1; /* the own bit must set after addr */ NVIC_EnableIRQ(USB_FS_IRQn); return true; } -void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) -{ - (void) rhport; +void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { + (void)rhport; const unsigned epn = ep_addr & 0xFu; if (0 == epn) { - USB_OTG_FS->EP_CTL[epn] |= USB_ENDPT_EPSTALL_MASK; + USB_OTG_FS->EP_CTL[epn] |= USB_ENDPT_EPSTALL_MASK; } else { - const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; - buffer_descriptor_t *bd = _dcd.bdt[epn][dir]; - bd[0].bdt_stall = 1; - bd[1].bdt_stall = 1; + const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; + buffer_descriptor_t *bd = _dcd.bdt[epn][dir]; + bd[0].bdt_stall = 1; + bd[1].bdt_stall = 1; } } -void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) -{ - (void) rhport; - const unsigned epn = ep_addr & 0xFu; - const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; - const unsigned odd = _dcd.endpoint[epn][dir].odd; - buffer_descriptor_t *bd = _dcd.bdt[epn][dir]; +void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { + (void)rhport; + const unsigned epn = ep_addr & 0xFu; + const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT; + const unsigned odd = _dcd.endpoint[epn][dir].odd; + buffer_descriptor_t *bd = _dcd.bdt[epn][dir]; bd[odd ^ 1].own = 0; bd[odd ^ 1].data = 1; @@ -447,19 +440,18 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) //--------------------------------------------------------------------+ // ISR //--------------------------------------------------------------------+ -void dcd_int_handler(uint8_t rhport) -{ - (void) rhport; +void dcd_int_handler(uint8_t rhport) { + (void)rhport; - uint32_t is = USB_OTG_FS->INT_STAT; - uint32_t msk = USB_OTG_FS->INT_ENB; + uint32_t is = USB_OTG_FS->INT_STAT; + uint32_t msk = USB_OTG_FS->INT_ENB; USB_OTG_FS->INT_STAT = is & ~msk; is &= msk; if (is & USB_ISTAT_ERROR_MASK) { /* TODO: */ - uint32_t es = USB_OTG_FS->ERR_STAT; + uint32_t es = USB_OTG_FS->ERR_STAT; USB_OTG_FS->ERR_STAT = es; - USB_OTG_FS->INT_STAT = is; /* discard any pending events */ + USB_OTG_FS->INT_STAT = is; /* discard any pending events */ return; } @@ -493,5 +485,4 @@ void dcd_int_handler(uint8_t rhport) return; } } - #endif diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index 9e5f5117f..730ca7fb1 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -426,6 +426,21 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { __DSB(); } +#if 0 +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void)rhport; + (void)ep_addr; + (void)largest_packet_size; + return false; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { + (void)rhport; + (void)desc_ep; + return false; +} +#endif + bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { (void) rhport; @@ -1062,5 +1077,4 @@ void tusb_hal_nrf_power_event(uint32_t event) { break; } } - #endif diff --git a/src/portable/nxp/khci/dcd_khci.c b/src/portable/nxp/khci/dcd_khci.c index 3d5e195a9..da1c5c888 100644 --- a/src/portable/nxp/khci/dcd_khci.c +++ b/src/portable/nxp/khci/dcd_khci.c @@ -428,6 +428,21 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) if (ie) NVIC_EnableIRQ(USB0_IRQn); } +#if 0 +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void) rhport; + (void) ep_addr; + (void) largest_packet_size; + return false; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) { + (void) rhport; + (void) desc_ep; + return false; +} + #endif + bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { (void) rhport; @@ -577,5 +592,4 @@ void dcd_int_handler(uint8_t rhport) process_tokdne(rhport); } } - #endif diff --git a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c index 855c59cd1..5516e1ba6 100644 --- a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c +++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c @@ -337,9 +337,17 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) return true; } -void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { - (void) rhport; (void) ep_addr; - // TODO implement dcd_edpt_close() +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void)rhport; + (void)ep_addr; + (void)largest_packet_size; + return false; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { + (void)rhport; + (void)desc_ep; + return false; } void dcd_edpt_close_all (uint8_t rhport) @@ -600,5 +608,4 @@ void dcd_int_handler(uint8_t rhport) TU_BREAKPOINT(); } } - #endif diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c index 7c637ce0c..1c135f3be 100644 --- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c +++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c @@ -432,6 +432,21 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) _dcd.ep[ep_id][0].cmd_sts.disable = _dcd.ep[ep_id][1].cmd_sts.disable = 1; } +#if 0 +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void)rhport; + (void)ep_addr; + (void)largest_packet_size; + return false; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { + (void)rhport; + (void)desc_ep; + return false; +} +#endif + static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset, uint16_t total_bytes) { uint16_t nbytes; ep_cmd_sts_t* ep_cs = get_ep_cs(ep_id); @@ -631,5 +646,4 @@ void dcd_int_handler(uint8_t rhport) // Endpoint transfer complete interrupt process_xfer_isr(rhport, int_status); } - #endif diff --git a/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c index 60afbd435..25ef117c2 100644 --- a/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c +++ b/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c @@ -113,6 +113,19 @@ void dcd_edpt_close_all (uint8_t rhport) (void) rhport; } +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void)rhport; + (void)ep_addr; + (void)largest_packet_size; + return false; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { + (void)rhport; + (void)desc_ep; + return false; +} + // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) { @@ -207,5 +220,4 @@ void __no_inline_not_in_flash_func(pio_usb_device_irq_handler)(uint8_t root_id) // clear all rport->ints &= ~ints; } - #endif diff --git a/src/portable/renesas/rusb2/dcd_rusb2.c b/src/portable/renesas/rusb2/dcd_rusb2.c index ecd28973c..2cc79aa74 100644 --- a/src/portable/renesas/rusb2/dcd_rusb2.c +++ b/src/portable/renesas/rusb2/dcd_rusb2.c @@ -859,6 +859,21 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) _dcd.ep[dir][epn] = 0; } +#if 0 +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void)rhport; + (void)ep_addr; + (void)largest_packet_size; + return false; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { + (void)rhport; + (void)desc_ep; + return false; +} +#endif + bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { rusb2_reg_t* rusb = RUSB2_REG(rhport); @@ -1028,5 +1043,4 @@ void dcd_int_handler(uint8_t rhport) } } } - #endif diff --git a/src/portable/sunxi/dcd_sunxi_musb.c b/src/portable/sunxi/dcd_sunxi_musb.c index f1f4897cb..8e6dc8c63 100644 --- a/src/portable/sunxi/dcd_sunxi_musb.c +++ b/src/portable/sunxi/dcd_sunxi_musb.c @@ -1082,6 +1082,21 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) musb_int_unmask(); } + #if 0 +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void)rhport; + (void)ep_addr; + (void)largest_packet_size; + return false; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { + (void)rhport; + (void)desc_ep; + return false; +} + #endif + // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) { @@ -1210,5 +1225,4 @@ void dcd_int_handler(uint8_t rhport) rxis &= ~TU_BIT(num); } } - #endif diff --git a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c index 64cbc5087..e4c28a56f 100644 --- a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c +++ b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c @@ -333,11 +333,20 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) return true; } -void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { - (void) rhport; (void) ep_addr; - // TODO implement dcd_edpt_close() +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void)rhport; + (void)ep_addr; + (void)largest_packet_size; + return false; } +bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { + (void)rhport; + (void)desc_ep; + return false; +} + + void dcd_edpt_close_all (uint8_t rhport) { (void) rhport; @@ -821,5 +830,4 @@ void dcd_int_handler(uint8_t rhport) } } - #endif diff --git a/src/portable/valentyusb/eptri/dcd_eptri.c b/src/portable/valentyusb/eptri/dcd_eptri.c index a03c94558..f0e52ae47 100644 --- a/src/portable/valentyusb/eptri/dcd_eptri.c +++ b/src/portable/valentyusb/eptri/dcd_eptri.c @@ -438,9 +438,17 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) return true; } -void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { - (void) rhport; (void) ep_addr; - // TODO implement dcd_edpt_close() +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void)rhport; + (void)ep_addr; + (void)largest_packet_size; + return false; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { + (void)rhport; + (void)desc_ep; + return false; } void dcd_edpt_close_all (uint8_t rhport) @@ -659,5 +667,4 @@ void dcd_int_handler(uint8_t rhport) } } } - #endif diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index c248ba14e..f8c3b05c3 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -283,12 +283,20 @@ void dcd_edpt_close_all(uint8_t rhport) { // TODO optional } -void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { (void) rhport; (void) ep_addr; - // TODO optional + (void)largest_packet_size; + return false; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { + (void)rhport; + (void)desc_ep; + return false; } + bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) { (void) rhport; uint8_t ep = tu_edpt_number(ep_addr); @@ -344,5 +352,4 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { } } } - #endif diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c index 4a208b9df..36fdc89ef 100644 --- a/src/portable/wch/dcd_ch32_usbhs.c +++ b/src/portable/wch/dcd_ch32_usbhs.c @@ -27,13 +27,14 @@ #include "tusb_option.h" -#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" +#if CFG_TUD_ENABLED && defined(TUP_USBIP_WCH_USBHS) && defined(CFG_TUD_WCH_USBIP_USBHS) && \ + (CFG_TUD_WCH_USBIP_USBHS == 1) + #include "ch32_usbhs_reg.h" -#include "device/dcd.h" + #include "device/dcd.h" -// Max number of bi-directional endpoints including EP0 -#define EP_MAX 16 + // Max number of bi-directional endpoints including EP0 + #define EP_MAX 16 typedef struct { uint8_t* buffer; @@ -288,6 +289,21 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { } } + #if 0 +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void) rhport; + (void) ep_addr; + (void) largest_packet_size; + return false; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) { + (void) rhport; + (void) desc_ep; + return false; +} + #endif + void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { (void) rhport; @@ -419,5 +435,4 @@ void dcd_int_handler(uint8_t rhport) { USBHSD->INT_FG = USBHS_SUSPEND_FLAG; /* Clear flag */ } } - #endif -- cgit v1.3.1 From 6b0d20d70dbe0462fc89a92ab0c0ca04a9c625d0 Mon Sep 17 00:00:00 2001 From: alt-0191 <2223147307@qq.com> Date: Thu, 26 Feb 2026 20:46:39 +0800 Subject: add WCH CH58x (CH582/CH583) BSP and USB FS device/host driver --- hw/bsp/ch58x/boards/yd-ch582m/board.cmake | 5 + hw/bsp/ch58x/boards/yd-ch582m/board.h | 57 +++ hw/bsp/ch58x/boards/yd-ch582m/board.mk | 3 + hw/bsp/ch58x/ch58x_it.c | 37 ++ hw/bsp/ch58x/ch58x_it.h | 46 ++ hw/bsp/ch58x/debug_uart.c | 80 ++++ hw/bsp/ch58x/debug_uart.h | 36 ++ hw/bsp/ch58x/family.c | 181 ++++++++ hw/bsp/ch58x/family.cmake | 103 +++++ hw/bsp/ch58x/family.mk | 49 ++ hw/bsp/ch58x/linker/ch582.ld | 167 +++++++ hw/bsp/ch58x/system_ch58x.c | 39 ++ hw/bsp/ch58x/system_ch58x.h | 43 ++ hw/bsp/ch58x/wch-riscv.cfg | 17 + src/common/tusb_mcu.h | 14 + src/portable/wch/ch58x_usbfs_reg.h | 299 +++++++++++++ src/portable/wch/dcd_ch58x_usbfs.c | 583 ++++++++++++++++++++++++ src/portable/wch/hcd_ch58x_usbfs.c | 712 ++++++++++++++++++++++++++++++ src/tusb_option.h | 1 + 19 files changed, 2472 insertions(+) create mode 100644 hw/bsp/ch58x/boards/yd-ch582m/board.cmake create mode 100644 hw/bsp/ch58x/boards/yd-ch582m/board.h create mode 100644 hw/bsp/ch58x/boards/yd-ch582m/board.mk create mode 100644 hw/bsp/ch58x/ch58x_it.c create mode 100644 hw/bsp/ch58x/ch58x_it.h create mode 100644 hw/bsp/ch58x/debug_uart.c create mode 100644 hw/bsp/ch58x/debug_uart.h create mode 100644 hw/bsp/ch58x/family.c create mode 100644 hw/bsp/ch58x/family.cmake create mode 100644 hw/bsp/ch58x/family.mk create mode 100644 hw/bsp/ch58x/linker/ch582.ld create mode 100644 hw/bsp/ch58x/system_ch58x.c create mode 100644 hw/bsp/ch58x/system_ch58x.h create mode 100644 hw/bsp/ch58x/wch-riscv.cfg create mode 100644 src/portable/wch/ch58x_usbfs_reg.h create mode 100644 src/portable/wch/dcd_ch58x_usbfs.c create mode 100644 src/portable/wch/hcd_ch58x_usbfs.c (limited to 'src/portable/wch') diff --git a/hw/bsp/ch58x/boards/yd-ch582m/board.cmake b/hw/bsp/ch58x/boards/yd-ch582m/board.cmake new file mode 100644 index 000000000..4129c4550 --- /dev/null +++ b/hw/bsp/ch58x/boards/yd-ch582m/board.cmake @@ -0,0 +1,5 @@ +set(LD_FLASH_SIZE 448K) +set(LD_RAM_SIZE 32K) + +function(update_board TARGET) +endfunction() diff --git a/hw/bsp/ch58x/boards/yd-ch582m/board.h b/hw/bsp/ch58x/boards/yd-ch582m/board.h new file mode 100644 index 000000000..6e25dbdd3 --- /dev/null +++ b/hw/bsp/ch58x/boards/yd-ch582m/board.h @@ -0,0 +1,57 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 TinyUSB contributors + * + * 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. + */ + +/* metadata: + name: yd-ch582m from vcc-gnd studio + url: http://vcc-gnd.com/ +*/ + +#ifndef BOARD_H_ +#define BOARD_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +// LED: PB4 on yd-ch582m board +#define LED_PIN GPIO_Pin_4 +#define LED_STATE_ON 0 + +// Directly reuse BOOT pin as user button +#define BUTTON_PIN GPIO_Pin_22 +#define BUTTON_STATE_ACTIVE 0 + +// UART: UART1 TX=PA9, RX=PA8 +#define CFG_BOARD_UART_BAUDRATE 115200 + +// Dual-port: USB1 (rhport 0) = Device, USB2 (rhport 1) = Host +// Swap these two if you want the opposite assignment +#define BOARD_TUD_RHPORT 0 +#define BOARD_TUH_RHPORT 1 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/hw/bsp/ch58x/boards/yd-ch582m/board.mk b/hw/bsp/ch58x/boards/yd-ch582m/board.mk new file mode 100644 index 000000000..a13979799 --- /dev/null +++ b/hw/bsp/ch58x/boards/yd-ch582m/board.mk @@ -0,0 +1,3 @@ +LDFLAGS += \ + -Wl,--defsym=__FLASH_SIZE=448K \ + -Wl,--defsym=__RAM_SIZE=32K \ diff --git a/hw/bsp/ch58x/ch58x_it.c b/hw/bsp/ch58x/ch58x_it.c new file mode 100644 index 000000000..2211e1eda --- /dev/null +++ b/hw/bsp/ch58x/ch58x_it.c @@ -0,0 +1,37 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 TinyUSB contributors + * + * 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 "ch58x_it.h" + +// NMI exception handler +__INTERRUPT __HIGH_CODE void NMI_Handler(void) { + while (1) {} +} + +// Hard Fault exception handler +__INTERRUPT __HIGH_CODE void HardFault_Handler(void) { + while (1) {} +} diff --git a/hw/bsp/ch58x/ch58x_it.h b/hw/bsp/ch58x/ch58x_it.h new file mode 100644 index 000000000..c98f732e1 --- /dev/null +++ b/hw/bsp/ch58x/ch58x_it.h @@ -0,0 +1,46 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 TinyUSB contributors + * + * 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. + */ + +#ifndef __CH58X_IT_H +#define __CH58X_IT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "CH58x_common.h" + +void NMI_Handler(void); +void HardFault_Handler(void); +void USB_IRQHandler(void); +void USB2_IRQHandler(void); +void SysTick_Handler(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __CH58X_IT_H */ diff --git a/hw/bsp/ch58x/debug_uart.c b/hw/bsp/ch58x/debug_uart.c new file mode 100644 index 000000000..e63606f33 --- /dev/null +++ b/hw/bsp/ch58x/debug_uart.c @@ -0,0 +1,80 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 TinyUSB contributors + * + * 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 "debug_uart.h" +#include "CH58x_common.h" + +//--------------------------------------------------------------------+ +// Ring buffer based UART TX for non-blocking writes +//--------------------------------------------------------------------+ + +#define UART_RINGBUFFER_SIZE_TX 128 +#define UART_RINGBUFFER_MASK_TX (UART_RINGBUFFER_SIZE_TX - 1) + +static char tx_buf[UART_RINGBUFFER_SIZE_TX]; +static unsigned int tx_produce; +static volatile unsigned int tx_consume; + +void uart_write(char c) { + unsigned int tx_produce_next = (tx_produce + 1) & UART_RINGBUFFER_MASK_TX; + + // If ring buffer is full, wait + while (tx_produce_next == tx_consume) {} + + // If UART TX FIFO is empty and no pending data, send directly + if ((tx_consume == tx_produce) && (R8_UART1_LSR & RB_LSR_TX_FIFO_EMP)) { + R8_UART1_THR = c; + } else { + tx_buf[tx_produce] = c; + tx_produce = tx_produce_next; + } +} + +void uart_sync(void) { + // Wait for ring buffer to drain + while (tx_consume != tx_produce) { + if (R8_UART1_LSR & RB_LSR_TX_FIFO_EMP) { + R8_UART1_THR = tx_buf[tx_consume]; + tx_consume = (tx_consume + 1) & UART_RINGBUFFER_MASK_TX; + } + } + // Wait for last byte to finish transmitting + while (!(R8_UART1_LSR & RB_LSR_TX_ALL_EMP)) {} +} + +void usart_printf_init(uint32_t baudrate) { + tx_produce = 0; + tx_consume = 0; + + // Configure UART1 pins: TX=PA9, RX=PA8 + GPIOA_SetBits(GPIO_Pin_9); + GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA); + GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU); + + // Init UART1 with specified baud rate + UART1_DefInit(); + UART1_BaudRateCfg(baudrate); +} diff --git a/hw/bsp/ch58x/debug_uart.h b/hw/bsp/ch58x/debug_uart.h new file mode 100644 index 000000000..458d838d9 --- /dev/null +++ b/hw/bsp/ch58x/debug_uart.h @@ -0,0 +1,36 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 TinyUSB contributors + * + * 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. + */ + +#ifndef DEBUG_UART_H_ +#define DEBUG_UART_H_ + +#include + +void uart_write(char c); +void uart_sync(void); +void usart_printf_init(uint32_t baudrate); + +#endif /* DEBUG_UART_H_ */ diff --git a/hw/bsp/ch58x/family.c b/hw/bsp/ch58x/family.c new file mode 100644 index 000000000..463ca5637 --- /dev/null +++ b/hw/bsp/ch58x/family.c @@ -0,0 +1,181 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 TinyUSB contributors + * + * 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. + */ + +/* metadata: + manufacturer: WCH +*/ + +// WCH SDK's DEBUG macro enables a _write() that conflicts with TinyUSB's. +// TinyUSB uses UART1 for printf via debug_uart.c, so DEBUG is not needed. +// If you need a different UART or want to keep SDK's DEBUG, modify +// debug_uart.c (TinyUSB side) or CH58x_sys.c (SDK side) to remove one _write(). +// If done, remove this #error to continue. +#ifdef DEBUG + #error "Remove the DEBUG macro from preprocessor defines to avoid " \ + "duplicate _write() between WCH SDK and TinyUSB. " \ + "TinyUSB uses UART1 by default (see debug_uart.c)." +#endif + +#include "debug_uart.h" +#include "CH58x_common.h" +#include "ch58x_it.h" + +#include "bsp/board_api.h" +#include "board.h" + +//--------------------------------------------------------------------+ +// Forward USB interrupt events to TinyUSB IRQ Handler +//--------------------------------------------------------------------+ + +__INTERRUPT __HIGH_CODE void USB_IRQHandler(void) { + tusb_int_handler(0, true); +} + +__INTERRUPT __HIGH_CODE void USB2_IRQHandler(void) { + tusb_int_handler(1, true); +} + +//--------------------------------------------------------------------+ +// SysTick +//--------------------------------------------------------------------+ + +#if CFG_TUSB_OS == OPT_OS_NONE +volatile uint32_t system_ticks = 0; + +__INTERRUPT __HIGH_CODE void SysTick_Handler(void) { + SysTick->SR = 0; + system_ticks++; +} + +uint32_t board_millis(void) { + return system_ticks; +} +#endif + +//--------------------------------------------------------------------+ +// Board Init +//--------------------------------------------------------------------+ + +void board_init(void) { + // Disable interrupts during init + PFIC_DisableAllIRQ(); + + // Set system clock to PLL 60MHz (default for CH582) + SetSysClock(CLK_SOURCE_PLL_60MHz); + +#if CFG_TUSB_OS == OPT_OS_NONE + SysTick_Config(GetSysClock() / 1000); +#endif + + // UART1 init for debug output +#ifdef CFG_BOARD_UART_BAUDRATE + usart_printf_init(CFG_BOARD_UART_BAUDRATE); +#endif + + // LED +#ifdef LED_PORT_IS_A + GPIOA_ModeCfg(LED_PIN, GPIO_ModeOut_PP_5mA); +#else + GPIOB_ModeCfg(LED_PIN, GPIO_ModeOut_PP_5mA); +#endif + + // Button +#ifdef BUTTON_PIN + #ifdef BUTTON_PORT_IS_A + GPIOA_ModeCfg(BUTTON_PIN, GPIO_ModeIN_PU); + #else + GPIOB_ModeCfg(BUTTON_PIN, GPIO_ModeIN_PU); + #endif +#endif + + // USB pin enable: enable analog function for USB1 and USB2 D+/D- + R16_PIN_ANALOG_IE |= RB_PIN_USB_IE | RB_PIN_USB2_IE; + + // D+ pull-up is only needed for the device-role port +#if CFG_TUD_ENABLED + #if BOARD_TUD_RHPORT == 0 + R16_PIN_ANALOG_IE |= RB_PIN_USB_DP_PU; + #else + R16_PIN_ANALOG_IE |= RB_PIN_USB2_DP_PU; + #endif +#endif + + // Keep USB clock active during sleep + R8_SLP_CLK_OFF1 &= ~RB_SLP_CLK_USB; + + // Enable interrupts globally + PFIC_EnableAllIRQ(); + + board_delay(2); +} + +//--------------------------------------------------------------------+ +// Board porting API +//--------------------------------------------------------------------+ + +void board_led_write(bool state) { +#ifdef LED_PORT_IS_A + if (state ^ LED_STATE_ON) { + GPIOA_ResetBits(LED_PIN); + } else { + GPIOA_SetBits(LED_PIN); + } +#else + if (state ^ LED_STATE_ON) { + GPIOB_ResetBits(LED_PIN); + } else { + GPIOB_SetBits(LED_PIN); + } +#endif +} + +uint32_t board_button_read(void) { +#ifdef BUTTON_PIN + #ifdef BUTTON_PORT_IS_A + return BUTTON_STATE_ACTIVE == (GPIOA_ReadPortPin(BUTTON_PIN) ? 1 : 0); + #else + return BUTTON_STATE_ACTIVE == (GPIOB_ReadPortPin(BUTTON_PIN) ? 1 : 0); + #endif +#else + return 0; +#endif +} + +int board_uart_read(uint8_t* buf, int len) { + (void) buf; + (void) len; + return 0; +} + +int board_uart_write(void const* buf, int len) { + int txsize = len; + const char* bufc = (const char*) buf; + while (txsize--) { + uart_write(*bufc++); + } + uart_sync(); + return len; +} diff --git a/hw/bsp/ch58x/family.cmake b/hw/bsp/ch58x/family.cmake new file mode 100644 index 000000000..9ad158662 --- /dev/null +++ b/hw/bsp/ch58x/family.cmake @@ -0,0 +1,103 @@ +include_guard() + +set(SDK_DIR ${TOP}/hw/mcu/wch/ch58x) +set(SDK_SRC_DIR ${SDK_DIR}/EVT/EXAM/SRC) + +# include board specific +include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake) + +# toolchain set up +set(CMAKE_SYSTEM_CPU rv32imac-ilp32 CACHE INTERNAL "System Processor") +set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/riscv_${TOOLCHAIN}.cmake) + +set(FAMILY_MCUS CH582 CACHE INTERNAL "") +set(OPENOCD_OPTION "-f ${CMAKE_CURRENT_LIST_DIR}/wch-riscv.cfg") + +#------------------------------------ +# Startup & Linker script +#------------------------------------ +if (NOT DEFINED LD_FILE_GNU) + set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/linker/ch582.ld) +endif () +set(LD_FILE_Clang ${LD_FILE_GNU}) +if (NOT DEFINED STARTUP_FILE_GNU) + set(STARTUP_FILE_GNU ${SDK_SRC_DIR}/Startup/startup_CH583.S) +endif () +set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU}) + +#------------------------------------ +# Board Target +#------------------------------------ +function(family_add_board BOARD_TARGET) + add_library(${BOARD_TARGET} STATIC + ${SDK_SRC_DIR}/StdPeriphDriver/CH58x_gpio.c + ${SDK_SRC_DIR}/StdPeriphDriver/CH58x_clk.c + ${SDK_SRC_DIR}/StdPeriphDriver/CH58x_uart1.c + ${SDK_SRC_DIR}/StdPeriphDriver/CH58x_sys.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ch58x_it.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/system_ch58x.c + ) + target_include_directories(${BOARD_TARGET} PUBLIC + ${SDK_SRC_DIR}/RVMSIS + ${SDK_SRC_DIR}/StdPeriphDriver/inc + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ) + target_compile_definitions(${BOARD_TARGET} PUBLIC + CFG_TUD_WCH_USBIP_USBFS=1 + FREQ_SYS=60000000 + ) + + update_board(${BOARD_TARGET}) + + if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + target_compile_options(${BOARD_TARGET} PUBLIC + -msmall-data-limit=8 + -mno-save-restore + -fmessage-length=0 + -fsigned-char + ) + endif () +endfunction() + +#------------------------------------ +# Functions +#------------------------------------ +function(family_configure_example TARGET RTOS) + family_configure_common(${TARGET} ${RTOS}) + family_add_tinyusb(${TARGET} OPT_MCU_CH582) + + target_sources(${TARGET} PUBLIC + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/debug_uart.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c + ${TOP}/src/portable/wch/dcd_ch58x_usbfs.c + ${TOP}/src/portable/wch/hcd_ch58x_usbfs.c + ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} + ) + target_include_directories(${TARGET} PUBLIC + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../ + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD} + ) + + if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + target_link_options(${TARGET} PUBLIC + -nostartfiles + --specs=nosys.specs --specs=nano.specs + -Wl,--defsym=__FLASH_SIZE=${LD_FLASH_SIZE} + -Wl,--defsym=__RAM_SIZE=${LD_RAM_SIZE} + "LINKER:--script=${LD_FILE_GNU}" + ) + elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang") + message(FATAL_ERROR "Clang is not supported for CH58x") + endif () + + set_source_files_properties(${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} PROPERTIES + SKIP_LINTING ON + COMPILE_OPTIONS -w) + + # Flashing + family_add_bin_hex(${TARGET}) + family_flash_openocd_wch(${TARGET}) + family_flash_wlink_rs(${TARGET}) +endfunction() diff --git a/hw/bsp/ch58x/family.mk b/hw/bsp/ch58x/family.mk new file mode 100644 index 000000000..41eb36c84 --- /dev/null +++ b/hw/bsp/ch58x/family.mk @@ -0,0 +1,49 @@ +# Toolchain from https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack +CROSS_COMPILE ?= riscv-none-elf- + +SDK_DIR = hw/mcu/wch/ch58x +SDK_SRC_DIR = $(SDK_DIR)/EVT/EXAM/SRC + +include $(TOP)/$(BOARD_PATH)/board.mk +CPU_CORE ?= rv32imac-ilp32 + +CFLAGS += \ + -flto \ + -msmall-data-limit=8 \ + -mno-save-restore \ + -fmessage-length=0 \ + -fsigned-char \ + -DCFG_TUSB_MCU=OPT_MCU_CH582 \ + -DCFG_TUD_WCH_USBIP_USBFS=1 \ + -DFREQ_SYS=60000000 \ + +LDFLAGS_GCC += \ + -nostdlib -nostartfiles \ + --specs=nosys.specs --specs=nano.specs \ + +SRC_C += \ + src/portable/wch/dcd_ch58x_usbfs.c \ + src/portable/wch/hcd_ch58x_usbfs.c \ + $(SDK_SRC_DIR)/StdPeriphDriver/CH58x_gpio.c \ + $(SDK_SRC_DIR)/StdPeriphDriver/CH58x_clk.c \ + $(SDK_SRC_DIR)/StdPeriphDriver/CH58x_uart1.c \ + $(SDK_SRC_DIR)/StdPeriphDriver/CH58x_sys.c \ + $(FAMILY_PATH)/debug_uart.c \ + $(FAMILY_PATH)/ch58x_it.c \ + $(FAMILY_PATH)/system_ch58x.c \ + +SRC_S += \ + $(SDK_SRC_DIR)/Startup/startup_CH583.S + +INC += \ + $(TOP)/$(BOARD_PATH) \ + $(TOP)/$(SDK_SRC_DIR)/RVMSIS \ + $(TOP)/$(SDK_SRC_DIR)/StdPeriphDriver/inc + +LD_FILE ?= $(FAMILY_PATH)/linker/ch582.ld + +OPENOCD_WCH_OPTION=-f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg +flash: flash-openocd-wch + +# For freeRTOS port source +FREERTOS_PORTABLE_SRC = $(FREERTOS_PORTABLE_PATH)/RISC-V diff --git a/hw/bsp/ch58x/linker/ch582.ld b/hw/bsp/ch58x/linker/ch582.ld new file mode 100644 index 000000000..821998a49 --- /dev/null +++ b/hw/bsp/ch58x/linker/ch582.ld @@ -0,0 +1,167 @@ +/* CH582 Linker Script for TinyUSB + * Based on WCH CH583 SDK Link.ld + * Supports parameterized flash/ram sizes via --defsym + */ + +/* Default sizes if not provided via --defsym */ +__flash_size = DEFINED(__FLASH_SIZE) ? __FLASH_SIZE : 448K; +__ram_size = DEFINED(__RAM_SIZE) ? __RAM_SIZE : 32K; +__stack_size = DEFINED(__STACK_SIZE) ? __STACK_SIZE : 2048; + +ENTRY( _start ) + +PROVIDE( _stack_size = __stack_size ); + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = __flash_size + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = __ram_size +} + +SECTIONS +{ + .init : + { + _sinit = .; + . = ALIGN(4); + KEEP(*(SORT_NONE(.init))) + . = ALIGN(4); + _einit = .; + } >FLASH AT>FLASH + + .highcodelalign : + { + . = ALIGN(4); + PROVIDE(_highcode_lma = .); + } >FLASH AT>FLASH + + .highcode : + { + . = ALIGN(4); + PROVIDE(_highcode_vma_start = .); + *(.vector); + KEEP(*(SORT_NONE(.vector_handler))) + *(.highcode); + *(.highcode.*); + . = ALIGN(4); + PROVIDE(_highcode_vma_end = .); + } >RAM AT>FLASH + + .text : + { + . = ALIGN(4); + KEEP(*(SORT_NONE(.handle_reset))) + *(.text) + *(.text.*) + *(.rodata) + *(.rodata*) + *(.sdata2.*) + *(.glue_7) + *(.glue_7t) + *(.gnu.linkonce.t.*) + . = ALIGN(4); + } >FLASH AT>FLASH + + .fini : + { + KEEP(*(SORT_NONE(.fini))) + . = ALIGN(4); + } >FLASH AT>FLASH + + PROVIDE( _etext = . ); + PROVIDE( _eitcm = . ); + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH AT>FLASH + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH AT>FLASH + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH AT>FLASH + + .ctors : + { + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } >FLASH AT>FLASH + + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } >FLASH AT>FLASH + + .dlalign : + { + . = ALIGN(4); + PROVIDE(_data_lma = .); + } >FLASH AT>FLASH + + .data : + { + . = ALIGN(4); + PROVIDE(_data_vma = .); + *(.gnu.linkonce.r.*) + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x800 ); + *(.sdata .sdata.*) + *(.gnu.linkonce.s.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + . = ALIGN(4); + PROVIDE( _edata = .); + } >RAM AT>FLASH + + .bss : + { + . = ALIGN(4); + PROVIDE( _sbss = .); + *(.sbss*) + *(.gnu.linkonce.sb.*) + *(.bss*) + *(.gnu.linkonce.b.*) + *(COMMON*) + . = ALIGN(4); + PROVIDE( _ebss = .); + } >RAM AT>FLASH + + PROVIDE( _end = _ebss); + PROVIDE( end = . ); + + .stack ORIGIN(RAM) + LENGTH(RAM) - __stack_size : + { + PROVIDE( _heap_end = . ); + . = ALIGN(4); + PROVIDE(_susrstack = . ); + . = . + __stack_size; + PROVIDE( _eusrstack = .); + __freertos_irq_stack_top = .; + } >RAM +} diff --git a/hw/bsp/ch58x/system_ch58x.c b/hw/bsp/ch58x/system_ch58x.c new file mode 100644 index 000000000..068c1a131 --- /dev/null +++ b/hw/bsp/ch58x/system_ch58x.c @@ -0,0 +1,39 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 TinyUSB contributors + * + * 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 "CH58x_common.h" +#include "system_ch58x.h" + +uint32_t SystemCoreClock = FREQ_SYS; + +void SystemInit(void) { + SetSysClock(CLK_SOURCE_PLL_60MHz); + SystemCoreClock = GetSysClock(); +} + +void SystemCoreClockUpdate(void) { + SystemCoreClock = GetSysClock(); +} diff --git a/hw/bsp/ch58x/system_ch58x.h b/hw/bsp/ch58x/system_ch58x.h new file mode 100644 index 000000000..ef32e603f --- /dev/null +++ b/hw/bsp/ch58x/system_ch58x.h @@ -0,0 +1,43 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 TinyUSB contributors + * + * 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. + */ + +#ifndef __SYSTEM_CH58X_H +#define __SYSTEM_CH58X_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t SystemCoreClock; // System Clock Frequency (Core Clock) + +extern void SystemInit(void); +extern void SystemCoreClockUpdate(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __SYSTEM_CH58X_H */ diff --git a/hw/bsp/ch58x/wch-riscv.cfg b/hw/bsp/ch58x/wch-riscv.cfg new file mode 100644 index 000000000..5913a2465 --- /dev/null +++ b/hw/bsp/ch58x/wch-riscv.cfg @@ -0,0 +1,17 @@ +adapter driver wlinke +adapter speed 6000 +transport select sdi + +wlink_set_address 0x00000000 +set _CHIPNAME wch_riscv +sdi newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00001 + +set _TARGETNAME $_CHIPNAME.cpu + +target create $_TARGETNAME.0 wch_riscv -chain-position $_TARGETNAME +$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 +set _FLASHNAME $_CHIPNAME.flash + +flash bank $_FLASHNAME wch_riscv 0x00000000 0 0 0 $_TARGETNAME.0 + +echo "Ready for Remote Connections" diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 34dd6af8d..02364d580 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -629,6 +629,20 @@ #define TUP_DCD_EDPT_CLOSE_API #endif +#elif TU_CHECK_MCU(OPT_MCU_CH582) + // CH58x has 2 independent USBFS controllers with merged EP registers, FS only. + #define TUP_USBIP_WCH_CH58X + + #ifndef CFG_TUD_WCH_USBIP_USBFS + #define CFG_TUD_WCH_USBIP_USBFS 1 + #endif + + #ifndef CFG_TUH_WCH_USBIP_USBFS + #define CFG_TUH_WCH_USBIP_USBFS 1 + #endif + + #define TUP_DCD_ENDPOINT_MAX 8 + //--------------------------------------------------------------------+ // Analog Devices //--------------------------------------------------------------------+ diff --git a/src/portable/wch/ch58x_usbfs_reg.h b/src/portable/wch/ch58x_usbfs_reg.h new file mode 100644 index 000000000..11479a4f6 --- /dev/null +++ b/src/portable/wch/ch58x_usbfs_reg.h @@ -0,0 +1,299 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 TinyUSB contributors + * + * 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. + */ + +#ifndef CH58X_USBFS_REG_H +#define CH58X_USBFS_REG_H + +#include + +//--------------------------------------------------------------------+ +// USB Base Addresses +//--------------------------------------------------------------------+ +#define CH58X_USB_BASE 0x40008000u +#define CH58X_USB2_BASE 0x40008400u + +//--------------------------------------------------------------------+ +// Global Control / Status Registers +//--------------------------------------------------------------------+ +#define CH58X_USB_CTRL(base) (*(volatile uint8_t *)((base) + 0x00)) +#define CH58X_UDEV_CTRL(base) (*(volatile uint8_t *)((base) + 0x01)) +#define CH58X_USB_INT_EN(base) (*(volatile uint8_t *)((base) + 0x02)) +#define CH58X_USB_DEV_AD(base) (*(volatile uint8_t *)((base) + 0x03)) +#define CH58X_USB_MIS_ST(base) (*(volatile uint8_t *)((base) + 0x05)) +#define CH58X_USB_INT_FG(base) (*(volatile uint8_t *)((base) + 0x06)) +#define CH58X_USB_INT_ST(base) (*(volatile uint8_t *)((base) + 0x07)) +#define CH58X_USB_RX_LEN(base) (*(volatile uint8_t *)((base) + 0x08)) + +//--------------------------------------------------------------------+ +// Endpoint Mode Registers +//--------------------------------------------------------------------+ +#define CH58X_UEP4_1_MOD(base) (*(volatile uint8_t *)((base) + 0x0C)) +#define CH58X_UEP2_3_MOD(base) (*(volatile uint8_t *)((base) + 0x0D)) +#define CH58X_UEP567_MOD(base) (*(volatile uint8_t *)((base) + 0x0E)) + +//--------------------------------------------------------------------+ +// Endpoint DMA / T_LEN / CTRL offset lookup tables +// EP0-EP4 are at low offsets, EP5-EP7 jump to higher offsets +// EP4 shares DMA with EP0 (no independent DMA register) +//--------------------------------------------------------------------+ +static const uint8_t ch58x_ep_dma_offset[] = { + 0x10, 0x14, 0x18, 0x1C, /* EP0, EP1, EP2, EP3 */ + 0xFF, /* EP4: shares with EP0, sentinel */ + 0x54, 0x58, 0x5C /* EP5, EP6, EP7 */ +}; + +static const uint8_t ch58x_ep_tlen_offset[] = { + 0x20, 0x24, 0x28, 0x2C, 0x30, /* EP0-EP4 */ + 0x64, 0x68, 0x6C /* EP5-EP7 */ +}; + +static const uint8_t ch58x_ep_ctrl_offset[] = { + 0x22, 0x26, 0x2A, 0x2E, 0x32, /* EP0-EP4 */ + 0x66, 0x6A, 0x6E /* EP5-EP7 */ +}; + +// EP DMA is 16-bit (only low 16 bits of RAM address, high bits implied 0x2000) +#define CH58X_EP_DMA(base, ep) (*(volatile uint16_t *)((base) + ch58x_ep_dma_offset[ep])) +#define CH58X_EP_TLEN(base, ep) (*(volatile uint8_t *)((base) + ch58x_ep_tlen_offset[ep])) +#define CH58X_EP_CTRL(base, ep) (*(volatile uint8_t *)((base) + ch58x_ep_ctrl_offset[ep])) + +//--------------------------------------------------------------------+ +// USB_CTRL (R8_USB_CTRL) bit definitions +//--------------------------------------------------------------------+ +#define CH58X_UC_DMA_EN 0x01 +#define CH58X_UC_CLR_ALL 0x02 +#define CH58X_UC_RESET_SIE 0x04 +#define CH58X_UC_INT_BUSY 0x08 +#define CH58X_UC_SYS_CTRL 0x10 +#define CH58X_UC_DEV_PU_EN 0x20 +#define CH58X_UC_LOW_SPEED 0x40 +#define CH58X_UC_HOST_MODE 0x80 + +//--------------------------------------------------------------------+ +// UDEV_CTRL (R8_UDEV_CTRL) bit definitions +//--------------------------------------------------------------------+ +#define CH58X_UD_PORT_EN 0x01 +#define CH58X_UD_GP_BIT 0x02 +#define CH58X_UD_LOW_SPEED 0x04 +#define CH58X_UD_PD_DIS 0x80 + +//--------------------------------------------------------------------+ +// INT_EN (R8_USB_INT_EN) bit definitions +//--------------------------------------------------------------------+ +#define CH58X_UIE_BUS_RST 0x01 +#define CH58X_UIE_DETECT 0x01 /* host mode alias */ +#define CH58X_UIE_TRANSFER 0x02 +#define CH58X_UIE_SUSPEND 0x04 +#define CH58X_UIE_HST_SOF 0x08 +#define CH58X_UIE_FIFO_OV 0x10 + +//--------------------------------------------------------------------+ +// INT_FG (R8_USB_INT_FG) bit definitions +//--------------------------------------------------------------------+ +#define CH58X_UIF_BUS_RST 0x01 +#define CH58X_UIF_DETECT 0x01 /* host mode alias */ +#define CH58X_UIF_TRANSFER 0x02 +#define CH58X_UIF_SUSPEND 0x04 +#define CH58X_UIF_HST_SOF 0x08 +#define CH58X_UIF_FIFO_OV 0x10 +#define CH58X_U_SIE_FREE 0x20 +#define CH58X_U_TOG_OK 0x40 +#define CH58X_U_IS_NAK 0x80 + +//--------------------------------------------------------------------+ +// INT_ST (R8_USB_INT_ST) parsing +//--------------------------------------------------------------------+ +#define CH58X_INT_ST_ENDP(x) (((x) >> 0) & 0x0F) +#define CH58X_INT_ST_TOKEN(x) (((x) >> 4) & 0x03) +#define CH58X_UIS_SETUP_ACT 0x80 + +// Token PID values +#define CH58X_PID_OUT 0 +#define CH58X_PID_SOF 1 +#define CH58X_PID_IN 2 +#define CH58X_PID_SETUP 3 + +//--------------------------------------------------------------------+ +// MIS_ST (R8_USB_MIS_ST) bit definitions +//--------------------------------------------------------------------+ +#define CH58X_UMS_DEV_ATTACH 0x01 +#define CH58X_UMS_DM_LEVEL 0x02 +#define CH58X_UMS_SUSPEND 0x04 +#define CH58X_UMS_BUS_RESET 0x08 +#define CH58X_UMS_R_FIFO_RDY 0x10 +#define CH58X_UMS_SIE_FREE 0x20 +#define CH58X_UMS_SOF_ACT 0x40 +#define CH58X_UMS_SOF_PRES 0x80 + +//--------------------------------------------------------------------+ +// EP CTRL register bit definitions (merged TX+RX in single 8-bit reg) +// +// Bit 7: RB_UEP_R_TOG RX data toggle +// Bit 6: RB_UEP_T_TOG TX data toggle +// Bit 5: (reserved) +// Bit 4: RB_UEP_AUTO_TOG auto toggle (EP1/2/3 only) +// Bit 3: R_RES1 RX response high +// Bit 2: R_RES0 RX response low +// Bit 1: T_RES1 TX response high +// Bit 0: T_RES0 TX response low +//--------------------------------------------------------------------+ + +// TX response bits[1:0] +#define CH58X_EP_T_RES_MASK 0x03 +#define CH58X_EP_T_RES_ACK 0x00 +#define CH58X_EP_T_RES_TOUT 0x01 /* ISO: no handshake */ +#define CH58X_EP_T_RES_NAK 0x02 +#define CH58X_EP_T_RES_STALL 0x03 + +// RX response bits[3:2] +#define CH58X_EP_R_RES_MASK 0x0C +#define CH58X_EP_R_RES_ACK 0x00 +#define CH58X_EP_R_RES_TOUT 0x04 /* ISO: no handshake */ +#define CH58X_EP_R_RES_NAK 0x08 +#define CH58X_EP_R_RES_STALL 0x0C + +// Toggle and auto-toggle +#define CH58X_EP_AUTO_TOG 0x10 /* bit 4, shared TX/RX */ +#define CH58X_EP_T_TOG 0x40 /* bit 6, TX DATA toggle */ +#define CH58X_EP_R_TOG 0x80 /* bit 7, RX DATA toggle */ + +//--------------------------------------------------------------------+ +// EP Mode register (UEP4_1_MOD) bit definitions +//--------------------------------------------------------------------+ +// R8_UEP4_1_MOD: EP4 in bits[3:2], EP1 in bits[7:4] +#define CH58X_UEP1_BUF_MOD 0x10 +#define CH58X_UEP1_TX_EN 0x40 +#define CH58X_UEP1_RX_EN 0x80 +#define CH58X_UEP4_TX_EN 0x04 +#define CH58X_UEP4_RX_EN 0x08 + +// R8_UEP2_3_MOD: EP3 in bits[7:4], EP2 in bits[3:0] +#define CH58X_UEP2_BUF_MOD 0x01 +#define CH58X_UEP2_TX_EN 0x04 +#define CH58X_UEP2_RX_EN 0x08 +#define CH58X_UEP3_BUF_MOD 0x10 +#define CH58X_UEP3_TX_EN 0x40 +#define CH58X_UEP3_RX_EN 0x80 + +// R8_UEP567_MOD +#define CH58X_UEP5_TX_EN 0x01 +#define CH58X_UEP5_RX_EN 0x02 +#define CH58X_UEP6_TX_EN 0x04 +#define CH58X_UEP6_RX_EN 0x08 +#define CH58X_UEP7_TX_EN 0x10 +#define CH58X_UEP7_RX_EN 0x20 + +//--------------------------------------------------------------------+ +// Host-mode Register Aliases +// In host mode: EP2 -> RX, EP3 -> TX, EP1_CTRL -> SETUP +//--------------------------------------------------------------------+ +#define CH58X_UHOST_CTRL(base) (*(volatile uint8_t *)((base) + 0x01)) // = UDEV_CTRL +#define CH58X_UH_EP_MOD(base) (*(volatile uint8_t *)((base) + 0x0D)) // = UEP2_3_MOD +#define CH58X_UH_RX_DMA(base) (*(volatile uint16_t *)((base) + 0x18)) // = UEP2_DMA +#define CH58X_UH_TX_DMA(base) (*(volatile uint16_t *)((base) + 0x1C)) // = UEP3_DMA +#define CH58X_UH_SETUP(base) (*(volatile uint8_t *)((base) + 0x26)) // = UEP1_CTRL +#define CH58X_UH_EP_PID(base) (*(volatile uint8_t *)((base) + 0x28)) // = UEP2_T_LEN +#define CH58X_UH_RX_CTRL(base) (*(volatile uint8_t *)((base) + 0x2A)) // = UEP2_CTRL +#define CH58X_UH_TX_LEN(base) (*(volatile uint8_t *)((base) + 0x2C)) // = UEP3_T_LEN +#define CH58X_UH_TX_CTRL(base) (*(volatile uint8_t *)((base) + 0x2E)) // = UEP3_CTRL + +//--------------------------------------------------------------------+ +// UHOST_CTRL (R8_UHOST_CTRL) bit definitions +//--------------------------------------------------------------------+ +#define CH58X_UH_PD_DIS 0x80 +#define CH58X_UH_LOW_SPEED 0x04 +#define CH58X_UH_BUS_RESET 0x02 +#define CH58X_UH_PORT_EN 0x01 + +//--------------------------------------------------------------------+ +// UH_EP_MOD (R8_UH_EP_MOD) bit definitions +//--------------------------------------------------------------------+ +#define CH58X_UH_EP_TX_EN 0x40 +#define CH58X_UH_EP_TBUF_MOD 0x10 +#define CH58X_UH_EP_RX_EN 0x08 +#define CH58X_UH_EP_RBUF_MOD 0x01 + +//--------------------------------------------------------------------+ +// UH_SETUP (R8_UH_SETUP) bit definitions +//--------------------------------------------------------------------+ +#define CH58X_UH_PRE_PID_EN 0x80 +#define CH58X_UH_SOF_EN 0x40 + +//--------------------------------------------------------------------+ +// UH_RX_CTRL (R8_UH_RX_CTRL) bit definitions +//--------------------------------------------------------------------+ +#define CH58X_UH_R_TOG 0x80 +#define CH58X_UH_R_AUTO_TOG 0x10 +#define CH58X_UH_R_RES 0x04 + +//--------------------------------------------------------------------+ +// UH_TX_CTRL (R8_UH_TX_CTRL) bit definitions +//--------------------------------------------------------------------+ +#define CH58X_UH_T_TOG 0x40 +#define CH58X_UH_T_AUTO_TOG 0x10 +#define CH58X_UH_T_RES 0x01 + +//--------------------------------------------------------------------+ +// USB_INT_ST host-mode bits +//--------------------------------------------------------------------+ +#define CH58X_UIS_H_RES_MASK 0x0F +#define CH58X_UIS_TOG_OK 0x40 + +//--------------------------------------------------------------------+ +// USB_DEV_AD bits +//--------------------------------------------------------------------+ +#define CH58X_UDA_GP_BIT 0x80 +#define CH58X_USB_ADDR_MASK 0x7F + +//--------------------------------------------------------------------+ +// Standard USB PID values (for host token and response) +//--------------------------------------------------------------------+ +#define CH58X_USB_PID_OUT 0x01 +#define CH58X_USB_PID_IN 0x09 +#define CH58X_USB_PID_SOF 0x05 +#define CH58X_USB_PID_SETUP 0x0D +#define CH58X_USB_PID_DATA0 0x03 +#define CH58X_USB_PID_DATA1 0x0B +#define CH58X_USB_PID_ACK 0x02 +#define CH58X_USB_PID_NAK 0x0A +#define CH58X_USB_PID_STALL 0x0E + +//--------------------------------------------------------------------+ +// PIN_ANALOG_IE register +//--------------------------------------------------------------------+ +#define CH58X_PIN_ANALOG_IE (*(volatile uint16_t *)0x4000101A) +#define CH58X_PIN_USB_DP_PU 0x40 +#define CH58X_PIN_USB_IE 0x80 +#define CH58X_PIN_USB2_DP_PU 0x10 +#define CH58X_PIN_USB2_IE 0x20 + +//--------------------------------------------------------------------+ +// Sleep clock control +//--------------------------------------------------------------------+ +#define CH58X_SLP_CLK_OFF1 (*(volatile uint8_t *)0x4000100D) +#define CH58X_SLP_CLK_USB 0x10 + +#endif /* CH58X_USBFS_REG_H */ diff --git a/src/portable/wch/dcd_ch58x_usbfs.c b/src/portable/wch/dcd_ch58x_usbfs.c new file mode 100644 index 000000000..11ff2c7b1 --- /dev/null +++ b/src/portable/wch/dcd_ch58x_usbfs.c @@ -0,0 +1,583 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 TinyUSB contributors + * + * 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_TUD_ENABLED && defined(TUP_USBIP_WCH_CH58X) && CFG_TUD_WCH_USBIP_USBFS + +#include "device/dcd.h" +#include "ch58x_usbfs_reg.h" + +//--------------------------------------------------------------------+ +// Configuration +//--------------------------------------------------------------------+ +#define EP_MAX 8 +#define EP_BUF_SIZE 64 + +//--------------------------------------------------------------------+ +// USB base address selection by rhport +//--------------------------------------------------------------------+ +static inline uint32_t get_usb_base(uint8_t rhport) { + return (rhport == 0) ? CH58X_USB_BASE : CH58X_USB2_BASE; +} + +//--------------------------------------------------------------------+ +// Register access helpers using base address +//--------------------------------------------------------------------+ +#define USB_CTRL(base) CH58X_USB_CTRL(base) +#define USB_UDEV_CTRL(base) CH58X_UDEV_CTRL(base) +#define USB_INT_EN(base) CH58X_USB_INT_EN(base) +#define USB_DEV_AD(base) CH58X_USB_DEV_AD(base) +#define USB_MIS_ST(base) CH58X_USB_MIS_ST(base) +#define USB_INT_FG(base) CH58X_USB_INT_FG(base) +#define USB_INT_ST(base) CH58X_USB_INT_ST(base) +#define USB_RX_LEN(base) CH58X_USB_RX_LEN(base) + +#define EP_DMA(base, ep) CH58X_EP_DMA(base, ep) +#define EP_TLEN(base, ep) CH58X_EP_TLEN(base, ep) +#define EP_CTRL(base, ep) CH58X_EP_CTRL(base, ep) + +//--------------------------------------------------------------------+ +// Inline helpers for merged EP CTRL register +//--------------------------------------------------------------------+ +static inline void ep_set_tx_response(uint32_t base, uint8_t ep, uint8_t resp) { + uint8_t ctrl = EP_CTRL(base, ep); + ctrl = (ctrl & ~CH58X_EP_T_RES_MASK) | resp; + EP_CTRL(base, ep) = ctrl; +} + +static inline void ep_set_rx_response(uint32_t base, uint8_t ep, uint8_t resp) { + uint8_t ctrl = EP_CTRL(base, ep); + ctrl = (ctrl & ~CH58X_EP_R_RES_MASK) | resp; + EP_CTRL(base, ep) = ctrl; +} + +static inline void ep_set_both_response(uint32_t base, uint8_t ep, uint8_t tx_resp, uint8_t rx_resp) { + uint8_t ctrl = EP_CTRL(base, ep); + ctrl = (ctrl & ~(CH58X_EP_T_RES_MASK | CH58X_EP_R_RES_MASK)) | tx_resp | rx_resp; + EP_CTRL(base, ep) = ctrl; +} + +//--------------------------------------------------------------------+ +// Private data structures +//--------------------------------------------------------------------+ +struct usb_xfer { + bool valid; + uint8_t* buffer; + size_t len; + size_t processed_len; + size_t max_size; +}; + +typedef struct { + uint32_t usb_base; + bool ep0_tog; + bool isochronous[EP_MAX]; + struct usb_xfer xfer[EP_MAX][2]; // [ep][dir] + + // EP0 + EP4 shared buffer: EP0 OUT(64) + EP4 OUT(64) + EP4 IN(64) + TU_ATTR_ALIGNED(4) uint8_t ep0_buffer[EP_BUF_SIZE + EP_BUF_SIZE + EP_BUF_SIZE]; + + // EP1-EP3: OUT(64) + IN(64) + TU_ATTR_ALIGNED(4) uint8_t ep1_buffer[2][EP_BUF_SIZE]; + TU_ATTR_ALIGNED(4) uint8_t ep2_buffer[2][EP_BUF_SIZE]; + TU_ATTR_ALIGNED(4) uint8_t ep3_buffer[2][EP_BUF_SIZE]; + + // EP5-EP7: OUT(64) + IN(64) + TU_ATTR_ALIGNED(4) uint8_t ep5_buffer[2][EP_BUF_SIZE]; + TU_ATTR_ALIGNED(4) uint8_t ep6_buffer[2][EP_BUF_SIZE]; + TU_ATTR_ALIGNED(4) uint8_t ep7_buffer[2][EP_BUF_SIZE]; +} dcd_data_t; + +// Per-port data (support up to 2 USB ports) +static dcd_data_t _dcd_data[2]; + +//--------------------------------------------------------------------+ +// Buffer address helpers +// EP0: ep0_buffer[0..63] +// EP4 OUT: ep0_buffer[64..127] EP4 IN: ep0_buffer[128..191] +// Other EPs: epX_buffer[0] = OUT, epX_buffer[1] = IN +//--------------------------------------------------------------------+ +static uint8_t* ep_out_buffer(dcd_data_t* d, uint8_t ep) { + switch (ep) { + case 0: return &d->ep0_buffer[0]; + case 1: return d->ep1_buffer[0]; + case 2: return d->ep2_buffer[0]; + case 3: return d->ep3_buffer[0]; + case 4: return &d->ep0_buffer[EP_BUF_SIZE]; + case 5: return d->ep5_buffer[0]; + case 6: return d->ep6_buffer[0]; + case 7: return d->ep7_buffer[0]; + default: return NULL; + } +} + +static uint8_t* ep_in_buffer(dcd_data_t* d, uint8_t ep) { + switch (ep) { + case 0: return &d->ep0_buffer[0]; // EP0 IN uses same buffer as OUT + case 1: return d->ep1_buffer[1]; + case 2: return d->ep2_buffer[1]; + case 3: return d->ep3_buffer[1]; + case 4: return &d->ep0_buffer[2 * EP_BUF_SIZE]; + case 5: return d->ep5_buffer[1]; + case 6: return d->ep6_buffer[1]; + case 7: return d->ep7_buffer[1]; + default: return NULL; + } +} + +// Get DMA base pointer for endpoint (the buffer whose address is set to DMA register) +// For EP4, DMA is shared with EP0, so we return EP0 buffer +static uint8_t* ep_dma_buffer(dcd_data_t* d, uint8_t ep) { + switch (ep) { + case 0: case 4: return &d->ep0_buffer[0]; + case 1: return d->ep1_buffer[0]; + case 2: return d->ep2_buffer[0]; + case 3: return d->ep3_buffer[0]; + case 5: return d->ep5_buffer[0]; + case 6: return d->ep6_buffer[0]; + case 7: return d->ep7_buffer[0]; + default: return NULL; + } +} + +//--------------------------------------------------------------------+ +// EP has auto-toggle support? +//--------------------------------------------------------------------+ +static inline bool ep_has_auto_toggle(uint8_t ep) { + return (ep >= 1 && ep <= 3); +} + +//--------------------------------------------------------------------+ +// Private transfer helpers +//--------------------------------------------------------------------+ +static void update_in(uint8_t rhport, uint8_t ep, bool force) { + dcd_data_t* d = &_dcd_data[rhport]; + uint32_t base = d->usb_base; + struct usb_xfer* xfer = &d->xfer[ep][TUSB_DIR_IN]; + + if (xfer->valid) { + if (force || xfer->len) { + size_t len = TU_MIN(xfer->max_size, xfer->len); + + // Copy data to IN buffer + uint8_t* buf = ep_in_buffer(d, ep); + if (len > 0 && xfer->buffer != NULL) { + memcpy(buf, xfer->buffer, len); + } + + xfer->buffer += len; + xfer->len -= len; + xfer->processed_len += len; + + EP_TLEN(base, ep) = (uint8_t) len; + + if (ep == 0) { + // EP0: manual toggle + uint8_t ctrl = EP_CTRL(base, 0); + ctrl = (ctrl & ~(CH58X_EP_T_RES_MASK | CH58X_EP_T_TOG)); + ctrl |= CH58X_EP_T_RES_ACK; + if (d->ep0_tog) ctrl |= CH58X_EP_T_TOG; + EP_CTRL(base, 0) = ctrl; + d->ep0_tog = !d->ep0_tog; + } else if (d->isochronous[ep]) { + ep_set_tx_response(base, ep, CH58X_EP_T_RES_TOUT); + } else { + ep_set_tx_response(base, ep, CH58X_EP_T_RES_ACK); + } + } else { + // Transfer complete + xfer->valid = false; + ep_set_tx_response(base, ep, CH58X_EP_T_RES_NAK); + dcd_event_xfer_complete(rhport, ep | TUSB_DIR_IN_MASK, + xfer->processed_len, XFER_RESULT_SUCCESS, true); + } + } +} + +static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { + dcd_data_t* d = &_dcd_data[rhport]; + uint32_t base = d->usb_base; + struct usb_xfer* xfer = &d->xfer[ep][TUSB_DIR_OUT]; + + if (xfer->valid) { + size_t len = TU_MIN(xfer->max_size, TU_MIN(xfer->len, rx_len)); + + // Copy from OUT buffer + if (len > 0 && xfer->buffer != NULL) { + uint8_t* buf = ep_out_buffer(d, ep); + memcpy(xfer->buffer, buf, len); + } + + xfer->buffer += len; + xfer->len -= len; + xfer->processed_len += len; + + if (xfer->len == 0 || len < xfer->max_size) { + xfer->valid = false; + dcd_event_xfer_complete(rhport, ep, xfer->processed_len, + XFER_RESULT_SUCCESS, true); + } + + if (ep == 0) { + ep_set_rx_response(base, 0, CH58X_EP_R_RES_ACK); + } + } +} + +//--------------------------------------------------------------------+ +// DCD API Implementation +//--------------------------------------------------------------------+ + +bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { + (void) rh_init; + dcd_data_t* d = &_dcd_data[rhport]; + uint32_t base = get_usb_base(rhport); + d->usb_base = base; + + // Clear state + tu_memclr(d->xfer, sizeof(d->xfer)); + tu_memclr(d->isochronous, sizeof(d->isochronous)); + d->ep0_tog = true; + + // Init control registers + USB_CTRL(base) = CH58X_UC_DEV_PU_EN | CH58X_UC_INT_BUSY | CH58X_UC_DMA_EN; + USB_UDEV_CTRL(base) = CH58X_UD_PD_DIS | CH58X_UD_PORT_EN; + USB_DEV_AD(base) = 0x00; + + // Clear all interrupt flags, then enable interrupts + USB_INT_FG(base) = 0xFF; + USB_INT_EN(base) = CH58X_UIE_BUS_RST | CH58X_UIE_TRANSFER | CH58X_UIE_SUSPEND; + + // EP0 setup (also sets EP4 DMA since they share) + EP_DMA(base, 0) = (uint16_t)(uint32_t) &d->ep0_buffer[0]; + EP_TLEN(base, 0) = 0; + EP_CTRL(base, 0) = CH58X_EP_R_RES_ACK | CH58X_EP_T_RES_NAK; + + // Enable all endpoints TX+RX + CH58X_UEP4_1_MOD(base) = CH58X_UEP1_RX_EN | CH58X_UEP1_TX_EN | + CH58X_UEP4_RX_EN | CH58X_UEP4_TX_EN; + CH58X_UEP2_3_MOD(base) = CH58X_UEP2_RX_EN | CH58X_UEP2_TX_EN | + CH58X_UEP3_RX_EN | CH58X_UEP3_TX_EN; + CH58X_UEP567_MOD(base) = CH58X_UEP5_RX_EN | CH58X_UEP5_TX_EN | + CH58X_UEP6_RX_EN | CH58X_UEP6_TX_EN | + CH58X_UEP7_RX_EN | CH58X_UEP7_TX_EN; + + // EP1-3: DMA + auto-toggle + NAK both directions + for (uint8_t ep = 1; ep <= 3; ep++) { + EP_DMA(base, ep) = (uint16_t)(uint32_t) ep_dma_buffer(d, ep); + EP_TLEN(base, ep) = 0; + EP_CTRL(base, ep) = CH58X_EP_AUTO_TOG | CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK; + } + + // EP4: no independent DMA, no auto-toggle + EP_TLEN(base, 4) = 0; + EP_CTRL(base, 4) = CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK; + + // EP5-7: DMA + no auto-toggle + for (uint8_t ep = 5; ep <= 7; ep++) { + EP_DMA(base, ep) = (uint16_t)(uint32_t) ep_dma_buffer(d, ep); + EP_TLEN(base, ep) = 0; + EP_CTRL(base, ep) = CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK; + } + + // Set EP0 max size + d->xfer[0][TUSB_DIR_OUT].max_size = EP_BUF_SIZE; + d->xfer[0][TUSB_DIR_IN].max_size = EP_BUF_SIZE; + + dcd_connect(rhport); + return true; +} + +void dcd_int_handler(uint8_t rhport) { + dcd_data_t* d = &_dcd_data[rhport]; + uint32_t base = d->usb_base; + uint8_t status = USB_INT_FG(base); + + if (status & CH58X_UIF_TRANSFER) { + uint8_t int_st = USB_INT_ST(base); + uint8_t ep = CH58X_INT_ST_ENDP(int_st); + uint8_t token = CH58X_INT_ST_TOKEN(int_st); + + // Check SETUP first via dedicated flag + if (int_st & CH58X_UIS_SETUP_ACT) { + // SETUP packet received on EP0 + ep_set_both_response(base, 0, CH58X_EP_T_RES_NAK, CH58X_EP_R_RES_ACK); + d->ep0_tog = true; + dcd_event_setup_received(rhport, ep_out_buffer(d, 0), true); + } else { + switch (token) { + case CH58X_PID_OUT: { + uint8_t rx_len = USB_RX_LEN(base); + if (!ep_has_auto_toggle(ep) && ep != 0) { + // Manual toggle for EP4-7 + EP_CTRL(base, ep) ^= CH58X_EP_R_TOG; + } + update_out(rhport, ep, rx_len); + break; + } + + case CH58X_PID_IN: { + if (!ep_has_auto_toggle(ep) && ep != 0) { + // Manual toggle for EP4-7 + EP_CTRL(base, ep) ^= CH58X_EP_T_TOG; + } + update_in(rhport, ep, false); + break; + } + + default: + break; + } + } + + USB_INT_FG(base) = CH58X_UIF_TRANSFER; + } else if (status & CH58X_UIF_BUS_RST) { + // Bus reset + d->ep0_tog = true; + d->xfer[0][TUSB_DIR_OUT].max_size = EP_BUF_SIZE; + d->xfer[0][TUSB_DIR_IN].max_size = EP_BUF_SIZE; + + USB_DEV_AD(base) = 0x00; + ep_set_rx_response(base, 0, CH58X_EP_R_RES_ACK); + + tusb_speed_t speed = (USB_MIS_ST(base) & CH58X_UMS_DM_LEVEL) ? + TUSB_SPEED_LOW : TUSB_SPEED_FULL; + dcd_event_bus_reset(rhport, speed, true); + + USB_INT_FG(base) = CH58X_UIF_BUS_RST; + } else if (status & CH58X_UIF_SUSPEND) { + if (USB_MIS_ST(base) & CH58X_UMS_SUSPEND) { + dcd_event_t event = {.rhport = rhport, .event_id = DCD_EVENT_SUSPEND}; + dcd_event_handler(&event, true); + } else { + dcd_event_t event = {.rhport = rhport, .event_id = DCD_EVENT_RESUME}; + dcd_event_handler(&event, true); + } + USB_INT_FG(base) = CH58X_UIF_SUSPEND; + } +} + +void dcd_int_enable(uint8_t rhport) { + (void) rhport; + // PFIC enable: USB_IRQn=22, USB2_IRQn=23 + volatile uint32_t* pfic_ienr = (volatile uint32_t*) 0xE000E100; + uint8_t irqn = (rhport == 0) ? 22 : 23; + pfic_ienr[irqn / 32] = (1u << (irqn % 32)); +} + +void dcd_int_disable(uint8_t rhport) { + (void) rhport; + volatile uint32_t* pfic_irer = (volatile uint32_t*) 0xE000E180; + uint8_t irqn = (rhport == 0) ? 22 : 23; + pfic_irer[irqn / 32] = (1u << (irqn % 32)); + __asm volatile ("fence.i"); +} + +void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { + (void) dev_addr; + // Address is set in status stage complete callback + dcd_edpt_xfer(rhport, 0x80, NULL, 0, false); +} + +void dcd_remote_wakeup(uint8_t rhport) { + uint32_t base = get_usb_base(rhport); + USB_UDEV_CTRL(base) |= CH58X_UD_GP_BIT; + for (volatile int i = 0; i < 60000; i++) { } // ~1ms resume signal + USB_UDEV_CTRL(base) &= ~CH58X_UD_GP_BIT; +} + +void dcd_connect(uint8_t rhport) { + uint32_t base = get_usb_base(rhport); + USB_CTRL(base) |= CH58X_UC_DEV_PU_EN; +} + +void dcd_disconnect(uint8_t rhport) { + uint32_t base = get_usb_base(rhport); + USB_CTRL(base) &= ~CH58X_UC_DEV_PU_EN; +} + +void dcd_sof_enable(uint8_t rhport, bool en) { + uint32_t base = get_usb_base(rhport); + if (en) { + USB_INT_EN(base) |= CH58X_UIE_HST_SOF; + } else { + USB_INT_EN(base) &= ~CH58X_UIE_HST_SOF; + } +} + +void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) { + dcd_data_t* d = &_dcd_data[rhport]; + uint32_t base = d->usb_base; + + if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && + request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && + request->bRequest == TUSB_REQ_SET_ADDRESS) { + USB_DEV_AD(base) = (uint8_t) request->wValue; + } + ep_set_both_response(base, 0, CH58X_EP_T_RES_NAK, CH58X_EP_R_RES_ACK); +} + +bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) { + dcd_data_t* d = &_dcd_data[rhport]; + uint32_t base = d->usb_base; + uint8_t ep = tu_edpt_number(desc_ep->bEndpointAddress); + uint8_t dir = tu_edpt_dir(desc_ep->bEndpointAddress); + TU_ASSERT(ep < EP_MAX); + + d->isochronous[ep] = (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS); + d->xfer[ep][dir].max_size = tu_edpt_packet_size(desc_ep); + + if (ep != 0) { + dcd_int_disable(rhport); + uint8_t ctrl = EP_CTRL(base, ep); + if (dir == TUSB_DIR_OUT) { + if (d->isochronous[ep]) { + ctrl = (ctrl & ~CH58X_EP_R_RES_MASK) | CH58X_EP_R_RES_TOUT; + } else { + // Start with NAK; dcd_edpt_xfer will set ACK when a transfer is submitted + ctrl = (ctrl & ~CH58X_EP_R_RES_MASK) | CH58X_EP_R_RES_NAK; + } + // Enable auto toggle for EP1-3 + if (ep_has_auto_toggle(ep)) { + ctrl |= CH58X_EP_AUTO_TOG; + } + } else { + EP_TLEN(base, ep) = 0; + ctrl = (ctrl & ~CH58X_EP_T_RES_MASK) | CH58X_EP_T_RES_NAK; + if (ep_has_auto_toggle(ep)) { + ctrl |= CH58X_EP_AUTO_TOG; + } + } + EP_CTRL(base, ep) = ctrl; + dcd_int_enable(rhport); + } + return true; +} + +void dcd_edpt_close_all(uint8_t rhport) { + dcd_data_t* d = &_dcd_data[rhport]; + uint32_t base = d->usb_base; + + for (uint8_t ep = 1; ep < EP_MAX; ep++) { + d->xfer[ep][TUSB_DIR_IN].valid = false; + d->xfer[ep][TUSB_DIR_OUT].valid = false; + d->isochronous[ep] = false; + EP_CTRL(base, ep) = CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK; + } +} + +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void) rhport; + (void) ep_addr; + (void) largest_packet_size; + return false; +} + +bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t* desc_ep) { + (void) rhport; + (void) desc_ep; + return false; +} + +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, + uint16_t total_bytes, bool is_isr) { + (void) is_isr; + uint8_t ep = tu_edpt_number(ep_addr); + uint8_t dir = tu_edpt_dir(ep_addr); + + dcd_data_t* d = &_dcd_data[rhport]; + struct usb_xfer* xfer = &d->xfer[ep][dir]; + + dcd_int_disable(rhport); + xfer->valid = true; + xfer->buffer = buffer; + xfer->len = total_bytes; + xfer->processed_len = 0; + dcd_int_enable(rhport); + + if (dir == TUSB_DIR_IN) { + update_in(rhport, ep, true); + } else { + // For OUT direction, set endpoint to ACK to start receiving data + if (ep != 0) { + if (d->isochronous[ep]) { + ep_set_rx_response(d->usb_base, ep, CH58X_EP_R_RES_TOUT); + } else { + ep_set_rx_response(d->usb_base, ep, CH58X_EP_R_RES_ACK); + } + } + } + return true; +} + +void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { + dcd_data_t* d = &_dcd_data[rhport]; + uint32_t base = d->usb_base; + uint8_t ep = tu_edpt_number(ep_addr); + uint8_t dir = tu_edpt_dir(ep_addr); + + dcd_int_disable(rhport); + if (ep == 0) { + // EP0: stall both directions + EP_CTRL(base, 0) = CH58X_EP_R_RES_STALL | CH58X_EP_T_RES_STALL | + CH58X_EP_R_TOG | CH58X_EP_T_TOG; + } else { + if (dir == TUSB_DIR_OUT) { + ep_set_rx_response(base, ep, CH58X_EP_R_RES_STALL); + } else { + ep_set_tx_response(base, ep, CH58X_EP_T_RES_STALL); + } + } + dcd_int_enable(rhport); +} + +void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { + dcd_data_t* d = &_dcd_data[rhport]; + uint32_t base = d->usb_base; + uint8_t ep = tu_edpt_number(ep_addr); + uint8_t dir = tu_edpt_dir(ep_addr); + + dcd_int_disable(rhport); + if (ep == 0) { + if (dir == TUSB_DIR_OUT) { + ep_set_rx_response(base, 0, CH58X_EP_R_RES_ACK); + } + } else { + uint8_t ctrl = EP_CTRL(base, ep); + if (dir == TUSB_DIR_OUT) { + ctrl &= ~(CH58X_EP_R_RES_MASK | CH58X_EP_R_TOG); + ctrl |= CH58X_EP_R_RES_ACK; + } else { + ctrl &= ~(CH58X_EP_T_RES_MASK | CH58X_EP_T_TOG); + ctrl |= CH58X_EP_T_RES_NAK; + } + EP_CTRL(base, ep) = ctrl; + } + dcd_int_enable(rhport); +} + +#endif /* CFG_TUD_ENABLED && TUP_USBIP_WCH_CH58X */ diff --git a/src/portable/wch/hcd_ch58x_usbfs.c b/src/portable/wch/hcd_ch58x_usbfs.c new file mode 100644 index 000000000..629c2a789 --- /dev/null +++ b/src/portable/wch/hcd_ch58x_usbfs.c @@ -0,0 +1,712 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 TinyUSB contributors + * + * 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_CH58X) && \ + defined(CFG_TUH_WCH_USBIP_USBFS) && CFG_TUH_WCH_USBIP_USBFS + +#include + +#include "host/hcd.h" +#include "host/usbh.h" +#include "host/usbh_pvt.h" + +#include "ch58x_usbfs_reg.h" + +//--------------------------------------------------------------------+ +// Configuration +//--------------------------------------------------------------------+ +#define USBFS_MAX_PACKET_SIZE 64 + +#define LOG_CH58X_HCD(...) TU_LOG3(__VA_ARGS__) + +//--------------------------------------------------------------------+ +// RX/TX buffers (must be 4-byte aligned and in lower 64KB of RAM) +// Separate buffers for each USB port to avoid DMA conflicts +//--------------------------------------------------------------------+ +TU_ATTR_ALIGNED(4) static uint8_t _rx_buf[2][USBFS_MAX_PACKET_SIZE]; +TU_ATTR_ALIGNED(4) static uint8_t _tx_buf[2][USBFS_MAX_PACKET_SIZE]; + +//--------------------------------------------------------------------+ +// USB base address selection by rhport +//--------------------------------------------------------------------+ +static inline uint32_t _get_usb_base(uint8_t rhport) { + return (rhport == 0) ? CH58X_USB_BASE : CH58X_USB2_BASE; +} + +//--------------------------------------------------------------------+ +// Endpoint record +//--------------------------------------------------------------------+ +typedef struct { + bool configured; + uint8_t dev_addr; + uint8_t ep_addr; + uint8_t max_packet_size; + uint8_t xfer_type; + uint8_t data_toggle; // 0=DATA0, 1=DATA1 + bool is_nak_pending; + uint16_t buflen; + uint8_t* buf; +} hcd_edpt_t; + +static hcd_edpt_t _edpt_list[CFG_TUH_DEVICE_MAX * 6] = {}; + +//--------------------------------------------------------------------+ +// Current transfer state (only one transfer at a time per root port) +//--------------------------------------------------------------------+ +typedef struct { + volatile bool is_busy; + uint8_t rhport; + uint8_t dev_addr; + uint8_t ep_addr; + uint32_t start_ms; + uint8_t* buffer; + uint16_t bufferlen; + uint16_t xferred_len; + bool nak_pending; +} hcd_xfer_t; + +static volatile hcd_xfer_t _current_xfer = {}; + +//--------------------------------------------------------------------+ +// Per-port state +//--------------------------------------------------------------------+ +typedef struct { + uint32_t usb_base; + bool int_enabled; +} hcd_port_t; + +static hcd_port_t _port_data[2] = {}; + +//--------------------------------------------------------------------+ +// Endpoint record management +//--------------------------------------------------------------------+ +static hcd_edpt_t* _get_edpt(uint8_t dev_addr, uint8_t ep_addr) { + for (size_t i = 0; i < TU_ARRAY_SIZE(_edpt_list); i++) { + hcd_edpt_t* e = &_edpt_list[i]; + if (e->configured && e->dev_addr == dev_addr && e->ep_addr == ep_addr) { + return e; + } + } + return NULL; +} + +static hcd_edpt_t* _alloc_edpt(void) { + for (size_t i = 0; i < TU_ARRAY_SIZE(_edpt_list); i++) { + if (!_edpt_list[i].configured) { + return &_edpt_list[i]; + } + } + return NULL; +} + +static hcd_edpt_t* _add_edpt(uint8_t dev_addr, uint8_t ep_addr, + uint16_t max_packet_size, uint8_t xfer_type) { + hcd_edpt_t* e = _alloc_edpt(); + TU_ASSERT(e != NULL, NULL); + + e->dev_addr = dev_addr; + e->ep_addr = ep_addr; + e->max_packet_size = (uint8_t) TU_MIN(max_packet_size, USBFS_MAX_PACKET_SIZE); + e->xfer_type = xfer_type; + e->data_toggle = 0; + e->is_nak_pending = false; + e->buflen = 0; + e->buf = NULL; + e->configured = true; + + return e; +} + +static hcd_edpt_t* _get_or_add_edpt(uint8_t dev_addr, uint8_t ep_addr, + uint16_t max_packet_size, uint8_t xfer_type) { + hcd_edpt_t* e = _get_edpt(dev_addr, ep_addr); + if (e != NULL) return e; + return _add_edpt(dev_addr, ep_addr, max_packet_size, xfer_type); +} + +static void _remove_edpts_for_device(uint8_t dev_addr) { + for (size_t i = 0; i < TU_ARRAY_SIZE(_edpt_list); i++) { + if (_edpt_list[i].configured && _edpt_list[i].dev_addr == dev_addr) { + _edpt_list[i].configured = false; + } + } +} + +//--------------------------------------------------------------------+ +// Low-level hardware helpers +//--------------------------------------------------------------------+ + +// Busywait delay (approximate microseconds at ~60MHz) +TU_ATTR_ALWAYS_INLINE static inline void _delay_loops(uint32_t count) { + volatile uint32_t c = count / 3; + if (c == 0) return; + while (c-- != 0) {} +} + +static void _hw_init_host(uint8_t rhport, bool enabled) { + uint32_t base = _port_data[rhport].usb_base; + + if (!enabled) { + // Reset SIE when disabling + CH58X_USB_CTRL(base) = CH58X_UC_RESET_SIE | CH58X_UC_CLR_ALL; + _delay_loops(600); // ~10us at 60MHz + CH58X_USB_CTRL(base) = 0; + return; + } + + // host mode, pull-down enabled, clear addr + CH58X_USB_CTRL(base) = CH58X_UC_HOST_MODE; + while (!(CH58X_USB_CTRL(base) & CH58X_UC_HOST_MODE)) {} + CH58X_UHOST_CTRL(base) = 0; + CH58X_USB_DEV_AD(base) = 0x00; + + // EP2 RX (IN), EP3 TX (OUT/SETUP) + CH58X_UH_EP_MOD(base) = CH58X_UH_EP_TX_EN | CH58X_UH_EP_RX_EN; + + // DMA: 16-bit address, lower 64KB only + CH58X_UH_RX_DMA(base) = (uint16_t)(uint32_t)_rx_buf[rhport]; + CH58X_UH_TX_DMA(base) = (uint16_t)(uint32_t)_tx_buf[rhport]; + + CH58X_UH_RX_CTRL(base) = 0x00; + CH58X_UH_TX_CTRL(base) = 0x00; + + CH58X_USB_CTRL(base) = CH58X_UC_HOST_MODE | CH58X_UC_INT_BUSY | CH58X_UC_DMA_EN; + CH58X_UH_SETUP(base) = CH58X_UH_SOF_EN; + + CH58X_USB_INT_FG(base) = 0xFF; // clear all flags + CH58X_USB_INT_EN(base) = CH58X_UIE_TRANSFER | CH58X_UIE_DETECT; +} + +static bool _hw_start_xfer(uint8_t rhport, uint8_t pid, uint8_t ep_addr, uint8_t data_toggle) { + uint32_t base = _port_data[rhport].usb_base; + + LOG_CH58X_HCD("_hw_start_xfer(pid=0x%02x, ep=0x%02x, tog=%d)\r\n", pid, ep_addr, data_toggle); + + // Workaround: small delay for low-speed devices + bool is_lowspeed = tuh_speed_get(_current_xfer.dev_addr) == TUSB_SPEED_LOW; + if (is_lowspeed) { + _delay_loops(60000000 / 1000000 * 40); // ~40us at 60MHz + } + + // Set toggle controls (same as SDK: R8_UH_RX_CTRL = R8_UH_TX_CTRL = tog) + uint8_t tog_ctrl = (data_toggle != 0) ? CH58X_UH_T_TOG : 0; + CH58X_UH_TX_CTRL(base) = tog_ctrl; + CH58X_UH_RX_CTRL(base) = (data_toggle != 0) ? CH58X_UH_R_TOG : 0; + + uint8_t pid_endp = (pid << 4) | (tu_edpt_number(ep_addr) & 0x0F); + + // clear flag, enable int, then set PID to start transfer + CH58X_USB_INT_FG(base) = CH58X_UIF_TRANSFER; + CH58X_USB_INT_EN(base) |= CH58X_UIE_TRANSFER; + CH58X_UH_EP_PID(base) = pid_endp; + + return true; +} + +static void _hw_set_device_addr(uint8_t rhport, uint8_t dev_addr) { + uint32_t base = _port_data[rhport].usb_base; + CH58X_USB_DEV_AD(base) = (CH58X_USB_DEV_AD(base) & CH58X_UDA_GP_BIT) | + (dev_addr & CH58X_USB_ADDR_MASK); +} + +static void _hw_set_speed(uint8_t rhport, tusb_speed_t speed) { + uint32_t base = _port_data[rhport].usb_base; + + LOG_CH58X_HCD("_hw_set_speed(%s)\r\n", + speed == TUSB_SPEED_FULL ? "Full" : "Low"); + + if (speed == TUSB_SPEED_LOW) { + CH58X_USB_CTRL(base) |= CH58X_UC_LOW_SPEED; + CH58X_UHOST_CTRL(base) |= CH58X_UH_LOW_SPEED; + } else { + CH58X_USB_CTRL(base) &= ~CH58X_UC_LOW_SPEED; + CH58X_UHOST_CTRL(base) &= ~CH58X_UH_LOW_SPEED; + CH58X_UH_SETUP(base) &= ~CH58X_UH_PRE_PID_EN; + } +} + +static void _hw_set_addr_speed(uint8_t rhport, uint8_t dev_addr) { + _hw_set_device_addr(rhport, dev_addr); + + tusb_speed_t rhport_speed = hcd_port_speed_get(rhport); + tusb_speed_t dev_speed = tuh_speed_get(dev_addr); + _hw_set_speed(rhport, dev_speed); + + // FS root + LS device: hub uses PRE PID, clear LS on host ctrl + if (rhport_speed == TUSB_SPEED_FULL && dev_speed == TUSB_SPEED_LOW) { + uint32_t base = _port_data[rhport].usb_base; + CH58X_UHOST_CTRL(base) &= ~CH58X_UH_LOW_SPEED; + } +} + +static bool _hw_device_attached(uint8_t rhport) { + uint32_t base = _port_data[rhport].usb_base; + return (CH58X_USB_MIS_ST(base) & CH58X_UMS_DEV_ATTACH) != 0; +} + +//--------------------------------------------------------------------+ +// NAK retry callback +//--------------------------------------------------------------------+ +static void _xfer_retry(void* param) { + LOG_CH58X_HCD("_xfer_retry()\r\n"); + hcd_edpt_t* edpt = (hcd_edpt_t*)param; + + if (_current_xfer.nak_pending) { + uint8_t rhport = _current_xfer.rhport; + _current_xfer.nak_pending = false; + edpt->is_nak_pending = false; + + uint8_t dev_addr = edpt->dev_addr; + uint8_t ep_addr = edpt->ep_addr; + uint16_t buflen = edpt->buflen; + uint8_t* buf = edpt->buf; + + // Check if endpoint is still valid + hcd_edpt_t* current = _get_edpt(dev_addr, ep_addr); + if (current) { + hcd_edpt_xfer(rhport, dev_addr, ep_addr, buf, buflen); + } + } +} + +//--------------------------------------------------------------------+ +// HCD API: Controller +//--------------------------------------------------------------------+ +bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { + (void)rh_init; + + _port_data[rhport].usb_base = _get_usb_base(rhport); + _port_data[rhport].int_enabled = false; + + // Clear endpoint records + tu_memclr(_edpt_list, sizeof(_edpt_list)); + tu_memclr((void*)&_current_xfer, sizeof(_current_xfer)); + + _hw_init_host(rhport, true); + + return true; +} + +bool hcd_deinit(uint8_t rhport) { + _hw_init_host(rhport, false); + return true; +} + +uint32_t hcd_frame_number(uint8_t rhport) { + (void)rhport; + return tusb_time_millis_api(); +} + +void hcd_int_enable(uint8_t rhport) { + // PFIC interrupt enable + volatile uint32_t* pfic_ienr = (volatile uint32_t*)0xE000E100; + uint8_t irqn = (rhport == 0) ? 22 : 23; // USB_IRQn or USB2_IRQn + pfic_ienr[irqn / 32] = (1u << (irqn % 32)); + _port_data[rhport].int_enabled = true; +} + +void hcd_int_disable(uint8_t rhport) { + volatile uint32_t* pfic_irer = (volatile uint32_t*)0xE000E180; + uint8_t irqn = (rhport == 0) ? 22 : 23; + pfic_irer[irqn / 32] = (1u << (irqn % 32)); + __asm volatile("fence.i"); + _port_data[rhport].int_enabled = false; +} + +//--------------------------------------------------------------------+ +// HCD API: Port +//--------------------------------------------------------------------+ +bool hcd_port_connect_status(uint8_t rhport) { + return _hw_device_attached(rhport); +} + +tusb_speed_t hcd_port_speed_get(uint8_t rhport) { + uint32_t base = _port_data[rhport].usb_base; + // DM level high = low-speed device, low = full-speed + if (CH58X_USB_MIS_ST(base) & CH58X_UMS_DM_LEVEL) { + return TUSB_SPEED_LOW; + } + return TUSB_SPEED_FULL; +} + +static bool _int_state_before_reset = false; + +void hcd_port_reset(uint8_t rhport) { + uint32_t base = _port_data[rhport].usb_base; + + LOG_CH58X_HCD("hcd_port_reset()\r\n"); + + _int_state_before_reset = _port_data[rhport].int_enabled; + hcd_int_disable(rhport); + + _hw_set_device_addr(rhport, 0x00); + + // Disable port and default to full-speed before reset (matches SDK ResetRootHubPort) + CH58X_UHOST_CTRL(base) &= ~CH58X_UH_PORT_EN; + _hw_set_speed(rhport, TUSB_SPEED_FULL); + + // Start bus reset (clear low-speed bit simultaneously) + CH58X_UHOST_CTRL(base) = (CH58X_UHOST_CTRL(base) & ~CH58X_UH_LOW_SPEED) | CH58X_UH_BUS_RESET; +} + +void hcd_port_reset_end(uint8_t rhport) { + uint32_t base = _port_data[rhport].usb_base; + + LOG_CH58X_HCD("hcd_port_reset_end()\r\n"); + + // End bus reset + CH58X_UHOST_CTRL(base) &= ~CH58X_UH_BUS_RESET; + tusb_time_delay_ms_api(2); + + // Detect speed and configure + if ((CH58X_UHOST_CTRL(base) & CH58X_UH_PORT_EN) == 0) { + if (hcd_port_speed_get(rhport) == TUSB_SPEED_LOW) { + _hw_set_speed(rhport, TUSB_SPEED_LOW); + } + } + + // Enable port and SOF + CH58X_UHOST_CTRL(base) |= CH58X_UH_PORT_EN; + CH58X_UH_SETUP(base) |= CH58X_UH_SOF_EN; + + // Suppress stale detect event + CH58X_USB_INT_FG(base) = CH58X_UIF_DETECT; + + if (_int_state_before_reset) { + hcd_int_enable(rhport); + } +} + +void hcd_device_close(uint8_t rhport, uint8_t dev_addr) { + (void)rhport; + LOG_CH58X_HCD("hcd_device_close(dev=0x%02x)\r\n", dev_addr); + _remove_edpts_for_device(dev_addr); +} + +//--------------------------------------------------------------------+ +// HCD API: Endpoint +//--------------------------------------------------------------------+ +bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const* ep_desc) { + 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; + uint32_t base = _port_data[rhport].usb_base; + + LOG_CH58X_HCD("hcd_edpt_open(dev=0x%02x, ep=0x%02x, mps=%d, type=%d)\r\n", + dev_addr, ep_addr, max_packet_size, xfer_type); + + // Wait for any pending transfer + while (_current_xfer.is_busy) {} + + if (ep_num == 0) { + TU_ASSERT(_get_or_add_edpt(dev_addr, 0x00, max_packet_size, xfer_type) != NULL, false); + TU_ASSERT(_get_or_add_edpt(dev_addr, 0x80, max_packet_size, xfer_type) != NULL, false); + } else { + TU_ASSERT(_get_or_add_edpt(dev_addr, ep_addr, max_packet_size, xfer_type) != NULL, false); + } + + // Ensure port is enabled with SOF + CH58X_UHOST_CTRL(base) |= CH58X_UH_PORT_EN; + CH58X_UH_SETUP(base) |= CH58X_UH_SOF_EN; + + _hw_set_addr_speed(rhport, dev_addr); + + return true; +} + +bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, + uint8_t* buffer, uint16_t buflen) { + uint32_t base = _port_data[rhport].usb_base; + + LOG_CH58X_HCD("hcd_edpt_xfer(dev=0x%02x, ep=0x%02x, len=%d)\r\n", + dev_addr, ep_addr, buflen); + + // Wait for any pending transfer + while (_current_xfer.is_busy) {} + _current_xfer.is_busy = true; + + hcd_edpt_t* edpt = _get_edpt(dev_addr, ep_addr); + TU_ASSERT(edpt != NULL); + + _hw_set_addr_speed(rhport, dev_addr); + + _current_xfer.rhport = rhport; + _current_xfer.dev_addr = dev_addr; + _current_xfer.ep_addr = ep_addr; + _current_xfer.buffer = buffer; + _current_xfer.bufferlen = buflen; + _current_xfer.start_ms = tusb_time_millis_api(); + _current_xfer.xferred_len = 0; + _current_xfer.nak_pending = false; + + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { + // IN transfer: host receives data + return _hw_start_xfer(rhport, CH58X_USB_PID_IN, ep_addr, edpt->data_toggle); + } else { + // OUT transfer: host sends data + uint16_t copylen = TU_MIN(edpt->max_packet_size, buflen); + CH58X_UH_TX_LEN(base) = (uint8_t)copylen; + memcpy(_tx_buf[rhport], buffer, copylen); + return _hw_start_xfer(rhport, CH58X_USB_PID_OUT, ep_addr, edpt->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; + return false; +} + +bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) { + uint32_t base = _port_data[rhport].usb_base; + + LOG_CH58X_HCD("hcd_setup_send(dev=0x%02x)\r\n", dev_addr); + + // Wait for any pending transfer + while (_current_xfer.is_busy) {} + _current_xfer.is_busy = true; + + _hw_set_addr_speed(rhport, dev_addr); + + hcd_edpt_t* edpt_tx = _get_edpt(dev_addr, 0x00); + hcd_edpt_t* edpt_rx = _get_edpt(dev_addr, 0x80); + TU_ASSERT(edpt_tx != NULL, false); + TU_ASSERT(edpt_rx != NULL, false); + + // SETUP always starts with DATA0; after SETUP, IN data starts with DATA1 + edpt_tx->data_toggle = 0; + edpt_rx->data_toggle = 1; + + memcpy(_tx_buf[rhport], setup_packet, 8); + CH58X_UH_TX_LEN(base) = 8; + + _current_xfer.rhport = rhport; + _current_xfer.dev_addr = dev_addr; + _current_xfer.ep_addr = 0x00; // SETUP always targets EP0 OUT + _current_xfer.start_ms = tusb_time_millis_api(); + _current_xfer.buffer = _tx_buf[rhport]; + _current_xfer.bufferlen = 8; + _current_xfer.xferred_len = 0; + _current_xfer.nak_pending = false; + + _hw_start_xfer(rhport, CH58X_USB_PID_SETUP, 0, 0); + + return true; +} + +bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { + uint32_t base = _port_data[rhport].usb_base; + uint8_t ep_num = tu_edpt_number(ep_addr); + + LOG_CH58X_HCD("hcd_edpt_clear_stall(dev=0x%02x, ep=0x%02x)\r\n", dev_addr, ep_addr); + + // Send CLEAR_FEATURE(ENDPOINT_HALT) via blocking transfer + uint8_t setup[8] = { + 0x02, 0x01, 0x00, 0x00, ep_addr, 0x00, 0x00, 0x00 + }; + memcpy(_tx_buf[rhport], setup, 8); + CH58X_UH_TX_LEN(base) = 8; + + bool prev_int = _port_data[rhport].int_enabled; + hcd_int_disable(rhport); + + CH58X_UH_EP_PID(base) = (CH58X_USB_PID_SETUP << 4) | 0x00; + CH58X_USB_INT_FG(base) = CH58X_UIF_TRANSFER; + while ((CH58X_USB_INT_FG(base) & CH58X_UIF_TRANSFER) == 0) {} + CH58X_UH_EP_PID(base) = 0; + + uint8_t response = CH58X_USB_INT_ST(base) & CH58X_UIS_H_RES_MASK; + (void)response; + + LOG_CH58X_HCD("clear_stall response=0x%02x\r\n", response); + + if (prev_int) { + hcd_int_enable(rhport); + } + + return true; +} + +//--------------------------------------------------------------------+ +// Interrupt Handler +//--------------------------------------------------------------------+ +void hcd_int_handler(uint8_t rhport, bool in_isr) { + uint32_t base = _port_data[rhport].usb_base; + + //-- Device attach/detach detection -- + if (CH58X_USB_INT_FG(base) & CH58X_UIF_DETECT) { + CH58X_USB_INT_FG(base) = CH58X_UIF_DETECT; + + bool attached = _hw_device_attached(rhport); + LOG_CH58X_HCD("hcd_int: detect, attached=%d\r\n", attached); + + if (attached) { + hcd_event_device_attach(rhport, in_isr); + } else { + hcd_event_device_remove(rhport, in_isr); + } + return; + } + + //-- Transfer complete -- + if (CH58X_USB_INT_FG(base) & CH58X_UIF_TRANSFER) { + // Read PID/endpoint before stopping (must read first!) + uint8_t pid_endp = CH58X_UH_EP_PID(base); + uint8_t int_st = CH58X_USB_INT_ST(base); + uint8_t int_fg = CH58X_USB_INT_FG(base); + uint8_t dev_addr = CH58X_USB_DEV_AD(base) & CH58X_USB_ADDR_MASK; + + // Stop USB transaction immediately (SDK: R8_UH_EP_PID = 0x00) + CH58X_UH_EP_PID(base) = 0x00; + + // Disable transfer interrupt (re-enabled when next transfer starts) + CH58X_USB_INT_EN(base) &= ~CH58X_UIE_TRANSFER; + + uint8_t request_pid = pid_endp >> 4; + uint8_t response_pid = int_st & CH58X_UIS_H_RES_MASK; + uint8_t ep_addr = pid_endp & 0x0F; + if (request_pid == CH58X_USB_PID_IN) { + ep_addr |= 0x80; + } + + LOG_CH58X_HCD("hcd_int: xfer pid=0x%02x ep=0x%02x resp=0x%02x\r\n", + request_pid, ep_addr, response_pid); + + hcd_edpt_t* edpt = _get_edpt(dev_addr, ep_addr); + if (edpt == NULL) { + // Unknown endpoint, discard + LOG_CH58X_HCD("hcd_int: unknown edpt dev=0x%02x ep=0x%02x\r\n", dev_addr, ep_addr); + _current_xfer.is_busy = false; + CH58X_USB_INT_FG(base) = CH58X_UIF_TRANSFER; + return; + } + + // Check toggle match - SDK uses R8_USB_INT_ST & RB_UIS_TOG_OK + if (int_st & CH58X_UIS_TOG_OK) { + edpt->data_toggle ^= 0x01; + + switch (request_pid) { + case CH58X_USB_PID_SETUP: + case CH58X_USB_PID_OUT: { + uint8_t tx_len = CH58X_UH_TX_LEN(base); + _current_xfer.bufferlen -= tx_len; + _current_xfer.xferred_len += tx_len; + + if (_current_xfer.bufferlen == 0) { + LOG_CH58X_HCD("OUT/SETUP complete, %d bytes\r\n", _current_xfer.xferred_len); + _current_xfer.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, + _current_xfer.xferred_len, XFER_RESULT_SUCCESS, in_isr); + } else { + // Multi-packet OUT: send next chunk + _current_xfer.buffer += tx_len; + uint16_t copylen = TU_MIN(edpt->max_packet_size, _current_xfer.bufferlen); + memcpy(_tx_buf[rhport], _current_xfer.buffer, copylen); + CH58X_UH_TX_LEN(base) = (uint8_t)copylen; + _hw_start_xfer(rhport, CH58X_USB_PID_OUT, ep_addr, edpt->data_toggle); + } + break; + } + + case CH58X_USB_PID_IN: { + uint8_t rx_len = CH58X_USB_RX_LEN(base); + _current_xfer.xferred_len += rx_len; + uint16_t xferred = _current_xfer.xferred_len; + + if (rx_len > 0 && _current_xfer.buffer != NULL) { + memcpy(_current_xfer.buffer, _rx_buf[rhport], rx_len); + _current_xfer.buffer += rx_len; + } + + if ((rx_len < edpt->max_packet_size) || (xferred == _current_xfer.bufferlen)) { + // Short packet or transfer complete + LOG_CH58X_HCD("IN complete, %d bytes\r\n", xferred); + _current_xfer.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, xferred, + XFER_RESULT_SUCCESS, in_isr); + } else { + // More data expected + _hw_start_xfer(rhport, CH58X_USB_PID_IN, ep_addr, edpt->data_toggle); + } + break; + } + + default: { + LOG_CH58X_HCD("unexpected PID 0x%02x\r\n", request_pid); + _current_xfer.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, in_isr); + break; + } + } + } else { + // Toggle mismatch, check response PID + if (response_pid == CH58X_USB_PID_STALL) { + LOG_CH58X_HCD("STALL response\r\n"); + edpt->data_toggle = 0; + _current_xfer.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_STALLED, in_isr); + } else if (response_pid == CH58X_USB_PID_NAK) { + LOG_CH58X_HCD("NAK response\r\n"); + // NAK: schedule retry via deferred callback for all endpoint types + // This avoids tight polling loops and allows other tasks to run + _current_xfer.is_busy = false; + _current_xfer.nak_pending = true; + + edpt->is_nak_pending = true; + edpt->buflen = _current_xfer.bufferlen; + edpt->buf = _current_xfer.buffer; + + hcd_event_t event = { + .rhport = rhport, + .dev_addr = dev_addr, + .event_id = USBH_EVENT_FUNC_CALL, + .func_call = { + .func = _xfer_retry, + .param = edpt + } + }; + hcd_event_handler(&event, in_isr); + } else if (response_pid == CH58X_USB_PID_DATA0 || response_pid == CH58X_USB_PID_DATA1) { + LOG_CH58X_HCD("toggle mismatch, DATA0/1 rx_len=%d\r\n", CH58X_USB_RX_LEN(base)); + _current_xfer.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, in_isr); + } else { + LOG_CH58X_HCD("unexpected response 0x%02x\r\n", response_pid); + _current_xfer.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, in_isr); + } + } + + // Clear transfer flag + CH58X_USB_INT_FG(base) = CH58X_UIF_TRANSFER; + } +} + +#endif /* CFG_TUH_ENABLED && TUP_USBIP_WCH_CH58X */ diff --git a/src/tusb_option.h b/src/tusb_option.h index 9eb8ee533..50998613a 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -193,6 +193,7 @@ #define OPT_MCU_CH32F20X 2210 ///< WCH CH32F20x #define OPT_MCU_CH32V20X 2220 ///< WCH CH32V20X #define OPT_MCU_CH32V103 2230 ///< WCH CH32V103 +#define OPT_MCU_CH58X 2240 ///< WCH CH582/CH583 // NXP LPC MCX #define OPT_MCU_MCXN9 2300 ///< NXP MCX N9 Series -- cgit v1.3.1 From 2e913256073a07a993b3d3cb9abe8e1db97686db Mon Sep 17 00:00:00 2001 From: alt-0191 <2223147307@qq.com> Date: Fri, 27 Feb 2026 01:30:39 +0800 Subject: ch58x: fix build flags and driver bugs --- hw/bsp/ch58x/family.mk | 14 ++++++-- src/portable/wch/ch58x_usbfs_reg.h | 37 ++++++++------------ src/portable/wch/dcd_ch58x_usbfs.c | 70 ++++++++++++++++++++------------------ src/portable/wch/hcd_ch58x_usbfs.c | 60 ++++++++++++++++---------------- src/tusb_option.h | 6 ++-- 5 files changed, 96 insertions(+), 91 deletions(-) (limited to 'src/portable/wch') diff --git a/hw/bsp/ch58x/family.mk b/hw/bsp/ch58x/family.mk index 566842f93..7b62af646 100644 --- a/hw/bsp/ch58x/family.mk +++ b/hw/bsp/ch58x/family.mk @@ -1,3 +1,9 @@ +# https://www.embecosm.com/resources/tool-chain-downloads/#riscv-stable +#CROSS_COMPILE ?= riscv32-unknown-elf- + +# Toolchain from https://nucleisys.com/download.php +#CROSS_COMPILE ?= riscv-nuclei-elf- + # Toolchain from https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack CROSS_COMPILE ?= riscv-none-elf- @@ -9,17 +15,21 @@ CPU_CORE ?= rv32imac-ilp32 CFLAGS += \ -flto \ - -msmall-data-limit=8 \ + -msmall-data-limit=16 \ -mno-save-restore \ -fmessage-length=0 \ -fsigned-char \ -DCFG_TUSB_MCU=OPT_MCU_CH58X \ -DCFG_TUD_WCH_USBIP_USBFS=1 \ -DFREQ_SYS=60000000 \ + -DDISK_LIB_ENABLE=0 \ + -DINT_SOFT \ + +CFLAGS += -Wno-error=strict-prototypes LDFLAGS_GCC += \ -nostdlib -nostartfiles \ - --specs=nosys.specs --specs=nano.specs \ + --specs=nosys.specs \ SRC_C += \ src/portable/wch/dcd_ch58x_usbfs.c \ diff --git a/src/portable/wch/ch58x_usbfs_reg.h b/src/portable/wch/ch58x_usbfs_reg.h index 11479a4f6..868589729 100644 --- a/src/portable/wch/ch58x_usbfs_reg.h +++ b/src/portable/wch/ch58x_usbfs_reg.h @@ -55,30 +55,23 @@ #define CH58X_UEP567_MOD(base) (*(volatile uint8_t *)((base) + 0x0E)) //--------------------------------------------------------------------+ -// Endpoint DMA / T_LEN / CTRL offset lookup tables -// EP0-EP4 are at low offsets, EP5-EP7 jump to higher offsets -// EP4 shares DMA with EP0 (no independent DMA register) -//--------------------------------------------------------------------+ -static const uint8_t ch58x_ep_dma_offset[] = { - 0x10, 0x14, 0x18, 0x1C, /* EP0, EP1, EP2, EP3 */ - 0xFF, /* EP4: shares with EP0, sentinel */ - 0x54, 0x58, 0x5C /* EP5, EP6, EP7 */ -}; - -static const uint8_t ch58x_ep_tlen_offset[] = { - 0x20, 0x24, 0x28, 0x2C, 0x30, /* EP0-EP4 */ - 0x64, 0x68, 0x6C /* EP5-EP7 */ -}; - -static const uint8_t ch58x_ep_ctrl_offset[] = { - 0x22, 0x26, 0x2A, 0x2E, 0x32, /* EP0-EP4 */ - 0x66, 0x6A, 0x6E /* EP5-EP7 */ -}; +// Endpoint DMA / T_LEN / CTRL register accessors +// +// EP0-EP3 DMA : base + 0x10 + ep*4 (EP4 shares EP0 DMA, no own register) +// EP5-EP7 DMA : base + 0x54 + (ep-5)*4 +// EP0-EP4 TLEN: base + 0x20 + ep*4 +// EP5-EP7 TLEN: base + 0x64 + (ep-5)*4 +// EP0-EP4 CTRL: base + 0x22 + ep*4 +// EP5-EP7 CTRL: base + 0x66 + (ep-5)*4 +// +// Using computed addresses avoids per-TU copies of static lookup tables. +// EP4 DMA is not accessed directly (it shares EP0's DMA register). +//--------------------------------------------------------------------+ // EP DMA is 16-bit (only low 16 bits of RAM address, high bits implied 0x2000) -#define CH58X_EP_DMA(base, ep) (*(volatile uint16_t *)((base) + ch58x_ep_dma_offset[ep])) -#define CH58X_EP_TLEN(base, ep) (*(volatile uint8_t *)((base) + ch58x_ep_tlen_offset[ep])) -#define CH58X_EP_CTRL(base, ep) (*(volatile uint8_t *)((base) + ch58x_ep_ctrl_offset[ep])) +#define CH58X_EP_DMA(base, ep) (*(volatile uint16_t *)((base) + ((ep) <= 3 ? (0x10u + (ep)*4u) : (0x54u + ((ep)-5u)*4u)))) +#define CH58X_EP_TLEN(base, ep) (*(volatile uint8_t *)((base) + ((ep) <= 4 ? (0x20u + (ep)*4u) : (0x64u + ((ep)-5u)*4u)))) +#define CH58X_EP_CTRL(base, ep) (*(volatile uint8_t *)((base) + ((ep) <= 4 ? (0x22u + (ep)*4u) : (0x66u + ((ep)-5u)*4u)))) //--------------------------------------------------------------------+ // USB_CTRL (R8_USB_CTRL) bit definitions diff --git a/src/portable/wch/dcd_ch58x_usbfs.c b/src/portable/wch/dcd_ch58x_usbfs.c index 11ff2c7b1..ea4a5ac4a 100644 --- a/src/portable/wch/dcd_ch58x_usbfs.c +++ b/src/portable/wch/dcd_ch58x_usbfs.c @@ -165,16 +165,16 @@ static uint8_t* ep_dma_buffer(dcd_data_t* d, uint8_t ep) { } //--------------------------------------------------------------------+ -// EP has auto-toggle support? +// AUTO_TOG supported on EP1/2/3/5/6/7 (no EP0 or EP4) //--------------------------------------------------------------------+ static inline bool ep_has_auto_toggle(uint8_t ep) { - return (ep >= 1 && ep <= 3); + return (ep >= 1 && ep <= 3) || (ep >= 5 && ep <= 7); } //--------------------------------------------------------------------+ // Private transfer helpers //--------------------------------------------------------------------+ -static void update_in(uint8_t rhport, uint8_t ep, bool force) { +static void update_in(uint8_t rhport, uint8_t ep, bool force, bool in_isr) { dcd_data_t* d = &_dcd_data[rhport]; uint32_t base = d->usb_base; struct usb_xfer* xfer = &d->xfer[ep][TUSB_DIR_IN]; @@ -213,12 +213,12 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force) { xfer->valid = false; ep_set_tx_response(base, ep, CH58X_EP_T_RES_NAK); dcd_event_xfer_complete(rhport, ep | TUSB_DIR_IN_MASK, - xfer->processed_len, XFER_RESULT_SUCCESS, true); + xfer->processed_len, XFER_RESULT_SUCCESS, in_isr); } } } -static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { +static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len, bool in_isr) { dcd_data_t* d = &_dcd_data[rhport]; uint32_t base = d->usb_base; struct usb_xfer* xfer = &d->xfer[ep][TUSB_DIR_OUT]; @@ -239,7 +239,7 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { if (xfer->len == 0 || len < xfer->max_size) { xfer->valid = false; dcd_event_xfer_complete(rhport, ep, xfer->processed_len, - XFER_RESULT_SUCCESS, true); + XFER_RESULT_SUCCESS, in_isr); } if (ep == 0) { @@ -297,11 +297,11 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { EP_TLEN(base, 4) = 0; EP_CTRL(base, 4) = CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK; - // EP5-7: DMA + no auto-toggle + // EP5-7: DMA + auto-toggle for (uint8_t ep = 5; ep <= 7; ep++) { EP_DMA(base, ep) = (uint16_t)(uint32_t) ep_dma_buffer(d, ep); EP_TLEN(base, ep) = 0; - EP_CTRL(base, ep) = CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK; + EP_CTRL(base, ep) = CH58X_EP_AUTO_TOG | CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK; } // Set EP0 max size @@ -325,18 +325,27 @@ void dcd_int_handler(uint8_t rhport) { // Check SETUP first via dedicated flag if (int_st & CH58X_UIS_SETUP_ACT) { // SETUP packet received on EP0 - ep_set_both_response(base, 0, CH58X_EP_T_RES_NAK, CH58X_EP_R_RES_ACK); + // After SETUP, both toggle bits must be set to DATA1 (SDK reference) + EP_CTRL(base, 0) = CH58X_EP_R_TOG | CH58X_EP_T_TOG | + CH58X_EP_R_RES_ACK | CH58X_EP_T_RES_NAK; d->ep0_tog = true; dcd_event_setup_received(rhport, ep_out_buffer(d, 0), true); } else { switch (token) { case CH58X_PID_OUT: { uint8_t rx_len = USB_RX_LEN(base); - if (!ep_has_auto_toggle(ep) && ep != 0) { - // Manual toggle for EP4-7 - EP_CTRL(base, ep) ^= CH58X_EP_R_TOG; + if (ep == 0) { + // EP0: always process (toggle managed via SETUP reset) + update_out(rhport, 0, rx_len, true); + } else if (int_st & CH58X_UIS_TOG_OK) { + // Toggle matched: data is valid + if (!ep_has_auto_toggle(ep)) { + // EP4: manual toggle + EP_CTRL(base, ep) ^= CH58X_EP_R_TOG; + } + update_out(rhport, ep, rx_len, true); } - update_out(rhport, ep, rx_len); + // else: toggle mismatch, discard packet per datasheet break; } @@ -345,7 +354,7 @@ void dcd_int_handler(uint8_t rhport) { // Manual toggle for EP4-7 EP_CTRL(base, ep) ^= CH58X_EP_T_TOG; } - update_in(rhport, ep, false); + update_in(rhport, ep, false, true); break; } @@ -370,19 +379,14 @@ void dcd_int_handler(uint8_t rhport) { USB_INT_FG(base) = CH58X_UIF_BUS_RST; } else if (status & CH58X_UIF_SUSPEND) { - if (USB_MIS_ST(base) & CH58X_UMS_SUSPEND) { - dcd_event_t event = {.rhport = rhport, .event_id = DCD_EVENT_SUSPEND}; - dcd_event_handler(&event, true); - } else { - dcd_event_t event = {.rhport = rhport, .event_id = DCD_EVENT_RESUME}; - dcd_event_handler(&event, true); - } + dcd_event_bus_signal(rhport, + (USB_MIS_ST(base) & CH58X_UMS_SUSPEND) ? DCD_EVENT_SUSPEND : DCD_EVENT_RESUME, + true); USB_INT_FG(base) = CH58X_UIF_SUSPEND; } } void dcd_int_enable(uint8_t rhport) { - (void) rhport; // PFIC enable: USB_IRQn=22, USB2_IRQn=23 volatile uint32_t* pfic_ienr = (volatile uint32_t*) 0xE000E100; uint8_t irqn = (rhport == 0) ? 22 : 23; @@ -390,7 +394,6 @@ void dcd_int_enable(uint8_t rhport) { } void dcd_int_disable(uint8_t rhport) { - (void) rhport; volatile uint32_t* pfic_irer = (volatile uint32_t*) 0xE000E180; uint8_t irqn = (rhport == 0) ? 22 : 23; pfic_irer[irqn / 32] = (1u << (irqn % 32)); @@ -406,7 +409,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { void dcd_remote_wakeup(uint8_t rhport) { uint32_t base = get_usb_base(rhport); USB_UDEV_CTRL(base) |= CH58X_UD_GP_BIT; - for (volatile int i = 0; i < 60000; i++) { } // ~1ms resume signal + tusb_time_delay_ms_api(1); // 1ms resume signal per USB spec USB_UDEV_CTRL(base) &= ~CH58X_UD_GP_BIT; } @@ -421,12 +424,10 @@ void dcd_disconnect(uint8_t rhport) { } void dcd_sof_enable(uint8_t rhport, bool en) { - uint32_t base = get_usb_base(rhport); - if (en) { - USB_INT_EN(base) |= CH58X_UIE_HST_SOF; - } else { - USB_INT_EN(base) &= ~CH58X_UIE_HST_SOF; - } + // CH58x has no device-mode SOF interrupt. + // RB_UIE_HST_SOF (0x08) is host-mode only and has no effect in device mode. + (void) rhport; + (void) en; } void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) { @@ -436,7 +437,9 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* req if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) { - USB_DEV_AD(base) = (uint8_t) request->wValue; + // Preserve GP_BIT (bit7) when setting device address + USB_DEV_AD(base) = (USB_DEV_AD(base) & CH58X_UDA_GP_BIT) | + ((uint8_t)request->wValue & CH58X_USB_ADDR_MASK); } ep_set_both_response(base, 0, CH58X_EP_T_RES_NAK, CH58X_EP_R_RES_ACK); } @@ -505,7 +508,6 @@ bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t* desc_ep) bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes, bool is_isr) { - (void) is_isr; uint8_t ep = tu_edpt_number(ep_addr); uint8_t dir = tu_edpt_dir(ep_addr); @@ -517,10 +519,9 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, xfer->buffer = buffer; xfer->len = total_bytes; xfer->processed_len = 0; - dcd_int_enable(rhport); if (dir == TUSB_DIR_IN) { - update_in(rhport, ep, true); + update_in(rhport, ep, true, is_isr); } else { // For OUT direction, set endpoint to ACK to start receiving data if (ep != 0) { @@ -531,6 +532,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, } } } + dcd_int_enable(rhport); return true; } diff --git a/src/portable/wch/hcd_ch58x_usbfs.c b/src/portable/wch/hcd_ch58x_usbfs.c index 629c2a789..8a8da9f16 100644 --- a/src/portable/wch/hcd_ch58x_usbfs.c +++ b/src/portable/wch/hcd_ch58x_usbfs.c @@ -422,7 +422,13 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const* dev_addr, ep_addr, max_packet_size, xfer_type); // Wait for any pending transfer - while (_current_xfer.is_busy) {} + uint32_t t0 = tusb_time_millis_api(); + while (_current_xfer.is_busy) { + if (tusb_time_millis_api() - t0 > 200) { + _current_xfer.is_busy = false; + break; + } + } if (ep_num == 0) { TU_ASSERT(_get_or_add_edpt(dev_addr, 0x00, max_packet_size, xfer_type) != NULL, false); @@ -447,8 +453,14 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, LOG_CH58X_HCD("hcd_edpt_xfer(dev=0x%02x, ep=0x%02x, len=%d)\r\n", dev_addr, ep_addr, buflen); - // Wait for any pending transfer - while (_current_xfer.is_busy) {} + // Wait for any pending transfer (with 200ms timeout to avoid deadlock on disconnect) + uint32_t t0 = tusb_time_millis_api(); + while (_current_xfer.is_busy) { + if (tusb_time_millis_api() - t0 > 200) { + _current_xfer.is_busy = false; + return false; + } + } _current_xfer.is_busy = true; hcd_edpt_t* edpt = _get_edpt(dev_addr, ep_addr); @@ -490,7 +502,13 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet LOG_CH58X_HCD("hcd_setup_send(dev=0x%02x)\r\n", dev_addr); // Wait for any pending transfer - while (_current_xfer.is_busy) {} + uint32_t t0 = tusb_time_millis_api(); + while (_current_xfer.is_busy) { + if (tusb_time_millis_api() - t0 > 200) { + _current_xfer.is_busy = false; + return false; + } + } _current_xfer.is_busy = true; _hw_set_addr_speed(rhport, dev_addr); @@ -522,33 +540,12 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet } bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { - uint32_t base = _port_data[rhport].usb_base; - uint8_t ep_num = tu_edpt_number(ep_addr); + (void) rhport; LOG_CH58X_HCD("hcd_edpt_clear_stall(dev=0x%02x, ep=0x%02x)\r\n", dev_addr, ep_addr); - - // Send CLEAR_FEATURE(ENDPOINT_HALT) via blocking transfer - uint8_t setup[8] = { - 0x02, 0x01, 0x00, 0x00, ep_addr, 0x00, 0x00, 0x00 - }; - memcpy(_tx_buf[rhport], setup, 8); - CH58X_UH_TX_LEN(base) = 8; - - bool prev_int = _port_data[rhport].int_enabled; - hcd_int_disable(rhport); - - CH58X_UH_EP_PID(base) = (CH58X_USB_PID_SETUP << 4) | 0x00; - CH58X_USB_INT_FG(base) = CH58X_UIF_TRANSFER; - while ((CH58X_USB_INT_FG(base) & CH58X_UIF_TRANSFER) == 0) {} - CH58X_UH_EP_PID(base) = 0; - - uint8_t response = CH58X_USB_INT_ST(base) & CH58X_UIS_H_RES_MASK; - (void)response; - - LOG_CH58X_HCD("clear_stall response=0x%02x\r\n", response); - - if (prev_int) { - hcd_int_enable(rhport); + hcd_edpt_t* edpt = _get_edpt(dev_addr, ep_addr); + if (edpt != NULL) { + edpt->data_toggle = 0; } return true; @@ -570,6 +567,10 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { if (attached) { hcd_event_device_attach(rhport, in_isr); } else { + // Stop any ongoing hardware transfer before reporting removal + CH58X_UH_EP_PID(base) = 0x00; + _current_xfer.is_busy = false; + _current_xfer.nak_pending = false; hcd_event_device_remove(rhport, in_isr); } return; @@ -580,7 +581,6 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { // Read PID/endpoint before stopping (must read first!) uint8_t pid_endp = CH58X_UH_EP_PID(base); uint8_t int_st = CH58X_USB_INT_ST(base); - uint8_t int_fg = CH58X_USB_INT_FG(base); uint8_t dev_addr = CH58X_USB_DEV_AD(base) & CH58X_USB_ADDR_MASK; // Stop USB transaction immediately (SDK: R8_UH_EP_PID = 0x00) diff --git a/src/tusb_option.h b/src/tusb_option.h index 699e3d44d..c75908e87 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -193,9 +193,9 @@ #define OPT_MCU_CH32F20X 2210 ///< WCH CH32F20x #define OPT_MCU_CH32V20X 2220 ///< WCH CH32V20X #define OPT_MCU_CH32V103 2230 ///< WCH CH32V103 -#define OPT_MCU_CH58X 2240 ///< WCH CH58x series (CH582/CH583) -#define OPT_MCU_CH582 OPT_MCU_CH58X ///< alias -#define OPT_MCU_CH583 OPT_MCU_CH58X ///< alias +#define OPT_MCU_CH58X 2240 ///< WCH CH58x +#define OPT_MCU_CH582 2240 ///< alias to CH58x series +#define OPT_MCU_CH583 2240 ///< alias to CH58x series // NXP LPC MCX #define OPT_MCU_MCXN9 2300 ///< NXP MCX N9 Series -- cgit v1.3.1 From 56f94bbb46bebf88e9be0332ebb9db03b30d1cb1 Mon Sep 17 00:00:00 2001 From: alt-0191 <2223147307@qq.com> Date: Fri, 13 Mar 2026 22:57:18 +0800 Subject: dcd_ch58x: fix toggle, SETUP race, and bus reset handling - Switch from AUTO_TOG to manual toggle for all endpoints to fix toggle mismatch after clear-stall causing bus resets - Fix SETUP race condition: track ep0_completion_pending and setup_pending to avoid arming stale EP0 transfers - Defer Set Address to ISR after status ZLP is ACK'd - Improve bus reset: reset all EPs, clear pending state - Fix EP4 DMA macro to correctly map to EP0 base (0x10) - Move CH58X_UIS_TOG_OK to common section (used by both DCD/HCD) - Add #ifndef guards for BOARD_TUD/TUH_RHPORT in board.h - Track isochronous per direction: isochronous[ep][dir] - NAK EP0 OUT on completion to prevent premature data acceptance --- hw/bsp/ch58x/boards/yd-ch582m/board.h | 4 + src/portable/wch/ch58x_usbfs_reg.h | 18 +--- src/portable/wch/dcd_ch58x_usbfs.c | 193 +++++++++++++++++++++------------- src/portable/wch/hcd_ch58x_usbfs.c | 2 +- 4 files changed, 131 insertions(+), 86 deletions(-) (limited to 'src/portable/wch') diff --git a/hw/bsp/ch58x/boards/yd-ch582m/board.h b/hw/bsp/ch58x/boards/yd-ch582m/board.h index 6e25dbdd3..a14ffd198 100644 --- a/hw/bsp/ch58x/boards/yd-ch582m/board.h +++ b/hw/bsp/ch58x/boards/yd-ch582m/board.h @@ -47,8 +47,12 @@ extern "C" { // Dual-port: USB1 (rhport 0) = Device, USB2 (rhport 1) = Host // Swap these two if you want the opposite assignment +#ifndef BOARD_TUD_RHPORT #define BOARD_TUD_RHPORT 0 +#endif +#ifndef BOARD_TUH_RHPORT #define BOARD_TUH_RHPORT 1 +#endif #ifdef __cplusplus } diff --git a/src/portable/wch/ch58x_usbfs_reg.h b/src/portable/wch/ch58x_usbfs_reg.h index 868589729..ed9f8d0f7 100644 --- a/src/portable/wch/ch58x_usbfs_reg.h +++ b/src/portable/wch/ch58x_usbfs_reg.h @@ -56,20 +56,10 @@ //--------------------------------------------------------------------+ // Endpoint DMA / T_LEN / CTRL register accessors -// -// EP0-EP3 DMA : base + 0x10 + ep*4 (EP4 shares EP0 DMA, no own register) -// EP5-EP7 DMA : base + 0x54 + (ep-5)*4 -// EP0-EP4 TLEN: base + 0x20 + ep*4 -// EP5-EP7 TLEN: base + 0x64 + (ep-5)*4 -// EP0-EP4 CTRL: base + 0x22 + ep*4 -// EP5-EP7 CTRL: base + 0x66 + (ep-5)*4 -// -// Using computed addresses avoids per-TU copies of static lookup tables. -// EP4 DMA is not accessed directly (it shares EP0's DMA register). //--------------------------------------------------------------------+ -// EP DMA is 16-bit (only low 16 bits of RAM address, high bits implied 0x2000) -#define CH58X_EP_DMA(base, ep) (*(volatile uint16_t *)((base) + ((ep) <= 3 ? (0x10u + (ep)*4u) : (0x54u + ((ep)-5u)*4u)))) +// EP DMA is 16-bit (only low 16 bits of RAM address, high bits implied 0x2000), EP4 shares EP0's DMA register (no independent DMA), so ep==4 maps to base+0x10 +#define CH58X_EP_DMA(base, ep) (*(volatile uint16_t *)((base) + ((ep) <= 3 ? (0x10u + (ep)*4u) : ((ep) == 4 ? 0x10u : (0x54u + ((ep)-5u)*4u))))) #define CH58X_EP_TLEN(base, ep) (*(volatile uint8_t *)((base) + ((ep) <= 4 ? (0x20u + (ep)*4u) : (0x64u + ((ep)-5u)*4u)))) #define CH58X_EP_CTRL(base, ep) (*(volatile uint8_t *)((base) + ((ep) <= 4 ? (0x22u + (ep)*4u) : (0x66u + ((ep)-5u)*4u)))) @@ -121,6 +111,7 @@ //--------------------------------------------------------------------+ #define CH58X_INT_ST_ENDP(x) (((x) >> 0) & 0x0F) #define CH58X_INT_ST_TOKEN(x) (((x) >> 4) & 0x03) +#define CH58X_UIS_TOG_OK 0x40 // toggle match flag (device and host) #define CH58X_UIS_SETUP_ACT 0x80 // Token PID values @@ -147,7 +138,7 @@ // Bit 7: RB_UEP_R_TOG RX data toggle // Bit 6: RB_UEP_T_TOG TX data toggle // Bit 5: (reserved) -// Bit 4: RB_UEP_AUTO_TOG auto toggle (EP1/2/3 only) +// Bit 4: RB_UEP_AUTO_TOG auto toggle (EP1/2/3/5/6/7, not EP0/EP4) // Bit 3: R_RES1 RX response high // Bit 2: R_RES0 RX response low // Bit 1: T_RES1 TX response high @@ -253,7 +244,6 @@ // USB_INT_ST host-mode bits //--------------------------------------------------------------------+ #define CH58X_UIS_H_RES_MASK 0x0F -#define CH58X_UIS_TOG_OK 0x40 //--------------------------------------------------------------------+ // USB_DEV_AD bits diff --git a/src/portable/wch/dcd_ch58x_usbfs.c b/src/portable/wch/dcd_ch58x_usbfs.c index ea4a5ac4a..f994638c8 100644 --- a/src/portable/wch/dcd_ch58x_usbfs.c +++ b/src/portable/wch/dcd_ch58x_usbfs.c @@ -95,7 +95,10 @@ struct usb_xfer { typedef struct { uint32_t usb_base; bool ep0_tog; - bool isochronous[EP_MAX]; + volatile uint8_t setup_pending; // SETUP arrived while EP0 completion pending in queue + volatile bool ep0_completion_pending; // EP0 XFER_COMPLETE in event queue, not yet processed + uint8_t pending_addr; // Address to set in ISR after Set Address status ZLP + bool isochronous[EP_MAX][2]; // [ep][dir] struct usb_xfer xfer[EP_MAX][2]; // [ep][dir] // EP0 + EP4 shared buffer: EP0 OUT(64) + EP4 OUT(64) + EP4 IN(64) @@ -117,9 +120,6 @@ static dcd_data_t _dcd_data[2]; //--------------------------------------------------------------------+ // Buffer address helpers -// EP0: ep0_buffer[0..63] -// EP4 OUT: ep0_buffer[64..127] EP4 IN: ep0_buffer[128..191] -// Other EPs: epX_buffer[0] = OUT, epX_buffer[1] = IN //--------------------------------------------------------------------+ static uint8_t* ep_out_buffer(dcd_data_t* d, uint8_t ep) { switch (ep) { @@ -149,8 +149,7 @@ static uint8_t* ep_in_buffer(dcd_data_t* d, uint8_t ep) { } } -// Get DMA base pointer for endpoint (the buffer whose address is set to DMA register) -// For EP4, DMA is shared with EP0, so we return EP0 buffer +// DMA base pointer (EP4 shares with EP0) static uint8_t* ep_dma_buffer(dcd_data_t* d, uint8_t ep) { switch (ep) { case 0: case 4: return &d->ep0_buffer[0]; @@ -164,12 +163,9 @@ static uint8_t* ep_dma_buffer(dcd_data_t* d, uint8_t ep) { } } -//--------------------------------------------------------------------+ -// AUTO_TOG supported on EP1/2/3/5/6/7 (no EP0 or EP4) -//--------------------------------------------------------------------+ -static inline bool ep_has_auto_toggle(uint8_t ep) { - return (ep >= 1 && ep <= 3) || (ep >= 5 && ep <= 7); -} +// AUTO_TOG is not used (EP1-3/5-7 support it). When clear-stall resets T_TOG/ +// R_TOG to DATA0, the hardware internal toggle doesn't sync, causing mismatch +// and bus resets. Use manual toggle (EP_CTRL ^= TOG) in ISR instead. //--------------------------------------------------------------------+ // Private transfer helpers @@ -203,7 +199,7 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force, bool in_isr) { if (d->ep0_tog) ctrl |= CH58X_EP_T_TOG; EP_CTRL(base, 0) = ctrl; d->ep0_tog = !d->ep0_tog; - } else if (d->isochronous[ep]) { + } else if (d->isochronous[ep][TUSB_DIR_IN]) { ep_set_tx_response(base, ep, CH58X_EP_T_RES_TOUT); } else { ep_set_tx_response(base, ep, CH58X_EP_T_RES_ACK); @@ -212,6 +208,7 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force, bool in_isr) { // Transfer complete xfer->valid = false; ep_set_tx_response(base, ep, CH58X_EP_T_RES_NAK); + if (ep == 0) d->ep0_completion_pending = true; dcd_event_xfer_complete(rhport, ep | TUSB_DIR_IN_MASK, xfer->processed_len, XFER_RESULT_SUCCESS, in_isr); } @@ -238,11 +235,13 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len, bool in_isr) { if (xfer->len == 0 || len < xfer->max_size) { xfer->valid = false; + // NAK to prevent hardware from accepting next OUT before a new xfer is queued + ep_set_rx_response(base, ep, CH58X_EP_R_RES_NAK); + if (ep == 0) d->ep0_completion_pending = true; dcd_event_xfer_complete(rhport, ep, xfer->processed_len, XFER_RESULT_SUCCESS, in_isr); - } - - if (ep == 0) { + } else if (ep == 0) { + // EP0 multi-packet: ensure ACK for next packet ep_set_rx_response(base, 0, CH58X_EP_R_RES_ACK); } } @@ -262,6 +261,12 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { tu_memclr(d->xfer, sizeof(d->xfer)); tu_memclr(d->isochronous, sizeof(d->isochronous)); d->ep0_tog = true; + d->setup_pending = 0; + d->ep0_completion_pending = false; + d->pending_addr = 0; + + // Reset USB control register first (SDK pattern) + USB_CTRL(base) = 0x00; // Init control registers USB_CTRL(base) = CH58X_UC_DEV_PU_EN | CH58X_UC_INT_BUSY | CH58X_UC_DMA_EN; @@ -286,22 +291,22 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { CH58X_UEP6_RX_EN | CH58X_UEP6_TX_EN | CH58X_UEP7_RX_EN | CH58X_UEP7_TX_EN; - // EP1-3: DMA + auto-toggle + NAK both directions + // EP1-3: DMA + manual toggle + NAK both directions for (uint8_t ep = 1; ep <= 3; ep++) { EP_DMA(base, ep) = (uint16_t)(uint32_t) ep_dma_buffer(d, ep); EP_TLEN(base, ep) = 0; - EP_CTRL(base, ep) = CH58X_EP_AUTO_TOG | CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK; + EP_CTRL(base, ep) = CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK; } // EP4: no independent DMA, no auto-toggle EP_TLEN(base, 4) = 0; EP_CTRL(base, 4) = CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK; - // EP5-7: DMA + auto-toggle + // EP5-7: DMA + manual toggle for (uint8_t ep = 5; ep <= 7; ep++) { EP_DMA(base, ep) = (uint16_t)(uint32_t) ep_dma_buffer(d, ep); EP_TLEN(base, ep) = 0; - EP_CTRL(base, ep) = CH58X_EP_AUTO_TOG | CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK; + EP_CTRL(base, ep) = CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK; } // Set EP0 max size @@ -322,36 +327,33 @@ void dcd_int_handler(uint8_t rhport) { uint8_t ep = CH58X_INT_ST_ENDP(int_st); uint8_t token = CH58X_INT_ST_TOKEN(int_st); - // Check SETUP first via dedicated flag - if (int_st & CH58X_UIS_SETUP_ACT) { - // SETUP packet received on EP0 - // After SETUP, both toggle bits must be set to DATA1 (SDK reference) - EP_CTRL(base, 0) = CH58X_EP_R_TOG | CH58X_EP_T_TOG | - CH58X_EP_R_RES_ACK | CH58X_EP_T_RES_NAK; - d->ep0_tog = true; - dcd_event_setup_received(rhport, ep_out_buffer(d, 0), true); - } else { + // Process regular token before SETUP to avoid losing it + if (token != CH58X_PID_SETUP) { switch (token) { case CH58X_PID_OUT: { uint8_t rx_len = USB_RX_LEN(base); if (ep == 0) { - // EP0: always process (toggle managed via SETUP reset) + // EP0: manual toggle, always process + EP_CTRL(base, 0) ^= CH58X_EP_R_TOG; update_out(rhport, 0, rx_len, true); } else if (int_st & CH58X_UIS_TOG_OK) { - // Toggle matched: data is valid - if (!ep_has_auto_toggle(ep)) { - // EP4: manual toggle - EP_CTRL(base, ep) ^= CH58X_EP_R_TOG; - } + // Toggle OK: manual toggle and process + EP_CTRL(base, ep) ^= CH58X_EP_R_TOG; update_out(rhport, ep, rx_len, true); } - // else: toggle mismatch, discard packet per datasheet + // else: toggle mismatch, discard break; } case CH58X_PID_IN: { - if (!ep_has_auto_toggle(ep) && ep != 0) { - // Manual toggle for EP4-7 + // Apply pending Set Address immediately after status ZLP + if (ep == 0 && d->pending_addr) { + USB_DEV_AD(base) = (USB_DEV_AD(base) & CH58X_UDA_GP_BIT) | + (d->pending_addr & CH58X_USB_ADDR_MASK); + d->pending_addr = 0; + } + if (ep != 0) { + // Manual toggle for all non-EP0 endpoints EP_CTRL(base, ep) ^= CH58X_EP_T_TOG; } update_in(rhport, ep, false, true); @@ -361,24 +363,61 @@ void dcd_int_handler(uint8_t rhport) { default: break; } + USB_INT_FG(base) = CH58X_UIF_TRANSFER; + } + + // SETUP_ACT is checked separately — it persists even if token field changed + if (int_st & CH58X_UIS_SETUP_ACT) { + // Reset toggles to DATA1, NAK both directions until stack is ready + EP_CTRL(base, 0) = CH58X_EP_R_TOG | CH58X_EP_T_TOG | + CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK; + d->ep0_tog = true; + + d->pending_addr = 0; + + // Mark stale EP0 completion so dcd_edpt_xfer can skip it + d->setup_pending = d->ep0_completion_pending ? 1 : 0; + d->ep0_completion_pending = false; + d->xfer[0][TUSB_DIR_OUT].valid = false; + d->xfer[0][TUSB_DIR_IN].valid = false; + + dcd_event_setup_received(rhport, ep_out_buffer(d, 0), true); + USB_INT_FG(base) = CH58X_UIF_TRANSFER; } + } - USB_INT_FG(base) = CH58X_UIF_TRANSFER; - } else if (status & CH58X_UIF_BUS_RST) { - // Bus reset + // Process bus reset: reset all endpoints immediately (matching WCH SDK pattern) + if (status & CH58X_UIF_BUS_RST) { d->ep0_tog = true; + d->setup_pending = 0; + d->ep0_completion_pending = false; + d->pending_addr = 0; + + // Reset EP0: ACK for RX (ready for SETUP), NAK for TX + EP_CTRL(base, 0) = CH58X_EP_R_RES_ACK | CH58X_EP_T_RES_NAK; + EP_TLEN(base, 0) = 0; d->xfer[0][TUSB_DIR_OUT].max_size = EP_BUF_SIZE; d->xfer[0][TUSB_DIR_IN].max_size = EP_BUF_SIZE; + // Reset EP1-7: NAK both directions, invalidate pending transfers + for (uint8_t ep = 1; ep < EP_MAX; ep++) { + d->xfer[ep][TUSB_DIR_IN].valid = false; + d->xfer[ep][TUSB_DIR_OUT].valid = false; + EP_CTRL(base, ep) = CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK; + EP_TLEN(base, ep) = 0; + } + USB_DEV_AD(base) = 0x00; - ep_set_rx_response(base, 0, CH58X_EP_R_RES_ACK); - tusb_speed_t speed = (USB_MIS_ST(base) & CH58X_UMS_DM_LEVEL) ? + tusb_speed_t speed = (USB_CTRL(base) & CH58X_UC_LOW_SPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL; dcd_event_bus_reset(rhport, speed, true); USB_INT_FG(base) = CH58X_UIF_BUS_RST; - } else if (status & CH58X_UIF_SUSPEND) { + } + + // Process suspend/resume + if (status & CH58X_UIF_SUSPEND) { dcd_event_bus_signal(rhport, (USB_MIS_ST(base) & CH58X_UMS_SUSPEND) ? DCD_EVENT_SUSPEND : DCD_EVENT_RESUME, true); @@ -401,16 +440,14 @@ void dcd_int_disable(uint8_t rhport) { } void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { - (void) dev_addr; - // Address is set in status stage complete callback + // Defer to ISR: apply address right after status ZLP is ACK'd + _dcd_data[rhport].pending_addr = dev_addr; dcd_edpt_xfer(rhport, 0x80, NULL, 0, false); } void dcd_remote_wakeup(uint8_t rhport) { - uint32_t base = get_usb_base(rhport); - USB_UDEV_CTRL(base) |= CH58X_UD_GP_BIT; - tusb_time_delay_ms_api(1); // 1ms resume signal per USB spec - USB_UDEV_CTRL(base) &= ~CH58X_UD_GP_BIT; + (void) rhport; + // TODO: not supported } void dcd_connect(uint8_t rhport) { @@ -424,8 +461,6 @@ void dcd_disconnect(uint8_t rhport) { } void dcd_sof_enable(uint8_t rhport, bool en) { - // CH58x has no device-mode SOF interrupt. - // RB_UIE_HST_SOF (0x08) is host-mode only and has no effect in device mode. (void) rhport; (void) en; } @@ -437,11 +472,20 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* req if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) { - // Preserve GP_BIT (bit7) when setting device address + // Safety net: re-apply address in case ISR path was skipped USB_DEV_AD(base) = (USB_DEV_AD(base) & CH58X_UDA_GP_BIT) | ((uint8_t)request->wValue & CH58X_USB_ADDR_MASK); } - ep_set_both_response(base, 0, CH58X_EP_T_RES_NAK, CH58X_EP_R_RES_ACK); + + dcd_int_disable(rhport); + d->ep0_completion_pending = false; + if (d->setup_pending) { + // SETUP already arrived — don't override its NAK with ACK + d->setup_pending = 0; + } else { + ep_set_both_response(base, 0, CH58X_EP_T_RES_NAK, CH58X_EP_R_RES_ACK); + } + dcd_int_enable(rhport); } bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) { @@ -451,29 +495,26 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) { uint8_t dir = tu_edpt_dir(desc_ep->bEndpointAddress); TU_ASSERT(ep < EP_MAX); - d->isochronous[ep] = (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS); + d->isochronous[ep][dir] = (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS); d->xfer[ep][dir].max_size = tu_edpt_packet_size(desc_ep); if (ep != 0) { dcd_int_disable(rhport); uint8_t ctrl = EP_CTRL(base, ep); if (dir == TUSB_DIR_OUT) { - if (d->isochronous[ep]) { + // Clear RX toggle to DATA0 per USB spec + ctrl &= ~CH58X_EP_R_TOG; + if (d->isochronous[ep][TUSB_DIR_OUT]) { ctrl = (ctrl & ~CH58X_EP_R_RES_MASK) | CH58X_EP_R_RES_TOUT; } else { // Start with NAK; dcd_edpt_xfer will set ACK when a transfer is submitted ctrl = (ctrl & ~CH58X_EP_R_RES_MASK) | CH58X_EP_R_RES_NAK; } - // Enable auto toggle for EP1-3 - if (ep_has_auto_toggle(ep)) { - ctrl |= CH58X_EP_AUTO_TOG; - } } else { + // Clear TX toggle to DATA0 per USB spec + ctrl &= ~CH58X_EP_T_TOG; EP_TLEN(base, ep) = 0; ctrl = (ctrl & ~CH58X_EP_T_RES_MASK) | CH58X_EP_T_RES_NAK; - if (ep_has_auto_toggle(ep)) { - ctrl |= CH58X_EP_AUTO_TOG; - } } EP_CTRL(base, ep) = ctrl; dcd_int_enable(rhport); @@ -488,7 +529,8 @@ void dcd_edpt_close_all(uint8_t rhport) { for (uint8_t ep = 1; ep < EP_MAX; ep++) { d->xfer[ep][TUSB_DIR_IN].valid = false; d->xfer[ep][TUSB_DIR_OUT].valid = false; - d->isochronous[ep] = false; + d->isochronous[ep][TUSB_DIR_OUT] = false; + d->isochronous[ep][TUSB_DIR_IN] = false; EP_CTRL(base, ep) = CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK; } } @@ -515,6 +557,17 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, struct usb_xfer* xfer = &d->xfer[ep][dir]; dcd_int_disable(rhport); + + // Skip stale EP0 arm if a new SETUP has already arrived + if (ep == 0) { + d->ep0_completion_pending = false; + if (d->setup_pending) { + d->setup_pending = 0; + dcd_int_enable(rhport); + return true; + } + } + xfer->valid = true; xfer->buffer = buffer; xfer->len = total_bytes; @@ -523,13 +576,11 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, if (dir == TUSB_DIR_IN) { update_in(rhport, ep, true, is_isr); } else { - // For OUT direction, set endpoint to ACK to start receiving data - if (ep != 0) { - if (d->isochronous[ep]) { - ep_set_rx_response(d->usb_base, ep, CH58X_EP_R_RES_TOUT); - } else { - ep_set_rx_response(d->usb_base, ep, CH58X_EP_R_RES_ACK); - } + + if (d->isochronous[ep][TUSB_DIR_OUT]) { + ep_set_rx_response(d->usb_base, ep, CH58X_EP_R_RES_TOUT); + } else { + ep_set_rx_response(d->usb_base, ep, CH58X_EP_R_RES_ACK); } } dcd_int_enable(rhport); diff --git a/src/portable/wch/hcd_ch58x_usbfs.c b/src/portable/wch/hcd_ch58x_usbfs.c index 8a8da9f16..2b1bd40bc 100644 --- a/src/portable/wch/hcd_ch58x_usbfs.c +++ b/src/portable/wch/hcd_ch58x_usbfs.c @@ -305,7 +305,7 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { // Clear endpoint records tu_memclr(_edpt_list, sizeof(_edpt_list)); - tu_memclr((void*)&_current_xfer, sizeof(_current_xfer)); + _current_xfer = (const hcd_xfer_t){0}; _hw_init_host(rhport, true); -- cgit v1.3.1 From dc87bab45f8123cbfa2b4b0ac6e1831c1172651f Mon Sep 17 00:00:00 2001 From: alt-0191 <2223147307@qq.com> Date: Fri, 13 Mar 2026 23:58:18 +0800 Subject: ch58x: code cleanup and minor fixes --- hw/bsp/ch58x/ch58x_it.h | 6 +- hw/bsp/ch58x/debug_uart.c | 6 +- hw/bsp/ch58x/debug_uart.h | 8 ++ hw/bsp/ch58x/system_ch58x.h | 6 +- src/portable/wch/ch58x_usbfs_reg.h | 9 ++ src/portable/wch/dcd_ch58x_usbfs.c | 30 +++--- src/portable/wch/hcd_ch58x_usbfs.c | 203 +++++++++++++++++++------------------ 7 files changed, 147 insertions(+), 121 deletions(-) (limited to 'src/portable/wch') diff --git a/hw/bsp/ch58x/ch58x_it.h b/hw/bsp/ch58x/ch58x_it.h index c98f732e1..18ea52bc9 100644 --- a/hw/bsp/ch58x/ch58x_it.h +++ b/hw/bsp/ch58x/ch58x_it.h @@ -24,8 +24,8 @@ * This file is part of the TinyUSB stack. */ -#ifndef __CH58X_IT_H -#define __CH58X_IT_H +#ifndef CH58X_IT_H_ +#define CH58X_IT_H_ #ifdef __cplusplus extern "C" { @@ -43,4 +43,4 @@ void SysTick_Handler(void); } #endif -#endif /* __CH58X_IT_H */ +#endif /* CH58X_IT_H_ */ diff --git a/hw/bsp/ch58x/debug_uart.c b/hw/bsp/ch58x/debug_uart.c index e63606f33..7dd133cb2 100644 --- a/hw/bsp/ch58x/debug_uart.c +++ b/hw/bsp/ch58x/debug_uart.c @@ -35,11 +35,11 @@ #define UART_RINGBUFFER_MASK_TX (UART_RINGBUFFER_SIZE_TX - 1) static char tx_buf[UART_RINGBUFFER_SIZE_TX]; -static unsigned int tx_produce; -static volatile unsigned int tx_consume; +static uint32_t tx_produce; +static volatile uint32_t tx_consume; void uart_write(char c) { - unsigned int tx_produce_next = (tx_produce + 1) & UART_RINGBUFFER_MASK_TX; + uint32_t tx_produce_next = (tx_produce + 1) & UART_RINGBUFFER_MASK_TX; // If ring buffer is full, wait while (tx_produce_next == tx_consume) {} diff --git a/hw/bsp/ch58x/debug_uart.h b/hw/bsp/ch58x/debug_uart.h index 458d838d9..44c3e7948 100644 --- a/hw/bsp/ch58x/debug_uart.h +++ b/hw/bsp/ch58x/debug_uart.h @@ -29,8 +29,16 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + void uart_write(char c); void uart_sync(void); void usart_printf_init(uint32_t baudrate); +#ifdef __cplusplus +} +#endif + #endif /* DEBUG_UART_H_ */ diff --git a/hw/bsp/ch58x/system_ch58x.h b/hw/bsp/ch58x/system_ch58x.h index ef32e603f..e96741ee8 100644 --- a/hw/bsp/ch58x/system_ch58x.h +++ b/hw/bsp/ch58x/system_ch58x.h @@ -24,8 +24,8 @@ * This file is part of the TinyUSB stack. */ -#ifndef __SYSTEM_CH58X_H -#define __SYSTEM_CH58X_H +#ifndef SYSTEM_CH58X_H_ +#define SYSTEM_CH58X_H_ #ifdef __cplusplus extern "C" { @@ -40,4 +40,4 @@ extern void SystemCoreClockUpdate(void); } #endif -#endif /* __SYSTEM_CH58X_H */ +#endif /* SYSTEM_CH58X_H_ */ diff --git a/src/portable/wch/ch58x_usbfs_reg.h b/src/portable/wch/ch58x_usbfs_reg.h index ed9f8d0f7..67b47e0b6 100644 --- a/src/portable/wch/ch58x_usbfs_reg.h +++ b/src/portable/wch/ch58x_usbfs_reg.h @@ -279,4 +279,13 @@ #define CH58X_SLP_CLK_OFF1 (*(volatile uint8_t *)0x4000100D) #define CH58X_SLP_CLK_USB 0x10 +//--------------------------------------------------------------------+ +// PFIC (Platform-level Fast Interrupt Controller) +//--------------------------------------------------------------------+ +#define CH58X_PFIC_IENR ((volatile uint32_t *)0xE000E100) // interrupt enable +#define CH58X_PFIC_IRER ((volatile uint32_t *)0xE000E180) // interrupt reset (disable) + +#define CH58X_USB_IRQn 22 +#define CH58X_USB2_IRQn 23 + #endif /* CH58X_USBFS_REG_H */ diff --git a/src/portable/wch/dcd_ch58x_usbfs.c b/src/portable/wch/dcd_ch58x_usbfs.c index f994638c8..c6f10b801 100644 --- a/src/portable/wch/dcd_ch58x_usbfs.c +++ b/src/portable/wch/dcd_ch58x_usbfs.c @@ -84,13 +84,13 @@ static inline void ep_set_both_response(uint32_t base, uint8_t ep, uint8_t tx_re //--------------------------------------------------------------------+ // Private data structures //--------------------------------------------------------------------+ -struct usb_xfer { +typedef struct { bool valid; uint8_t* buffer; size_t len; size_t processed_len; size_t max_size; -}; +} xfer_ctl_t; typedef struct { uint32_t usb_base; @@ -99,7 +99,7 @@ typedef struct { volatile bool ep0_completion_pending; // EP0 XFER_COMPLETE in event queue, not yet processed uint8_t pending_addr; // Address to set in ISR after Set Address status ZLP bool isochronous[EP_MAX][2]; // [ep][dir] - struct usb_xfer xfer[EP_MAX][2]; // [ep][dir] + xfer_ctl_t xfer[EP_MAX][2]; // [ep][dir] // EP0 + EP4 shared buffer: EP0 OUT(64) + EP4 OUT(64) + EP4 IN(64) TU_ATTR_ALIGNED(4) uint8_t ep0_buffer[EP_BUF_SIZE + EP_BUF_SIZE + EP_BUF_SIZE]; @@ -173,7 +173,7 @@ static uint8_t* ep_dma_buffer(dcd_data_t* d, uint8_t ep) { static void update_in(uint8_t rhport, uint8_t ep, bool force, bool in_isr) { dcd_data_t* d = &_dcd_data[rhport]; uint32_t base = d->usb_base; - struct usb_xfer* xfer = &d->xfer[ep][TUSB_DIR_IN]; + xfer_ctl_t* xfer = &d->xfer[ep][TUSB_DIR_IN]; if (xfer->valid) { if (force || xfer->len) { @@ -218,7 +218,7 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force, bool in_isr) { static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len, bool in_isr) { dcd_data_t* d = &_dcd_data[rhport]; uint32_t base = d->usb_base; - struct usb_xfer* xfer = &d->xfer[ep][TUSB_DIR_OUT]; + xfer_ctl_t* xfer = &d->xfer[ep][TUSB_DIR_OUT]; if (xfer->valid) { size_t len = TU_MIN(xfer->max_size, TU_MIN(xfer->len, rx_len)); @@ -426,16 +426,13 @@ void dcd_int_handler(uint8_t rhport) { } void dcd_int_enable(uint8_t rhport) { - // PFIC enable: USB_IRQn=22, USB2_IRQn=23 - volatile uint32_t* pfic_ienr = (volatile uint32_t*) 0xE000E100; - uint8_t irqn = (rhport == 0) ? 22 : 23; - pfic_ienr[irqn / 32] = (1u << (irqn % 32)); + uint8_t irqn = (rhport == 0) ? CH58X_USB_IRQn : CH58X_USB2_IRQn; + CH58X_PFIC_IENR[irqn / 32] = (1u << (irqn % 32)); } void dcd_int_disable(uint8_t rhport) { - volatile uint32_t* pfic_irer = (volatile uint32_t*) 0xE000E180; - uint8_t irqn = (rhport == 0) ? 22 : 23; - pfic_irer[irqn / 32] = (1u << (irqn % 32)); + uint8_t irqn = (rhport == 0) ? CH58X_USB_IRQn : CH58X_USB2_IRQn; + CH58X_PFIC_IRER[irqn / 32] = (1u << (irqn % 32)); __asm volatile ("fence.i"); } @@ -496,7 +493,11 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) { TU_ASSERT(ep < EP_MAX); d->isochronous[ep][dir] = (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS); - d->xfer[ep][dir].max_size = tu_edpt_packet_size(desc_ep); + uint16_t max_size = tu_edpt_packet_size(desc_ep); + if (max_size > EP_BUF_SIZE) { + max_size = EP_BUF_SIZE; + } + d->xfer[ep][dir].max_size = max_size; if (ep != 0) { dcd_int_disable(rhport); @@ -554,7 +555,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint8_t dir = tu_edpt_dir(ep_addr); dcd_data_t* d = &_dcd_data[rhport]; - struct usb_xfer* xfer = &d->xfer[ep][dir]; + xfer_ctl_t* xfer = &d->xfer[ep][dir]; dcd_int_disable(rhport); @@ -576,7 +577,6 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, if (dir == TUSB_DIR_IN) { update_in(rhport, ep, true, is_isr); } else { - if (d->isochronous[ep][TUSB_DIR_OUT]) { ep_set_rx_response(d->usb_base, ep, CH58X_EP_R_RES_TOUT); } else { diff --git a/src/portable/wch/hcd_ch58x_usbfs.c b/src/portable/wch/hcd_ch58x_usbfs.c index 2b1bd40bc..37dd08539 100644 --- a/src/portable/wch/hcd_ch58x_usbfs.c +++ b/src/portable/wch/hcd_ch58x_usbfs.c @@ -90,7 +90,8 @@ typedef struct { bool nak_pending; } hcd_xfer_t; -static volatile hcd_xfer_t _current_xfer = {}; +// One transfer state per root port (indexed by rhport). +static volatile hcd_xfer_t _current_xfer[2] = {}; //--------------------------------------------------------------------+ // Per-port state @@ -98,6 +99,7 @@ static volatile hcd_xfer_t _current_xfer = {}; typedef struct { uint32_t usb_base; bool int_enabled; + bool int_state_before_reset; } hcd_port_t; static hcd_port_t _port_data[2] = {}; @@ -208,7 +210,7 @@ static bool _hw_start_xfer(uint8_t rhport, uint8_t pid, uint8_t ep_addr, uint8_t LOG_CH58X_HCD("_hw_start_xfer(pid=0x%02x, ep=0x%02x, tog=%d)\r\n", pid, ep_addr, data_toggle); // Workaround: small delay for low-speed devices - bool is_lowspeed = tuh_speed_get(_current_xfer.dev_addr) == TUSB_SPEED_LOW; + bool is_lowspeed = tuh_speed_get(_current_xfer[rhport].dev_addr) == TUSB_SPEED_LOW; if (is_lowspeed) { _delay_loops(60000000 / 1000000 * 40); // ~40us at 60MHz } @@ -276,20 +278,23 @@ static void _xfer_retry(void* param) { LOG_CH58X_HCD("_xfer_retry()\r\n"); hcd_edpt_t* edpt = (hcd_edpt_t*)param; - if (_current_xfer.nak_pending) { - uint8_t rhport = _current_xfer.rhport; - _current_xfer.nak_pending = false; - edpt->is_nak_pending = false; - - uint8_t dev_addr = edpt->dev_addr; - uint8_t ep_addr = edpt->ep_addr; - uint16_t buflen = edpt->buflen; - uint8_t* buf = edpt->buf; - - // Check if endpoint is still valid - hcd_edpt_t* current = _get_edpt(dev_addr, ep_addr); - if (current) { - hcd_edpt_xfer(rhport, dev_addr, ep_addr, buf, buflen); + // Find which rhport this endpoint belongs to by checking both ports + for (uint8_t rp = 0; rp < 2; rp++) { + if (_current_xfer[rp].nak_pending) { + _current_xfer[rp].nak_pending = false; + edpt->is_nak_pending = false; + + uint8_t dev_addr = edpt->dev_addr; + uint8_t ep_addr = edpt->ep_addr; + uint16_t buflen = edpt->buflen; + uint8_t* buf = edpt->buf; + + // Check if endpoint is still valid + hcd_edpt_t* current = _get_edpt(dev_addr, ep_addr); + if (current) { + hcd_edpt_xfer(rp, dev_addr, ep_addr, buf, buflen); + } + break; } } } @@ -303,9 +308,13 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { _port_data[rhport].usb_base = _get_usb_base(rhport); _port_data[rhport].int_enabled = false; - // Clear endpoint records - tu_memclr(_edpt_list, sizeof(_edpt_list)); - _current_xfer = (const hcd_xfer_t){0}; + // Clear endpoint records only on first init to avoid wiping state of the other rhport + static bool _first_init = true; + if (_first_init) { + tu_memclr(_edpt_list, sizeof(_edpt_list)); + _first_init = false; + } + _current_xfer[rhport] = (const hcd_xfer_t){0}; _hw_init_host(rhport, true); @@ -323,17 +332,14 @@ uint32_t hcd_frame_number(uint8_t rhport) { } void hcd_int_enable(uint8_t rhport) { - // PFIC interrupt enable - volatile uint32_t* pfic_ienr = (volatile uint32_t*)0xE000E100; - uint8_t irqn = (rhport == 0) ? 22 : 23; // USB_IRQn or USB2_IRQn - pfic_ienr[irqn / 32] = (1u << (irqn % 32)); + uint8_t irqn = (rhport == 0) ? CH58X_USB_IRQn : CH58X_USB2_IRQn; + CH58X_PFIC_IENR[irqn / 32] = (1u << (irqn % 32)); _port_data[rhport].int_enabled = true; } void hcd_int_disable(uint8_t rhport) { - volatile uint32_t* pfic_irer = (volatile uint32_t*)0xE000E180; - uint8_t irqn = (rhport == 0) ? 22 : 23; - pfic_irer[irqn / 32] = (1u << (irqn % 32)); + uint8_t irqn = (rhport == 0) ? CH58X_USB_IRQn : CH58X_USB2_IRQn; + CH58X_PFIC_IRER[irqn / 32] = (1u << (irqn % 32)); __asm volatile("fence.i"); _port_data[rhport].int_enabled = false; } @@ -347,21 +353,18 @@ bool hcd_port_connect_status(uint8_t rhport) { tusb_speed_t hcd_port_speed_get(uint8_t rhport) { uint32_t base = _port_data[rhport].usb_base; - // DM level high = low-speed device, low = full-speed if (CH58X_USB_MIS_ST(base) & CH58X_UMS_DM_LEVEL) { return TUSB_SPEED_LOW; } return TUSB_SPEED_FULL; } -static bool _int_state_before_reset = false; - void hcd_port_reset(uint8_t rhport) { uint32_t base = _port_data[rhport].usb_base; LOG_CH58X_HCD("hcd_port_reset()\r\n"); - _int_state_before_reset = _port_data[rhport].int_enabled; + _port_data[rhport].int_state_before_reset = _port_data[rhport].int_enabled; hcd_int_disable(rhport); _hw_set_device_addr(rhport, 0x00); @@ -397,7 +400,7 @@ void hcd_port_reset_end(uint8_t rhport) { // Suppress stale detect event CH58X_USB_INT_FG(base) = CH58X_UIF_DETECT; - if (_int_state_before_reset) { + if (_port_data[rhport].int_state_before_reset) { hcd_int_enable(rhport); } } @@ -423,9 +426,9 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const* // Wait for any pending transfer uint32_t t0 = tusb_time_millis_api(); - while (_current_xfer.is_busy) { + while (_current_xfer[rhport].is_busy) { if (tusb_time_millis_api() - t0 > 200) { - _current_xfer.is_busy = false; + _current_xfer[rhport].is_busy = false; break; } } @@ -455,27 +458,27 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, // Wait for any pending transfer (with 200ms timeout to avoid deadlock on disconnect) uint32_t t0 = tusb_time_millis_api(); - while (_current_xfer.is_busy) { + while (_current_xfer[rhport].is_busy) { if (tusb_time_millis_api() - t0 > 200) { - _current_xfer.is_busy = false; + _current_xfer[rhport].is_busy = false; return false; } } - _current_xfer.is_busy = true; + _current_xfer[rhport].is_busy = true; hcd_edpt_t* edpt = _get_edpt(dev_addr, ep_addr); TU_ASSERT(edpt != NULL); _hw_set_addr_speed(rhport, dev_addr); - _current_xfer.rhport = rhport; - _current_xfer.dev_addr = dev_addr; - _current_xfer.ep_addr = ep_addr; - _current_xfer.buffer = buffer; - _current_xfer.bufferlen = buflen; - _current_xfer.start_ms = tusb_time_millis_api(); - _current_xfer.xferred_len = 0; - _current_xfer.nak_pending = false; + _current_xfer[rhport].rhport = rhport; + _current_xfer[rhport].dev_addr = dev_addr; + _current_xfer[rhport].ep_addr = ep_addr; + _current_xfer[rhport].buffer = buffer; + _current_xfer[rhport].bufferlen = buflen; + _current_xfer[rhport].start_ms = tusb_time_millis_api(); + _current_xfer[rhport].xferred_len = 0; + _current_xfer[rhport].nak_pending = false; if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { // IN transfer: host receives data @@ -503,13 +506,13 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet // Wait for any pending transfer uint32_t t0 = tusb_time_millis_api(); - while (_current_xfer.is_busy) { + while (_current_xfer[rhport].is_busy) { if (tusb_time_millis_api() - t0 > 200) { - _current_xfer.is_busy = false; + _current_xfer[rhport].is_busy = false; return false; } } - _current_xfer.is_busy = true; + _current_xfer[rhport].is_busy = true; _hw_set_addr_speed(rhport, dev_addr); @@ -525,14 +528,14 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet memcpy(_tx_buf[rhport], setup_packet, 8); CH58X_UH_TX_LEN(base) = 8; - _current_xfer.rhport = rhport; - _current_xfer.dev_addr = dev_addr; - _current_xfer.ep_addr = 0x00; // SETUP always targets EP0 OUT - _current_xfer.start_ms = tusb_time_millis_api(); - _current_xfer.buffer = _tx_buf[rhport]; - _current_xfer.bufferlen = 8; - _current_xfer.xferred_len = 0; - _current_xfer.nak_pending = false; + _current_xfer[rhport].rhport = rhport; + _current_xfer[rhport].dev_addr = dev_addr; + _current_xfer[rhport].ep_addr = 0x00; // SETUP always targets EP0 OUT + _current_xfer[rhport].start_ms = tusb_time_millis_api(); + _current_xfer[rhport].buffer = _tx_buf[rhport]; + _current_xfer[rhport].bufferlen = 8; + _current_xfer[rhport].xferred_len = 0; + _current_xfer[rhport].nak_pending = false; _hw_start_xfer(rhport, CH58X_USB_PID_SETUP, 0, 0); @@ -569,8 +572,8 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { } else { // Stop any ongoing hardware transfer before reporting removal CH58X_UH_EP_PID(base) = 0x00; - _current_xfer.is_busy = false; - _current_xfer.nak_pending = false; + _current_xfer[rhport].is_busy = false; + _current_xfer[rhport].nak_pending = false; hcd_event_device_remove(rhport, in_isr); } return; @@ -603,7 +606,7 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { if (edpt == NULL) { // Unknown endpoint, discard LOG_CH58X_HCD("hcd_int: unknown edpt dev=0x%02x ep=0x%02x\r\n", dev_addr, ep_addr); - _current_xfer.is_busy = false; + _current_xfer[rhport].is_busy = false; CH58X_USB_INT_FG(base) = CH58X_UIF_TRANSFER; return; } @@ -616,19 +619,19 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { case CH58X_USB_PID_SETUP: case CH58X_USB_PID_OUT: { uint8_t tx_len = CH58X_UH_TX_LEN(base); - _current_xfer.bufferlen -= tx_len; - _current_xfer.xferred_len += tx_len; + _current_xfer[rhport].bufferlen -= tx_len; + _current_xfer[rhport].xferred_len += tx_len; - if (_current_xfer.bufferlen == 0) { - LOG_CH58X_HCD("OUT/SETUP complete, %d bytes\r\n", _current_xfer.xferred_len); - _current_xfer.is_busy = false; + if (_current_xfer[rhport].bufferlen == 0) { + LOG_CH58X_HCD("OUT/SETUP complete, %d bytes\r\n", _current_xfer[rhport].xferred_len); + _current_xfer[rhport].is_busy = false; hcd_event_xfer_complete(dev_addr, ep_addr, - _current_xfer.xferred_len, XFER_RESULT_SUCCESS, in_isr); + _current_xfer[rhport].xferred_len, XFER_RESULT_SUCCESS, in_isr); } else { // Multi-packet OUT: send next chunk - _current_xfer.buffer += tx_len; - uint16_t copylen = TU_MIN(edpt->max_packet_size, _current_xfer.bufferlen); - memcpy(_tx_buf[rhport], _current_xfer.buffer, copylen); + _current_xfer[rhport].buffer += tx_len; + uint16_t copylen = TU_MIN(edpt->max_packet_size, _current_xfer[rhport].bufferlen); + memcpy(_tx_buf[rhport], _current_xfer[rhport].buffer, copylen); CH58X_UH_TX_LEN(base) = (uint8_t)copylen; _hw_start_xfer(rhport, CH58X_USB_PID_OUT, ep_addr, edpt->data_toggle); } @@ -637,18 +640,18 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { case CH58X_USB_PID_IN: { uint8_t rx_len = CH58X_USB_RX_LEN(base); - _current_xfer.xferred_len += rx_len; - uint16_t xferred = _current_xfer.xferred_len; + _current_xfer[rhport].xferred_len += rx_len; + uint16_t xferred = _current_xfer[rhport].xferred_len; - if (rx_len > 0 && _current_xfer.buffer != NULL) { - memcpy(_current_xfer.buffer, _rx_buf[rhport], rx_len); - _current_xfer.buffer += rx_len; + if (rx_len > 0 && _current_xfer[rhport].buffer != NULL) { + memcpy(_current_xfer[rhport].buffer, _rx_buf[rhport], rx_len); + _current_xfer[rhport].buffer += rx_len; } - if ((rx_len < edpt->max_packet_size) || (xferred == _current_xfer.bufferlen)) { + if ((rx_len < edpt->max_packet_size) || (xferred == _current_xfer[rhport].bufferlen)) { // Short packet or transfer complete LOG_CH58X_HCD("IN complete, %d bytes\r\n", xferred); - _current_xfer.is_busy = false; + _current_xfer[rhport].is_busy = false; hcd_event_xfer_complete(dev_addr, ep_addr, xferred, XFER_RESULT_SUCCESS, in_isr); } else { @@ -660,7 +663,7 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { default: { LOG_CH58X_HCD("unexpected PID 0x%02x\r\n", request_pid); - _current_xfer.is_busy = false; + _current_xfer[rhport].is_busy = false; hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, in_isr); break; } @@ -670,36 +673,42 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { if (response_pid == CH58X_USB_PID_STALL) { LOG_CH58X_HCD("STALL response\r\n"); edpt->data_toggle = 0; - _current_xfer.is_busy = false; + _current_xfer[rhport].is_busy = false; hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_STALLED, in_isr); } else if (response_pid == CH58X_USB_PID_NAK) { LOG_CH58X_HCD("NAK response\r\n"); - // NAK: schedule retry via deferred callback for all endpoint types - // This avoids tight polling loops and allows other tasks to run - _current_xfer.is_busy = false; - _current_xfer.nak_pending = true; - - edpt->is_nak_pending = true; - edpt->buflen = _current_xfer.bufferlen; - edpt->buf = _current_xfer.buffer; - - hcd_event_t event = { - .rhport = rhport, - .dev_addr = dev_addr, - .event_id = USBH_EVENT_FUNC_CALL, - .func_call = { - .func = _xfer_retry, - .param = edpt - } - }; - hcd_event_handler(&event, in_isr); + // For interrupt endpoints, treat NAK as a successful 0-byte poll so + // that upper layers can reschedule based on the endpoint interval. + if (edpt->xfer_type == TUSB_XFER_INTERRUPT) { + _current_xfer[rhport].is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_SUCCESS, in_isr); + } else { + // For non-interrupt endpoints, schedule retry via deferred callback. + _current_xfer[rhport].is_busy = false; + _current_xfer[rhport].nak_pending = true; + + edpt->is_nak_pending = true; + edpt->buflen = _current_xfer[rhport].bufferlen; + edpt->buf = _current_xfer[rhport].buffer; + + hcd_event_t event = { + .rhport = rhport, + .dev_addr = dev_addr, + .event_id = USBH_EVENT_FUNC_CALL, + .func_call = { + .func = _xfer_retry, + .param = edpt + } + }; + hcd_event_handler(&event, in_isr); + } } else if (response_pid == CH58X_USB_PID_DATA0 || response_pid == CH58X_USB_PID_DATA1) { LOG_CH58X_HCD("toggle mismatch, DATA0/1 rx_len=%d\r\n", CH58X_USB_RX_LEN(base)); - _current_xfer.is_busy = false; + _current_xfer[rhport].is_busy = false; hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, in_isr); } else { LOG_CH58X_HCD("unexpected response 0x%02x\r\n", response_pid); - _current_xfer.is_busy = false; + _current_xfer[rhport].is_busy = false; hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, in_isr); } } -- cgit v1.3.1 From 7258db344e99398a5e10f4c65b24d38c6b94b92b Mon Sep 17 00:00:00 2001 From: mickabrig7 Date: Tue, 28 Apr 2026 12:24:00 +0900 Subject: fix(dcd_ch32_usbfs): fix dropped bulk OUT packets by properly re-arming EP_RX_CTRL state --- src/portable/wch/dcd_ch32_usbfs.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/portable/wch') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 5cd25e33e..39c1cfb4a 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -118,6 +118,9 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { if (ep == 0) { EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; + } else { + EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | + (xfer->valid ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK); } } } @@ -312,6 +315,8 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t if (dir == TUSB_DIR_IN) { update_in(rhport, ep, true); + } else { + EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | USBFS_EP_R_RES_ACK; } return true; } -- cgit v1.3.1 From d202477ebe0f8805bf88fcee4c0d5968d146dfbd Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 22 May 2026 18:02:23 +0200 Subject: dcd/ch32fs: reset EP regs on bus reset Signed-off-by: HiFiPhile --- src/portable/wch/dcd_ch32_usbfs.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'src/portable/wch') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 39c1cfb4a..0727664c9 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -125,6 +125,16 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { } } +static void reset_ep_ctrls(void) { + for (uint8_t ep = 1; ep < EP_MAX; ep++) { + EP_DMA(ep) = (uint32_t) &data.buffer[ep][0]; + EP_TX_LEN(ep) = 0; + EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NYET; + EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NYET; + } + EP_DMA(3) = (uint32_t) &data.ep3_buffer.out[0]; +} + /* public functions */ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { (void) rh_init; @@ -148,13 +158,7 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { USBOTG_FS->UEP5_6_MOD = 0xCC; USBOTG_FS->UEP7_MOD = 0x0C; - for (uint8_t ep = 1; ep < EP_MAX; ep++) { - EP_DMA(ep) = (uint32_t) &data.buffer[ep][0]; - EP_TX_LEN(ep) = 0; - EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK; - EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NAK; - } - EP_DMA(3) = (uint32_t) &data.ep3_buffer.out[0]; + reset_ep_ctrls(); dcd_connect(rhport); @@ -201,6 +205,8 @@ void dcd_int_handler(uint8_t rhport) { USBOTG_FS->DEV_ADDR = 0x00; EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; + reset_ep_ctrls(); + USBOTG_FS->INT_FG = USBFS_INT_FG_BUS_RST; } else if (status & USBFS_INT_FG_SUSPEND) { dcd_event_t event = {.rhport = rhport, .event_id = DCD_EVENT_SUSPEND}; -- cgit v1.3.1 From 66c5f6d45dc90f947261e2e4e62918c2ceb0ce11 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 22 May 2026 18:04:44 +0200 Subject: dcd/ch32fs: only enable EP0 ACK if no data stage, reduce race Signed-off-by: HiFiPhile --- src/portable/wch/dcd_ch32_usbfs.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/portable/wch') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 0727664c9..e4abbd824 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -186,9 +186,12 @@ void dcd_int_handler(uint8_t rhport) { case PID_SETUP: // setup clears stall EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK; - EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; - data.ep0_tog = true; + + tusb_control_request_t const* setup = + (tusb_control_request_t const*) &data.buffer[0][TUSB_DIR_OUT][0]; + EP_RX_CTRL(0) = (setup->wLength == 0) ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK; + dcd_event_setup_received(rhport, &data.buffer[0][TUSB_DIR_OUT][0], true); break; } -- cgit v1.3.1 From 61a8f688c800626962cfed4022f4672b35ceb3ae Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 22 May 2026 18:13:42 +0200 Subject: dcd/ch32fs: fix ISO IN transfer OUT is still buggy Signed-off-by: HiFiPhile --- src/portable/wch/dcd_ch32_usbfs.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'src/portable/wch') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index e4abbd824..f6c573b47 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -119,8 +119,10 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { if (ep == 0) { EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; } else { - EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | - (xfer->valid ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK); + uint8_t rx_res = data.isochronous[ep] + ? USBFS_EP_R_RES_NYET + : (xfer->valid ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK); + EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | rx_res; } } } @@ -272,18 +274,12 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) { uint8_t dir = tu_edpt_dir(desc_ep->bEndpointAddress); TU_ASSERT(ep < EP_MAX); - data.isochronous[ep] = desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS; data.xfer[ep][dir].max_size = tu_edpt_packet_size(desc_ep); if (ep != 0) { if (dir == TUSB_DIR_OUT) { - if (data.isochronous[ep]) { - EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NYET; - } else { - EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_ACK; - } + EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_T_RES_NAK; } else { - EP_TX_LEN(ep) = 0; EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK; } } @@ -299,13 +295,18 @@ bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet (void) rhport; (void) ep_addr; (void)largest_packet_size; - return false; + uint8_t ep = tu_edpt_number(ep_addr); + uint8_t dir = tu_edpt_dir(ep_addr); + + data.isochronous[ep] = true; + data.xfer[ep][dir].max_size = largest_packet_size; + return true; } bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { (void)rhport; (void)desc_ep; - return false; + return true; } bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { @@ -325,7 +326,8 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t if (dir == TUSB_DIR_IN) { update_in(rhport, ep, true); } else { - EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | USBFS_EP_R_RES_ACK; + uint8_t rx_res = data.isochronous[ep] ? USBFS_EP_R_RES_NYET : USBFS_EP_R_RES_ACK; + EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | rx_res; } return true; } -- cgit v1.3.1 From 28d4ec5723428cbdb085ecdaa70e7fd2bf7f893d Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 22 May 2026 18:14:58 +0200 Subject: dcd/ch32fs: reset EP on clear stall Signed-off-by: HiFiPhile --- src/portable/wch/dcd_ch32_usbfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/portable/wch') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index f6c573b47..8f583510c 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -362,9 +362,9 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { } } else { if (dir == TUSB_DIR_OUT) { - EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~(USBFS_EP_R_RES_MASK | USBFS_EP_R_TOG)) | USBFS_EP_R_RES_ACK; + EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NAK; } else { - EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK | USBFS_EP_T_TOG)) | USBFS_EP_T_RES_NAK; + EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK; } } } -- cgit v1.3.1 From e14b0e8514ace0043472d9cb0779152fccade1ee Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 23 May 2026 13:02:53 +0200 Subject: dcd/ch32fs: set EP to NAK earlier to reduce spuroius transfer Signed-off-by: HiFiPhile --- src/portable/wch/dcd_ch32_usbfs.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'src/portable/wch') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 8f583510c..3ba6eee87 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -66,6 +66,13 @@ static struct { static void update_in(uint8_t rhport, uint8_t ep, bool force) { struct usb_xfer* xfer = &data.xfer[ep][TUSB_DIR_IN]; if (xfer->valid) { + // Set EP to NAK to avoid spurious tramsfer + if (ep == 0) { + EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK | (data.ep0_tog ? USBFS_EP_T_TOG : 0); + } else if (!data.isochronous[ep]) { + EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NAK; + } + if (force || xfer->len) { size_t len = TU_MIN(xfer->max_size, xfer->len); if (ep == 0) { @@ -101,6 +108,13 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force) { static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { struct usb_xfer* xfer = &data.xfer[ep][TUSB_DIR_OUT]; if (xfer->valid) { + // Set EP to NAK to avoid spurious tramsfer + if (ep == 0) { + EP_RX_CTRL(0) = USBFS_EP_R_RES_NAK; + } else if (!data.isochronous[ep]) { + EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | USBFS_EP_R_RES_NAK; + } + size_t len = TU_MIN(xfer->max_size, TU_MIN(xfer->len, rx_len)); if (ep == 3) { memcpy(xfer->buffer, data.ep3_buffer.out, len); @@ -116,9 +130,7 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { dcd_event_xfer_complete(rhport, ep, xfer->processed_len, XFER_RESULT_SUCCESS, true); } - if (ep == 0) { - EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; - } else { + if (ep != 0) { uint8_t rx_res = data.isochronous[ep] ? USBFS_EP_R_RES_NYET : (xfer->valid ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK); @@ -173,10 +185,11 @@ void dcd_int_handler(uint8_t rhport) { if (status & USBFS_INT_FG_TRANSFER) { uint8_t ep = USBFS_INT_ST_MASK_UIS_ENDP(USBOTG_FS->INT_ST); uint8_t token = USBFS_INT_ST_MASK_UIS_TOKEN(USBOTG_FS->INT_ST); + uint16_t rx_len = USBOTG_FS->RX_LEN; + USBOTG_FS->INT_FG = USBFS_INT_FG_TRANSFER; switch (token) { case PID_OUT: { - uint16_t rx_len = USBOTG_FS->RX_LEN; update_out(rhport, ep, rx_len); break; } @@ -198,7 +211,6 @@ void dcd_int_handler(uint8_t rhport) { break; } - USBOTG_FS->INT_FG = USBFS_INT_FG_TRANSFER; } else if (status & USBFS_INT_FG_BUS_RST) { data.ep0_tog = true; data.xfer[0][TUSB_DIR_OUT].max_size = 64; -- cgit v1.3.1 From b66fc7e88400caf7748779c7dc0b9c90f90e626b Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 23 May 2026 13:10:47 +0200 Subject: dcd/ch32x : code reformat Signed-off-by: HiFiPhile --- src/portable/wch/dcd_ch32_usbfs.c | 159 ++++++++++++++++--------------- src/portable/wch/dcd_ch32_usbhs.c | 191 +++++++++++++++++++------------------- 2 files changed, 173 insertions(+), 177 deletions(-) (limited to 'src/portable/wch') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 3ba6eee87..37677276c 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -29,29 +29,29 @@ #if CFG_TUD_ENABLED && defined(TUP_USBIP_WCH_USBFS) && CFG_TUD_WCH_USBIP_USBFS -#include "device/dcd.h" -#include "ch32_usbfs_reg.h" + #include "device/dcd.h" + #include "ch32_usbfs_reg.h" -/* private defines */ -#define EP_MAX (8) + /* private defines */ + #define EP_MAX (8) -#define EP_DMA(ep) ((&USBOTG_FS->UEP0_DMA)[ep]) -#define EP_TX_LEN(ep) ((&USBOTG_FS->UEP0_TX_LEN)[2 * ep]) -#define EP_TX_CTRL(ep) ((&USBOTG_FS->UEP0_TX_CTRL)[4 * ep]) -#define EP_RX_CTRL(ep) ((&USBOTG_FS->UEP0_RX_CTRL)[4 * ep]) + #define EP_DMA(ep) ((&USBOTG_FS->UEP0_DMA)[ep]) + #define EP_TX_LEN(ep) ((&USBOTG_FS->UEP0_TX_LEN)[2 * ep]) + #define EP_TX_CTRL(ep) ((&USBOTG_FS->UEP0_TX_CTRL)[4 * ep]) + #define EP_RX_CTRL(ep) ((&USBOTG_FS->UEP0_RX_CTRL)[4 * ep]) /* private data */ struct usb_xfer { - bool valid; - uint8_t* buffer; - size_t len; - size_t processed_len; - size_t max_size; + bool valid; + uint8_t *buffer; + size_t len; + size_t processed_len; + size_t max_size; }; static struct { - bool ep0_tog; - bool isochronous[EP_MAX]; + bool ep0_tog; + bool isochronous[EP_MAX]; struct usb_xfer xfer[EP_MAX][2]; TU_ATTR_ALIGNED(4) uint8_t buffer[EP_MAX][2][64]; TU_ATTR_ALIGNED(4) struct { @@ -64,7 +64,7 @@ static struct { /* private helpers */ static void update_in(uint8_t rhport, uint8_t ep, bool force) { - struct usb_xfer* xfer = &data.xfer[ep][TUSB_DIR_IN]; + struct usb_xfer *xfer = &data.xfer[ep][TUSB_DIR_IN]; if (xfer->valid) { // Set EP to NAK to avoid spurious tramsfer if (ep == 0) { @@ -89,24 +89,22 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force) { EP_TX_LEN(ep) = len; if (ep == 0) { EP_TX_CTRL(0) = USBFS_EP_T_RES_ACK | (data.ep0_tog ? USBFS_EP_T_TOG : 0); - data.ep0_tog = !data.ep0_tog; + data.ep0_tog = !data.ep0_tog; } else if (data.isochronous[ep]) { EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NYET; } else { EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_ACK; } } else { - xfer->valid = false; + xfer->valid = false; EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NAK; - dcd_event_xfer_complete( - rhport, ep | TUSB_DIR_IN_MASK, xfer->processed_len, - XFER_RESULT_SUCCESS, true); + dcd_event_xfer_complete(rhport, ep | TUSB_DIR_IN_MASK, xfer->processed_len, XFER_RESULT_SUCCESS, true); } } } static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { - struct usb_xfer* xfer = &data.xfer[ep][TUSB_DIR_OUT]; + struct usb_xfer *xfer = &data.xfer[ep][TUSB_DIR_OUT]; if (xfer->valid) { // Set EP to NAK to avoid spurious tramsfer if (ep == 0) { @@ -131,9 +129,8 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { } if (ep != 0) { - uint8_t rx_res = data.isochronous[ep] - ? USBFS_EP_R_RES_NYET - : (xfer->valid ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK); + uint8_t rx_res = + data.isochronous[ep] ? USBFS_EP_R_RES_NYET : (xfer->valid ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK); EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | rx_res; } } @@ -141,28 +138,28 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { static void reset_ep_ctrls(void) { for (uint8_t ep = 1; ep < EP_MAX; ep++) { - EP_DMA(ep) = (uint32_t) &data.buffer[ep][0]; - EP_TX_LEN(ep) = 0; + EP_DMA(ep) = (uint32_t)&data.buffer[ep][0]; + EP_TX_LEN(ep) = 0; EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NYET; EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NYET; } - EP_DMA(3) = (uint32_t) &data.ep3_buffer.out[0]; + EP_DMA(3) = (uint32_t)&data.ep3_buffer.out[0]; } /* public functions */ -bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { - (void) rh_init; +bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { + (void)rh_init; // init registers USBOTG_FS->BASE_CTRL = USBFS_CTRL_SYS_CTRL | USBFS_CTRL_INT_BUSY | USBFS_CTRL_DMA_EN; USBOTG_FS->UDEV_CTRL = USBFS_UDEV_CTRL_PD_DIS | USBFS_UDEV_CTRL_PORT_EN; - USBOTG_FS->DEV_ADDR = 0x00; + USBOTG_FS->DEV_ADDR = 0x00; USBOTG_FS->INT_FG = 0xFF; USBOTG_FS->INT_EN = USBFS_INT_EN_BUS_RST | USBFS_INT_EN_TRANSFER | USBFS_INT_EN_SUSPEND; // setup endpoint 0 - EP_DMA(0) = (uint32_t) &data.buffer[0][0]; - EP_TX_LEN(0) = 0; + EP_DMA(0) = (uint32_t)&data.buffer[0][0]; + EP_TX_LEN(0) = 0; EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK; EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; @@ -170,7 +167,7 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { USBOTG_FS->UEP4_1_MOD = 0xCC; USBOTG_FS->UEP2_3_MOD = 0xCC; USBOTG_FS->UEP5_6_MOD = 0xCC; - USBOTG_FS->UEP7_MOD = 0x0C; + USBOTG_FS->UEP7_MOD = 0x0C; reset_ep_ctrls(); @@ -180,12 +177,12 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { } void dcd_int_handler(uint8_t rhport) { - (void) rhport; + (void)rhport; uint8_t status = USBOTG_FS->INT_FG; if (status & USBFS_INT_FG_TRANSFER) { - uint8_t ep = USBFS_INT_ST_MASK_UIS_ENDP(USBOTG_FS->INT_ST); - uint8_t token = USBFS_INT_ST_MASK_UIS_TOKEN(USBOTG_FS->INT_ST); - uint16_t rx_len = USBOTG_FS->RX_LEN; + uint8_t ep = USBFS_INT_ST_MASK_UIS_ENDP(USBOTG_FS->INT_ST); + uint8_t token = USBFS_INT_ST_MASK_UIS_TOKEN(USBOTG_FS->INT_ST); + uint16_t rx_len = USBOTG_FS->RX_LEN; USBOTG_FS->INT_FG = USBFS_INT_FG_TRANSFER; switch (token) { @@ -201,26 +198,27 @@ void dcd_int_handler(uint8_t rhport) { case PID_SETUP: // setup clears stall EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK; - data.ep0_tog = true; + data.ep0_tog = true; - tusb_control_request_t const* setup = - (tusb_control_request_t const*) &data.buffer[0][TUSB_DIR_OUT][0]; - EP_RX_CTRL(0) = (setup->wLength == 0) ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK; + const tusb_control_request_t *setup = (const tusb_control_request_t *)&data.buffer[0][TUSB_DIR_OUT][0]; + EP_RX_CTRL(0) = (setup->wLength == 0) ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK; dcd_event_setup_received(rhport, &data.buffer[0][TUSB_DIR_OUT][0], true); break; } } else if (status & USBFS_INT_FG_BUS_RST) { - data.ep0_tog = true; + data.ep0_tog = true; data.xfer[0][TUSB_DIR_OUT].max_size = 64; - data.xfer[0][TUSB_DIR_IN].max_size = 64; + data.xfer[0][TUSB_DIR_IN].max_size = 64; - //dcd_event_bus_reset(rhport, (USBOTG_FS->BASE_CTRL & USBFS_CTRL_LOW_SPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL, true); - dcd_event_bus_reset(rhport, (USBOTG_FS->UDEV_CTRL & USBFS_UDEV_CTRL_LOW_SPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL, true); + // dcd_event_bus_reset(rhport, (USBOTG_FS->BASE_CTRL & USBFS_CTRL_LOW_SPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL, + // true); + dcd_event_bus_reset(rhport, (USBOTG_FS->UDEV_CTRL & USBFS_UDEV_CTRL_LOW_SPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL, + true); USBOTG_FS->DEV_ADDR = 0x00; - EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; + EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; reset_ep_ctrls(); @@ -233,56 +231,55 @@ void dcd_int_handler(uint8_t rhport) { } void dcd_int_enable(uint8_t rhport) { - (void) rhport; + (void)rhport; NVIC_EnableIRQ(USBHD_IRQn); } void dcd_int_disable(uint8_t rhport) { - (void) rhport; + (void)rhport; NVIC_DisableIRQ(USBHD_IRQn); } void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { - (void) dev_addr; + (void)dev_addr; dcd_edpt_xfer(rhport, 0x80, NULL, 0, false); // zlp status response } void dcd_remote_wakeup(uint8_t rhport) { - (void) rhport; + (void)rhport; // TODO optional } void dcd_connect(uint8_t rhport) { - (void) rhport; + (void)rhport; USBOTG_FS->BASE_CTRL |= USBFS_CTRL_DEV_PUEN; } void dcd_disconnect(uint8_t rhport) { - (void) rhport; + (void)rhport; USBOTG_FS->BASE_CTRL &= ~USBFS_CTRL_DEV_PUEN; } void dcd_sof_enable(uint8_t rhport, bool en) { - (void) rhport; - (void) en; + (void)rhport; + (void)en; // TODO implement later } -void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) { - (void) rhport; +void dcd_edpt0_status_complete(uint8_t rhport, const tusb_control_request_t *request) { + (void)rhport; if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && - request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && - request->bRequest == TUSB_REQ_SET_ADDRESS) { - USBOTG_FS->DEV_ADDR = (uint8_t) request->wValue; + request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) { + USBOTG_FS->DEV_ADDR = (uint8_t)request->wValue; } EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK; EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; } -bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) { - (void) rhport; - uint8_t ep = tu_edpt_number(desc_ep->bEndpointAddress); +bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { + (void)rhport; + uint8_t ep = tu_edpt_number(desc_ep->bEndpointAddress); uint8_t dir = tu_edpt_dir(desc_ep->bEndpointAddress); TU_ASSERT(ep < EP_MAX); @@ -299,18 +296,18 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) { } void dcd_edpt_close_all(uint8_t rhport) { - (void) rhport; + (void)rhport; // TODO optional } bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { - (void) rhport; - (void) ep_addr; + (void)rhport; + (void)ep_addr; (void)largest_packet_size; - uint8_t ep = tu_edpt_number(ep_addr); + uint8_t ep = tu_edpt_number(ep_addr); uint8_t dir = tu_edpt_dir(ep_addr); - data.isochronous[ep] = true; + data.isochronous[ep] = true; data.xfer[ep][dir].max_size = largest_packet_size; return true; } @@ -321,17 +318,17 @@ bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) return true; } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { - (void) is_isr; - (void) rhport; - uint8_t ep = tu_edpt_number(ep_addr); +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool is_isr) { + (void)is_isr; + (void)rhport; + uint8_t ep = tu_edpt_number(ep_addr); uint8_t dir = tu_edpt_dir(ep_addr); - struct usb_xfer* xfer = &data.xfer[ep][dir]; + struct usb_xfer *xfer = &data.xfer[ep][dir]; dcd_int_disable(rhport); - xfer->valid = true; - xfer->buffer = buffer; - xfer->len = total_bytes; + xfer->valid = true; + xfer->buffer = buffer; + xfer->len = total_bytes; xfer->processed_len = 0; dcd_int_enable(rhport); @@ -345,14 +342,14 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t } void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { - (void) rhport; - uint8_t ep = tu_edpt_number(ep_addr); + (void)rhport; + uint8_t ep = tu_edpt_number(ep_addr); uint8_t dir = tu_edpt_dir(ep_addr); if (ep == 0) { if (dir == TUSB_DIR_OUT) { EP_RX_CTRL(0) = USBFS_EP_R_RES_STALL; } else { - EP_TX_LEN(0) = 0; + EP_TX_LEN(0) = 0; EP_TX_CTRL(0) = USBFS_EP_T_RES_STALL; } } else { @@ -365,8 +362,8 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { } void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { - (void) rhport; - uint8_t ep = tu_edpt_number(ep_addr); + (void)rhport; + uint8_t ep = tu_edpt_number(ep_addr); uint8_t dir = tu_edpt_dir(ep_addr); if (ep == 0) { if (dir == TUSB_DIR_OUT) { diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c index 11734de37..01ff6eba3 100644 --- a/src/portable/wch/dcd_ch32_usbhs.c +++ b/src/portable/wch/dcd_ch32_usbhs.c @@ -37,12 +37,12 @@ #define EP_MAX 16 typedef struct { - uint8_t* buffer; + uint8_t *buffer; uint16_t total_len; uint16_t queued_len; uint16_t max_size; - bool is_last_packet; - bool is_iso; + bool is_last_packet; + bool is_iso; } xfer_ctl_t; typedef enum { @@ -50,16 +50,16 @@ typedef enum { EP_RESPONSE_NAK, } ep_response_list_t; -#define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir] + #define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir] static xfer_ctl_t xfer_status[EP_MAX][2]; -#define EP_TX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_TX_LEN) + (ep) * 2) -#define EP_TX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_TX_CTRL) + (ep) * 4) -#define EP_RX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_RX_CTRL) + (ep) * 4) -#define EP_RX_MAX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_MAX_LEN) + (ep) * 2) + #define EP_TX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_TX_LEN) + (ep) * 2) + #define EP_TX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_TX_CTRL) + (ep) * 4) + #define EP_RX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_RX_CTRL) + (ep) * 4) + #define EP_RX_MAX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_MAX_LEN) + (ep) * 2) -#define EP_TX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_TX_DMA) + (ep - 1)) -#define EP_RX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_RX_DMA) + (ep - 1)) + #define EP_TX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_TX_DMA) + (ep - 1)) + #define EP_RX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_RX_DMA) + (ep - 1)) /* Endpoint Buffer */ TU_ATTR_ALIGNED(4) static uint8_t ep0_buffer[CFG_TUD_ENDPOINT0_SIZE]; @@ -96,15 +96,15 @@ static void ep_set_response_and_toggle(uint8_t ep_num, tusb_dir_t ep_dir, ep_res } } -static void xfer_data_packet(uint8_t ep_num, tusb_dir_t ep_dir, xfer_ctl_t* xfer) { +static void xfer_data_packet(uint8_t ep_num, tusb_dir_t ep_dir, xfer_ctl_t *xfer) { if (ep_dir == TUSB_DIR_IN) { - uint16_t remaining = xfer->total_len - xfer->queued_len; + uint16_t remaining = xfer->total_len - xfer->queued_len; uint16_t next_tx_size = TU_MIN(remaining, xfer->max_size); if (ep_num == 0) { memcpy(ep0_buffer, &xfer->buffer[xfer->queued_len], next_tx_size); } else { - EP_TX_DMA_ADDR(ep_num) = (uint32_t) &xfer->buffer[xfer->queued_len]; + EP_TX_DMA_ADDR(ep_num) = (uint32_t)&xfer->buffer[xfer->queued_len]; } EP_TX_LEN(ep_num) = next_tx_size; @@ -117,7 +117,7 @@ static void xfer_data_packet(uint8_t ep_num, tusb_dir_t ep_dir, xfer_ctl_t* xfer USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num); } } else { /* TUSB_DIR_OUT */ - uint16_t left_to_receive = xfer->total_len - xfer->queued_len; + uint16_t left_to_receive = xfer->total_len - xfer->queued_len; uint16_t max_possible_rx_size = TU_MIN(xfer->max_size, left_to_receive); if (max_possible_rx_size == left_to_receive) { @@ -125,16 +125,16 @@ static void xfer_data_packet(uint8_t ep_num, tusb_dir_t ep_dir, xfer_ctl_t* xfer } if (ep_num > 0) { - EP_RX_DMA_ADDR(ep_num) = (uint32_t) &xfer->buffer[xfer->queued_len]; - EP_RX_MAX_LEN(ep_num) = max_possible_rx_size; + EP_RX_DMA_ADDR(ep_num) = (uint32_t)&xfer->buffer[xfer->queued_len]; + EP_RX_MAX_LEN(ep_num) = max_possible_rx_size; } } ep_set_response_and_toggle(ep_num, ep_dir, USBHS_EP_R_RES_ACK); } -bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { - (void) rhport; - (void) rh_init; +bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { + (void)rhport; + (void)rh_init; memset(&xfer_status, 0, sizeof(xfer_status)); @@ -143,32 +143,32 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { USBHSD->CONTROL = 0; -#if TUD_OPT_HIGH_SPEED + #if TUD_OPT_HIGH_SPEED USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_HIGH_SPEED; -#else - #error OPT_MODE_FULL_SPEED not currently supported on CH32 + #else + #error OPT_MODE_FULL_SPEED not currently supported on CH32 USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_FULL_SPEED; -#endif + #endif USBHSD->INT_EN = 0; USBHSD->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_BUS_RST_EN | USBHS_SUSPEND_EN | USBHS_ISO_ACT_EN; USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN; - USBHSD->ENDP_TYPE = 0x00; - USBHSD->BUF_MODE = 0x00; + USBHSD->ENDP_TYPE = 0x00; + USBHSD->BUF_MODE = 0x00; for (int ep = 0; ep < EP_MAX; ep++) { - EP_TX_LEN(ep) = 0; + EP_TX_LEN(ep) = 0; EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK; EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; EP_RX_MAX_LEN(ep) = 0; } - USBHSD->UEP0_DMA = (uint32_t) ep0_buffer; - USBHSD->UEP0_MAX_LEN = CFG_TUD_ENDPOINT0_SIZE; + USBHSD->UEP0_DMA = (uint32_t)ep0_buffer; + USBHSD->UEP0_MAX_LEN = CFG_TUD_ENDPOINT0_SIZE; xfer_status[0][TUSB_DIR_OUT].max_size = CFG_TUD_ENDPOINT0_SIZE; - xfer_status[0][TUSB_DIR_IN].max_size = CFG_TUD_ENDPOINT0_SIZE; + xfer_status[0][TUSB_DIR_IN].max_size = CFG_TUD_ENDPOINT0_SIZE; USBHSD->DEV_AD = 0; USBHSD->CONTROL |= USBHS_DEV_PU_EN; @@ -177,20 +177,20 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { } void dcd_int_enable(uint8_t rhport) { - (void) rhport; + (void)rhport; NVIC_EnableIRQ(USBHS_IRQn); } void dcd_int_disable(uint8_t rhport) { - (void) rhport; + (void)rhport; NVIC_DisableIRQ(USBHS_IRQn); } void dcd_edpt_close_all(uint8_t rhport) { - (void) rhport; + (void)rhport; for (size_t ep = 1; ep < EP_MAX; ep++) { - EP_TX_LEN(ep) = 0; + EP_TX_LEN(ep) = 0; EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK; EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; @@ -201,18 +201,18 @@ void dcd_edpt_close_all(uint8_t rhport) { } void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { - (void) dev_addr; + (void)dev_addr; // Response with zlp status dcd_edpt_xfer(rhport, 0x80, NULL, 0, false); } void dcd_remote_wakeup(uint8_t rhport) { - (void) rhport; + (void)rhport; } void dcd_sof_enable(uint8_t rhport, bool en) { - (void) rhport; + (void)rhport; if (en) { USBHSD->INT_EN |= USBHS_SOF_ACT_EN; } else { @@ -220,24 +220,23 @@ void dcd_sof_enable(uint8_t rhport, bool en) { } } -void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) { - (void) rhport; +void dcd_edpt0_status_complete(uint8_t rhport, const tusb_control_request_t *request) { + (void)rhport; if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && - request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && - request->bRequest == TUSB_REQ_SET_ADDRESS) { - USBHSD->DEV_AD = (uint8_t) request->wValue; + request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) { + USBHSD->DEV_AD = (uint8_t)request->wValue; } EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; EP_RX_CTRL(0) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0; } -bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) { - (void) rhport; +bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_edpt) { + (void)rhport; - uint8_t const ep_num = tu_edpt_number(desc_edpt->bEndpointAddress); - tusb_dir_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress); + const uint8_t ep_num = tu_edpt_number(desc_edpt->bEndpointAddress); + const tusb_dir_t dir = tu_edpt_dir(desc_edpt->bEndpointAddress); TU_ASSERT(ep_num < EP_MAX); @@ -245,8 +244,8 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) { return true; } - xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, dir); - xfer->max_size = tu_edpt_packet_size(desc_edpt); + xfer_ctl_t *xfer = XFER_CTL_BASE(ep_num, dir); + xfer->max_size = tu_edpt_packet_size(desc_edpt); xfer->is_iso = (desc_edpt->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS); if (dir == TUSB_DIR_OUT) { @@ -263,7 +262,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) { /* Enable all types except Isochronous to avoid ISO_ACT interrupt generation */ USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num); } - EP_TX_LEN(ep_num) = 0; + EP_TX_LEN(ep_num) = 0; EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; } @@ -271,19 +270,19 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) { } void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { - (void) rhport; + (void)rhport; - uint8_t const ep_num = tu_edpt_number(ep_addr); - tusb_dir_t const dir = tu_edpt_dir(ep_addr); + const uint8_t ep_num = tu_edpt_number(ep_addr); + const tusb_dir_t dir = tu_edpt_dir(ep_addr); if (dir == TUSB_DIR_OUT) { - EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; + EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; EP_RX_MAX_LEN(ep_num) = 0; USBHSD->ENDP_TYPE &= ~(USBHS_EP0_R_TYP << ep_num); USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_R_EN << ep_num); - } else { // TUSB_DIR_IN + } else { // TUSB_DIR_IN EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; - EP_TX_LEN(ep_num) = 0; + EP_TX_LEN(ep_num) = 0; USBHSD->ENDP_TYPE &= ~(USBHS_EP0_T_TYP << ep_num); USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_T_EN << ep_num); } @@ -305,24 +304,24 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) #endif void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { - (void) rhport; + (void)rhport; - uint8_t const ep_num = tu_edpt_number(ep_addr); - tusb_dir_t const dir = tu_edpt_dir(ep_addr); + const uint8_t ep_num = tu_edpt_number(ep_addr); + const tusb_dir_t dir = tu_edpt_dir(ep_addr); if (dir == TUSB_DIR_OUT) { EP_RX_CTRL(ep_num) = USBHS_EP_R_RES_STALL; } else { - EP_TX_LEN(0) = 0; + EP_TX_LEN(0) = 0; EP_TX_CTRL(ep_num) = USBHS_EP_T_RES_STALL; } } void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { - (void) rhport; + (void)rhport; - uint8_t const ep_num = tu_edpt_number(ep_addr); - tusb_dir_t const dir = tu_edpt_dir(ep_addr); + const uint8_t ep_num = tu_edpt_number(ep_addr); + const tusb_dir_t dir = tu_edpt_dir(ep_addr); if (dir == TUSB_DIR_OUT) { EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; @@ -331,16 +330,16 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { } } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) { - (void) is_isr; - (void) rhport; - uint8_t const ep_num = tu_edpt_number(ep_addr); - tusb_dir_t const dir = tu_edpt_dir(ep_addr); +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool is_isr) { + (void)is_isr; + (void)rhport; + const uint8_t ep_num = tu_edpt_number(ep_addr); + const tusb_dir_t dir = tu_edpt_dir(ep_addr); - xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, dir); - xfer->buffer = buffer; - xfer->total_len = total_bytes; - xfer->queued_len = 0; + xfer_ctl_t *xfer = XFER_CTL_BASE(ep_num, dir); + xfer->buffer = buffer; + xfer->total_len = total_bytes; + xfer->queued_len = 0; xfer->is_last_packet = false; xfer_data_packet(ep_num, dir, xfer); @@ -349,22 +348,22 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t } void dcd_int_handler(uint8_t rhport) { - (void) rhport; + (void)rhport; - uint8_t int_flag = USBHSD->INT_FG; + uint8_t int_flag = USBHSD->INT_FG; uint8_t int_status = USBHSD->INT_ST; if (int_flag & (USBHS_ISO_ACT_FLAG | USBHS_TRANSFER_FLAG)) { - uint8_t const token = int_status & MASK_UIS_TOKEN; + const uint8_t token = int_status & MASK_UIS_TOKEN; if (token == USBHS_TOKEN_PID_SOF) { uint32_t frame_count = USBHSD->FRAME_NO & USBHS_FRAME_NO_NUM_MASK; dcd_event_sof(rhport, frame_count, true); - }else { - uint8_t const ep_num = int_status & MASK_UIS_ENDP; - tusb_dir_t const ep_dir = (token == USBHS_TOKEN_PID_IN) ? TUSB_DIR_IN : TUSB_DIR_OUT; - uint8_t const ep_addr = tu_edpt_addr(ep_num, ep_dir); - xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, ep_dir); + } else { + const uint8_t ep_num = int_status & MASK_UIS_ENDP; + const tusb_dir_t ep_dir = (token == USBHS_TOKEN_PID_IN) ? TUSB_DIR_IN : TUSB_DIR_OUT; + const uint8_t ep_addr = tu_edpt_addr(ep_num, ep_dir); + xfer_ctl_t *xfer = XFER_CTL_BASE(ep_num, ep_dir); if (token == USBHS_TOKEN_PID_OUT) { uint16_t rx_len = USBHSD->RX_LEN; @@ -405,28 +404,28 @@ void dcd_int_handler(uint8_t rhport) { } else if (int_flag & USBHS_BUS_RST_FLAG) { // TODO CH32 does not detect actual speed at this time (should be known at end of reset) // This interrupt probably triggered at start of bus reset -// tusb_speed_t actual_speed; -// switch(USBHSD->SPEED_TYPE & USBHS_SPEED_TYPE_MASK){ -// case USBHS_SPEED_TYPE_HIGH: -// actual_speed = TUSB_SPEED_HIGH; -// break; -// case USBHS_SPEED_TYPE_FULL: -// actual_speed = TUSB_SPEED_FULL; -// break; -// case USBHS_SPEED_TYPE_LOW: -// actual_speed = TUSB_SPEED_LOW; -// break; -// default: -// TU_ASSERT(0,); -// break; -// } -// dcd_event_bus_reset(0, actual_speed, true); + // tusb_speed_t actual_speed; + // switch(USBHSD->SPEED_TYPE & USBHS_SPEED_TYPE_MASK){ + // case USBHS_SPEED_TYPE_HIGH: + // actual_speed = TUSB_SPEED_HIGH; + // break; + // case USBHS_SPEED_TYPE_FULL: + // actual_speed = TUSB_SPEED_FULL; + // break; + // case USBHS_SPEED_TYPE_LOW: + // actual_speed = TUSB_SPEED_LOW; + // break; + // default: + // TU_ASSERT(0,); + // break; + // } + // dcd_event_bus_reset(0, actual_speed, true); dcd_event_bus_reset(0, TUSB_SPEED_HIGH, true); USBHSD->DEV_AD = 0; - EP_RX_CTRL(0) = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0; - EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; + EP_RX_CTRL(0) = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0; + EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; USBHSD->INT_FG = USBHS_BUS_RST_FLAG; /* Clear flag */ } else if (int_flag & USBHS_SUSPEND_FLAG) { -- cgit v1.3.1 From 08cd5c3270e79ed2e63c8941c13c84027a5c003e Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 23 May 2026 17:45:16 +0200 Subject: dcd/ch32fs: clear INT flag after processing Signed-off-by: HiFiPhile --- src/portable/wch/dcd_ch32_usbfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/portable/wch') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 37677276c..4ecaf129e 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -183,7 +183,6 @@ void dcd_int_handler(uint8_t rhport) { uint8_t ep = USBFS_INT_ST_MASK_UIS_ENDP(USBOTG_FS->INT_ST); uint8_t token = USBFS_INT_ST_MASK_UIS_TOKEN(USBOTG_FS->INT_ST); uint16_t rx_len = USBOTG_FS->RX_LEN; - USBOTG_FS->INT_FG = USBFS_INT_FG_TRANSFER; switch (token) { case PID_OUT: { @@ -207,6 +206,7 @@ void dcd_int_handler(uint8_t rhport) { break; } + USBOTG_FS->INT_FG = USBFS_INT_FG_TRANSFER; } else if (status & USBFS_INT_FG_BUS_RST) { data.ep0_tog = true; data.xfer[0][TUSB_DIR_OUT].max_size = 64; -- cgit v1.3.1 From c6beac24ca280ce13e538f0b9459553abc825571 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 23 May 2026 19:21:59 +0200 Subject: dcd/ch32fs: do not set EP0 to ACK on status complete It would casue race condition, SETUP packet is always acked. Signed-off-by: HiFiPhile --- src/portable/wch/dcd_ch32_usbfs.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/portable/wch') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 4ecaf129e..ca3ce7ba8 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -273,8 +273,6 @@ void dcd_edpt0_status_complete(uint8_t rhport, const tusb_control_request_t *req request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) { USBOTG_FS->DEV_ADDR = (uint8_t)request->wValue; } - EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK; - EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; } bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { -- cgit v1.3.1 From 420de14b50dc2b9c1ed7ba587ef22eb227739eee Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 23 May 2026 19:30:22 +0200 Subject: dcd/ch32hs: refactor transfer flow Refactor the driver to follow USBFS style for easier maintenance. Replace the old packet/response helpers with explicit queue and update paths for IN and OUT transfers. Introduce transfer validity tracking and per-endpoint data toggle state. Reset toggle state on init, close-all, endpoint close, clear-stall, and bus reset. Initialize endpoint controls consistently in NAK + TOG_0 mode. Tighten EP0 setup/status handling and route transfer IRQ processing through the transfer-flag path. Stop enabling ISO_ACT in INT_EN and clear unhandled interrupt flags explicitly. Signed-off-by: HiFiPhile --- src/portable/wch/dcd_ch32_usbhs.c | 282 ++++++++++++++++++++++---------------- 1 file changed, 163 insertions(+), 119 deletions(-) (limited to 'src/portable/wch') diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c index 01ff6eba3..cfe5e646f 100644 --- a/src/portable/wch/dcd_ch32_usbhs.c +++ b/src/portable/wch/dcd_ch32_usbhs.c @@ -24,7 +24,6 @@ * * This file is part of the TinyUSB stack. */ - #include "tusb_option.h" #if CFG_TUD_ENABLED && defined(TUP_USBIP_WCH_USBHS) && defined(CFG_TUD_WCH_USBIP_USBHS) && \ @@ -41,15 +40,10 @@ typedef struct { uint16_t total_len; uint16_t queued_len; uint16_t max_size; - bool is_last_packet; bool is_iso; + bool valid; } xfer_ctl_t; -typedef enum { - EP_RESPONSE_ACK, - EP_RESPONSE_NAK, -} ep_response_list_t; - #define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir] static xfer_ctl_t xfer_status[EP_MAX][2]; @@ -63,73 +57,127 @@ static xfer_ctl_t xfer_status[EP_MAX][2]; /* Endpoint Buffer */ TU_ATTR_ALIGNED(4) static uint8_t ep0_buffer[CFG_TUD_ENDPOINT0_SIZE]; +static bool ep0_tog; +static bool ep_data_tog[EP_MAX][2]; -static void ep_set_response_and_toggle(uint8_t ep_num, tusb_dir_t ep_dir, ep_response_list_t response_type) { +static void set_ep_toggle(uint8_t ep_num, tusb_dir_t ep_dir, bool data1) { if (ep_dir == TUSB_DIR_IN) { - uint8_t response = (response_type == EP_RESPONSE_ACK) ? USBHS_EP_T_RES_ACK : USBHS_EP_T_RES_NAK; - if (ep_num == 0) { - if (response_type == EP_RESPONSE_ACK) { - if (EP_TX_LEN(ep_num) == 0) { - EP_TX_CTRL(ep_num) |= USBHS_EP_T_TOG_1; - } else { - EP_TX_CTRL(ep_num) ^= USBHS_EP_T_TOG_1; - } - } - } - if (xfer_status[ep_num][TUSB_DIR_IN].is_iso == true) { - EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG; - } else { - EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | response; - } + EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_TOG_MASK)) | + (data1 ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0); } else { - uint8_t response = (response_type == EP_RESPONSE_ACK) ? USBHS_EP_R_RES_ACK : USBHS_EP_R_RES_NAK; - if (ep_num == 0) { - if (response_type == EP_RESPONSE_ACK) { - if (xfer_status[ep_num][TUSB_DIR_OUT].queued_len == 0) { - EP_RX_CTRL(ep_num) |= USBHS_EP_R_TOG_1; - } - } else { - EP_RX_CTRL(ep_num) ^= USBHS_EP_R_TOG_1; - } - } - EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_RES_MASK)) | response; + EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_TOG_MASK)) | + (data1 ? USBHS_EP_R_TOG_1 : USBHS_EP_R_TOG_0); } } -static void xfer_data_packet(uint8_t ep_num, tusb_dir_t ep_dir, xfer_ctl_t *xfer) { - if (ep_dir == TUSB_DIR_IN) { - uint16_t remaining = xfer->total_len - xfer->queued_len; - uint16_t next_tx_size = TU_MIN(remaining, xfer->max_size); +static void queue_in_packet(uint8_t ep_num, xfer_ctl_t* xfer) { + uint16_t remaining = xfer->total_len - xfer->queued_len; + uint16_t tx_len = TU_MIN(remaining, xfer->max_size); - if (ep_num == 0) { - memcpy(ep0_buffer, &xfer->buffer[xfer->queued_len], next_tx_size); - } else { - EP_TX_DMA_ADDR(ep_num) = (uint32_t)&xfer->buffer[xfer->queued_len]; - } + if (ep_num == 0) { + memcpy(ep0_buffer, &xfer->buffer[xfer->queued_len], tx_len); + } else { + EP_TX_DMA_ADDR(ep_num) = (uint32_t) &xfer->buffer[xfer->queued_len]; + } - EP_TX_LEN(ep_num) = next_tx_size; - xfer->queued_len += next_tx_size; - if (xfer->queued_len == xfer->total_len) { - xfer->is_last_packet = true; - } - if (xfer->is_iso == true) { - /* Enable EP to generate ISA_ACT interrupt */ - USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num); - } - } else { /* TUSB_DIR_OUT */ - uint16_t left_to_receive = xfer->total_len - xfer->queued_len; - uint16_t max_possible_rx_size = TU_MIN(xfer->max_size, left_to_receive); + EP_TX_LEN(ep_num) = tx_len; + xfer->queued_len += tx_len; + + if (ep_num == 0) { + EP_TX_CTRL(0) = USBHS_EP_T_RES_ACK | (ep0_tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0); + ep0_tog = !ep0_tog; + } else if (xfer->is_iso) { + EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_NYET; + } else { + set_ep_toggle(ep_num, TUSB_DIR_IN, ep_data_tog[ep_num][TUSB_DIR_IN]); + EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_ACK; + } +} - if (max_possible_rx_size == left_to_receive) { - xfer->is_last_packet = true; +static void queue_out_packet(uint8_t ep_num, xfer_ctl_t* xfer) { + uint16_t remaining = xfer->total_len - xfer->queued_len; + uint16_t rx_len = TU_MIN(remaining, xfer->max_size); + + if (ep_num > 0) { + EP_RX_DMA_ADDR(ep_num) = (uint32_t) &xfer->buffer[xfer->queued_len]; + EP_RX_MAX_LEN(ep_num) = rx_len; + } + + if (ep_num == 0) { + EP_RX_CTRL(0) = (EP_RX_CTRL(0) & ~(USBHS_EP_R_RES_MASK)) | USBHS_EP_R_RES_ACK; + } else if (xfer->is_iso) { + EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_RES_MASK)) | USBHS_EP_R_RES_NYET; + } else { + set_ep_toggle(ep_num, TUSB_DIR_OUT, ep_data_tog[ep_num][TUSB_DIR_OUT]); + EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_RES_MASK)) | USBHS_EP_R_RES_ACK; + } +} + +static void update_in(uint8_t rhport, uint8_t ep_num, bool force) { + xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, TUSB_DIR_IN); + if (!xfer->valid) { + return; + } + + if (!force && ep_num != 0 && !xfer->is_iso) { + ep_data_tog[ep_num][TUSB_DIR_IN] = !ep_data_tog[ep_num][TUSB_DIR_IN]; + } + + if (ep_num == 0) { + EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | (ep0_tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0); + } else if (!xfer->is_iso) { + EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_NAK; + } + + if (force || (xfer->total_len > xfer->queued_len)) { + queue_in_packet(ep_num, xfer); + } else { + xfer->valid = false; + if (ep_num != 0) { + EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_NAK; } + dcd_event_xfer_complete(rhport, ep_num | TUSB_DIR_IN_MASK, xfer->queued_len, XFER_RESULT_SUCCESS, true); + } +} + +static void update_out(uint8_t rhport, uint8_t ep_num, uint16_t rx_len) { + xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, TUSB_DIR_OUT); + if (!xfer->valid) { + return; + } + + if (ep_num == 0) { + EP_RX_CTRL(0) = (EP_RX_CTRL(0) & ~(USBHS_EP_R_RES_MASK)) | USBHS_EP_R_RES_NAK; + } else if (!xfer->is_iso) { + EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_RES_MASK)) | USBHS_EP_R_RES_NAK; + } - if (ep_num > 0) { - EP_RX_DMA_ADDR(ep_num) = (uint32_t)&xfer->buffer[xfer->queued_len]; - EP_RX_MAX_LEN(ep_num) = max_possible_rx_size; + uint16_t remaining = xfer->total_len - xfer->queued_len; + uint16_t len = TU_MIN(rx_len, TU_MIN(remaining, xfer->max_size)); + + if (ep_num == 0) { + memcpy(&xfer->buffer[xfer->queued_len], ep0_buffer, len); + } + + xfer->queued_len += len; + + if (ep_num != 0 && !xfer->is_iso) { + ep_data_tog[ep_num][TUSB_DIR_OUT] = !ep_data_tog[ep_num][TUSB_DIR_OUT]; + } + + if ((xfer->queued_len == xfer->total_len) || (len < xfer->max_size)) { + xfer->valid = false; + dcd_event_xfer_complete(rhport, ep_num, xfer->queued_len, XFER_RESULT_SUCCESS, true); + } + + if (ep_num != 0) { + if (xfer->valid) { + queue_out_packet(ep_num, xfer); + } else { + uint8_t rx_res = xfer->is_iso ? USBHS_EP_R_RES_NYET : USBHS_EP_R_RES_NAK; + EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_RES_MASK)) | rx_res; } } - ep_set_response_and_toggle(ep_num, ep_dir, USBHS_EP_R_RES_ACK); } bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { @@ -137,6 +185,8 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { (void)rh_init; memset(&xfer_status, 0, sizeof(xfer_status)); + memset(ep_data_tog, 0, sizeof(ep_data_tog)); + ep0_tog = true; USBHSD->HOST_CTRL = 0x00; USBHSD->HOST_CTRL = USBHS_PHY_SUSPENDM; @@ -151,7 +201,7 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { #endif USBHSD->INT_EN = 0; - USBHSD->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_BUS_RST_EN | USBHS_SUSPEND_EN | USBHS_ISO_ACT_EN; + USBHSD->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_BUS_RST_EN | USBHS_SUSPEND_EN; USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN; USBHSD->ENDP_TYPE = 0x00; @@ -159,8 +209,8 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { for (int ep = 0; ep < EP_MAX; ep++) { EP_TX_LEN(ep) = 0; - EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK; - EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; + EP_TX_CTRL(ep) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; + EP_RX_CTRL(ep) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0; EP_RX_MAX_LEN(ep) = 0; } @@ -189,10 +239,12 @@ void dcd_int_disable(uint8_t rhport) { void dcd_edpt_close_all(uint8_t rhport) { (void)rhport; + memset(ep_data_tog, 0, sizeof(ep_data_tog)); + for (size_t ep = 1; ep < EP_MAX; ep++) { EP_TX_LEN(ep) = 0; - EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK; - EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; + EP_TX_CTRL(ep) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; + EP_RX_CTRL(ep) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0; EP_RX_MAX_LEN(ep) = 0; } @@ -222,14 +274,10 @@ void dcd_sof_enable(uint8_t rhport, bool en) { void dcd_edpt0_status_complete(uint8_t rhport, const tusb_control_request_t *request) { (void)rhport; - if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) { USBHSD->DEV_AD = (uint8_t)request->wValue; } - - EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; - EP_RX_CTRL(0) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0; } bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_edpt) { @@ -246,11 +294,12 @@ bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_edpt) { xfer_ctl_t *xfer = XFER_CTL_BASE(ep_num, dir); xfer->max_size = tu_edpt_packet_size(desc_edpt); + ep_data_tog[ep_num][dir] = false; xfer->is_iso = (desc_edpt->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS); if (dir == TUSB_DIR_OUT) { USBHSD->ENDP_CONFIG |= (USBHS_EP0_R_EN << ep_num); - EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; + EP_RX_CTRL(ep_num) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0; if (xfer->is_iso == true) { USBHSD->ENDP_TYPE |= (USBHS_EP0_R_TYP << ep_num); } @@ -258,12 +307,10 @@ bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_edpt) { } else { if (xfer->is_iso == true) { USBHSD->ENDP_TYPE |= (USBHS_EP0_T_TYP << ep_num); - } else { - /* Enable all types except Isochronous to avoid ISO_ACT interrupt generation */ - USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num); } + USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num); EP_TX_LEN(ep_num) = 0; - EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; + EP_TX_CTRL(ep_num) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; } return true; @@ -276,13 +323,15 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { const tusb_dir_t dir = tu_edpt_dir(ep_addr); if (dir == TUSB_DIR_OUT) { - EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; + EP_RX_CTRL(ep_num) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0; EP_RX_MAX_LEN(ep_num) = 0; + ep_data_tog[ep_num][TUSB_DIR_OUT] = false; USBHSD->ENDP_TYPE &= ~(USBHS_EP0_R_TYP << ep_num); USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_R_EN << ep_num); } else { // TUSB_DIR_IN - EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; + EP_TX_CTRL(ep_num) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; EP_TX_LEN(ep_num) = 0; + ep_data_tog[ep_num][TUSB_DIR_IN] = false; USBHSD->ENDP_TYPE &= ~(USBHS_EP0_T_TYP << ep_num); USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_T_EN << ep_num); } @@ -324,9 +373,11 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { const tusb_dir_t dir = tu_edpt_dir(ep_addr); if (dir == TUSB_DIR_OUT) { - EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK; + EP_RX_CTRL(ep_num) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0; + ep_data_tog[ep_num][TUSB_DIR_OUT] = false; } else { - EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_R_RES_NAK; + EP_TX_CTRL(ep_num) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; + ep_data_tog[ep_num][TUSB_DIR_IN] = false; } } @@ -340,9 +391,21 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to xfer->buffer = buffer; xfer->total_len = total_bytes; xfer->queued_len = 0; - xfer->is_last_packet = false; + xfer->valid = true; + + if (ep_num == 0 && dir == TUSB_DIR_OUT) { + if (total_bytes == 0) { + EP_RX_CTRL(0) = (EP_RX_CTRL(0) & ~(USBHS_EP_R_TOG_MASK)) | USBHS_EP_R_TOG_1; + } else { + EP_RX_CTRL(0) ^= USBHS_EP_R_TOG_1; + } + } - xfer_data_packet(ep_num, dir, xfer); + if (dir == TUSB_DIR_IN) { + update_in(rhport, ep_num, true); + } else { + queue_out_packet(ep_num, xfer); + } return true; } @@ -353,51 +416,27 @@ void dcd_int_handler(uint8_t rhport) { uint8_t int_flag = USBHSD->INT_FG; uint8_t int_status = USBHSD->INT_ST; - if (int_flag & (USBHS_ISO_ACT_FLAG | USBHS_TRANSFER_FLAG)) { + if (int_flag & USBHS_TRANSFER_FLAG) { const uint8_t token = int_status & MASK_UIS_TOKEN; + const uint8_t ep_num = int_status & MASK_UIS_ENDP; + const uint16_t len = USBHSD->RX_LEN; if (token == USBHS_TOKEN_PID_SOF) { uint32_t frame_count = USBHSD->FRAME_NO & USBHS_FRAME_NO_NUM_MASK; dcd_event_sof(rhport, frame_count, true); - } else { - const uint8_t ep_num = int_status & MASK_UIS_ENDP; - const tusb_dir_t ep_dir = (token == USBHS_TOKEN_PID_IN) ? TUSB_DIR_IN : TUSB_DIR_OUT; - const uint8_t ep_addr = tu_edpt_addr(ep_num, ep_dir); - xfer_ctl_t *xfer = XFER_CTL_BASE(ep_num, ep_dir); - - if (token == USBHS_TOKEN_PID_OUT) { - uint16_t rx_len = USBHSD->RX_LEN; - - if (ep_num == 0) { - memcpy(&xfer->buffer[xfer->queued_len], ep0_buffer, rx_len); - } - - xfer->queued_len += rx_len; - if (rx_len < xfer->max_size) { - xfer->is_last_packet = true; - } - } else if (token == USBHS_TOKEN_PID_IN) { - if (xfer->is_iso && xfer->is_last_packet) { - /* Disable EP to avoid ISO_ACT interrupt generation */ - USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_T_EN << ep_num); - } else { - // Do nothing, no need to update xfer->is_last_packet, it is already updated in xfer_data_packet - } - } - - if (xfer->is_last_packet == true) { - ep_set_response_and_toggle(ep_num, ep_dir, EP_RESPONSE_NAK); - dcd_event_xfer_complete(0, ep_addr, xfer->queued_len, XFER_RESULT_SUCCESS, true); - } else { - /* prepare next part of packet to xref */ - xfer_data_packet(ep_num, ep_dir, xfer); - } + } else if (token == USBHS_TOKEN_PID_OUT) { + update_out(rhport, ep_num, len); + } else if (token == USBHS_TOKEN_PID_IN) { + update_in(rhport, ep_num, false); } - - USBHSD->INT_FG = (int_flag & (USBHS_ISO_ACT_FLAG | USBHS_TRANSFER_FLAG)); /* Clear flag */ + USBHSD->INT_FG = (int_flag & USBHS_TRANSFER_FLAG); /* Clear flag */ } else if (int_flag & USBHS_SETUP_FLAG) { - ep_set_response_and_toggle(0, TUSB_DIR_IN, EP_RESPONSE_NAK); - ep_set_response_and_toggle(0, TUSB_DIR_OUT, EP_RESPONSE_NAK); + tusb_control_request_t const* setup = + (tusb_control_request_t const*) ep0_buffer; + ep0_tog = true; + EP_RX_CTRL(0) = (setup->wLength == 0) ? USBHS_EP_R_RES_ACK : USBHS_EP_R_RES_NAK; + EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK; + dcd_event_setup_received(0, ep0_buffer, true); USBHSD->INT_FG = USBHS_SETUP_FLAG; /* Clear flag */ @@ -424,6 +463,8 @@ void dcd_int_handler(uint8_t rhport) { dcd_event_bus_reset(0, TUSB_SPEED_HIGH, true); USBHSD->DEV_AD = 0; + memset(ep_data_tog, 0, sizeof(ep_data_tog)); + ep0_tog = true; EP_RX_CTRL(0) = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0; EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; @@ -433,6 +474,9 @@ void dcd_int_handler(uint8_t rhport) { dcd_event_handler(&event, true); USBHSD->INT_FG = USBHS_SUSPEND_FLAG; /* Clear flag */ + } else { + // Unhandled interrupt + USBHSD->INT_FG = int_flag; /* Clear all flags */ } } #endif -- cgit v1.3.1 From 311fb46eb2f963254af6ab206b74828a0ba0273c Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 23 May 2026 20:06:50 +0200 Subject: dcd/ch32x: optmize CTRL reg writing, basically revert e14b0e85 Signed-off-by: HiFiPhile --- src/portable/wch/dcd_ch32_usbfs.c | 26 +++++++++----------------- src/portable/wch/dcd_ch32_usbhs.c | 19 ++++++------------- 2 files changed, 15 insertions(+), 30 deletions(-) (limited to 'src/portable/wch') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index ca3ce7ba8..af0f17785 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -66,13 +66,6 @@ static struct { static void update_in(uint8_t rhport, uint8_t ep, bool force) { struct usb_xfer *xfer = &data.xfer[ep][TUSB_DIR_IN]; if (xfer->valid) { - // Set EP to NAK to avoid spurious tramsfer - if (ep == 0) { - EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK | (data.ep0_tog ? USBFS_EP_T_TOG : 0); - } else if (!data.isochronous[ep]) { - EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NAK; - } - if (force || xfer->len) { size_t len = TU_MIN(xfer->max_size, xfer->len); if (ep == 0) { @@ -96,8 +89,12 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force) { EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_ACK; } } else { - xfer->valid = false; - EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NAK; + xfer->valid = false; + if (ep == 0) { + EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK | (data.ep0_tog ? USBFS_EP_T_TOG : 0); + } else if (!data.isochronous[ep]) { + EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NAK; + } dcd_event_xfer_complete(rhport, ep | TUSB_DIR_IN_MASK, xfer->processed_len, XFER_RESULT_SUCCESS, true); } } @@ -106,13 +103,6 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force) { static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { struct usb_xfer *xfer = &data.xfer[ep][TUSB_DIR_OUT]; if (xfer->valid) { - // Set EP to NAK to avoid spurious tramsfer - if (ep == 0) { - EP_RX_CTRL(0) = USBFS_EP_R_RES_NAK; - } else if (!data.isochronous[ep]) { - EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | USBFS_EP_R_RES_NAK; - } - size_t len = TU_MIN(xfer->max_size, TU_MIN(xfer->len, rx_len)); if (ep == 3) { memcpy(xfer->buffer, data.ep3_buffer.out, len); @@ -128,7 +118,9 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { dcd_event_xfer_complete(rhport, ep, xfer->processed_len, XFER_RESULT_SUCCESS, true); } - if (ep != 0) { + if (ep == 0) { + EP_RX_CTRL(0) = USBFS_EP_R_RES_NAK; + } else { uint8_t rx_res = data.isochronous[ep] ? USBFS_EP_R_RES_NYET : (xfer->valid ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK); EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | rx_res; diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c index cfe5e646f..a6dd5bb79 100644 --- a/src/portable/wch/dcd_ch32_usbhs.c +++ b/src/portable/wch/dcd_ch32_usbhs.c @@ -123,17 +123,13 @@ static void update_in(uint8_t rhport, uint8_t ep_num, bool force) { ep_data_tog[ep_num][TUSB_DIR_IN] = !ep_data_tog[ep_num][TUSB_DIR_IN]; } - if (ep_num == 0) { - EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | (ep0_tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0); - } else if (!xfer->is_iso) { - EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_NAK; - } - if (force || (xfer->total_len > xfer->queued_len)) { queue_in_packet(ep_num, xfer); } else { xfer->valid = false; - if (ep_num != 0) { + if (ep_num == 0) { + EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | (ep0_tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0); + } else { EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_NAK; } dcd_event_xfer_complete(rhport, ep_num | TUSB_DIR_IN_MASK, xfer->queued_len, XFER_RESULT_SUCCESS, true); @@ -146,12 +142,6 @@ static void update_out(uint8_t rhport, uint8_t ep_num, uint16_t rx_len) { return; } - if (ep_num == 0) { - EP_RX_CTRL(0) = (EP_RX_CTRL(0) & ~(USBHS_EP_R_RES_MASK)) | USBHS_EP_R_RES_NAK; - } else if (!xfer->is_iso) { - EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_RES_MASK)) | USBHS_EP_R_RES_NAK; - } - uint16_t remaining = xfer->total_len - xfer->queued_len; uint16_t len = TU_MIN(rx_len, TU_MIN(remaining, xfer->max_size)); @@ -167,6 +157,9 @@ static void update_out(uint8_t rhport, uint8_t ep_num, uint16_t rx_len) { if ((xfer->queued_len == xfer->total_len) || (len < xfer->max_size)) { xfer->valid = false; + if (ep_num == 0) { + EP_RX_CTRL(0) = (EP_RX_CTRL(0) & ~(USBHS_EP_R_RES_MASK)) | USBHS_EP_R_RES_NAK; + } dcd_event_xfer_complete(rhport, ep_num, xfer->queued_len, XFER_RESULT_SUCCESS, true); } -- cgit v1.3.1 From d63a45509fd283f5ffccc29cd8569e6efd075c59 Mon Sep 17 00:00:00 2001 From: Jie Feng Date: Thu, 21 May 2026 14:52:38 +0800 Subject: ch32_usbhs: fix endpoint stall length index and clear-stall response Fix issue in the stall handling: - dcd_edpt_stall() for an IN endpoint cleared EP_TX_LEN(0) instead of EP_TX_LEN(ep_num), clobbering endpoint 0's transmit length register when stalling any other IN endpoint. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/portable/wch/dcd_ch32_usbhs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/portable/wch') diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c index a6dd5bb79..ea3b052ad 100644 --- a/src/portable/wch/dcd_ch32_usbhs.c +++ b/src/portable/wch/dcd_ch32_usbhs.c @@ -354,7 +354,7 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { if (dir == TUSB_DIR_OUT) { EP_RX_CTRL(ep_num) = USBHS_EP_R_RES_STALL; } else { - EP_TX_LEN(0) = 0; + EP_TX_LEN(ep_num) = 0; EP_TX_CTRL(ep_num) = USBHS_EP_T_RES_STALL; } } -- cgit v1.3.1 From ad8cbc4668ab8d92e2eebb834c230e9d18ad8e57 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 18 Jun 2026 10:58:58 +0700 Subject: dcd/ch32_usbfs: support CH32V103 combined endpoint control register CH32V103 uses the older USBFS IP: a single combined UEPn_CTRL register per endpoint (IN response in bits [1:0], OUT response in [3:2], shared auto-toggle, separate IN/OUT toggles) instead of the separate UEPn_TX_CTRL/UEPn_RX_CTRL bytes of the newer IP (CH32V20x/V307). The shared driver was written for the newer IP, so EP0 control transfers never worked on V103: the OUT response was written to a reserved byte and the IN write clobbered the OUT bits. - ch32_usbfs_reg.h: annotate the V103 register struct with byte offsets and add a union exposing the combined UEPn_CTRL at the UEPn_TX_CTRL offset; define CH32_USBFS_EP_CTRL_COMBINED and the combined-register bit positions. - dcd_ch32_usbfs.c: abstract EP control access behind ep_tx/rx_ctrl_set() (full write) and ep_tx/rx_set_response() (response-only RMW). The newer-IP path is unchanged; the combined path read-modify-writes the single register and arms the post-SETUP data stage at DATA1. - bsp/ch32v10x: implement board_get_unique_id() (real chip UID) and drop the CSR 0x800 writes that corrupted the QingKe V3 interrupt config and left all interrupts disabled (the USB ISR never ran). Verified on ch32v103r_r1_1v0: enumerates and passes HIL for cdc_msc, hid, msc, midi, mtp, dfu, etc. Co-Authored-By: Claude Opus 4.8 (1M context) --- hw/bsp/ch32v10x/family.c | 39 +++++------ src/portable/wch/ch32_usbfs_reg.h | 140 +++++++++++++++++++++++++------------- src/portable/wch/dcd_ch32_usbfs.c | 95 +++++++++++++++++++------- 3 files changed, 181 insertions(+), 93 deletions(-) (limited to 'src/portable/wch') diff --git a/hw/bsp/ch32v10x/family.c b/hw/bsp/ch32v10x/family.c index 9f5dc5572..aa709b0d8 100644 --- a/hw/bsp/ch32v10x/family.c +++ b/hw/bsp/ch32v10x/family.c @@ -66,26 +66,14 @@ uint32_t tusb_time_millis_api(void) { } #endif -// 0x800 CSR register is writable in U-mode -// according to manual: https://www.wch-ic.com/downloads/QingKeV3_Processor_Manual_PDF.html -__attribute__((always_inline)) RV_STATIC_INLINE -void __wch_vendor_enable_irq(void) -{ - __asm volatile ("csrs 0x800, %0" : : "r" (0x88) ); -} - -__attribute__((always_inline)) RV_STATIC_INLINE -void __wch_vendor_disable_irq(void) -{ - __asm volatile ("csrc 0x800, %0" : : "r" (0x88) ); - __asm volatile ("fence.i"); -} - void board_init(void) { - /* __disable_irq() in CH32V103 EVT attempts to call - * `csrc mstatus, 0x88` in U-mode, which is allowed ONLY in M-mode. - * Replace this with CSR 0x800 to avoid hard-fault. */ - __wch_vendor_disable_irq(); + /* Do NOT toggle the global interrupt enable here. + * CH32V103 startup enters U-mode (mret with mstatus.MPP=0), so: + * - the SDK __disable_irq()/__enable_irq() write mstatus, which faults in U-mode; + * - writing CSR 0x800 (INTSYSCR) corrupts the QingKe V3 interrupt-mode config, + * which made the USB interrupt vector to a bad address (PC=0) and hang. + * The startup already leaves interrupts correctly configured, and machine-mode + * interrupts are globally enabled while running in U-mode regardless of mstatus.MIE. */ #if CFG_TUSB_OS == OPT_OS_NONE SysTick_Config(SystemCoreClock / 1000); @@ -142,8 +130,6 @@ void board_init(void) { USART_Init(USART1, &usart); USART_Cmd(USART1, ENABLE); - __wch_vendor_enable_irq(); - board_led_write(true); } @@ -155,6 +141,17 @@ uint32_t board_button_read(void) { return BUTTON_STATE_ACTIVE == GPIO_ReadInputDataBit(BUTTON_PORT, BUTTON_PIN); } +size_t board_get_unique_id(uint8_t id[], size_t max_len) { + (void) max_len; + volatile uint32_t* ch32_uuid = ((volatile uint32_t*) 0x1FFFF7E8UL); + uint32_t* serial_32 = (uint32_t*) (uintptr_t) id; + serial_32[0] = ch32_uuid[0]; + serial_32[1] = ch32_uuid[1]; + serial_32[2] = ch32_uuid[2]; + + return 12; +} + int board_uart_read(uint8_t *buf, int len) { (void) buf; (void) len; diff --git a/src/portable/wch/ch32_usbfs_reg.h b/src/portable/wch/ch32_usbfs_reg.h index 68be64f5e..7ffdc6cef 100644 --- a/src/portable/wch/ch32_usbfs_reg.h +++ b/src/portable/wch/ch32_usbfs_reg.h @@ -39,59 +39,92 @@ #include #elif CFG_TUSB_MCU == OPT_MCU_CH32V103 #include + // Newer-IP layout (separate UEPn_TX_CTRL/UEPn_RX_CTRL). The older IP (CH32V103) has a single + // combined control register at the UEPn_TX_CTRL offset, with UEPn_RX_CTRL reserved; the union + // exposes that same byte as UEPn_CTRL. Offsets are byte offsets from the peripheral base. + // TODO unify into a single struct shared by all WCH USBFS parts. typedef struct { - __IO uint8_t BASE_CTRL; - __IO uint8_t UDEV_CTRL; - __IO uint8_t INT_EN; - __IO uint8_t DEV_ADDR; - __IO uint8_t Reserve0; - __IO uint8_t MIS_ST; - __IO uint8_t INT_FG; - __IO uint8_t INT_ST; - __IO uint32_t RX_LEN; - __IO uint8_t UEP4_1_MOD; - __IO uint8_t UEP2_3_MOD; - __IO uint8_t UEP5_6_MOD; - __IO uint8_t UEP7_MOD; - __IO uint32_t UEP0_DMA; - __IO uint32_t UEP1_DMA; - __IO uint32_t UEP2_DMA; - __IO uint32_t UEP3_DMA; - __IO uint32_t UEP4_DMA; - __IO uint32_t UEP5_DMA; - __IO uint32_t UEP6_DMA; - __IO uint32_t UEP7_DMA; - __IO uint16_t UEP0_TX_LEN; - __IO uint8_t UEP0_TX_CTRL; - __IO uint8_t UEP0_RX_CTRL; - __IO uint16_t UEP1_TX_LEN; - __IO uint8_t UEP1_TX_CTRL; - __IO uint8_t UEP1_RX_CTRL; - __IO uint16_t UEP2_TX_LEN; - __IO uint8_t UEP2_TX_CTRL; - __IO uint8_t UEP2_RX_CTRL; - __IO uint16_t UEP3_TX_LEN; - __IO uint8_t UEP3_TX_CTRL; - __IO uint8_t UEP3_RX_CTRL; - __IO uint16_t UEP4_TX_LEN; - __IO uint8_t UEP4_TX_CTRL; - __IO uint8_t UEP4_RX_CTRL; - __IO uint16_t UEP5_TX_LEN; - __IO uint8_t UEP5_TX_CTRL; - __IO uint8_t UEP5_RX_CTRL; - __IO uint16_t UEP6_TX_LEN; - __IO uint8_t UEP6_TX_CTRL; - __IO uint8_t UEP6_RX_CTRL; - __IO uint16_t UEP7_TX_LEN; - __IO uint8_t UEP7_TX_CTRL; - __IO uint8_t UEP7_RX_CTRL; - __IO uint32_t Reserve1; - __IO uint32_t OTG_CR; - __IO uint32_t OTG_SR; + __IO uint8_t BASE_CTRL; // 0x00 + __IO uint8_t UDEV_CTRL; // 0x01 + __IO uint8_t INT_EN; // 0x02 + __IO uint8_t DEV_ADDR; // 0x03 + __IO uint8_t Reserve0; // 0x04 + __IO uint8_t MIS_ST; // 0x05 + __IO uint8_t INT_FG; // 0x06 + __IO uint8_t INT_ST; // 0x07 + __IO uint32_t RX_LEN; // 0x08 + __IO uint8_t UEP4_1_MOD; // 0x0C + __IO uint8_t UEP2_3_MOD; // 0x0D + __IO uint8_t UEP5_6_MOD; // 0x0E + __IO uint8_t UEP7_MOD; // 0x0F + __IO uint32_t UEP0_DMA; // 0x10 + __IO uint32_t UEP1_DMA; // 0x14 + __IO uint32_t UEP2_DMA; // 0x18 + __IO uint32_t UEP3_DMA; // 0x1C + __IO uint32_t UEP4_DMA; // 0x20 + __IO uint32_t UEP5_DMA; // 0x24 + __IO uint32_t UEP6_DMA; // 0x28 + __IO uint32_t UEP7_DMA; // 0x2C + __IO uint16_t UEP0_TX_LEN; // 0x30 + union { + __IO uint8_t UEP0_TX_CTRL; + __IO uint8_t UEP0_CTRL; + }; // 0x32 (TX_CTRL: IN | CTRL: combined) + __IO uint8_t UEP0_RX_CTRL; // 0x33 (OUT ctrl; reserved on combined IP) + __IO uint16_t UEP1_TX_LEN; // 0x34 + union { + __IO uint8_t UEP1_TX_CTRL; + __IO uint8_t UEP1_CTRL; + }; // 0x36 + __IO uint8_t UEP1_RX_CTRL; // 0x37 + __IO uint16_t UEP2_TX_LEN; // 0x38 + union { + __IO uint8_t UEP2_TX_CTRL; + __IO uint8_t UEP2_CTRL; + }; // 0x3A + __IO uint8_t UEP2_RX_CTRL; // 0x3B + __IO uint16_t UEP3_TX_LEN; // 0x3C + union { + __IO uint8_t UEP3_TX_CTRL; + __IO uint8_t UEP3_CTRL; + }; // 0x3E + __IO uint8_t UEP3_RX_CTRL; // 0x3F + __IO uint16_t UEP4_TX_LEN; // 0x40 + union { + __IO uint8_t UEP4_TX_CTRL; + __IO uint8_t UEP4_CTRL; + }; // 0x42 + __IO uint8_t UEP4_RX_CTRL; // 0x43 + __IO uint16_t UEP5_TX_LEN; // 0x44 + union { + __IO uint8_t UEP5_TX_CTRL; + __IO uint8_t UEP5_CTRL; + }; // 0x46 + __IO uint8_t UEP5_RX_CTRL; // 0x47 + __IO uint16_t UEP6_TX_LEN; // 0x48 + union { + __IO uint8_t UEP6_TX_CTRL; + __IO uint8_t UEP6_CTRL; + }; // 0x4A + __IO uint8_t UEP6_RX_CTRL; // 0x4B + __IO uint16_t UEP7_TX_LEN; // 0x4C + union { + __IO uint8_t UEP7_TX_CTRL; + __IO uint8_t UEP7_CTRL; + }; // 0x4E + __IO uint8_t UEP7_RX_CTRL; // 0x4F + __IO uint32_t Reserve1; // 0x50 + __IO uint32_t OTG_CR; // 0x54 + __IO uint32_t OTG_SR; // 0x58 } USBOTG_FS_TypeDef; #define USBOTG_FS ((USBOTG_FS_TypeDef *) 0x40023400) + + // CH32V103 has the older USBFS IP: a single combined control register per endpoint + // (UEPn_CTRL) instead of separate TX_CTRL/RX_CTRL bytes. The struct's UEPn_TX_CTRL field + // aliases that combined register (same address); UEPn_RX_CTRL maps to unused padding. + #define CH32_USBFS_EP_CTRL_COMBINED 1 #elif CFG_TUSB_MCU == OPT_MCU_CH32V20X #include #elif CFG_TUSB_MCU == OPT_MCU_CH32V307 @@ -166,6 +199,17 @@ #define USBFS_EP_R_RES_NAK (2 << 0) #define USBFS_EP_R_RES_STALL (3 << 0) +#ifdef CH32_USBFS_EP_CTRL_COMBINED +// Combined per-endpoint control register (older IP, e.g. CH32V103): IN response in +// bits [1:0], OUT response in bits [3:2], shared auto-toggle, separate IN/OUT toggle. +#define USBFS_EPC_T_RES_MASK 0x03 +#define USBFS_EPC_R_RES_MASK 0x0C +#define USBFS_EPC_R_RES_SHIFT 2 +#define USBFS_EPC_AUTO_TOG 0x10 +#define USBFS_EPC_T_TOG 0x40 +#define USBFS_EPC_R_TOG 0x80 +#endif + // token PID #define PID_OUT 0 #define PID_SOF 1 diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index af0f17785..dae31da91 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -40,6 +40,52 @@ #define EP_TX_CTRL(ep) ((&USBOTG_FS->UEP0_TX_CTRL)[4 * ep]) #define EP_RX_CTRL(ep) ((&USBOTG_FS->UEP0_RX_CTRL)[4 * ep]) +// Endpoint control register access. The newer USBFS IP (CH32V20x/V307/X035) has separate +// TX_CTRL and RX_CTRL bytes per endpoint; the older IP (CH32V103) has a single combined +// UEPn_CTRL register. These helpers hide the difference so the rest of the driver is shared. +// Values use the newer-IP encoding (USBFS_EP_T_*/USBFS_EP_R_*); the combined path remaps them. +#ifdef CH32_USBFS_EP_CTRL_COMBINED + #define EP_CTRL(ep) EP_TX_CTRL(ep) // UEPn_TX_CTRL field aliases the combined UEPn_CTRL register + + static inline uint8_t ep_tx_to_comb(uint8_t v) { + uint8_t c = v & USBFS_EP_T_RES_MASK; // IN response: bits [1:0] in both encodings + if (v & USBFS_EP_T_TOG) { c |= USBFS_EPC_T_TOG; } + if (v & USBFS_EP_T_AUTO_TOG) { c |= USBFS_EPC_AUTO_TOG; } + return c; + } + static inline uint8_t ep_rx_to_comb(uint8_t v) { + uint8_t c = (uint8_t) ((v & USBFS_EP_R_RES_MASK) << USBFS_EPC_R_RES_SHIFT); // OUT response -> bits [3:2] + if (v & USBFS_EP_R_TOG) { c |= USBFS_EPC_R_TOG; } + if (v & USBFS_EP_R_AUTO_TOG) { c |= USBFS_EPC_AUTO_TOG; } + return c; + } + // Set IN side (response/toggle/auto-tog), preserving the OUT response + OUT toggle. + static inline void ep_tx_ctrl_set(uint8_t ep, uint8_t v) { + EP_CTRL(ep) = (uint8_t) ((EP_CTRL(ep) & (USBFS_EPC_R_RES_MASK | USBFS_EPC_R_TOG)) | ep_tx_to_comb(v)); + } + // Set OUT side, preserving the IN response + IN toggle. + static inline void ep_rx_ctrl_set(uint8_t ep, uint8_t v) { + EP_CTRL(ep) = (uint8_t) ((EP_CTRL(ep) & (USBFS_EPC_T_RES_MASK | USBFS_EPC_T_TOG)) | ep_rx_to_comb(v)); + } + static inline void ep_tx_set_response(uint8_t ep, uint8_t res) { + EP_CTRL(ep) = (uint8_t) ((EP_CTRL(ep) & ~USBFS_EPC_T_RES_MASK) | (res & USBFS_EP_T_RES_MASK)); + } + static inline void ep_rx_set_response(uint8_t ep, uint8_t res) { + EP_CTRL(ep) = (uint8_t) ((EP_CTRL(ep) & ~USBFS_EPC_R_RES_MASK) | ((res & USBFS_EP_R_RES_MASK) << USBFS_EPC_R_RES_SHIFT)); + } + #define EP0_SETUP_RX_TOG USBFS_EP_R_TOG // combined IP: data/status stage after SETUP is DATA1 +#else + static inline void ep_tx_ctrl_set(uint8_t ep, uint8_t v) { EP_TX_CTRL(ep) = v; } + static inline void ep_rx_ctrl_set(uint8_t ep, uint8_t v) { EP_RX_CTRL(ep) = v; } + static inline void ep_tx_set_response(uint8_t ep, uint8_t res) { + EP_TX_CTRL(ep) = (uint8_t) ((EP_TX_CTRL(ep) & ~USBFS_EP_T_RES_MASK) | res); + } + static inline void ep_rx_set_response(uint8_t ep, uint8_t res) { + EP_RX_CTRL(ep) = (uint8_t) ((EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | res); + } + #define EP0_SETUP_RX_TOG 0 +#endif + /* private data */ struct usb_xfer { bool valid; @@ -81,19 +127,19 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force) { EP_TX_LEN(ep) = len; if (ep == 0) { - EP_TX_CTRL(0) = USBFS_EP_T_RES_ACK | (data.ep0_tog ? USBFS_EP_T_TOG : 0); + ep_tx_ctrl_set(0, USBFS_EP_T_RES_ACK | (data.ep0_tog ? USBFS_EP_T_TOG : 0)); data.ep0_tog = !data.ep0_tog; } else if (data.isochronous[ep]) { - EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NYET; + ep_tx_set_response(ep, USBFS_EP_T_RES_NYET); } else { - EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_ACK; + ep_tx_set_response(ep, USBFS_EP_T_RES_ACK); } } else { xfer->valid = false; if (ep == 0) { - EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK | (data.ep0_tog ? USBFS_EP_T_TOG : 0); + ep_tx_ctrl_set(0, USBFS_EP_T_RES_NAK | (data.ep0_tog ? USBFS_EP_T_TOG : 0)); } else if (!data.isochronous[ep]) { - EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NAK; + ep_tx_set_response(ep, USBFS_EP_T_RES_NAK); } dcd_event_xfer_complete(rhport, ep | TUSB_DIR_IN_MASK, xfer->processed_len, XFER_RESULT_SUCCESS, true); } @@ -119,11 +165,11 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { } if (ep == 0) { - EP_RX_CTRL(0) = USBFS_EP_R_RES_NAK; + ep_rx_set_response(0, USBFS_EP_R_RES_NAK); } else { uint8_t rx_res = data.isochronous[ep] ? USBFS_EP_R_RES_NYET : (xfer->valid ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK); - EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | rx_res; + ep_rx_set_response(ep, rx_res); } } } @@ -132,8 +178,8 @@ static void reset_ep_ctrls(void) { for (uint8_t ep = 1; ep < EP_MAX; ep++) { EP_DMA(ep) = (uint32_t)&data.buffer[ep][0]; EP_TX_LEN(ep) = 0; - EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NYET; - EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NYET; + ep_tx_ctrl_set(ep, USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NYET); + ep_rx_ctrl_set(ep, USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NYET); } EP_DMA(3) = (uint32_t)&data.ep3_buffer.out[0]; } @@ -152,8 +198,8 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { // setup endpoint 0 EP_DMA(0) = (uint32_t)&data.buffer[0][0]; EP_TX_LEN(0) = 0; - EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK; - EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; + ep_tx_ctrl_set(0, USBFS_EP_T_RES_NAK); + ep_rx_ctrl_set(0, USBFS_EP_R_RES_ACK); // enable other endpoints but NAK everything USBOTG_FS->UEP4_1_MOD = 0xCC; @@ -188,11 +234,12 @@ void dcd_int_handler(uint8_t rhport) { case PID_SETUP: // setup clears stall - EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK; + ep_tx_ctrl_set(0, USBFS_EP_T_RES_NAK); data.ep0_tog = true; const tusb_control_request_t *setup = (const tusb_control_request_t *)&data.buffer[0][TUSB_DIR_OUT][0]; - EP_RX_CTRL(0) = (setup->wLength == 0) ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK; + // EP0_SETUP_RX_TOG arms the data/status stage at DATA1 on the combined-control IP + ep_rx_ctrl_set(0, ((setup->wLength == 0) ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK) | EP0_SETUP_RX_TOG); dcd_event_setup_received(rhport, &data.buffer[0][TUSB_DIR_OUT][0], true); break; @@ -210,7 +257,7 @@ void dcd_int_handler(uint8_t rhport) { true); USBOTG_FS->DEV_ADDR = 0x00; - EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; + ep_rx_ctrl_set(0, USBFS_EP_R_RES_ACK); reset_ep_ctrls(); @@ -277,9 +324,9 @@ bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { if (ep != 0) { if (dir == TUSB_DIR_OUT) { - EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_T_RES_NAK; + ep_rx_ctrl_set(ep, USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NAK); } else { - EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK; + ep_tx_ctrl_set(ep, USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK); } } return true; @@ -326,7 +373,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to update_in(rhport, ep, true); } else { uint8_t rx_res = data.isochronous[ep] ? USBFS_EP_R_RES_NYET : USBFS_EP_R_RES_ACK; - EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | rx_res; + ep_rx_set_response(ep, rx_res); } return true; } @@ -337,16 +384,16 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { uint8_t dir = tu_edpt_dir(ep_addr); if (ep == 0) { if (dir == TUSB_DIR_OUT) { - EP_RX_CTRL(0) = USBFS_EP_R_RES_STALL; + ep_rx_ctrl_set(0, USBFS_EP_R_RES_STALL); } else { EP_TX_LEN(0) = 0; - EP_TX_CTRL(0) = USBFS_EP_T_RES_STALL; + ep_tx_ctrl_set(0, USBFS_EP_T_RES_STALL); } } else { if (dir == TUSB_DIR_OUT) { - EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | USBFS_EP_R_RES_STALL; + ep_rx_set_response(ep, USBFS_EP_R_RES_STALL); } else { - EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~USBFS_EP_T_RES_MASK) | USBFS_EP_T_RES_STALL; + ep_tx_set_response(ep, USBFS_EP_T_RES_STALL); } } } @@ -357,13 +404,13 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { uint8_t dir = tu_edpt_dir(ep_addr); if (ep == 0) { if (dir == TUSB_DIR_OUT) { - EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK; + ep_rx_ctrl_set(0, USBFS_EP_R_RES_ACK); } } else { if (dir == TUSB_DIR_OUT) { - EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NAK; + ep_rx_ctrl_set(ep, USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NAK); } else { - EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK; + ep_tx_ctrl_set(ep, USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK); } } } -- cgit v1.3.1 From ea5b8d677f22f4bd1574f864fd0487dfd329c090 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 18 Jun 2026 17:59:30 +0700 Subject: dcd/ch58x: drive CH582/583 with shared dcd_ch32_usbfs.c Replace PR #3515's separate dcd_ch58x_usbfs.c / hcd_ch58x_usbfs.c with the shared WCH USBFS device driver (combined per-endpoint control, like CH32V103), adding two CH58x-specific behaviors guarded so CH32V103/V20x/V307 are unchanged: - CH32_USBFS_EP_MANUAL_TOG: CH58x's hardware AUTO_TOG does not stay in sync, so the ISR toggles DATA0/DATA1 manually and discards toggle-mismatched OUT packets. Fixes multi-packet bulk-IN (e.g. MSC READ10) that otherwise hung. - CH32_USBFS_EP4_SHARES_EP0: EP4 has no DMA register and overlays EP0's region (EP0[0:63] + EP4 OUT[64:127] + EP4 IN[128:191]); add a 192-byte shared buffer and buffer-pointer helpers (transparent for the other parts). Fixes cdc_dual_ports (Port1 is on EP4). Add the ch582m_evt board. Device only on USB0 (rhport 0): the shared hcd_ch32_usbfs.c is CH32V20x-specific and cannot drive CH58x, so host / USB2 (rhport 1) is left commented out in the BSP for easy re-add. Verified on ch582m_evt via local HIL: all device examples pass. Co-Authored-By: Claude Opus 4.8 (1M context) --- hw/bsp/ch58x/boards/ch582m_evt/board.cmake | 5 + hw/bsp/ch58x/boards/ch582m_evt/board.h | 61 +++ hw/bsp/ch58x/boards/ch582m_evt/board.mk | 3 + hw/bsp/ch58x/boards/yd-ch582m/board.h | 10 +- hw/bsp/ch58x/ch58x_it.h | 2 +- hw/bsp/ch58x/family.c | 27 +- hw/bsp/ch58x/family.cmake | 3 +- hw/bsp/ch58x/family.mk | 3 +- src/common/tusb_mcu.h | 11 +- src/portable/wch/ch32_usbfs_reg.h | 48 ++ src/portable/wch/ch58x_usbfs_reg.h | 291 ------------ src/portable/wch/dcd_ch32_usbfs.c | 125 +++-- src/portable/wch/dcd_ch58x_usbfs.c | 636 ------------------------- src/portable/wch/hcd_ch58x_usbfs.c | 721 ----------------------------- 14 files changed, 244 insertions(+), 1702 deletions(-) create mode 100644 hw/bsp/ch58x/boards/ch582m_evt/board.cmake create mode 100644 hw/bsp/ch58x/boards/ch582m_evt/board.h create mode 100644 hw/bsp/ch58x/boards/ch582m_evt/board.mk delete mode 100644 src/portable/wch/ch58x_usbfs_reg.h delete mode 100644 src/portable/wch/dcd_ch58x_usbfs.c delete mode 100644 src/portable/wch/hcd_ch58x_usbfs.c (limited to 'src/portable/wch') diff --git a/hw/bsp/ch58x/boards/ch582m_evt/board.cmake b/hw/bsp/ch58x/boards/ch582m_evt/board.cmake new file mode 100644 index 000000000..4129c4550 --- /dev/null +++ b/hw/bsp/ch58x/boards/ch582m_evt/board.cmake @@ -0,0 +1,5 @@ +set(LD_FLASH_SIZE 448K) +set(LD_RAM_SIZE 32K) + +function(update_board TARGET) +endfunction() diff --git a/hw/bsp/ch58x/boards/ch582m_evt/board.h b/hw/bsp/ch58x/boards/ch582m_evt/board.h new file mode 100644 index 000000000..c3483bf17 --- /dev/null +++ b/hw/bsp/ch58x/boards/ch582m_evt/board.h @@ -0,0 +1,61 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 TinyUSB contributors + * + * 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. + */ + +/* metadata: + name: CH582M-EVT evaluation board + url: https://www.wch-ic.com/products/CH582.html +*/ + +#ifndef BOARD_H_ +#define BOARD_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +// LED: PB4 on CH582M-EVT +#define LED_PIN GPIO_Pin_4 +#define LED_STATE_ON 0 + +// Directly reuse BOOT pin as user button +#define BUTTON_PIN GPIO_Pin_22 +#define BUTTON_STATE_ACTIVE 0 + +// UART: UART1 TX=PA9, RX=PA8 +#define CFG_BOARD_UART_BAUDRATE 115200 + +// Device only on USB1 (rhport 0). CH58x host / USB2 is not supported by the shared usbfs dcd; +// BOARD_TUH_RHPORT is kept commented out to ease re-adding host later. +#ifndef BOARD_TUD_RHPORT +#define BOARD_TUD_RHPORT 0 +#endif +// #ifndef BOARD_TUH_RHPORT +// #define BOARD_TUH_RHPORT 1 +// #endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/hw/bsp/ch58x/boards/ch582m_evt/board.mk b/hw/bsp/ch58x/boards/ch582m_evt/board.mk new file mode 100644 index 000000000..a13979799 --- /dev/null +++ b/hw/bsp/ch58x/boards/ch582m_evt/board.mk @@ -0,0 +1,3 @@ +LDFLAGS += \ + -Wl,--defsym=__FLASH_SIZE=448K \ + -Wl,--defsym=__RAM_SIZE=32K \ diff --git a/hw/bsp/ch58x/boards/yd-ch582m/board.h b/hw/bsp/ch58x/boards/yd-ch582m/board.h index a14ffd198..0da5747bc 100644 --- a/hw/bsp/ch58x/boards/yd-ch582m/board.h +++ b/hw/bsp/ch58x/boards/yd-ch582m/board.h @@ -45,14 +45,14 @@ extern "C" { // UART: UART1 TX=PA9, RX=PA8 #define CFG_BOARD_UART_BAUDRATE 115200 -// Dual-port: USB1 (rhport 0) = Device, USB2 (rhport 1) = Host -// Swap these two if you want the opposite assignment +// Device only on USB1 (rhport 0). CH58x host / USB2 is not supported by the shared usbfs dcd; +// BOARD_TUH_RHPORT is kept commented out to ease re-adding host later. #ifndef BOARD_TUD_RHPORT #define BOARD_TUD_RHPORT 0 #endif -#ifndef BOARD_TUH_RHPORT -#define BOARD_TUH_RHPORT 1 -#endif +// #ifndef BOARD_TUH_RHPORT +// #define BOARD_TUH_RHPORT 1 +// #endif #ifdef __cplusplus } diff --git a/hw/bsp/ch58x/ch58x_it.h b/hw/bsp/ch58x/ch58x_it.h index 18ea52bc9..3e050344d 100644 --- a/hw/bsp/ch58x/ch58x_it.h +++ b/hw/bsp/ch58x/ch58x_it.h @@ -36,7 +36,7 @@ extern "C" { void NMI_Handler(void); void HardFault_Handler(void); void USB_IRQHandler(void); -void USB2_IRQHandler(void); +// void USB2_IRQHandler(void); // host on USB2 (rhport 1) — re-add together with the host driver void SysTick_Handler(void); #ifdef __cplusplus diff --git a/hw/bsp/ch58x/family.c b/hw/bsp/ch58x/family.c index 3b1382e61..8e5f2826b 100644 --- a/hw/bsp/ch58x/family.c +++ b/hw/bsp/ch58x/family.c @@ -50,13 +50,16 @@ // Forward USB interrupt events to TinyUSB IRQ Handler //--------------------------------------------------------------------+ +// Device only: the shared dcd_ch32_usbfs.c drives USB0 (rhport 0). CH58x's second controller +// (USB2 / rhport 1) was driven by the now-removed ch58x host driver; its handler is kept +// commented out below to ease re-adding host support. __INTERRUPT __HIGH_CODE void USB_IRQHandler(void) { tusb_int_handler(0, true); } -__INTERRUPT __HIGH_CODE void USB2_IRQHandler(void) { - tusb_int_handler(1, true); -} +// __INTERRUPT __HIGH_CODE void USB2_IRQHandler(void) { +// tusb_int_handler(1, true); +// } //--------------------------------------------------------------------+ // SysTick @@ -111,16 +114,12 @@ void board_init(void) { #endif #endif - // USB pin enable: enable analog function for USB1 and USB2 D+/D- - R16_PIN_ANALOG_IE |= RB_PIN_USB_IE | RB_PIN_USB2_IE; - - // D+ pull-up is only needed for the device-role port + // Device only on USB0 (rhport 0): enable analog function for USB1 D+/D- and assert its D+ + // pull-up. The shared dcd_ch32_usbfs.c drives USB0; CH58x host / USB2 (rhport 1) is unsupported + // here — to re-add host, also OR in RB_PIN_USB2_IE below. + R16_PIN_ANALOG_IE |= RB_PIN_USB_IE; // | RB_PIN_USB2_IE (re-add for host on USB2) #if CFG_TUD_ENABLED - #if BOARD_TUD_RHPORT == 0 - R16_PIN_ANALOG_IE |= RB_PIN_USB_DP_PU; - #else - R16_PIN_ANALOG_IE |= RB_PIN_USB2_DP_PU; - #endif + R16_PIN_ANALOG_IE |= RB_PIN_USB_DP_PU; #endif // Keep USB clock active during sleep @@ -164,6 +163,10 @@ uint32_t board_button_read(void) { #endif } +// Note: CH58x exposes no memory-mapped unique-ID register (unlike ch32v10x/v20x at +// 0x1FFFF7E8), and the SDK's GET_UNIQUE_ID() is a BootROM stub not present in +// libISP583.a. So board_get_unique_id() falls back to the fixed default in board.c. + int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; diff --git a/hw/bsp/ch58x/family.cmake b/hw/bsp/ch58x/family.cmake index b4835cb41..cbe1ffe72 100644 --- a/hw/bsp/ch58x/family.cmake +++ b/hw/bsp/ch58x/family.cmake @@ -77,8 +77,7 @@ function(family_configure_example TARGET RTOS) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/debug_uart.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c - ${TOP}/src/portable/wch/dcd_ch58x_usbfs.c - ${TOP}/src/portable/wch/hcd_ch58x_usbfs.c + ${TOP}/src/portable/wch/dcd_ch32_usbfs.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} ) target_include_directories(${TARGET} PUBLIC diff --git a/hw/bsp/ch58x/family.mk b/hw/bsp/ch58x/family.mk index 71c2cada6..2ef90a8c3 100644 --- a/hw/bsp/ch58x/family.mk +++ b/hw/bsp/ch58x/family.mk @@ -33,8 +33,7 @@ LDFLAGS_GCC += \ LIBS += $(TOP)/$(SDK_SRC_DIR)/StdPeriphDriver/libISP583.a SRC_C += \ - src/portable/wch/dcd_ch58x_usbfs.c \ - src/portable/wch/hcd_ch58x_usbfs.c \ + src/portable/wch/dcd_ch32_usbfs.c \ $(SDK_SRC_DIR)/StdPeriphDriver/CH58x_gpio.c \ $(SDK_SRC_DIR)/StdPeriphDriver/CH58x_clk.c \ $(SDK_SRC_DIR)/StdPeriphDriver/CH58x_uart1.c \ diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 8408d3ae0..f2a2d92a5 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -660,17 +660,16 @@ #endif #elif TU_CHECK_MCU(OPT_MCU_CH58X) - // CH582/583 has 2 independent USBFS controllers with merged EP registers, FS only. - #define TUP_USBIP_WCH_CH58X + // CH582/583 USBFS: older WCH USBFS IP with a single combined per-endpoint control register + // (like CH32V103), driven by the shared dcd_ch32_usbfs.c on USB0 (rhport 0). Device only: + // the shared hcd_ch32_usbfs.c is CH32V20x-specific and does not support CH58x, so host / + // USB2 (rhport 1) is not provided here. + #define TUP_USBIP_WCH_USBFS #ifndef CFG_TUD_WCH_USBIP_USBFS #define CFG_TUD_WCH_USBIP_USBFS 1 #endif - #ifndef CFG_TUH_WCH_USBIP_USBFS - #define CFG_TUH_WCH_USBIP_USBFS 1 - #endif - #define TUP_DCD_ENDPOINT_MAX 8 //--------------------------------------------------------------------+ diff --git a/src/portable/wch/ch32_usbfs_reg.h b/src/portable/wch/ch32_usbfs_reg.h index 7ffdc6cef..0d61e183c 100644 --- a/src/portable/wch/ch32_usbfs_reg.h +++ b/src/portable/wch/ch32_usbfs_reg.h @@ -130,6 +130,53 @@ #elif CFG_TUSB_MCU == OPT_MCU_CH32V307 #include #define USBHD_IRQn OTG_FS_IRQn +#elif CFG_TUSB_MCU == OPT_MCU_CH58X + #include "CH58x_common.h" + // CH582/583 USBFS device controller: same combined per-endpoint control register as + // CH32V103 (IN response bits[1:0], OUT response bits[3:2]) but a different register map - + // the EP control/length block sits lower (EP0_CTRL @ +0x22), EP5-7 are split out, EP4 + // shares EP0's DMA buffer, and EP5/6/7 mode bits live in one UEP567_MOD. The control/status + // block matches CH32. Two FS controllers exist (USB @ 0x40008000, USB2 @ 0x40008400); the + // device uses USB0. EP registers are accessed via the CH58X macros below (not the struct). + #define CH58X_USBFS_BASE 0x40008000u + typedef struct { + __IO uint8_t BASE_CTRL; // 0x00 + __IO uint8_t UDEV_CTRL; // 0x01 + __IO uint8_t INT_EN; // 0x02 + __IO uint8_t DEV_ADDR; // 0x03 + __IO uint8_t Reserve0; // 0x04 + __IO uint8_t MIS_ST; // 0x05 + __IO uint8_t INT_FG; // 0x06 + __IO uint8_t INT_ST; // 0x07 + __IO uint8_t RX_LEN; // 0x08 (8-bit on CH58X) + __IO uint8_t Reserve1[3]; // 0x09..0x0B + __IO uint8_t UEP4_1_MOD; // 0x0C + __IO uint8_t UEP2_3_MOD; // 0x0D + __IO uint8_t UEP567_MOD; // 0x0E + } USBOTG_FS_TypeDef; + #define USBOTG_FS ((USBOTG_FS_TypeDef *) CH58X_USBFS_BASE) + + #define CH32_USBFS_EP_CTRL_COMBINED 1 + #define CH32_USBFS_EP_REGS_CUSTOM 1 // EP register macros provided here, not by the driver + // CH58x's hardware AUTO_TOG does not stay in sync (notably across clear-stall and multi-packet + // bulk transfers), causing data-toggle mismatch and bus resets. Drive the toggle manually in + // the ISR instead. CH32V103/V20x/V307 keep AUTO_TOG (this macro is undefined for them). + #define CH32_USBFS_EP_MANUAL_TOG 1 + // CH58x EP4 has no DMA register of its own: it overlays EP0's DMA region as + // EP0[0:63] + EP4_OUT[64:127] + EP4_IN[128:191], so EP0 needs a 192-byte buffer. + #define CH32_USBFS_EP4_SHARES_EP0 1 + #define USBHD_IRQn USB_IRQn + #ifndef NVIC_EnableIRQ + #define NVIC_EnableIRQ(n) PFIC_EnableIRQ(n) + #define NVIC_DisableIRQ(n) PFIC_DisableIRQ(n) + #endif + + // EP register access. EP0-4: T_LEN @ +0x20+ep*4, CTRL @ +0x22+ep*4. EP5-7 split: T_LEN @ + // +0x64, CTRL @ +0x66. DMA: EP0-3 @ +0x10+ep*4, EP5-7 @ +0x54; EP4 shares EP0's buffer + // (no own DMA reg) so its slot points at a reserved word. + #define EP_TX_LEN(ep) (*(volatile uint8_t *)(CH58X_USBFS_BASE + ((ep) <= 4u ? 0x20u + (ep)*4u : 0x64u + ((ep)-5u)*4u))) + #define EP_CTRL(ep) (*(volatile uint8_t *)(CH58X_USBFS_BASE + ((ep) <= 4u ? 0x22u + (ep)*4u : 0x66u + ((ep)-5u)*4u))) + #define EP_DMA(ep) (*(volatile uint16_t *)(CH58X_USBFS_BASE + ((ep) <= 3u ? 0x10u + (ep)*4u : (ep) == 4u ? 0x40u : 0x54u + ((ep)-5u)*4u))) #endif #ifdef __GNUC__ @@ -170,6 +217,7 @@ // INT_ST #define USBFS_INT_ST_MASK_UIS_ENDP(x) (((x) >> 0) & 0x0F) #define USBFS_INT_ST_MASK_UIS_TOKEN(x) (((x) >> 4) & 0x03) +#define USBFS_INT_ST_TOG_OK (1 << 6) // received packet's data toggle matched expectation // UDEV_CTRL #define USBFS_UDEV_CTRL_PORT_EN (1 << 0) diff --git a/src/portable/wch/ch58x_usbfs_reg.h b/src/portable/wch/ch58x_usbfs_reg.h deleted file mode 100644 index 67b47e0b6..000000000 --- a/src/portable/wch/ch58x_usbfs_reg.h +++ /dev/null @@ -1,291 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2024 TinyUSB contributors - * - * 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. - */ - -#ifndef CH58X_USBFS_REG_H -#define CH58X_USBFS_REG_H - -#include - -//--------------------------------------------------------------------+ -// USB Base Addresses -//--------------------------------------------------------------------+ -#define CH58X_USB_BASE 0x40008000u -#define CH58X_USB2_BASE 0x40008400u - -//--------------------------------------------------------------------+ -// Global Control / Status Registers -//--------------------------------------------------------------------+ -#define CH58X_USB_CTRL(base) (*(volatile uint8_t *)((base) + 0x00)) -#define CH58X_UDEV_CTRL(base) (*(volatile uint8_t *)((base) + 0x01)) -#define CH58X_USB_INT_EN(base) (*(volatile uint8_t *)((base) + 0x02)) -#define CH58X_USB_DEV_AD(base) (*(volatile uint8_t *)((base) + 0x03)) -#define CH58X_USB_MIS_ST(base) (*(volatile uint8_t *)((base) + 0x05)) -#define CH58X_USB_INT_FG(base) (*(volatile uint8_t *)((base) + 0x06)) -#define CH58X_USB_INT_ST(base) (*(volatile uint8_t *)((base) + 0x07)) -#define CH58X_USB_RX_LEN(base) (*(volatile uint8_t *)((base) + 0x08)) - -//--------------------------------------------------------------------+ -// Endpoint Mode Registers -//--------------------------------------------------------------------+ -#define CH58X_UEP4_1_MOD(base) (*(volatile uint8_t *)((base) + 0x0C)) -#define CH58X_UEP2_3_MOD(base) (*(volatile uint8_t *)((base) + 0x0D)) -#define CH58X_UEP567_MOD(base) (*(volatile uint8_t *)((base) + 0x0E)) - -//--------------------------------------------------------------------+ -// Endpoint DMA / T_LEN / CTRL register accessors -//--------------------------------------------------------------------+ - -// EP DMA is 16-bit (only low 16 bits of RAM address, high bits implied 0x2000), EP4 shares EP0's DMA register (no independent DMA), so ep==4 maps to base+0x10 -#define CH58X_EP_DMA(base, ep) (*(volatile uint16_t *)((base) + ((ep) <= 3 ? (0x10u + (ep)*4u) : ((ep) == 4 ? 0x10u : (0x54u + ((ep)-5u)*4u))))) -#define CH58X_EP_TLEN(base, ep) (*(volatile uint8_t *)((base) + ((ep) <= 4 ? (0x20u + (ep)*4u) : (0x64u + ((ep)-5u)*4u)))) -#define CH58X_EP_CTRL(base, ep) (*(volatile uint8_t *)((base) + ((ep) <= 4 ? (0x22u + (ep)*4u) : (0x66u + ((ep)-5u)*4u)))) - -//--------------------------------------------------------------------+ -// USB_CTRL (R8_USB_CTRL) bit definitions -//--------------------------------------------------------------------+ -#define CH58X_UC_DMA_EN 0x01 -#define CH58X_UC_CLR_ALL 0x02 -#define CH58X_UC_RESET_SIE 0x04 -#define CH58X_UC_INT_BUSY 0x08 -#define CH58X_UC_SYS_CTRL 0x10 -#define CH58X_UC_DEV_PU_EN 0x20 -#define CH58X_UC_LOW_SPEED 0x40 -#define CH58X_UC_HOST_MODE 0x80 - -//--------------------------------------------------------------------+ -// UDEV_CTRL (R8_UDEV_CTRL) bit definitions -//--------------------------------------------------------------------+ -#define CH58X_UD_PORT_EN 0x01 -#define CH58X_UD_GP_BIT 0x02 -#define CH58X_UD_LOW_SPEED 0x04 -#define CH58X_UD_PD_DIS 0x80 - -//--------------------------------------------------------------------+ -// INT_EN (R8_USB_INT_EN) bit definitions -//--------------------------------------------------------------------+ -#define CH58X_UIE_BUS_RST 0x01 -#define CH58X_UIE_DETECT 0x01 /* host mode alias */ -#define CH58X_UIE_TRANSFER 0x02 -#define CH58X_UIE_SUSPEND 0x04 -#define CH58X_UIE_HST_SOF 0x08 -#define CH58X_UIE_FIFO_OV 0x10 - -//--------------------------------------------------------------------+ -// INT_FG (R8_USB_INT_FG) bit definitions -//--------------------------------------------------------------------+ -#define CH58X_UIF_BUS_RST 0x01 -#define CH58X_UIF_DETECT 0x01 /* host mode alias */ -#define CH58X_UIF_TRANSFER 0x02 -#define CH58X_UIF_SUSPEND 0x04 -#define CH58X_UIF_HST_SOF 0x08 -#define CH58X_UIF_FIFO_OV 0x10 -#define CH58X_U_SIE_FREE 0x20 -#define CH58X_U_TOG_OK 0x40 -#define CH58X_U_IS_NAK 0x80 - -//--------------------------------------------------------------------+ -// INT_ST (R8_USB_INT_ST) parsing -//--------------------------------------------------------------------+ -#define CH58X_INT_ST_ENDP(x) (((x) >> 0) & 0x0F) -#define CH58X_INT_ST_TOKEN(x) (((x) >> 4) & 0x03) -#define CH58X_UIS_TOG_OK 0x40 // toggle match flag (device and host) -#define CH58X_UIS_SETUP_ACT 0x80 - -// Token PID values -#define CH58X_PID_OUT 0 -#define CH58X_PID_SOF 1 -#define CH58X_PID_IN 2 -#define CH58X_PID_SETUP 3 - -//--------------------------------------------------------------------+ -// MIS_ST (R8_USB_MIS_ST) bit definitions -//--------------------------------------------------------------------+ -#define CH58X_UMS_DEV_ATTACH 0x01 -#define CH58X_UMS_DM_LEVEL 0x02 -#define CH58X_UMS_SUSPEND 0x04 -#define CH58X_UMS_BUS_RESET 0x08 -#define CH58X_UMS_R_FIFO_RDY 0x10 -#define CH58X_UMS_SIE_FREE 0x20 -#define CH58X_UMS_SOF_ACT 0x40 -#define CH58X_UMS_SOF_PRES 0x80 - -//--------------------------------------------------------------------+ -// EP CTRL register bit definitions (merged TX+RX in single 8-bit reg) -// -// Bit 7: RB_UEP_R_TOG RX data toggle -// Bit 6: RB_UEP_T_TOG TX data toggle -// Bit 5: (reserved) -// Bit 4: RB_UEP_AUTO_TOG auto toggle (EP1/2/3/5/6/7, not EP0/EP4) -// Bit 3: R_RES1 RX response high -// Bit 2: R_RES0 RX response low -// Bit 1: T_RES1 TX response high -// Bit 0: T_RES0 TX response low -//--------------------------------------------------------------------+ - -// TX response bits[1:0] -#define CH58X_EP_T_RES_MASK 0x03 -#define CH58X_EP_T_RES_ACK 0x00 -#define CH58X_EP_T_RES_TOUT 0x01 /* ISO: no handshake */ -#define CH58X_EP_T_RES_NAK 0x02 -#define CH58X_EP_T_RES_STALL 0x03 - -// RX response bits[3:2] -#define CH58X_EP_R_RES_MASK 0x0C -#define CH58X_EP_R_RES_ACK 0x00 -#define CH58X_EP_R_RES_TOUT 0x04 /* ISO: no handshake */ -#define CH58X_EP_R_RES_NAK 0x08 -#define CH58X_EP_R_RES_STALL 0x0C - -// Toggle and auto-toggle -#define CH58X_EP_AUTO_TOG 0x10 /* bit 4, shared TX/RX */ -#define CH58X_EP_T_TOG 0x40 /* bit 6, TX DATA toggle */ -#define CH58X_EP_R_TOG 0x80 /* bit 7, RX DATA toggle */ - -//--------------------------------------------------------------------+ -// EP Mode register (UEP4_1_MOD) bit definitions -//--------------------------------------------------------------------+ -// R8_UEP4_1_MOD: EP4 in bits[3:2], EP1 in bits[7:4] -#define CH58X_UEP1_BUF_MOD 0x10 -#define CH58X_UEP1_TX_EN 0x40 -#define CH58X_UEP1_RX_EN 0x80 -#define CH58X_UEP4_TX_EN 0x04 -#define CH58X_UEP4_RX_EN 0x08 - -// R8_UEP2_3_MOD: EP3 in bits[7:4], EP2 in bits[3:0] -#define CH58X_UEP2_BUF_MOD 0x01 -#define CH58X_UEP2_TX_EN 0x04 -#define CH58X_UEP2_RX_EN 0x08 -#define CH58X_UEP3_BUF_MOD 0x10 -#define CH58X_UEP3_TX_EN 0x40 -#define CH58X_UEP3_RX_EN 0x80 - -// R8_UEP567_MOD -#define CH58X_UEP5_TX_EN 0x01 -#define CH58X_UEP5_RX_EN 0x02 -#define CH58X_UEP6_TX_EN 0x04 -#define CH58X_UEP6_RX_EN 0x08 -#define CH58X_UEP7_TX_EN 0x10 -#define CH58X_UEP7_RX_EN 0x20 - -//--------------------------------------------------------------------+ -// Host-mode Register Aliases -// In host mode: EP2 -> RX, EP3 -> TX, EP1_CTRL -> SETUP -//--------------------------------------------------------------------+ -#define CH58X_UHOST_CTRL(base) (*(volatile uint8_t *)((base) + 0x01)) // = UDEV_CTRL -#define CH58X_UH_EP_MOD(base) (*(volatile uint8_t *)((base) + 0x0D)) // = UEP2_3_MOD -#define CH58X_UH_RX_DMA(base) (*(volatile uint16_t *)((base) + 0x18)) // = UEP2_DMA -#define CH58X_UH_TX_DMA(base) (*(volatile uint16_t *)((base) + 0x1C)) // = UEP3_DMA -#define CH58X_UH_SETUP(base) (*(volatile uint8_t *)((base) + 0x26)) // = UEP1_CTRL -#define CH58X_UH_EP_PID(base) (*(volatile uint8_t *)((base) + 0x28)) // = UEP2_T_LEN -#define CH58X_UH_RX_CTRL(base) (*(volatile uint8_t *)((base) + 0x2A)) // = UEP2_CTRL -#define CH58X_UH_TX_LEN(base) (*(volatile uint8_t *)((base) + 0x2C)) // = UEP3_T_LEN -#define CH58X_UH_TX_CTRL(base) (*(volatile uint8_t *)((base) + 0x2E)) // = UEP3_CTRL - -//--------------------------------------------------------------------+ -// UHOST_CTRL (R8_UHOST_CTRL) bit definitions -//--------------------------------------------------------------------+ -#define CH58X_UH_PD_DIS 0x80 -#define CH58X_UH_LOW_SPEED 0x04 -#define CH58X_UH_BUS_RESET 0x02 -#define CH58X_UH_PORT_EN 0x01 - -//--------------------------------------------------------------------+ -// UH_EP_MOD (R8_UH_EP_MOD) bit definitions -//--------------------------------------------------------------------+ -#define CH58X_UH_EP_TX_EN 0x40 -#define CH58X_UH_EP_TBUF_MOD 0x10 -#define CH58X_UH_EP_RX_EN 0x08 -#define CH58X_UH_EP_RBUF_MOD 0x01 - -//--------------------------------------------------------------------+ -// UH_SETUP (R8_UH_SETUP) bit definitions -//--------------------------------------------------------------------+ -#define CH58X_UH_PRE_PID_EN 0x80 -#define CH58X_UH_SOF_EN 0x40 - -//--------------------------------------------------------------------+ -// UH_RX_CTRL (R8_UH_RX_CTRL) bit definitions -//--------------------------------------------------------------------+ -#define CH58X_UH_R_TOG 0x80 -#define CH58X_UH_R_AUTO_TOG 0x10 -#define CH58X_UH_R_RES 0x04 - -//--------------------------------------------------------------------+ -// UH_TX_CTRL (R8_UH_TX_CTRL) bit definitions -//--------------------------------------------------------------------+ -#define CH58X_UH_T_TOG 0x40 -#define CH58X_UH_T_AUTO_TOG 0x10 -#define CH58X_UH_T_RES 0x01 - -//--------------------------------------------------------------------+ -// USB_INT_ST host-mode bits -//--------------------------------------------------------------------+ -#define CH58X_UIS_H_RES_MASK 0x0F - -//--------------------------------------------------------------------+ -// USB_DEV_AD bits -//--------------------------------------------------------------------+ -#define CH58X_UDA_GP_BIT 0x80 -#define CH58X_USB_ADDR_MASK 0x7F - -//--------------------------------------------------------------------+ -// Standard USB PID values (for host token and response) -//--------------------------------------------------------------------+ -#define CH58X_USB_PID_OUT 0x01 -#define CH58X_USB_PID_IN 0x09 -#define CH58X_USB_PID_SOF 0x05 -#define CH58X_USB_PID_SETUP 0x0D -#define CH58X_USB_PID_DATA0 0x03 -#define CH58X_USB_PID_DATA1 0x0B -#define CH58X_USB_PID_ACK 0x02 -#define CH58X_USB_PID_NAK 0x0A -#define CH58X_USB_PID_STALL 0x0E - -//--------------------------------------------------------------------+ -// PIN_ANALOG_IE register -//--------------------------------------------------------------------+ -#define CH58X_PIN_ANALOG_IE (*(volatile uint16_t *)0x4000101A) -#define CH58X_PIN_USB_DP_PU 0x40 -#define CH58X_PIN_USB_IE 0x80 -#define CH58X_PIN_USB2_DP_PU 0x10 -#define CH58X_PIN_USB2_IE 0x20 - -//--------------------------------------------------------------------+ -// Sleep clock control -//--------------------------------------------------------------------+ -#define CH58X_SLP_CLK_OFF1 (*(volatile uint8_t *)0x4000100D) -#define CH58X_SLP_CLK_USB 0x10 - -//--------------------------------------------------------------------+ -// PFIC (Platform-level Fast Interrupt Controller) -//--------------------------------------------------------------------+ -#define CH58X_PFIC_IENR ((volatile uint32_t *)0xE000E100) // interrupt enable -#define CH58X_PFIC_IRER ((volatile uint32_t *)0xE000E180) // interrupt reset (disable) - -#define CH58X_USB_IRQn 22 -#define CH58X_USB2_IRQn 23 - -#endif /* CH58X_USBFS_REG_H */ diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index dae31da91..7beb91e16 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -35,17 +35,23 @@ /* private defines */ #define EP_MAX (8) + // Struct-based EP register access (uniform layout). Some parts (e.g. CH58X) have a different + // register map and define EP_DMA/EP_TX_LEN/EP_CTRL themselves in ch32_usbfs_reg.h. + #ifndef CH32_USBFS_EP_REGS_CUSTOM #define EP_DMA(ep) ((&USBOTG_FS->UEP0_DMA)[ep]) #define EP_TX_LEN(ep) ((&USBOTG_FS->UEP0_TX_LEN)[2 * ep]) #define EP_TX_CTRL(ep) ((&USBOTG_FS->UEP0_TX_CTRL)[4 * ep]) #define EP_RX_CTRL(ep) ((&USBOTG_FS->UEP0_RX_CTRL)[4 * ep]) + #endif // Endpoint control register access. The newer USBFS IP (CH32V20x/V307/X035) has separate // TX_CTRL and RX_CTRL bytes per endpoint; the older IP (CH32V103) has a single combined // UEPn_CTRL register. These helpers hide the difference so the rest of the driver is shared. // Values use the newer-IP encoding (USBFS_EP_T_*/USBFS_EP_R_*); the combined path remaps them. #ifdef CH32_USBFS_EP_CTRL_COMBINED + #ifndef EP_CTRL // parts with a custom register map (CH58X) define EP_CTRL directly in reg.h #define EP_CTRL(ep) EP_TX_CTRL(ep) // UEPn_TX_CTRL field aliases the combined UEPn_CTRL register + #endif static inline uint8_t ep_tx_to_comb(uint8_t v) { uint8_t c = v & USBFS_EP_T_RES_MASK; // IN response: bits [1:0] in both encodings @@ -86,6 +92,17 @@ #define EP0_SETUP_RX_TOG 0 #endif +// Hardware auto data-toggle flag. Parts whose AUTO_TOG is reliable OR it into the EP setup so the +// controller flips DATA0/DATA1 itself; CH58x (CH32_USBFS_EP_MANUAL_TOG) leaves it clear and the +// ISR flips the toggle bit after each packet instead. +#ifdef CH32_USBFS_EP_MANUAL_TOG + #define EP_T_AUTO_TOG 0 + #define EP_R_AUTO_TOG 0 +#else + #define EP_T_AUTO_TOG USBFS_EP_T_AUTO_TOG + #define EP_R_AUTO_TOG USBFS_EP_R_AUTO_TOG +#endif + /* private data */ struct usb_xfer { bool valid; @@ -100,6 +117,12 @@ static struct { bool isochronous[EP_MAX]; struct usb_xfer xfer[EP_MAX][2]; TU_ATTR_ALIGNED(4) uint8_t buffer[EP_MAX][2][64]; +#ifdef CH32_USBFS_EP4_SHARES_EP0 + // CH58X: EP0 and EP4 share one DMA region (EP4 has no DMA register). Layout: + // EP0 [0:63] (half-duplex, OUT+IN) + EP4 OUT [64:127] + EP4 IN [128:191]. buffer[0]/buffer[4] + // are left unused for this part. + TU_ATTR_ALIGNED(4) uint8_t ep0_ep4_buffer[3 * 64]; +#endif TU_ATTR_ALIGNED(4) struct { // OUT transfers >64 bytes will overwrite queued IN data! uint8_t out[64]; @@ -108,19 +131,50 @@ static struct { } ep3_buffer; } data; +// DMA / copy buffer pointers per endpoint. The WCH USBFS buffer holds OUT (RX) at offset 0 and +// IN (TX) at +64; EP0 is half-duplex and reuses its OUT chunk for IN; EP3 has an enlarged IN +// buffer for throughput. On CH58X, EP4 overlays EP0's region (see ep0_ep4_buffer above). +static inline uint32_t ep_dma_addr(uint8_t ep) { +#ifdef CH32_USBFS_EP4_SHARES_EP0 + if (ep == 0) { return (uint32_t) &data.ep0_ep4_buffer[0]; } +#endif + if (ep == 3) { return (uint32_t) &data.ep3_buffer.out[0]; } + return (uint32_t) &data.buffer[ep][0]; +} +static inline uint8_t* ep_out_buf(uint8_t ep) { +#ifdef CH32_USBFS_EP4_SHARES_EP0 + if (ep == 0) { return &data.ep0_ep4_buffer[0]; } + if (ep == 4) { return &data.ep0_ep4_buffer[64]; } +#endif + if (ep == 3) { return data.ep3_buffer.out; } + return data.buffer[ep][TUSB_DIR_OUT]; +} +static inline uint8_t* ep_in_buf(uint8_t ep) { +#ifdef CH32_USBFS_EP4_SHARES_EP0 + if (ep == 0) { return &data.ep0_ep4_buffer[0]; } // EP0 half-duplex: IN reuses OUT chunk + if (ep == 4) { return &data.ep0_ep4_buffer[128]; } +#endif + if (ep == 0) { return data.buffer[0][TUSB_DIR_OUT]; } // EP0 half-duplex: IN reuses OUT chunk + if (ep == 3) { return data.ep3_buffer.in; } + return data.buffer[ep][TUSB_DIR_IN]; +} +// EP4 on CH58X has no DMA register (shares EP0's); skip its EP_DMA() write. +static inline bool ep_shares_ep0_dma(uint8_t ep) { +#ifdef CH32_USBFS_EP4_SHARES_EP0 + return ep == 4; +#else + (void) ep; + return false; +#endif +} + /* private helpers */ static void update_in(uint8_t rhport, uint8_t ep, bool force) { struct usb_xfer *xfer = &data.xfer[ep][TUSB_DIR_IN]; if (xfer->valid) { if (force || xfer->len) { size_t len = TU_MIN(xfer->max_size, xfer->len); - if (ep == 0) { - memcpy(data.buffer[ep][TUSB_DIR_OUT], xfer->buffer, len); // ep0 uses same chunk - } else if (ep == 3) { - memcpy(data.ep3_buffer.in, xfer->buffer, len); - } else { - memcpy(data.buffer[ep][TUSB_DIR_IN], xfer->buffer, len); - } + memcpy(ep_in_buf(ep), xfer->buffer, len); xfer->buffer += len; xfer->len -= len; xfer->processed_len += len; @@ -150,11 +204,7 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { struct usb_xfer *xfer = &data.xfer[ep][TUSB_DIR_OUT]; if (xfer->valid) { size_t len = TU_MIN(xfer->max_size, TU_MIN(xfer->len, rx_len)); - if (ep == 3) { - memcpy(xfer->buffer, data.ep3_buffer.out, len); - } else { - memcpy(xfer->buffer, data.buffer[ep][TUSB_DIR_OUT], len); - } + memcpy(xfer->buffer, ep_out_buf(ep), len); xfer->buffer += len; xfer->len -= len; xfer->processed_len += len; @@ -176,12 +226,11 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { static void reset_ep_ctrls(void) { for (uint8_t ep = 1; ep < EP_MAX; ep++) { - EP_DMA(ep) = (uint32_t)&data.buffer[ep][0]; + if (!ep_shares_ep0_dma(ep)) { EP_DMA(ep) = ep_dma_addr(ep); } EP_TX_LEN(ep) = 0; - ep_tx_ctrl_set(ep, USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NYET); - ep_rx_ctrl_set(ep, USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NYET); + ep_tx_ctrl_set(ep, EP_T_AUTO_TOG | USBFS_EP_T_RES_NYET); + ep_rx_ctrl_set(ep, EP_R_AUTO_TOG | USBFS_EP_R_RES_NYET); } - EP_DMA(3) = (uint32_t)&data.ep3_buffer.out[0]; } /* public functions */ @@ -195,8 +244,8 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { USBOTG_FS->INT_FG = 0xFF; USBOTG_FS->INT_EN = USBFS_INT_EN_BUS_RST | USBFS_INT_EN_TRANSFER | USBFS_INT_EN_SUSPEND; - // setup endpoint 0 - EP_DMA(0) = (uint32_t)&data.buffer[0][0]; + // setup endpoint 0 (also backs EP4's buffer on CH58X via the shared DMA region) + EP_DMA(0) = ep_dma_addr(0); EP_TX_LEN(0) = 0; ep_tx_ctrl_set(0, USBFS_EP_T_RES_NAK); ep_rx_ctrl_set(0, USBFS_EP_R_RES_ACK); @@ -204,8 +253,14 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { // enable other endpoints but NAK everything USBOTG_FS->UEP4_1_MOD = 0xCC; USBOTG_FS->UEP2_3_MOD = 0xCC; +#ifdef CH32_USBFS_EP_REGS_CUSTOM + // CH58X: a single mode register enables EP5/6/7 RX+TX (different bit layout than CH32). + USBOTG_FS->UEP567_MOD = RB_UEP5_RX_EN | RB_UEP5_TX_EN | RB_UEP6_RX_EN | RB_UEP6_TX_EN | + RB_UEP7_RX_EN | RB_UEP7_TX_EN; +#else USBOTG_FS->UEP5_6_MOD = 0xCC; USBOTG_FS->UEP7_MOD = 0x0C; +#endif reset_ep_ctrls(); @@ -218,17 +273,31 @@ void dcd_int_handler(uint8_t rhport) { (void)rhport; uint8_t status = USBOTG_FS->INT_FG; if (status & USBFS_INT_FG_TRANSFER) { - uint8_t ep = USBFS_INT_ST_MASK_UIS_ENDP(USBOTG_FS->INT_ST); - uint8_t token = USBFS_INT_ST_MASK_UIS_TOKEN(USBOTG_FS->INT_ST); + uint8_t int_st = USBOTG_FS->INT_ST; + uint8_t ep = USBFS_INT_ST_MASK_UIS_ENDP(int_st); + uint8_t token = USBFS_INT_ST_MASK_UIS_TOKEN(int_st); uint16_t rx_len = USBOTG_FS->RX_LEN; switch (token) { case PID_OUT: { +#ifdef CH32_USBFS_EP_MANUAL_TOG + // Manual toggle: drop OUT packets whose data toggle doesn't match (host retransmit), + // otherwise flip the expected RX toggle for the next packet. EP0 is driven by the + // SETUP/status flow below, so its toggle is left to that path. + if (ep != 0) { + if (!(int_st & USBFS_INT_ST_TOG_OK)) { break; } + EP_CTRL(ep) ^= USBFS_EPC_R_TOG; + } +#endif update_out(rhport, ep, rx_len); break; } case PID_IN: +#ifdef CH32_USBFS_EP_MANUAL_TOG + // Manual toggle: flip the TX toggle after each ACK'd IN packet (EP0 manages its own). + if (ep != 0) { EP_CTRL(ep) ^= USBFS_EPC_T_TOG; } +#endif update_in(rhport, ep, false); break; @@ -237,11 +306,12 @@ void dcd_int_handler(uint8_t rhport) { ep_tx_ctrl_set(0, USBFS_EP_T_RES_NAK); data.ep0_tog = true; - const tusb_control_request_t *setup = (const tusb_control_request_t *)&data.buffer[0][TUSB_DIR_OUT][0]; + uint8_t *ep0_out = ep_out_buf(0); + const tusb_control_request_t *setup = (const tusb_control_request_t *)ep0_out; // EP0_SETUP_RX_TOG arms the data/status stage at DATA1 on the combined-control IP ep_rx_ctrl_set(0, ((setup->wLength == 0) ? USBFS_EP_R_RES_ACK : USBFS_EP_R_RES_NAK) | EP0_SETUP_RX_TOG); - dcd_event_setup_received(rhport, &data.buffer[0][TUSB_DIR_OUT][0], true); + dcd_event_setup_received(rhport, ep0_out, true); break; } @@ -323,10 +393,12 @@ bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { data.xfer[ep][dir].max_size = tu_edpt_packet_size(desc_ep); if (ep != 0) { + // Opening clears the toggle to DATA0 (ep_*_ctrl_set writes the toggle bit clear since v has no + // R/T_TOG); with manual toggle EP_*_AUTO_TOG is 0 so the ISR owns subsequent toggling. if (dir == TUSB_DIR_OUT) { - ep_rx_ctrl_set(ep, USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NAK); + ep_rx_ctrl_set(ep, EP_R_AUTO_TOG | USBFS_EP_R_RES_NAK); } else { - ep_tx_ctrl_set(ep, USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK); + ep_tx_ctrl_set(ep, EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK); } } return true; @@ -407,10 +479,11 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { ep_rx_ctrl_set(0, USBFS_EP_R_RES_ACK); } } else { + // clear-stall resets the toggle to DATA0 (USB spec); manual-toggle parts then re-sync via ISR if (dir == TUSB_DIR_OUT) { - ep_rx_ctrl_set(ep, USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NAK); + ep_rx_ctrl_set(ep, EP_R_AUTO_TOG | USBFS_EP_R_RES_NAK); } else { - ep_tx_ctrl_set(ep, USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK); + ep_tx_ctrl_set(ep, EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK); } } } diff --git a/src/portable/wch/dcd_ch58x_usbfs.c b/src/portable/wch/dcd_ch58x_usbfs.c deleted file mode 100644 index c6f10b801..000000000 --- a/src/portable/wch/dcd_ch58x_usbfs.c +++ /dev/null @@ -1,636 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2024 TinyUSB contributors - * - * 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_TUD_ENABLED && defined(TUP_USBIP_WCH_CH58X) && CFG_TUD_WCH_USBIP_USBFS - -#include "device/dcd.h" -#include "ch58x_usbfs_reg.h" - -//--------------------------------------------------------------------+ -// Configuration -//--------------------------------------------------------------------+ -#define EP_MAX 8 -#define EP_BUF_SIZE 64 - -//--------------------------------------------------------------------+ -// USB base address selection by rhport -//--------------------------------------------------------------------+ -static inline uint32_t get_usb_base(uint8_t rhport) { - return (rhport == 0) ? CH58X_USB_BASE : CH58X_USB2_BASE; -} - -//--------------------------------------------------------------------+ -// Register access helpers using base address -//--------------------------------------------------------------------+ -#define USB_CTRL(base) CH58X_USB_CTRL(base) -#define USB_UDEV_CTRL(base) CH58X_UDEV_CTRL(base) -#define USB_INT_EN(base) CH58X_USB_INT_EN(base) -#define USB_DEV_AD(base) CH58X_USB_DEV_AD(base) -#define USB_MIS_ST(base) CH58X_USB_MIS_ST(base) -#define USB_INT_FG(base) CH58X_USB_INT_FG(base) -#define USB_INT_ST(base) CH58X_USB_INT_ST(base) -#define USB_RX_LEN(base) CH58X_USB_RX_LEN(base) - -#define EP_DMA(base, ep) CH58X_EP_DMA(base, ep) -#define EP_TLEN(base, ep) CH58X_EP_TLEN(base, ep) -#define EP_CTRL(base, ep) CH58X_EP_CTRL(base, ep) - -//--------------------------------------------------------------------+ -// Inline helpers for merged EP CTRL register -//--------------------------------------------------------------------+ -static inline void ep_set_tx_response(uint32_t base, uint8_t ep, uint8_t resp) { - uint8_t ctrl = EP_CTRL(base, ep); - ctrl = (ctrl & ~CH58X_EP_T_RES_MASK) | resp; - EP_CTRL(base, ep) = ctrl; -} - -static inline void ep_set_rx_response(uint32_t base, uint8_t ep, uint8_t resp) { - uint8_t ctrl = EP_CTRL(base, ep); - ctrl = (ctrl & ~CH58X_EP_R_RES_MASK) | resp; - EP_CTRL(base, ep) = ctrl; -} - -static inline void ep_set_both_response(uint32_t base, uint8_t ep, uint8_t tx_resp, uint8_t rx_resp) { - uint8_t ctrl = EP_CTRL(base, ep); - ctrl = (ctrl & ~(CH58X_EP_T_RES_MASK | CH58X_EP_R_RES_MASK)) | tx_resp | rx_resp; - EP_CTRL(base, ep) = ctrl; -} - -//--------------------------------------------------------------------+ -// Private data structures -//--------------------------------------------------------------------+ -typedef struct { - bool valid; - uint8_t* buffer; - size_t len; - size_t processed_len; - size_t max_size; -} xfer_ctl_t; - -typedef struct { - uint32_t usb_base; - bool ep0_tog; - volatile uint8_t setup_pending; // SETUP arrived while EP0 completion pending in queue - volatile bool ep0_completion_pending; // EP0 XFER_COMPLETE in event queue, not yet processed - uint8_t pending_addr; // Address to set in ISR after Set Address status ZLP - bool isochronous[EP_MAX][2]; // [ep][dir] - xfer_ctl_t xfer[EP_MAX][2]; // [ep][dir] - - // EP0 + EP4 shared buffer: EP0 OUT(64) + EP4 OUT(64) + EP4 IN(64) - TU_ATTR_ALIGNED(4) uint8_t ep0_buffer[EP_BUF_SIZE + EP_BUF_SIZE + EP_BUF_SIZE]; - - // EP1-EP3: OUT(64) + IN(64) - TU_ATTR_ALIGNED(4) uint8_t ep1_buffer[2][EP_BUF_SIZE]; - TU_ATTR_ALIGNED(4) uint8_t ep2_buffer[2][EP_BUF_SIZE]; - TU_ATTR_ALIGNED(4) uint8_t ep3_buffer[2][EP_BUF_SIZE]; - - // EP5-EP7: OUT(64) + IN(64) - TU_ATTR_ALIGNED(4) uint8_t ep5_buffer[2][EP_BUF_SIZE]; - TU_ATTR_ALIGNED(4) uint8_t ep6_buffer[2][EP_BUF_SIZE]; - TU_ATTR_ALIGNED(4) uint8_t ep7_buffer[2][EP_BUF_SIZE]; -} dcd_data_t; - -// Per-port data (support up to 2 USB ports) -static dcd_data_t _dcd_data[2]; - -//--------------------------------------------------------------------+ -// Buffer address helpers -//--------------------------------------------------------------------+ -static uint8_t* ep_out_buffer(dcd_data_t* d, uint8_t ep) { - switch (ep) { - case 0: return &d->ep0_buffer[0]; - case 1: return d->ep1_buffer[0]; - case 2: return d->ep2_buffer[0]; - case 3: return d->ep3_buffer[0]; - case 4: return &d->ep0_buffer[EP_BUF_SIZE]; - case 5: return d->ep5_buffer[0]; - case 6: return d->ep6_buffer[0]; - case 7: return d->ep7_buffer[0]; - default: return NULL; - } -} - -static uint8_t* ep_in_buffer(dcd_data_t* d, uint8_t ep) { - switch (ep) { - case 0: return &d->ep0_buffer[0]; // EP0 IN uses same buffer as OUT - case 1: return d->ep1_buffer[1]; - case 2: return d->ep2_buffer[1]; - case 3: return d->ep3_buffer[1]; - case 4: return &d->ep0_buffer[2 * EP_BUF_SIZE]; - case 5: return d->ep5_buffer[1]; - case 6: return d->ep6_buffer[1]; - case 7: return d->ep7_buffer[1]; - default: return NULL; - } -} - -// DMA base pointer (EP4 shares with EP0) -static uint8_t* ep_dma_buffer(dcd_data_t* d, uint8_t ep) { - switch (ep) { - case 0: case 4: return &d->ep0_buffer[0]; - case 1: return d->ep1_buffer[0]; - case 2: return d->ep2_buffer[0]; - case 3: return d->ep3_buffer[0]; - case 5: return d->ep5_buffer[0]; - case 6: return d->ep6_buffer[0]; - case 7: return d->ep7_buffer[0]; - default: return NULL; - } -} - -// AUTO_TOG is not used (EP1-3/5-7 support it). When clear-stall resets T_TOG/ -// R_TOG to DATA0, the hardware internal toggle doesn't sync, causing mismatch -// and bus resets. Use manual toggle (EP_CTRL ^= TOG) in ISR instead. - -//--------------------------------------------------------------------+ -// Private transfer helpers -//--------------------------------------------------------------------+ -static void update_in(uint8_t rhport, uint8_t ep, bool force, bool in_isr) { - dcd_data_t* d = &_dcd_data[rhport]; - uint32_t base = d->usb_base; - xfer_ctl_t* xfer = &d->xfer[ep][TUSB_DIR_IN]; - - if (xfer->valid) { - if (force || xfer->len) { - size_t len = TU_MIN(xfer->max_size, xfer->len); - - // Copy data to IN buffer - uint8_t* buf = ep_in_buffer(d, ep); - if (len > 0 && xfer->buffer != NULL) { - memcpy(buf, xfer->buffer, len); - } - - xfer->buffer += len; - xfer->len -= len; - xfer->processed_len += len; - - EP_TLEN(base, ep) = (uint8_t) len; - - if (ep == 0) { - // EP0: manual toggle - uint8_t ctrl = EP_CTRL(base, 0); - ctrl = (ctrl & ~(CH58X_EP_T_RES_MASK | CH58X_EP_T_TOG)); - ctrl |= CH58X_EP_T_RES_ACK; - if (d->ep0_tog) ctrl |= CH58X_EP_T_TOG; - EP_CTRL(base, 0) = ctrl; - d->ep0_tog = !d->ep0_tog; - } else if (d->isochronous[ep][TUSB_DIR_IN]) { - ep_set_tx_response(base, ep, CH58X_EP_T_RES_TOUT); - } else { - ep_set_tx_response(base, ep, CH58X_EP_T_RES_ACK); - } - } else { - // Transfer complete - xfer->valid = false; - ep_set_tx_response(base, ep, CH58X_EP_T_RES_NAK); - if (ep == 0) d->ep0_completion_pending = true; - dcd_event_xfer_complete(rhport, ep | TUSB_DIR_IN_MASK, - xfer->processed_len, XFER_RESULT_SUCCESS, in_isr); - } - } -} - -static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len, bool in_isr) { - dcd_data_t* d = &_dcd_data[rhport]; - uint32_t base = d->usb_base; - xfer_ctl_t* xfer = &d->xfer[ep][TUSB_DIR_OUT]; - - if (xfer->valid) { - size_t len = TU_MIN(xfer->max_size, TU_MIN(xfer->len, rx_len)); - - // Copy from OUT buffer - if (len > 0 && xfer->buffer != NULL) { - uint8_t* buf = ep_out_buffer(d, ep); - memcpy(xfer->buffer, buf, len); - } - - xfer->buffer += len; - xfer->len -= len; - xfer->processed_len += len; - - if (xfer->len == 0 || len < xfer->max_size) { - xfer->valid = false; - // NAK to prevent hardware from accepting next OUT before a new xfer is queued - ep_set_rx_response(base, ep, CH58X_EP_R_RES_NAK); - if (ep == 0) d->ep0_completion_pending = true; - dcd_event_xfer_complete(rhport, ep, xfer->processed_len, - XFER_RESULT_SUCCESS, in_isr); - } else if (ep == 0) { - // EP0 multi-packet: ensure ACK for next packet - ep_set_rx_response(base, 0, CH58X_EP_R_RES_ACK); - } - } -} - -//--------------------------------------------------------------------+ -// DCD API Implementation -//--------------------------------------------------------------------+ - -bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { - (void) rh_init; - dcd_data_t* d = &_dcd_data[rhport]; - uint32_t base = get_usb_base(rhport); - d->usb_base = base; - - // Clear state - tu_memclr(d->xfer, sizeof(d->xfer)); - tu_memclr(d->isochronous, sizeof(d->isochronous)); - d->ep0_tog = true; - d->setup_pending = 0; - d->ep0_completion_pending = false; - d->pending_addr = 0; - - // Reset USB control register first (SDK pattern) - USB_CTRL(base) = 0x00; - - // Init control registers - USB_CTRL(base) = CH58X_UC_DEV_PU_EN | CH58X_UC_INT_BUSY | CH58X_UC_DMA_EN; - USB_UDEV_CTRL(base) = CH58X_UD_PD_DIS | CH58X_UD_PORT_EN; - USB_DEV_AD(base) = 0x00; - - // Clear all interrupt flags, then enable interrupts - USB_INT_FG(base) = 0xFF; - USB_INT_EN(base) = CH58X_UIE_BUS_RST | CH58X_UIE_TRANSFER | CH58X_UIE_SUSPEND; - - // EP0 setup (also sets EP4 DMA since they share) - EP_DMA(base, 0) = (uint16_t)(uint32_t) &d->ep0_buffer[0]; - EP_TLEN(base, 0) = 0; - EP_CTRL(base, 0) = CH58X_EP_R_RES_ACK | CH58X_EP_T_RES_NAK; - - // Enable all endpoints TX+RX - CH58X_UEP4_1_MOD(base) = CH58X_UEP1_RX_EN | CH58X_UEP1_TX_EN | - CH58X_UEP4_RX_EN | CH58X_UEP4_TX_EN; - CH58X_UEP2_3_MOD(base) = CH58X_UEP2_RX_EN | CH58X_UEP2_TX_EN | - CH58X_UEP3_RX_EN | CH58X_UEP3_TX_EN; - CH58X_UEP567_MOD(base) = CH58X_UEP5_RX_EN | CH58X_UEP5_TX_EN | - CH58X_UEP6_RX_EN | CH58X_UEP6_TX_EN | - CH58X_UEP7_RX_EN | CH58X_UEP7_TX_EN; - - // EP1-3: DMA + manual toggle + NAK both directions - for (uint8_t ep = 1; ep <= 3; ep++) { - EP_DMA(base, ep) = (uint16_t)(uint32_t) ep_dma_buffer(d, ep); - EP_TLEN(base, ep) = 0; - EP_CTRL(base, ep) = CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK; - } - - // EP4: no independent DMA, no auto-toggle - EP_TLEN(base, 4) = 0; - EP_CTRL(base, 4) = CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK; - - // EP5-7: DMA + manual toggle - for (uint8_t ep = 5; ep <= 7; ep++) { - EP_DMA(base, ep) = (uint16_t)(uint32_t) ep_dma_buffer(d, ep); - EP_TLEN(base, ep) = 0; - EP_CTRL(base, ep) = CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK; - } - - // Set EP0 max size - d->xfer[0][TUSB_DIR_OUT].max_size = EP_BUF_SIZE; - d->xfer[0][TUSB_DIR_IN].max_size = EP_BUF_SIZE; - - dcd_connect(rhport); - return true; -} - -void dcd_int_handler(uint8_t rhport) { - dcd_data_t* d = &_dcd_data[rhport]; - uint32_t base = d->usb_base; - uint8_t status = USB_INT_FG(base); - - if (status & CH58X_UIF_TRANSFER) { - uint8_t int_st = USB_INT_ST(base); - uint8_t ep = CH58X_INT_ST_ENDP(int_st); - uint8_t token = CH58X_INT_ST_TOKEN(int_st); - - // Process regular token before SETUP to avoid losing it - if (token != CH58X_PID_SETUP) { - switch (token) { - case CH58X_PID_OUT: { - uint8_t rx_len = USB_RX_LEN(base); - if (ep == 0) { - // EP0: manual toggle, always process - EP_CTRL(base, 0) ^= CH58X_EP_R_TOG; - update_out(rhport, 0, rx_len, true); - } else if (int_st & CH58X_UIS_TOG_OK) { - // Toggle OK: manual toggle and process - EP_CTRL(base, ep) ^= CH58X_EP_R_TOG; - update_out(rhport, ep, rx_len, true); - } - // else: toggle mismatch, discard - break; - } - - case CH58X_PID_IN: { - // Apply pending Set Address immediately after status ZLP - if (ep == 0 && d->pending_addr) { - USB_DEV_AD(base) = (USB_DEV_AD(base) & CH58X_UDA_GP_BIT) | - (d->pending_addr & CH58X_USB_ADDR_MASK); - d->pending_addr = 0; - } - if (ep != 0) { - // Manual toggle for all non-EP0 endpoints - EP_CTRL(base, ep) ^= CH58X_EP_T_TOG; - } - update_in(rhport, ep, false, true); - break; - } - - default: - break; - } - USB_INT_FG(base) = CH58X_UIF_TRANSFER; - } - - // SETUP_ACT is checked separately — it persists even if token field changed - if (int_st & CH58X_UIS_SETUP_ACT) { - // Reset toggles to DATA1, NAK both directions until stack is ready - EP_CTRL(base, 0) = CH58X_EP_R_TOG | CH58X_EP_T_TOG | - CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK; - d->ep0_tog = true; - - d->pending_addr = 0; - - // Mark stale EP0 completion so dcd_edpt_xfer can skip it - d->setup_pending = d->ep0_completion_pending ? 1 : 0; - d->ep0_completion_pending = false; - d->xfer[0][TUSB_DIR_OUT].valid = false; - d->xfer[0][TUSB_DIR_IN].valid = false; - - dcd_event_setup_received(rhport, ep_out_buffer(d, 0), true); - USB_INT_FG(base) = CH58X_UIF_TRANSFER; - } - } - - // Process bus reset: reset all endpoints immediately (matching WCH SDK pattern) - if (status & CH58X_UIF_BUS_RST) { - d->ep0_tog = true; - d->setup_pending = 0; - d->ep0_completion_pending = false; - d->pending_addr = 0; - - // Reset EP0: ACK for RX (ready for SETUP), NAK for TX - EP_CTRL(base, 0) = CH58X_EP_R_RES_ACK | CH58X_EP_T_RES_NAK; - EP_TLEN(base, 0) = 0; - d->xfer[0][TUSB_DIR_OUT].max_size = EP_BUF_SIZE; - d->xfer[0][TUSB_DIR_IN].max_size = EP_BUF_SIZE; - - // Reset EP1-7: NAK both directions, invalidate pending transfers - for (uint8_t ep = 1; ep < EP_MAX; ep++) { - d->xfer[ep][TUSB_DIR_IN].valid = false; - d->xfer[ep][TUSB_DIR_OUT].valid = false; - EP_CTRL(base, ep) = CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK; - EP_TLEN(base, ep) = 0; - } - - USB_DEV_AD(base) = 0x00; - - tusb_speed_t speed = (USB_CTRL(base) & CH58X_UC_LOW_SPEED) ? - TUSB_SPEED_LOW : TUSB_SPEED_FULL; - dcd_event_bus_reset(rhport, speed, true); - - USB_INT_FG(base) = CH58X_UIF_BUS_RST; - } - - // Process suspend/resume - if (status & CH58X_UIF_SUSPEND) { - dcd_event_bus_signal(rhport, - (USB_MIS_ST(base) & CH58X_UMS_SUSPEND) ? DCD_EVENT_SUSPEND : DCD_EVENT_RESUME, - true); - USB_INT_FG(base) = CH58X_UIF_SUSPEND; - } -} - -void dcd_int_enable(uint8_t rhport) { - uint8_t irqn = (rhport == 0) ? CH58X_USB_IRQn : CH58X_USB2_IRQn; - CH58X_PFIC_IENR[irqn / 32] = (1u << (irqn % 32)); -} - -void dcd_int_disable(uint8_t rhport) { - uint8_t irqn = (rhport == 0) ? CH58X_USB_IRQn : CH58X_USB2_IRQn; - CH58X_PFIC_IRER[irqn / 32] = (1u << (irqn % 32)); - __asm volatile ("fence.i"); -} - -void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { - // Defer to ISR: apply address right after status ZLP is ACK'd - _dcd_data[rhport].pending_addr = dev_addr; - dcd_edpt_xfer(rhport, 0x80, NULL, 0, false); -} - -void dcd_remote_wakeup(uint8_t rhport) { - (void) rhport; - // TODO: not supported -} - -void dcd_connect(uint8_t rhport) { - uint32_t base = get_usb_base(rhport); - USB_CTRL(base) |= CH58X_UC_DEV_PU_EN; -} - -void dcd_disconnect(uint8_t rhport) { - uint32_t base = get_usb_base(rhport); - USB_CTRL(base) &= ~CH58X_UC_DEV_PU_EN; -} - -void dcd_sof_enable(uint8_t rhport, bool en) { - (void) rhport; - (void) en; -} - -void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) { - dcd_data_t* d = &_dcd_data[rhport]; - uint32_t base = d->usb_base; - - if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && - request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && - request->bRequest == TUSB_REQ_SET_ADDRESS) { - // Safety net: re-apply address in case ISR path was skipped - USB_DEV_AD(base) = (USB_DEV_AD(base) & CH58X_UDA_GP_BIT) | - ((uint8_t)request->wValue & CH58X_USB_ADDR_MASK); - } - - dcd_int_disable(rhport); - d->ep0_completion_pending = false; - if (d->setup_pending) { - // SETUP already arrived — don't override its NAK with ACK - d->setup_pending = 0; - } else { - ep_set_both_response(base, 0, CH58X_EP_T_RES_NAK, CH58X_EP_R_RES_ACK); - } - dcd_int_enable(rhport); -} - -bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) { - dcd_data_t* d = &_dcd_data[rhport]; - uint32_t base = d->usb_base; - uint8_t ep = tu_edpt_number(desc_ep->bEndpointAddress); - uint8_t dir = tu_edpt_dir(desc_ep->bEndpointAddress); - TU_ASSERT(ep < EP_MAX); - - d->isochronous[ep][dir] = (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS); - uint16_t max_size = tu_edpt_packet_size(desc_ep); - if (max_size > EP_BUF_SIZE) { - max_size = EP_BUF_SIZE; - } - d->xfer[ep][dir].max_size = max_size; - - if (ep != 0) { - dcd_int_disable(rhport); - uint8_t ctrl = EP_CTRL(base, ep); - if (dir == TUSB_DIR_OUT) { - // Clear RX toggle to DATA0 per USB spec - ctrl &= ~CH58X_EP_R_TOG; - if (d->isochronous[ep][TUSB_DIR_OUT]) { - ctrl = (ctrl & ~CH58X_EP_R_RES_MASK) | CH58X_EP_R_RES_TOUT; - } else { - // Start with NAK; dcd_edpt_xfer will set ACK when a transfer is submitted - ctrl = (ctrl & ~CH58X_EP_R_RES_MASK) | CH58X_EP_R_RES_NAK; - } - } else { - // Clear TX toggle to DATA0 per USB spec - ctrl &= ~CH58X_EP_T_TOG; - EP_TLEN(base, ep) = 0; - ctrl = (ctrl & ~CH58X_EP_T_RES_MASK) | CH58X_EP_T_RES_NAK; - } - EP_CTRL(base, ep) = ctrl; - dcd_int_enable(rhport); - } - return true; -} - -void dcd_edpt_close_all(uint8_t rhport) { - dcd_data_t* d = &_dcd_data[rhport]; - uint32_t base = d->usb_base; - - for (uint8_t ep = 1; ep < EP_MAX; ep++) { - d->xfer[ep][TUSB_DIR_IN].valid = false; - d->xfer[ep][TUSB_DIR_OUT].valid = false; - d->isochronous[ep][TUSB_DIR_OUT] = false; - d->isochronous[ep][TUSB_DIR_IN] = false; - EP_CTRL(base, ep) = CH58X_EP_R_RES_NAK | CH58X_EP_T_RES_NAK; - } -} - -bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { - (void) rhport; - (void) ep_addr; - (void) largest_packet_size; - return false; -} - -bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t* desc_ep) { - (void) rhport; - (void) desc_ep; - return false; -} - -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, - uint16_t total_bytes, bool is_isr) { - uint8_t ep = tu_edpt_number(ep_addr); - uint8_t dir = tu_edpt_dir(ep_addr); - - dcd_data_t* d = &_dcd_data[rhport]; - xfer_ctl_t* xfer = &d->xfer[ep][dir]; - - dcd_int_disable(rhport); - - // Skip stale EP0 arm if a new SETUP has already arrived - if (ep == 0) { - d->ep0_completion_pending = false; - if (d->setup_pending) { - d->setup_pending = 0; - dcd_int_enable(rhport); - return true; - } - } - - xfer->valid = true; - xfer->buffer = buffer; - xfer->len = total_bytes; - xfer->processed_len = 0; - - if (dir == TUSB_DIR_IN) { - update_in(rhport, ep, true, is_isr); - } else { - if (d->isochronous[ep][TUSB_DIR_OUT]) { - ep_set_rx_response(d->usb_base, ep, CH58X_EP_R_RES_TOUT); - } else { - ep_set_rx_response(d->usb_base, ep, CH58X_EP_R_RES_ACK); - } - } - dcd_int_enable(rhport); - return true; -} - -void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { - dcd_data_t* d = &_dcd_data[rhport]; - uint32_t base = d->usb_base; - uint8_t ep = tu_edpt_number(ep_addr); - uint8_t dir = tu_edpt_dir(ep_addr); - - dcd_int_disable(rhport); - if (ep == 0) { - // EP0: stall both directions - EP_CTRL(base, 0) = CH58X_EP_R_RES_STALL | CH58X_EP_T_RES_STALL | - CH58X_EP_R_TOG | CH58X_EP_T_TOG; - } else { - if (dir == TUSB_DIR_OUT) { - ep_set_rx_response(base, ep, CH58X_EP_R_RES_STALL); - } else { - ep_set_tx_response(base, ep, CH58X_EP_T_RES_STALL); - } - } - dcd_int_enable(rhport); -} - -void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { - dcd_data_t* d = &_dcd_data[rhport]; - uint32_t base = d->usb_base; - uint8_t ep = tu_edpt_number(ep_addr); - uint8_t dir = tu_edpt_dir(ep_addr); - - dcd_int_disable(rhport); - if (ep == 0) { - if (dir == TUSB_DIR_OUT) { - ep_set_rx_response(base, 0, CH58X_EP_R_RES_ACK); - } - } else { - uint8_t ctrl = EP_CTRL(base, ep); - if (dir == TUSB_DIR_OUT) { - ctrl &= ~(CH58X_EP_R_RES_MASK | CH58X_EP_R_TOG); - ctrl |= CH58X_EP_R_RES_ACK; - } else { - ctrl &= ~(CH58X_EP_T_RES_MASK | CH58X_EP_T_TOG); - ctrl |= CH58X_EP_T_RES_NAK; - } - EP_CTRL(base, ep) = ctrl; - } - dcd_int_enable(rhport); -} - -#endif /* CFG_TUD_ENABLED && TUP_USBIP_WCH_CH58X */ diff --git a/src/portable/wch/hcd_ch58x_usbfs.c b/src/portable/wch/hcd_ch58x_usbfs.c deleted file mode 100644 index 37dd08539..000000000 --- a/src/portable/wch/hcd_ch58x_usbfs.c +++ /dev/null @@ -1,721 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2024 TinyUSB contributors - * - * 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_CH58X) && \ - defined(CFG_TUH_WCH_USBIP_USBFS) && CFG_TUH_WCH_USBIP_USBFS - -#include - -#include "host/hcd.h" -#include "host/usbh.h" -#include "host/usbh_pvt.h" - -#include "ch58x_usbfs_reg.h" - -//--------------------------------------------------------------------+ -// Configuration -//--------------------------------------------------------------------+ -#define USBFS_MAX_PACKET_SIZE 64 - -#define LOG_CH58X_HCD(...) TU_LOG3(__VA_ARGS__) - -//--------------------------------------------------------------------+ -// RX/TX buffers (must be 4-byte aligned and in lower 64KB of RAM) -// Separate buffers for each USB port to avoid DMA conflicts -//--------------------------------------------------------------------+ -TU_ATTR_ALIGNED(4) static uint8_t _rx_buf[2][USBFS_MAX_PACKET_SIZE]; -TU_ATTR_ALIGNED(4) static uint8_t _tx_buf[2][USBFS_MAX_PACKET_SIZE]; - -//--------------------------------------------------------------------+ -// USB base address selection by rhport -//--------------------------------------------------------------------+ -static inline uint32_t _get_usb_base(uint8_t rhport) { - return (rhport == 0) ? CH58X_USB_BASE : CH58X_USB2_BASE; -} - -//--------------------------------------------------------------------+ -// Endpoint record -//--------------------------------------------------------------------+ -typedef struct { - bool configured; - uint8_t dev_addr; - uint8_t ep_addr; - uint8_t max_packet_size; - uint8_t xfer_type; - uint8_t data_toggle; // 0=DATA0, 1=DATA1 - bool is_nak_pending; - uint16_t buflen; - uint8_t* buf; -} hcd_edpt_t; - -static hcd_edpt_t _edpt_list[CFG_TUH_DEVICE_MAX * 6] = {}; - -//--------------------------------------------------------------------+ -// Current transfer state (only one transfer at a time per root port) -//--------------------------------------------------------------------+ -typedef struct { - volatile bool is_busy; - uint8_t rhport; - uint8_t dev_addr; - uint8_t ep_addr; - uint32_t start_ms; - uint8_t* buffer; - uint16_t bufferlen; - uint16_t xferred_len; - bool nak_pending; -} hcd_xfer_t; - -// One transfer state per root port (indexed by rhport). -static volatile hcd_xfer_t _current_xfer[2] = {}; - -//--------------------------------------------------------------------+ -// Per-port state -//--------------------------------------------------------------------+ -typedef struct { - uint32_t usb_base; - bool int_enabled; - bool int_state_before_reset; -} hcd_port_t; - -static hcd_port_t _port_data[2] = {}; - -//--------------------------------------------------------------------+ -// Endpoint record management -//--------------------------------------------------------------------+ -static hcd_edpt_t* _get_edpt(uint8_t dev_addr, uint8_t ep_addr) { - for (size_t i = 0; i < TU_ARRAY_SIZE(_edpt_list); i++) { - hcd_edpt_t* e = &_edpt_list[i]; - if (e->configured && e->dev_addr == dev_addr && e->ep_addr == ep_addr) { - return e; - } - } - return NULL; -} - -static hcd_edpt_t* _alloc_edpt(void) { - for (size_t i = 0; i < TU_ARRAY_SIZE(_edpt_list); i++) { - if (!_edpt_list[i].configured) { - return &_edpt_list[i]; - } - } - return NULL; -} - -static hcd_edpt_t* _add_edpt(uint8_t dev_addr, uint8_t ep_addr, - uint16_t max_packet_size, uint8_t xfer_type) { - hcd_edpt_t* e = _alloc_edpt(); - TU_ASSERT(e != NULL, NULL); - - e->dev_addr = dev_addr; - e->ep_addr = ep_addr; - e->max_packet_size = (uint8_t) TU_MIN(max_packet_size, USBFS_MAX_PACKET_SIZE); - e->xfer_type = xfer_type; - e->data_toggle = 0; - e->is_nak_pending = false; - e->buflen = 0; - e->buf = NULL; - e->configured = true; - - return e; -} - -static hcd_edpt_t* _get_or_add_edpt(uint8_t dev_addr, uint8_t ep_addr, - uint16_t max_packet_size, uint8_t xfer_type) { - hcd_edpt_t* e = _get_edpt(dev_addr, ep_addr); - if (e != NULL) return e; - return _add_edpt(dev_addr, ep_addr, max_packet_size, xfer_type); -} - -static void _remove_edpts_for_device(uint8_t dev_addr) { - for (size_t i = 0; i < TU_ARRAY_SIZE(_edpt_list); i++) { - if (_edpt_list[i].configured && _edpt_list[i].dev_addr == dev_addr) { - _edpt_list[i].configured = false; - } - } -} - -//--------------------------------------------------------------------+ -// Low-level hardware helpers -//--------------------------------------------------------------------+ - -// Busywait delay (approximate microseconds at ~60MHz) -TU_ATTR_ALWAYS_INLINE static inline void _delay_loops(uint32_t count) { - volatile uint32_t c = count / 3; - if (c == 0) return; - while (c-- != 0) {} -} - -static void _hw_init_host(uint8_t rhport, bool enabled) { - uint32_t base = _port_data[rhport].usb_base; - - if (!enabled) { - // Reset SIE when disabling - CH58X_USB_CTRL(base) = CH58X_UC_RESET_SIE | CH58X_UC_CLR_ALL; - _delay_loops(600); // ~10us at 60MHz - CH58X_USB_CTRL(base) = 0; - return; - } - - // host mode, pull-down enabled, clear addr - CH58X_USB_CTRL(base) = CH58X_UC_HOST_MODE; - while (!(CH58X_USB_CTRL(base) & CH58X_UC_HOST_MODE)) {} - CH58X_UHOST_CTRL(base) = 0; - CH58X_USB_DEV_AD(base) = 0x00; - - // EP2 RX (IN), EP3 TX (OUT/SETUP) - CH58X_UH_EP_MOD(base) = CH58X_UH_EP_TX_EN | CH58X_UH_EP_RX_EN; - - // DMA: 16-bit address, lower 64KB only - CH58X_UH_RX_DMA(base) = (uint16_t)(uint32_t)_rx_buf[rhport]; - CH58X_UH_TX_DMA(base) = (uint16_t)(uint32_t)_tx_buf[rhport]; - - CH58X_UH_RX_CTRL(base) = 0x00; - CH58X_UH_TX_CTRL(base) = 0x00; - - CH58X_USB_CTRL(base) = CH58X_UC_HOST_MODE | CH58X_UC_INT_BUSY | CH58X_UC_DMA_EN; - CH58X_UH_SETUP(base) = CH58X_UH_SOF_EN; - - CH58X_USB_INT_FG(base) = 0xFF; // clear all flags - CH58X_USB_INT_EN(base) = CH58X_UIE_TRANSFER | CH58X_UIE_DETECT; -} - -static bool _hw_start_xfer(uint8_t rhport, uint8_t pid, uint8_t ep_addr, uint8_t data_toggle) { - uint32_t base = _port_data[rhport].usb_base; - - LOG_CH58X_HCD("_hw_start_xfer(pid=0x%02x, ep=0x%02x, tog=%d)\r\n", pid, ep_addr, data_toggle); - - // Workaround: small delay for low-speed devices - bool is_lowspeed = tuh_speed_get(_current_xfer[rhport].dev_addr) == TUSB_SPEED_LOW; - if (is_lowspeed) { - _delay_loops(60000000 / 1000000 * 40); // ~40us at 60MHz - } - - // Set toggle controls (same as SDK: R8_UH_RX_CTRL = R8_UH_TX_CTRL = tog) - uint8_t tog_ctrl = (data_toggle != 0) ? CH58X_UH_T_TOG : 0; - CH58X_UH_TX_CTRL(base) = tog_ctrl; - CH58X_UH_RX_CTRL(base) = (data_toggle != 0) ? CH58X_UH_R_TOG : 0; - - uint8_t pid_endp = (pid << 4) | (tu_edpt_number(ep_addr) & 0x0F); - - // clear flag, enable int, then set PID to start transfer - CH58X_USB_INT_FG(base) = CH58X_UIF_TRANSFER; - CH58X_USB_INT_EN(base) |= CH58X_UIE_TRANSFER; - CH58X_UH_EP_PID(base) = pid_endp; - - return true; -} - -static void _hw_set_device_addr(uint8_t rhport, uint8_t dev_addr) { - uint32_t base = _port_data[rhport].usb_base; - CH58X_USB_DEV_AD(base) = (CH58X_USB_DEV_AD(base) & CH58X_UDA_GP_BIT) | - (dev_addr & CH58X_USB_ADDR_MASK); -} - -static void _hw_set_speed(uint8_t rhport, tusb_speed_t speed) { - uint32_t base = _port_data[rhport].usb_base; - - LOG_CH58X_HCD("_hw_set_speed(%s)\r\n", - speed == TUSB_SPEED_FULL ? "Full" : "Low"); - - if (speed == TUSB_SPEED_LOW) { - CH58X_USB_CTRL(base) |= CH58X_UC_LOW_SPEED; - CH58X_UHOST_CTRL(base) |= CH58X_UH_LOW_SPEED; - } else { - CH58X_USB_CTRL(base) &= ~CH58X_UC_LOW_SPEED; - CH58X_UHOST_CTRL(base) &= ~CH58X_UH_LOW_SPEED; - CH58X_UH_SETUP(base) &= ~CH58X_UH_PRE_PID_EN; - } -} - -static void _hw_set_addr_speed(uint8_t rhport, uint8_t dev_addr) { - _hw_set_device_addr(rhport, dev_addr); - - tusb_speed_t rhport_speed = hcd_port_speed_get(rhport); - tusb_speed_t dev_speed = tuh_speed_get(dev_addr); - _hw_set_speed(rhport, dev_speed); - - // FS root + LS device: hub uses PRE PID, clear LS on host ctrl - if (rhport_speed == TUSB_SPEED_FULL && dev_speed == TUSB_SPEED_LOW) { - uint32_t base = _port_data[rhport].usb_base; - CH58X_UHOST_CTRL(base) &= ~CH58X_UH_LOW_SPEED; - } -} - -static bool _hw_device_attached(uint8_t rhport) { - uint32_t base = _port_data[rhport].usb_base; - return (CH58X_USB_MIS_ST(base) & CH58X_UMS_DEV_ATTACH) != 0; -} - -//--------------------------------------------------------------------+ -// NAK retry callback -//--------------------------------------------------------------------+ -static void _xfer_retry(void* param) { - LOG_CH58X_HCD("_xfer_retry()\r\n"); - hcd_edpt_t* edpt = (hcd_edpt_t*)param; - - // Find which rhport this endpoint belongs to by checking both ports - for (uint8_t rp = 0; rp < 2; rp++) { - if (_current_xfer[rp].nak_pending) { - _current_xfer[rp].nak_pending = false; - edpt->is_nak_pending = false; - - uint8_t dev_addr = edpt->dev_addr; - uint8_t ep_addr = edpt->ep_addr; - uint16_t buflen = edpt->buflen; - uint8_t* buf = edpt->buf; - - // Check if endpoint is still valid - hcd_edpt_t* current = _get_edpt(dev_addr, ep_addr); - if (current) { - hcd_edpt_xfer(rp, dev_addr, ep_addr, buf, buflen); - } - break; - } - } -} - -//--------------------------------------------------------------------+ -// HCD API: Controller -//--------------------------------------------------------------------+ -bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { - (void)rh_init; - - _port_data[rhport].usb_base = _get_usb_base(rhport); - _port_data[rhport].int_enabled = false; - - // Clear endpoint records only on first init to avoid wiping state of the other rhport - static bool _first_init = true; - if (_first_init) { - tu_memclr(_edpt_list, sizeof(_edpt_list)); - _first_init = false; - } - _current_xfer[rhport] = (const hcd_xfer_t){0}; - - _hw_init_host(rhport, true); - - return true; -} - -bool hcd_deinit(uint8_t rhport) { - _hw_init_host(rhport, false); - return true; -} - -uint32_t hcd_frame_number(uint8_t rhport) { - (void)rhport; - return tusb_time_millis_api(); -} - -void hcd_int_enable(uint8_t rhport) { - uint8_t irqn = (rhport == 0) ? CH58X_USB_IRQn : CH58X_USB2_IRQn; - CH58X_PFIC_IENR[irqn / 32] = (1u << (irqn % 32)); - _port_data[rhport].int_enabled = true; -} - -void hcd_int_disable(uint8_t rhport) { - uint8_t irqn = (rhport == 0) ? CH58X_USB_IRQn : CH58X_USB2_IRQn; - CH58X_PFIC_IRER[irqn / 32] = (1u << (irqn % 32)); - __asm volatile("fence.i"); - _port_data[rhport].int_enabled = false; -} - -//--------------------------------------------------------------------+ -// HCD API: Port -//--------------------------------------------------------------------+ -bool hcd_port_connect_status(uint8_t rhport) { - return _hw_device_attached(rhport); -} - -tusb_speed_t hcd_port_speed_get(uint8_t rhport) { - uint32_t base = _port_data[rhport].usb_base; - if (CH58X_USB_MIS_ST(base) & CH58X_UMS_DM_LEVEL) { - return TUSB_SPEED_LOW; - } - return TUSB_SPEED_FULL; -} - -void hcd_port_reset(uint8_t rhport) { - uint32_t base = _port_data[rhport].usb_base; - - LOG_CH58X_HCD("hcd_port_reset()\r\n"); - - _port_data[rhport].int_state_before_reset = _port_data[rhport].int_enabled; - hcd_int_disable(rhport); - - _hw_set_device_addr(rhport, 0x00); - - // Disable port and default to full-speed before reset (matches SDK ResetRootHubPort) - CH58X_UHOST_CTRL(base) &= ~CH58X_UH_PORT_EN; - _hw_set_speed(rhport, TUSB_SPEED_FULL); - - // Start bus reset (clear low-speed bit simultaneously) - CH58X_UHOST_CTRL(base) = (CH58X_UHOST_CTRL(base) & ~CH58X_UH_LOW_SPEED) | CH58X_UH_BUS_RESET; -} - -void hcd_port_reset_end(uint8_t rhport) { - uint32_t base = _port_data[rhport].usb_base; - - LOG_CH58X_HCD("hcd_port_reset_end()\r\n"); - - // End bus reset - CH58X_UHOST_CTRL(base) &= ~CH58X_UH_BUS_RESET; - tusb_time_delay_ms_api(2); - - // Detect speed and configure - if ((CH58X_UHOST_CTRL(base) & CH58X_UH_PORT_EN) == 0) { - if (hcd_port_speed_get(rhport) == TUSB_SPEED_LOW) { - _hw_set_speed(rhport, TUSB_SPEED_LOW); - } - } - - // Enable port and SOF - CH58X_UHOST_CTRL(base) |= CH58X_UH_PORT_EN; - CH58X_UH_SETUP(base) |= CH58X_UH_SOF_EN; - - // Suppress stale detect event - CH58X_USB_INT_FG(base) = CH58X_UIF_DETECT; - - if (_port_data[rhport].int_state_before_reset) { - hcd_int_enable(rhport); - } -} - -void hcd_device_close(uint8_t rhport, uint8_t dev_addr) { - (void)rhport; - LOG_CH58X_HCD("hcd_device_close(dev=0x%02x)\r\n", dev_addr); - _remove_edpts_for_device(dev_addr); -} - -//--------------------------------------------------------------------+ -// HCD API: Endpoint -//--------------------------------------------------------------------+ -bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const* ep_desc) { - 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; - uint32_t base = _port_data[rhport].usb_base; - - LOG_CH58X_HCD("hcd_edpt_open(dev=0x%02x, ep=0x%02x, mps=%d, type=%d)\r\n", - dev_addr, ep_addr, max_packet_size, xfer_type); - - // Wait for any pending transfer - uint32_t t0 = tusb_time_millis_api(); - while (_current_xfer[rhport].is_busy) { - if (tusb_time_millis_api() - t0 > 200) { - _current_xfer[rhport].is_busy = false; - break; - } - } - - if (ep_num == 0) { - TU_ASSERT(_get_or_add_edpt(dev_addr, 0x00, max_packet_size, xfer_type) != NULL, false); - TU_ASSERT(_get_or_add_edpt(dev_addr, 0x80, max_packet_size, xfer_type) != NULL, false); - } else { - TU_ASSERT(_get_or_add_edpt(dev_addr, ep_addr, max_packet_size, xfer_type) != NULL, false); - } - - // Ensure port is enabled with SOF - CH58X_UHOST_CTRL(base) |= CH58X_UH_PORT_EN; - CH58X_UH_SETUP(base) |= CH58X_UH_SOF_EN; - - _hw_set_addr_speed(rhport, dev_addr); - - return true; -} - -bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, - uint8_t* buffer, uint16_t buflen) { - uint32_t base = _port_data[rhport].usb_base; - - LOG_CH58X_HCD("hcd_edpt_xfer(dev=0x%02x, ep=0x%02x, len=%d)\r\n", - dev_addr, ep_addr, buflen); - - // Wait for any pending transfer (with 200ms timeout to avoid deadlock on disconnect) - uint32_t t0 = tusb_time_millis_api(); - while (_current_xfer[rhport].is_busy) { - if (tusb_time_millis_api() - t0 > 200) { - _current_xfer[rhport].is_busy = false; - return false; - } - } - _current_xfer[rhport].is_busy = true; - - hcd_edpt_t* edpt = _get_edpt(dev_addr, ep_addr); - TU_ASSERT(edpt != NULL); - - _hw_set_addr_speed(rhport, dev_addr); - - _current_xfer[rhport].rhport = rhport; - _current_xfer[rhport].dev_addr = dev_addr; - _current_xfer[rhport].ep_addr = ep_addr; - _current_xfer[rhport].buffer = buffer; - _current_xfer[rhport].bufferlen = buflen; - _current_xfer[rhport].start_ms = tusb_time_millis_api(); - _current_xfer[rhport].xferred_len = 0; - _current_xfer[rhport].nak_pending = false; - - if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { - // IN transfer: host receives data - return _hw_start_xfer(rhport, CH58X_USB_PID_IN, ep_addr, edpt->data_toggle); - } else { - // OUT transfer: host sends data - uint16_t copylen = TU_MIN(edpt->max_packet_size, buflen); - CH58X_UH_TX_LEN(base) = (uint8_t)copylen; - memcpy(_tx_buf[rhport], buffer, copylen); - return _hw_start_xfer(rhport, CH58X_USB_PID_OUT, ep_addr, edpt->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; - return false; -} - -bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) { - uint32_t base = _port_data[rhport].usb_base; - - LOG_CH58X_HCD("hcd_setup_send(dev=0x%02x)\r\n", dev_addr); - - // Wait for any pending transfer - uint32_t t0 = tusb_time_millis_api(); - while (_current_xfer[rhport].is_busy) { - if (tusb_time_millis_api() - t0 > 200) { - _current_xfer[rhport].is_busy = false; - return false; - } - } - _current_xfer[rhport].is_busy = true; - - _hw_set_addr_speed(rhport, dev_addr); - - hcd_edpt_t* edpt_tx = _get_edpt(dev_addr, 0x00); - hcd_edpt_t* edpt_rx = _get_edpt(dev_addr, 0x80); - TU_ASSERT(edpt_tx != NULL, false); - TU_ASSERT(edpt_rx != NULL, false); - - // SETUP always starts with DATA0; after SETUP, IN data starts with DATA1 - edpt_tx->data_toggle = 0; - edpt_rx->data_toggle = 1; - - memcpy(_tx_buf[rhport], setup_packet, 8); - CH58X_UH_TX_LEN(base) = 8; - - _current_xfer[rhport].rhport = rhport; - _current_xfer[rhport].dev_addr = dev_addr; - _current_xfer[rhport].ep_addr = 0x00; // SETUP always targets EP0 OUT - _current_xfer[rhport].start_ms = tusb_time_millis_api(); - _current_xfer[rhport].buffer = _tx_buf[rhport]; - _current_xfer[rhport].bufferlen = 8; - _current_xfer[rhport].xferred_len = 0; - _current_xfer[rhport].nak_pending = false; - - _hw_start_xfer(rhport, CH58X_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; - - LOG_CH58X_HCD("hcd_edpt_clear_stall(dev=0x%02x, ep=0x%02x)\r\n", dev_addr, ep_addr); - hcd_edpt_t* edpt = _get_edpt(dev_addr, ep_addr); - if (edpt != NULL) { - edpt->data_toggle = 0; - } - - return true; -} - -//--------------------------------------------------------------------+ -// Interrupt Handler -//--------------------------------------------------------------------+ -void hcd_int_handler(uint8_t rhport, bool in_isr) { - uint32_t base = _port_data[rhport].usb_base; - - //-- Device attach/detach detection -- - if (CH58X_USB_INT_FG(base) & CH58X_UIF_DETECT) { - CH58X_USB_INT_FG(base) = CH58X_UIF_DETECT; - - bool attached = _hw_device_attached(rhport); - LOG_CH58X_HCD("hcd_int: detect, attached=%d\r\n", attached); - - if (attached) { - hcd_event_device_attach(rhport, in_isr); - } else { - // Stop any ongoing hardware transfer before reporting removal - CH58X_UH_EP_PID(base) = 0x00; - _current_xfer[rhport].is_busy = false; - _current_xfer[rhport].nak_pending = false; - hcd_event_device_remove(rhport, in_isr); - } - return; - } - - //-- Transfer complete -- - if (CH58X_USB_INT_FG(base) & CH58X_UIF_TRANSFER) { - // Read PID/endpoint before stopping (must read first!) - uint8_t pid_endp = CH58X_UH_EP_PID(base); - uint8_t int_st = CH58X_USB_INT_ST(base); - uint8_t dev_addr = CH58X_USB_DEV_AD(base) & CH58X_USB_ADDR_MASK; - - // Stop USB transaction immediately (SDK: R8_UH_EP_PID = 0x00) - CH58X_UH_EP_PID(base) = 0x00; - - // Disable transfer interrupt (re-enabled when next transfer starts) - CH58X_USB_INT_EN(base) &= ~CH58X_UIE_TRANSFER; - - uint8_t request_pid = pid_endp >> 4; - uint8_t response_pid = int_st & CH58X_UIS_H_RES_MASK; - uint8_t ep_addr = pid_endp & 0x0F; - if (request_pid == CH58X_USB_PID_IN) { - ep_addr |= 0x80; - } - - LOG_CH58X_HCD("hcd_int: xfer pid=0x%02x ep=0x%02x resp=0x%02x\r\n", - request_pid, ep_addr, response_pid); - - hcd_edpt_t* edpt = _get_edpt(dev_addr, ep_addr); - if (edpt == NULL) { - // Unknown endpoint, discard - LOG_CH58X_HCD("hcd_int: unknown edpt dev=0x%02x ep=0x%02x\r\n", dev_addr, ep_addr); - _current_xfer[rhport].is_busy = false; - CH58X_USB_INT_FG(base) = CH58X_UIF_TRANSFER; - return; - } - - // Check toggle match - SDK uses R8_USB_INT_ST & RB_UIS_TOG_OK - if (int_st & CH58X_UIS_TOG_OK) { - edpt->data_toggle ^= 0x01; - - switch (request_pid) { - case CH58X_USB_PID_SETUP: - case CH58X_USB_PID_OUT: { - uint8_t tx_len = CH58X_UH_TX_LEN(base); - _current_xfer[rhport].bufferlen -= tx_len; - _current_xfer[rhport].xferred_len += tx_len; - - if (_current_xfer[rhport].bufferlen == 0) { - LOG_CH58X_HCD("OUT/SETUP complete, %d bytes\r\n", _current_xfer[rhport].xferred_len); - _current_xfer[rhport].is_busy = false; - hcd_event_xfer_complete(dev_addr, ep_addr, - _current_xfer[rhport].xferred_len, XFER_RESULT_SUCCESS, in_isr); - } else { - // Multi-packet OUT: send next chunk - _current_xfer[rhport].buffer += tx_len; - uint16_t copylen = TU_MIN(edpt->max_packet_size, _current_xfer[rhport].bufferlen); - memcpy(_tx_buf[rhport], _current_xfer[rhport].buffer, copylen); - CH58X_UH_TX_LEN(base) = (uint8_t)copylen; - _hw_start_xfer(rhport, CH58X_USB_PID_OUT, ep_addr, edpt->data_toggle); - } - break; - } - - case CH58X_USB_PID_IN: { - uint8_t rx_len = CH58X_USB_RX_LEN(base); - _current_xfer[rhport].xferred_len += rx_len; - uint16_t xferred = _current_xfer[rhport].xferred_len; - - if (rx_len > 0 && _current_xfer[rhport].buffer != NULL) { - memcpy(_current_xfer[rhport].buffer, _rx_buf[rhport], rx_len); - _current_xfer[rhport].buffer += rx_len; - } - - if ((rx_len < edpt->max_packet_size) || (xferred == _current_xfer[rhport].bufferlen)) { - // Short packet or transfer complete - LOG_CH58X_HCD("IN complete, %d bytes\r\n", xferred); - _current_xfer[rhport].is_busy = false; - hcd_event_xfer_complete(dev_addr, ep_addr, xferred, - XFER_RESULT_SUCCESS, in_isr); - } else { - // More data expected - _hw_start_xfer(rhport, CH58X_USB_PID_IN, ep_addr, edpt->data_toggle); - } - break; - } - - default: { - LOG_CH58X_HCD("unexpected PID 0x%02x\r\n", request_pid); - _current_xfer[rhport].is_busy = false; - hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, in_isr); - break; - } - } - } else { - // Toggle mismatch, check response PID - if (response_pid == CH58X_USB_PID_STALL) { - LOG_CH58X_HCD("STALL response\r\n"); - edpt->data_toggle = 0; - _current_xfer[rhport].is_busy = false; - hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_STALLED, in_isr); - } else if (response_pid == CH58X_USB_PID_NAK) { - LOG_CH58X_HCD("NAK response\r\n"); - // For interrupt endpoints, treat NAK as a successful 0-byte poll so - // that upper layers can reschedule based on the endpoint interval. - if (edpt->xfer_type == TUSB_XFER_INTERRUPT) { - _current_xfer[rhport].is_busy = false; - hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_SUCCESS, in_isr); - } else { - // For non-interrupt endpoints, schedule retry via deferred callback. - _current_xfer[rhport].is_busy = false; - _current_xfer[rhport].nak_pending = true; - - edpt->is_nak_pending = true; - edpt->buflen = _current_xfer[rhport].bufferlen; - edpt->buf = _current_xfer[rhport].buffer; - - hcd_event_t event = { - .rhport = rhport, - .dev_addr = dev_addr, - .event_id = USBH_EVENT_FUNC_CALL, - .func_call = { - .func = _xfer_retry, - .param = edpt - } - }; - hcd_event_handler(&event, in_isr); - } - } else if (response_pid == CH58X_USB_PID_DATA0 || response_pid == CH58X_USB_PID_DATA1) { - LOG_CH58X_HCD("toggle mismatch, DATA0/1 rx_len=%d\r\n", CH58X_USB_RX_LEN(base)); - _current_xfer[rhport].is_busy = false; - hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, in_isr); - } else { - LOG_CH58X_HCD("unexpected response 0x%02x\r\n", response_pid); - _current_xfer[rhport].is_busy = false; - hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, in_isr); - } - } - - // Clear transfer flag - CH58X_USB_INT_FG(base) = CH58X_UIF_TRANSFER; - } -} - -#endif /* CFG_TUH_ENABLED && TUP_USBIP_WCH_CH58X */ -- cgit v1.3.1 From dcb060c894713d60ce0ab009733e5d59a32d0d23 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 19 Jun 2026 21:37:52 +0700 Subject: dcd/ch58x: complete the EP register map and right-size EP buffers Tidy the CH58x register/buffer layout the initial port left rough. Register map (USBOTG_FS_TypeDef): - Extend the struct to the full CH583/582 datasheet Table 17-2 map instead of stopping at UEP567_MOD (0x0E) with the per-endpoint registers living only in raw-address macros. - Express the per-endpoint DMA/length/control registers as arrays of 4-byte slots (ch58x_ep_dma_t / ch58x_ep_ctrl_t): EP0-3 DMA at 0x10, EP0-4 ctrl at 0x20, EP5-7 DMA/ctrl split to 0x54/0x64 (EP4 has no DMA register of its own; it shares EP0's). TU_VERIFY_STATIC pins the slot sizes and block offsets, so the EP_TX_LEN/EP_CTRL/EP_DMA macros walk each block by the 4-byte stride (pointer arithmetic off slot 0, so the unused ternary branch can't trip -Warray-bounds). - Gate the two driver sites on CFG_TUSB_MCU == OPT_MCU_CH58X directly rather than the CH32_USBFS_EP_REGS_CUSTOM alias, which was only ever defined in the CH58x branch. EP buffers (the data struct): - Replace buffer[EP_MAX][2][64] on CH58x with named per-endpoint buffers: EP0/EP4 use the dedicated 192B ep0_ep4_buffer, so the old array left buffer[0]/buffer[4] allocated-but-unused. - Drop EP3's oversized iso buffer (out[64] + in[1023]); EP3 is bulk-only on CH58x, so it uses a plain 128-byte buffer like the others. The data struct shrinks from ~2636 to 1292 bytes. - Keep the now uniformly-64-byte buffers safe: dcd_edpt_iso_alloc()/iso_activate() refuse isochronous on CH58x (no iso support; 8-bit T_LEN caps a packet at 255B), and update_in()/update_out() additionally cap each packet copy to 64 bytes so a class that ignores the iso-alloc result cannot run a memcpy past a buffer into a neighbour's. Non-CH58x parts (e.g. ch32v103) keep the struct-based macros, buffer[EP_MAX], and the iso buffer unchanged. Verified on ch582m_evt HIL (ci.lan): all device examples pass; ch32v103 build unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/portable/wch/ch32_usbfs_reg.h | 59 ++++++++++++++-------- src/portable/wch/dcd_ch32_usbfs.c | 102 +++++++++++++++++++++++++++++++------- 2 files changed, 123 insertions(+), 38 deletions(-) (limited to 'src/portable/wch') diff --git a/src/portable/wch/ch32_usbfs_reg.h b/src/portable/wch/ch32_usbfs_reg.h index 0d61e183c..9c58c467f 100644 --- a/src/portable/wch/ch32_usbfs_reg.h +++ b/src/portable/wch/ch32_usbfs_reg.h @@ -137,27 +137,53 @@ // the EP control/length block sits lower (EP0_CTRL @ +0x22), EP5-7 are split out, EP4 // shares EP0's DMA buffer, and EP5/6/7 mode bits live in one UEP567_MOD. The control/status // block matches CH32. Two FS controllers exist (USB @ 0x40008000, USB2 @ 0x40008400); the - // device uses USB0. EP registers are accessed via the CH58X macros below (not the struct). + // device uses USB0. Full register map per CH583/582 datasheet Table 17-2; the parameterized + // EP_* macros below index off these named fields. #define CH58X_USBFS_BASE 0x40008000u + // Per-endpoint register slots, 4-byte stride each; the EP_* macros index arrays of these. typedef struct { - __IO uint8_t BASE_CTRL; // 0x00 - __IO uint8_t UDEV_CTRL; // 0x01 - __IO uint8_t INT_EN; // 0x02 - __IO uint8_t DEV_ADDR; // 0x03 + __IO uint16_t DMA; // R16_UEPn_DMA: endpoint n buffer start address + __IO uint16_t reserved; + } ch58x_ep_dma_t; + typedef struct { + __IO uint8_t T_LEN; // R8_UEPn_T_LEN (+0): transmit length + __IO uint8_t reserved0; + __IO uint8_t CTRL; // R8_UEPn_CTRL (+2): endpoint control + __IO uint8_t reserved1; + } ch58x_ep_ctrl_t; + typedef struct { + __IO uint8_t BASE_CTRL; // 0x00 R8_USB_CTRL + __IO uint8_t UDEV_CTRL; // 0x01 R8_UDEV_CTRL + __IO uint8_t INT_EN; // 0x02 R8_USB_INT_EN + __IO uint8_t DEV_ADDR; // 0x03 R8_USB_DEV_AD __IO uint8_t Reserve0; // 0x04 - __IO uint8_t MIS_ST; // 0x05 - __IO uint8_t INT_FG; // 0x06 - __IO uint8_t INT_ST; // 0x07 - __IO uint8_t RX_LEN; // 0x08 (8-bit on CH58X) + __IO uint8_t MIS_ST; // 0x05 R8_USB_MIS_ST + __IO uint8_t INT_FG; // 0x06 R8_USB_INT_FG + __IO uint8_t INT_ST; // 0x07 R8_USB_INT_ST + __IO uint8_t RX_LEN; // 0x08 R8_USB_RX_LEN (8-bit on CH58X) __IO uint8_t Reserve1[3]; // 0x09..0x0B - __IO uint8_t UEP4_1_MOD; // 0x0C - __IO uint8_t UEP2_3_MOD; // 0x0D - __IO uint8_t UEP567_MOD; // 0x0E + __IO uint8_t UEP4_1_MOD; // 0x0C R8_UEP4_1_MOD + __IO uint8_t UEP2_3_MOD; // 0x0D R8_UEP2_3_MOD + __IO uint8_t UEP567_MOD; // 0x0E R8_UEP567_MOD + __IO uint8_t Reserve2; // 0x0F + ch58x_ep_dma_t EP_DMA_0_3[4]; // 0x10 EP0-3 DMA (EP4 has no DMA reg; it shares EP0's, index 0) + ch58x_ep_ctrl_t EP_CTRL_0_4[5]; // 0x20 EP0-4 length/control + __IO uint8_t Reserve3[0x54u - 0x34u]; // 0x34..0x53 + ch58x_ep_dma_t EP_DMA_5_7[3]; // 0x54 EP5-7 DMA + __IO uint8_t Reserve4[0x64u - 0x60u]; // 0x60..0x63 + ch58x_ep_ctrl_t EP_CTRL_5_7[3]; // 0x64 EP5-7 length/control } USBOTG_FS_TypeDef; #define USBOTG_FS ((USBOTG_FS_TypeDef *) CH58X_USBFS_BASE) + // 4-byte slot stride + these block offsets pin every EP register to its datasheet address. + TU_VERIFY_STATIC(sizeof(ch58x_ep_dma_t) == 4, "CH58x EP DMA slot must be 4 bytes"); + TU_VERIFY_STATIC(sizeof(ch58x_ep_ctrl_t) == 4, "CH58x EP ctrl slot must be 4 bytes"); + TU_VERIFY_STATIC(offsetof(USBOTG_FS_TypeDef, EP_DMA_0_3) == 0x10, "CH58x EP_DMA_0_3 @0x10"); + TU_VERIFY_STATIC(offsetof(USBOTG_FS_TypeDef, EP_CTRL_0_4) == 0x20, "CH58x EP_CTRL_0_4 @0x20"); + TU_VERIFY_STATIC(offsetof(USBOTG_FS_TypeDef, EP_DMA_5_7) == 0x54, "CH58x EP_DMA_5_7 @0x54"); + TU_VERIFY_STATIC(offsetof(USBOTG_FS_TypeDef, EP_CTRL_5_7) == 0x64, "CH58x EP_CTRL_5_7 @0x64"); + #define CH32_USBFS_EP_CTRL_COMBINED 1 - #define CH32_USBFS_EP_REGS_CUSTOM 1 // EP register macros provided here, not by the driver // CH58x's hardware AUTO_TOG does not stay in sync (notably across clear-stall and multi-packet // bulk transfers), causing data-toggle mismatch and bus resets. Drive the toggle manually in // the ISR instead. CH32V103/V20x/V307 keep AUTO_TOG (this macro is undefined for them). @@ -170,13 +196,6 @@ #define NVIC_EnableIRQ(n) PFIC_EnableIRQ(n) #define NVIC_DisableIRQ(n) PFIC_DisableIRQ(n) #endif - - // EP register access. EP0-4: T_LEN @ +0x20+ep*4, CTRL @ +0x22+ep*4. EP5-7 split: T_LEN @ - // +0x64, CTRL @ +0x66. DMA: EP0-3 @ +0x10+ep*4, EP5-7 @ +0x54; EP4 shares EP0's buffer - // (no own DMA reg) so its slot points at a reserved word. - #define EP_TX_LEN(ep) (*(volatile uint8_t *)(CH58X_USBFS_BASE + ((ep) <= 4u ? 0x20u + (ep)*4u : 0x64u + ((ep)-5u)*4u))) - #define EP_CTRL(ep) (*(volatile uint8_t *)(CH58X_USBFS_BASE + ((ep) <= 4u ? 0x22u + (ep)*4u : 0x66u + ((ep)-5u)*4u))) - #define EP_DMA(ep) (*(volatile uint16_t *)(CH58X_USBFS_BASE + ((ep) <= 3u ? 0x10u + (ep)*4u : (ep) == 4u ? 0x40u : 0x54u + ((ep)-5u)*4u))) #endif #ifdef __GNUC__ diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 7beb91e16..12b45c784 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -35,13 +35,25 @@ /* private defines */ #define EP_MAX (8) - // Struct-based EP register access (uniform layout). Some parts (e.g. CH58X) have a different - // register map and define EP_DMA/EP_TX_LEN/EP_CTRL themselves in ch32_usbfs_reg.h. - #ifndef CH32_USBFS_EP_REGS_CUSTOM - #define EP_DMA(ep) ((&USBOTG_FS->UEP0_DMA)[ep]) - #define EP_TX_LEN(ep) ((&USBOTG_FS->UEP0_TX_LEN)[2 * ep]) - #define EP_TX_CTRL(ep) ((&USBOTG_FS->UEP0_TX_CTRL)[4 * ep]) - #define EP_RX_CTRL(ep) ((&USBOTG_FS->UEP0_RX_CTRL)[4 * ep]) + // Struct-based EP register access (uniform layout). CH58X has a different register map and + // defines EP_DMA/EP_TX_LEN/EP_CTRL itself in ch32_usbfs_reg.h. + #if CFG_TUSB_MCU == OPT_MCU_CH58X + // CH58X EP registers split into a low block (EP0-4) and a high block (EP5-7). Walk from each + // block's first slot by the 4-byte slot stride (pointer arithmetic off slot 0, so the unused + // ternary branch's index can't trip -Warray-bounds). EP4 has no DMA register of its own (it + // shares EP0's, slot 0) and is never written (see ep_shares_ep0_dma()). + #define EP_TX_LEN(ep) (*((ep) <= 4u ? &USBOTG_FS->EP_CTRL_0_4[0].T_LEN + (ep) * 4u \ + : &USBOTG_FS->EP_CTRL_5_7[0].T_LEN + ((ep) - 5u) * 4u)) + #define EP_CTRL(ep) (*((ep) <= 4u ? &USBOTG_FS->EP_CTRL_0_4[0].CTRL + (ep) * 4u \ + : &USBOTG_FS->EP_CTRL_5_7[0].CTRL + ((ep) - 5u) * 4u)) + #define EP_DMA(ep) (*((ep) <= 3u ? &USBOTG_FS->EP_DMA_0_3[0].DMA + (ep) * 2u \ + : (ep) == 4u ? &USBOTG_FS->EP_DMA_0_3[0].DMA \ + : &USBOTG_FS->EP_DMA_5_7[0].DMA + ((ep) - 5u) * 2u)) + #else + #define EP_DMA(ep) ((&USBOTG_FS->UEP0_DMA)[ep]) + #define EP_TX_LEN(ep) ((&USBOTG_FS->UEP0_TX_LEN)[2 * ep]) + #define EP_TX_CTRL(ep) ((&USBOTG_FS->UEP0_TX_CTRL)[4 * ep]) + #define EP_RX_CTRL(ep) ((&USBOTG_FS->UEP0_RX_CTRL)[4 * ep]) #endif // Endpoint control register access. The newer USBFS IP (CH32V20x/V307/X035) has separate @@ -116,48 +128,82 @@ static struct { bool ep0_tog; bool isochronous[EP_MAX]; struct usb_xfer xfer[EP_MAX][2]; - TU_ATTR_ALIGNED(4) uint8_t buffer[EP_MAX][2][64]; #ifdef CH32_USBFS_EP4_SHARES_EP0 - // CH58X: EP0 and EP4 share one DMA region (EP4 has no DMA register). Layout: - // EP0 [0:63] (half-duplex, OUT+IN) + EP4 OUT [64:127] + EP4 IN [128:191]. buffer[0]/buffer[4] - // are left unused for this part. + // CH58X buffers laid out by hand so EP0/EP4 don't burn two unused buffer[] slots. EP0 and EP4 + // share one contiguous 192-byte DMA region (EP4 has no DMA register of its own): + // EP0 [0:63] (half-duplex OUT+IN) + EP4 OUT [64:127] + EP4 IN [128:191]. Every other endpoint + // (incl. EP3, which is bulk-only here — CH58X has no isochronous support) gets a plain 128-byte + // OUT+IN buffer, so no oversized EP3 buffer is needed. TU_ATTR_ALIGNED(4) uint8_t ep0_ep4_buffer[3 * 64]; -#endif + TU_ATTR_ALIGNED(4) uint8_t ep1_buffer[2][64]; + TU_ATTR_ALIGNED(4) uint8_t ep2_buffer[2][64]; + TU_ATTR_ALIGNED(4) uint8_t ep3_buffer[2][64]; + TU_ATTR_ALIGNED(4) uint8_t ep5_buffer[2][64]; + TU_ATTR_ALIGNED(4) uint8_t ep6_buffer[2][64]; + TU_ATTR_ALIGNED(4) uint8_t ep7_buffer[2][64]; +#else + TU_ATTR_ALIGNED(4) uint8_t buffer[EP_MAX][2][64]; + // EP3 IN gets an enlarged buffer for full-speed isochronous (packets up to 1023 B). TU_ATTR_ALIGNED(4) struct { // OUT transfers >64 bytes will overwrite queued IN data! uint8_t out[64]; uint8_t in[1023]; uint8_t pad; } ep3_buffer; +#endif } data; // DMA / copy buffer pointers per endpoint. The WCH USBFS buffer holds OUT (RX) at offset 0 and // IN (TX) at +64; EP0 is half-duplex and reuses its OUT chunk for IN; EP3 has an enlarged IN -// buffer for throughput. On CH58X, EP4 overlays EP0's region (see ep0_ep4_buffer above). -static inline uint32_t ep_dma_addr(uint8_t ep) { +// buffer for throughput. On CH58X, EP0/EP4 share ep0_ep4_buffer and the regular endpoints use +// their own named buffer (see the struct above). #ifdef CH32_USBFS_EP4_SHARES_EP0 - if (ep == 0) { return (uint32_t) &data.ep0_ep4_buffer[0]; } +// OUT base of the regular CH58X endpoints (EP1/2/3/5/6/7; EP0/EP4 share ep0_ep4_buffer). +static inline uint8_t* ch58x_ep_buffer(uint8_t ep) { + switch (ep) { + case 1: return data.ep1_buffer[0]; + case 2: return data.ep2_buffer[0]; + case 3: return data.ep3_buffer[0]; + case 5: return data.ep5_buffer[0]; + case 6: return data.ep6_buffer[0]; + default: return data.ep7_buffer[0]; // ep == 7 + } +} #endif + +static inline uint32_t ep_dma_addr(uint8_t ep) { +#ifdef CH32_USBFS_EP4_SHARES_EP0 + if (ep == 0 || ep == 4) { return (uint32_t) &data.ep0_ep4_buffer[0]; } // EP4 shares EP0's DMA + return (uint32_t) ch58x_ep_buffer(ep); +#else if (ep == 3) { return (uint32_t) &data.ep3_buffer.out[0]; } return (uint32_t) &data.buffer[ep][0]; +#endif } + static inline uint8_t* ep_out_buf(uint8_t ep) { #ifdef CH32_USBFS_EP4_SHARES_EP0 if (ep == 0) { return &data.ep0_ep4_buffer[0]; } if (ep == 4) { return &data.ep0_ep4_buffer[64]; } -#endif + return ch58x_ep_buffer(ep); +#else if (ep == 3) { return data.ep3_buffer.out; } return data.buffer[ep][TUSB_DIR_OUT]; +#endif } + static inline uint8_t* ep_in_buf(uint8_t ep) { #ifdef CH32_USBFS_EP4_SHARES_EP0 if (ep == 0) { return &data.ep0_ep4_buffer[0]; } // EP0 half-duplex: IN reuses OUT chunk if (ep == 4) { return &data.ep0_ep4_buffer[128]; } -#endif + return ch58x_ep_buffer(ep) + 64; // IN at +64 within the endpoint's 128-byte buffer +#else if (ep == 0) { return data.buffer[0][TUSB_DIR_OUT]; } // EP0 half-duplex: IN reuses OUT chunk if (ep == 3) { return data.ep3_buffer.in; } return data.buffer[ep][TUSB_DIR_IN]; +#endif } + // EP4 on CH58X has no DMA register (shares EP0's); skip its EP_DMA() write. static inline bool ep_shares_ep0_dma(uint8_t ep) { #ifdef CH32_USBFS_EP4_SHARES_EP0 @@ -174,6 +220,12 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force) { if (xfer->valid) { if (force || xfer->len) { size_t len = TU_MIN(xfer->max_size, xfer->len); +#if CFG_TUSB_MCU == OPT_MCU_CH58X + // Every CH58x endpoint buffer is 64 bytes. Isochronous (which would push max_size up to 1023) + // is refused in dcd_edpt_iso_alloc(), but some classes (e.g. video) ignore that result, so cap + // the copy here to guarantee we never write past the buffer into a neighbouring endpoint's. + len = TU_MIN(len, 64u); +#endif memcpy(ep_in_buf(ep), xfer->buffer, len); xfer->buffer += len; xfer->len -= len; @@ -204,6 +256,9 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { struct usb_xfer *xfer = &data.xfer[ep][TUSB_DIR_OUT]; if (xfer->valid) { size_t len = TU_MIN(xfer->max_size, TU_MIN(xfer->len, rx_len)); +#if CFG_TUSB_MCU == OPT_MCU_CH58X + len = TU_MIN(len, 64u); // cap to the 64-byte EP buffer (see update_in) +#endif memcpy(xfer->buffer, ep_out_buf(ep), len); xfer->buffer += len; xfer->len -= len; @@ -253,7 +308,7 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { // enable other endpoints but NAK everything USBOTG_FS->UEP4_1_MOD = 0xCC; USBOTG_FS->UEP2_3_MOD = 0xCC; -#ifdef CH32_USBFS_EP_REGS_CUSTOM +#if CFG_TUSB_MCU == OPT_MCU_CH58X // CH58X: a single mode register enables EP5/6/7 RX+TX (different bit layout than CH32). USBOTG_FS->UEP567_MOD = RB_UEP5_RX_EN | RB_UEP5_TX_EN | RB_UEP6_RX_EN | RB_UEP6_TX_EN | RB_UEP7_RX_EN | RB_UEP7_TX_EN; @@ -413,18 +468,29 @@ bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet (void)rhport; (void)ep_addr; (void)largest_packet_size; +#if CFG_TUSB_MCU == OPT_MCU_CH58X + // No isochronous support on CH58x: its 8-bit T_LEN caps a packet at 255B and the endpoints use + // plain 64-byte buffers, so accepting an iso max_size (up to 1023) would let update_in()/ + // update_out() run off the end of the buffer into neighbouring ones. Refuse it outright. + return false; +#else uint8_t ep = tu_edpt_number(ep_addr); uint8_t dir = tu_edpt_dir(ep_addr); data.isochronous[ep] = true; data.xfer[ep][dir].max_size = largest_packet_size; return true; +#endif } bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { (void)rhport; (void)desc_ep; +#if CFG_TUSB_MCU == OPT_MCU_CH58X + return false; // CH58x has no isochronous support (see dcd_edpt_iso_alloc) +#else return true; +#endif } bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool is_isr) { -- cgit v1.3.1 From 0c4c0be4589b2807abde5ef9ab156b6aaaad6616 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 19 Jun 2026 22:54:50 +0700 Subject: dcd/ch58x: keep IRQ masked across the EP-arming RMW in dcd_edpt_xfer dcd_edpt_xfer() re-enabled the USB interrupt before update_in() / ep_rx_set_response(), which read-modify-write the (combined) EP control register. On CH58x the ISR RMWs that same register to flip the manual data toggle, so a transfer interrupt landing mid-RMW could drop the toggle flip and desync the endpoint. Move dcd_int_enable() to after the arming so the whole sequence is atomic w.r.t. the ISR (matching the CH32X035 port #3703). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/portable/wch/dcd_ch32_usbfs.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/portable/wch') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 12b45c784..e8b3c86b2 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -500,12 +500,14 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to uint8_t dir = tu_edpt_dir(ep_addr); struct usb_xfer *xfer = &data.xfer[ep][dir]; + // Keep the IRQ masked across the whole arming sequence: update_in()/ep_rx_set_response() do a + // read-modify-write of the (combined) EP control register, which the ISR also RMWs to flip the + // manual data toggle; re-enabling before they run lets a transfer IRQ clobber that toggle. dcd_int_disable(rhport); xfer->valid = true; xfer->buffer = buffer; xfer->len = total_bytes; xfer->processed_len = 0; - dcd_int_enable(rhport); if (dir == TUSB_DIR_IN) { update_in(rhport, ep, true); @@ -513,6 +515,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to uint8_t rx_res = data.isochronous[ep] ? USBFS_EP_R_RES_NYET : USBFS_EP_R_RES_ACK; ep_rx_set_response(ep, rx_res); } + dcd_int_enable(rhport); return true; } -- cgit v1.3.1 From 58b5447b606b49c76187c48e5b76690f4a111143 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 19 Jun 2026 22:55:54 +0700 Subject: dcd/ch58x: advance EP0 OUT data toggle for multi-packet control transfers The manual-toggle ISR skipped EP0 entirely (if (ep != 0)), so EP0's RX data toggle was set to DATA1 once at SETUP and never advanced. A control-OUT whose data stage exceeds the EP0 packet size (a vendor/WebUSB OUT, a large HID SET_REPORT, or an HS DFU download) desynced on the second packet and stalled. EP0 has no hardware auto-toggle on CH58x (per the datasheet RB_UEP_AUTO_TOG applies only to EP1/2/3/5/6/7), so flip its RX toggle on every OUT and always process the packet -- restoring what the removed dcd_ch58x_usbfs.c did. The HIL examples keep their control-OUT data stages within a single packet, so this was latent. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/portable/wch/dcd_ch32_usbfs.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'src/portable/wch') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index e8b3c86b2..164b6f7bf 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -336,10 +336,13 @@ void dcd_int_handler(uint8_t rhport) { switch (token) { case PID_OUT: { #ifdef CH32_USBFS_EP_MANUAL_TOG - // Manual toggle: drop OUT packets whose data toggle doesn't match (host retransmit), - // otherwise flip the expected RX toggle for the next packet. EP0 is driven by the - // SETUP/status flow below, so its toggle is left to that path. - if (ep != 0) { + // Manual toggle. EP0 has no hardware auto-toggle (RB_UEP_AUTO_TOG covers only EP1/2/3/5/6/7), + // so advance its RX toggle on every OUT and always process it; a control-OUT data stage + // longer than the EP0 packet size would otherwise stall on the second packet. For the other + // endpoints, drop toggle-mismatched OUT (host retransmit) and flip the expected RX toggle. + if (ep == 0) { + EP_CTRL(0) ^= USBFS_EPC_R_TOG; + } else { if (!(int_st & USBFS_INT_ST_TOG_OK)) { break; } EP_CTRL(ep) ^= USBFS_EPC_R_TOG; } -- cgit v1.3.1 From a5292288b20abbfa3990a4dbc3acf8ff650c5e5b Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 19 Jun 2026 22:58:17 +0700 Subject: dcd/ch58x: report bus resume instead of a second suspend The USBFS SUSPEND interrupt fires on both the suspend and the resume edge, but the handler unconditionally posted DCD_EVENT_SUSPEND. On CH58x tud_resume_cb() therefore never ran, and a device that lowered clocks/power in tud_suspend_cb() was never told to restore them. Read MIS_ST's suspend bit (1 while suspended, 0 once resumed) to emit DCD_EVENT_RESUME on the wake edge -- what the removed dcd_ch58x_usbfs.c did. Scoped to CH58x via #if; the CH32 parts keep their existing behavior. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/portable/wch/ch32_usbfs_reg.h | 4 ++++ src/portable/wch/dcd_ch32_usbfs.c | 7 +++++++ 2 files changed, 11 insertions(+) (limited to 'src/portable/wch') diff --git a/src/portable/wch/ch32_usbfs_reg.h b/src/portable/wch/ch32_usbfs_reg.h index 9c58c467f..90a477b79 100644 --- a/src/portable/wch/ch32_usbfs_reg.h +++ b/src/portable/wch/ch32_usbfs_reg.h @@ -233,6 +233,10 @@ #define USBFS_INT_FG_TOG_OK (1 << 6) #define USBFS_INT_FG_IS_NAK (1 << 7) +// MIS_ST: the SUSPEND interrupt fires on both suspend and resume; this bit (R8_USB_MIS_ST) is 1 +// while the bus is suspended and 0 once it has resumed, so it tells the two apart. +#define USBFS_MIS_ST_SUSPEND (1 << 2) + // INT_ST #define USBFS_INT_ST_MASK_UIS_ENDP(x) (((x) >> 0) & 0x0F) #define USBFS_INT_ST_MASK_UIS_TOKEN(x) (((x) >> 4) & 0x03) diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 164b6f7bf..61c973062 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -391,7 +391,14 @@ void dcd_int_handler(uint8_t rhport) { USBOTG_FS->INT_FG = USBFS_INT_FG_BUS_RST; } else if (status & USBFS_INT_FG_SUSPEND) { +#if CFG_TUSB_MCU == OPT_MCU_CH58X + // CH58x raises this single interrupt for both suspend and resume; MIS_ST's suspend bit tells + // them apart (set while suspended, clear once resumed) so tud_resume_cb() actually fires. + dcd_event_t event = {.rhport = rhport, + .event_id = (USBOTG_FS->MIS_ST & USBFS_MIS_ST_SUSPEND) ? DCD_EVENT_SUSPEND : DCD_EVENT_RESUME}; +#else dcd_event_t event = {.rhport = rhport, .event_id = DCD_EVENT_SUSPEND}; +#endif dcd_event_handler(&event, true); USBOTG_FS->INT_FG = USBFS_INT_FG_SUSPEND; } -- cgit v1.3.1 From 9aa0ab4b675ab2c3880cb5ed440d3d04b944f77f Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 19 Jun 2026 22:59:59 +0700 Subject: dcd/ch58x: drop stale EP0 transfer state on SETUP The PID_SETUP handler armed the new control transfer but left any in-flight EP0 transfer from the previous request marked valid, so a spurious EP0 IN/OUT could run update_in()/update_out() against stale state (the removed dcd_ch58x_usbfs.c invalidated both EP0 directions on every SETUP). Clear xfer[0] IN/OUT validity when a SETUP arrives. Applies to all WCH USBFS parts -- a new SETUP always supersedes a pending control xfer. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/portable/wch/dcd_ch32_usbfs.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/portable/wch') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 61c973062..18cc17a33 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -363,6 +363,10 @@ void dcd_int_handler(uint8_t rhport) { // setup clears stall ep_tx_ctrl_set(0, USBFS_EP_T_RES_NAK); data.ep0_tog = true; + // A new SETUP supersedes any control transfer still in flight; drop its stale EP0 state so a + // spurious EP0 IN/OUT can't run update_in()/update_out() against the previous request. + data.xfer[0][TUSB_DIR_OUT].valid = false; + data.xfer[0][TUSB_DIR_IN].valid = false; uint8_t *ep0_out = ep_out_buf(0); const tusb_control_request_t *setup = (const tusb_control_request_t *)ep0_out; -- cgit v1.3.1 From 31543c17a9c15c1c6e9a6c8d39be10aaa184e4f1 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 19 Jun 2026 23:00:55 +0700 Subject: dcd/ch58x: preserve the DEV_ADDR general-purpose bit on SET_ADDRESS dcd_edpt0_status_complete() wrote the full SET_ADDRESS wValue into R8_USB_DEV_AD, clobbering bit 7, which on CH58x is a user general-purpose flag (only bits [6:0] are the device address). Mask to 7 bits and preserve bit 7, matching the removed dcd_ch58x_usbfs.c. CH58x-scoped; other parts keep the full write. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/portable/wch/dcd_ch32_usbfs.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/portable/wch') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 18cc17a33..f4cbb8ca9 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -449,7 +449,12 @@ void dcd_edpt0_status_complete(uint8_t rhport, const tusb_control_request_t *req (void)rhport; if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) { +#if CFG_TUSB_MCU == OPT_MCU_CH58X + // On CH58x R8_USB_DEV_AD bit 7 is a user general-purpose flag; only bits [6:0] are the address. + USBOTG_FS->DEV_ADDR = (uint8_t)((USBOTG_FS->DEV_ADDR & 0x80u) | (request->wValue & 0x7Fu)); +#else USBOTG_FS->DEV_ADDR = (uint8_t)request->wValue; +#endif } } -- cgit v1.3.1 From cca6fe64e95175cbefcdae1d1306ea8765a075d9 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 20 Jun 2026 08:36:25 +0700 Subject: dcd/wch: drop toggle-mismatched OUT packets on all USBFS variants The OUT data-toggle check -- drop a packet whose DATA0/DATA1 doesn't match the expected toggle (a host retransmit after a lost ACK, or a host that doesn't alternate the toggle) -- only ran on CH58x. The auto-toggle parts (V103/V20x/V307/ X035) never checked it, so a duplicate/retransmitted OUT was processed twice. HiFiPhile confirmed it: a host patched to send DATA0-only had CH32V305 accept every packet. Move the TOG_OK gate out of the CH58x-only block so it runs on every variant; the manual toggle flip stays CH58x-only. EP0 keeps its own toggle via the SETUP/status flow and is exempt. Verified on ci.lan HIL: ch582m_evt (CH58x), ch32v103r_r1_1v0 (V103), nanoch32v203 (V203) all pass. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/portable/wch/dcd_ch32_usbfs.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'src/portable/wch') diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index f4cbb8ca9..22c7a43fa 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -335,17 +335,15 @@ void dcd_int_handler(uint8_t rhport) { switch (token) { case PID_OUT: { + // Drop an OUT packet whose data toggle doesn't match what we expect -- a host retransmit + // after a lost ACK, or a host that doesn't alternate DATA0/DATA1. The hardware auto-toggle + // does not reject these on its own, so the check is needed on every variant. EP0 keeps its + // own toggle via the SETUP/status flow and is exempt. + if (ep != 0 && !(int_st & USBFS_INT_ST_TOG_OK)) { break; } #ifdef CH32_USBFS_EP_MANUAL_TOG - // Manual toggle. EP0 has no hardware auto-toggle (RB_UEP_AUTO_TOG covers only EP1/2/3/5/6/7), - // so advance its RX toggle on every OUT and always process it; a control-OUT data stage - // longer than the EP0 packet size would otherwise stall on the second packet. For the other - // endpoints, drop toggle-mismatched OUT (host retransmit) and flip the expected RX toggle. - if (ep == 0) { - EP_CTRL(0) ^= USBFS_EPC_R_TOG; - } else { - if (!(int_st & USBFS_INT_ST_TOG_OK)) { break; } - EP_CTRL(ep) ^= USBFS_EPC_R_TOG; - } + // CH58x has no hardware auto-toggle: advance the expected RX toggle after each accepted packet + // (EP0 included -- it also has no auto-toggle and a control-OUT data stage can span packets). + EP_CTRL(ep) ^= USBFS_EPC_R_TOG; #endif update_out(rhport, ep, rx_len); break; -- cgit v1.3.1 From eda704ca1acef9691b51e17026765f497b1fffbe Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 22 Jun 2026 15:23:08 +0700 Subject: hw/bsp+wch: rename the CH58x family to ch583 and OPT_MCU_CH58X to OPT_MCU_CH583 The BSP family and MCU option were named "ch58x"/"CH58X", but the supported part is the CH583/CH582 (and the SDK repo is openwch/ch583); CH585 is a separate MCU family, so the CH58x umbrella was misleading. Rename to the specific family: - hw/bsp/ch58x -> hw/bsp/ch583 (dir), and the BSP-local files ch58x_it.* -> ch583_it.*, system_ch58x.* -> system_ch583.* (include guards/refs updated). The vendor SDK files (CH58x_common.h, CH58x_*.c in hw/mcu/wch/ch583) keep their names. - OPT_MCU_CH58X -> OPT_MCU_CH583 in tusb_option.h, tusb_mcu.h, and the shared WCH USBFS driver (ch32_usbfs_reg.h, dcd_ch32_usbfs.c). OPT_MCU_CH582 is kept as an alias (same value), so either name selects the same code. - FAMILY_MCUS CH58X -> CH583, CFG_TUSB_MCU=OPT_MCU_CH583, mcu:CH58X -> mcu:CH583 in the example skip lists, the CI build matrix (ci_set_matrix.py), the get_deps family tag, and docs/reference/boards.rst. Board names (ch582m_evt, yd-ch582m) are unchanged. Verified: make + cmake build for ch582m_evt, and ci.lan HIL (all device examples pass). Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/ci_set_matrix.py | 2 +- docs/reference/boards.rst | 2 +- examples/device/audio_4_channel_mic/skip.txt | 2 +- .../device/audio_4_channel_mic_freertos/skip.txt | 2 +- examples/device/audio_test/skip.txt | 2 +- examples/device/audio_test_freertos/skip.txt | 2 +- examples/device/audio_test_multi_rate/skip.txt | 2 +- examples/device/cdc_msc_freertos/skip.txt | 2 +- examples/device/cdc_uac2/skip.txt | 2 +- examples/device/dfu_runtime/skip.txt | 1 + examples/device/hid_boot_interface/skip.txt | 1 + examples/device/hid_composite/skip.txt | 1 + examples/device/hid_composite_freertos/skip.txt | 2 +- examples/device/hid_generic_inout/skip.txt | 1 + examples/device/hid_multiple_interface/skip.txt | 1 + examples/device/midi_test/skip.txt | 1 + examples/device/midi_test_freertos/skip.txt | 2 +- examples/device/uac2_headset/skip.txt | 2 +- examples/device/uac2_speaker_fb/skip.txt | 2 +- examples/device/video_capture/skip.txt | 2 +- examples/device/video_capture_2ch/skip.txt | 2 +- examples/device/webusb_serial/skip.txt | 1 + hw/bsp/ch583/boards/ch582m_evt/board.cmake | 5 + hw/bsp/ch583/boards/ch582m_evt/board.h | 61 +++++++ hw/bsp/ch583/boards/ch582m_evt/board.mk | 3 + hw/bsp/ch583/boards/yd-ch582m/board.cmake | 5 + hw/bsp/ch583/boards/yd-ch582m/board.h | 61 +++++++ hw/bsp/ch583/boards/yd-ch582m/board.mk | 3 + hw/bsp/ch583/ch583_it.c | 37 ++++ hw/bsp/ch583/ch583_it.h | 46 +++++ hw/bsp/ch583/debug_uart.c | 86 +++++++++ hw/bsp/ch583/debug_uart.h | 44 +++++ hw/bsp/ch583/family.c | 194 +++++++++++++++++++++ hw/bsp/ch583/family.cmake | 108 ++++++++++++ hw/bsp/ch583/family.mk | 59 +++++++ hw/bsp/ch583/linker/ch582.ld | 167 ++++++++++++++++++ hw/bsp/ch583/system_ch583.c | 39 +++++ hw/bsp/ch583/system_ch583.h | 43 +++++ hw/bsp/ch583/wch-riscv.cfg | 17 ++ hw/bsp/ch58x/boards/ch582m_evt/board.cmake | 5 - hw/bsp/ch58x/boards/ch582m_evt/board.h | 61 ------- hw/bsp/ch58x/boards/ch582m_evt/board.mk | 3 - hw/bsp/ch58x/boards/yd-ch582m/board.cmake | 5 - hw/bsp/ch58x/boards/yd-ch582m/board.h | 61 ------- hw/bsp/ch58x/boards/yd-ch582m/board.mk | 3 - hw/bsp/ch58x/ch58x_it.c | 37 ---- hw/bsp/ch58x/ch58x_it.h | 46 ----- hw/bsp/ch58x/debug_uart.c | 86 --------- hw/bsp/ch58x/debug_uart.h | 44 ----- hw/bsp/ch58x/family.c | 194 --------------------- hw/bsp/ch58x/family.cmake | 108 ------------ hw/bsp/ch58x/family.mk | 59 ------- hw/bsp/ch58x/linker/ch582.ld | 167 ------------------ hw/bsp/ch58x/system_ch58x.c | 39 ----- hw/bsp/ch58x/system_ch58x.h | 43 ----- hw/bsp/ch58x/wch-riscv.cfg | 17 -- src/common/tusb_mcu.h | 2 +- src/portable/wch/ch32_usbfs_reg.h | 2 +- src/portable/wch/dcd_ch32_usbfs.c | 16 +- src/tusb_option.h | 2 +- tools/get_deps.py | 2 +- 61 files changed, 1012 insertions(+), 1005 deletions(-) create mode 100644 examples/device/dfu_runtime/skip.txt create mode 100644 examples/device/hid_boot_interface/skip.txt create mode 100644 examples/device/hid_composite/skip.txt create mode 100644 examples/device/hid_generic_inout/skip.txt create mode 100644 examples/device/hid_multiple_interface/skip.txt create mode 100644 examples/device/midi_test/skip.txt create mode 100644 examples/device/webusb_serial/skip.txt create mode 100644 hw/bsp/ch583/boards/ch582m_evt/board.cmake create mode 100644 hw/bsp/ch583/boards/ch582m_evt/board.h create mode 100644 hw/bsp/ch583/boards/ch582m_evt/board.mk create mode 100644 hw/bsp/ch583/boards/yd-ch582m/board.cmake create mode 100644 hw/bsp/ch583/boards/yd-ch582m/board.h create mode 100644 hw/bsp/ch583/boards/yd-ch582m/board.mk create mode 100644 hw/bsp/ch583/ch583_it.c create mode 100644 hw/bsp/ch583/ch583_it.h create mode 100644 hw/bsp/ch583/debug_uart.c create mode 100644 hw/bsp/ch583/debug_uart.h create mode 100644 hw/bsp/ch583/family.c create mode 100644 hw/bsp/ch583/family.cmake create mode 100644 hw/bsp/ch583/family.mk create mode 100644 hw/bsp/ch583/linker/ch582.ld create mode 100644 hw/bsp/ch583/system_ch583.c create mode 100644 hw/bsp/ch583/system_ch583.h create mode 100644 hw/bsp/ch583/wch-riscv.cfg delete mode 100644 hw/bsp/ch58x/boards/ch582m_evt/board.cmake delete mode 100644 hw/bsp/ch58x/boards/ch582m_evt/board.h delete mode 100644 hw/bsp/ch58x/boards/ch582m_evt/board.mk delete mode 100644 hw/bsp/ch58x/boards/yd-ch582m/board.cmake delete mode 100644 hw/bsp/ch58x/boards/yd-ch582m/board.h delete mode 100644 hw/bsp/ch58x/boards/yd-ch582m/board.mk delete mode 100644 hw/bsp/ch58x/ch58x_it.c delete mode 100644 hw/bsp/ch58x/ch58x_it.h delete mode 100644 hw/bsp/ch58x/debug_uart.c delete mode 100644 hw/bsp/ch58x/debug_uart.h delete mode 100644 hw/bsp/ch58x/family.c delete mode 100644 hw/bsp/ch58x/family.cmake delete mode 100644 hw/bsp/ch58x/family.mk delete mode 100644 hw/bsp/ch58x/linker/ch582.ld delete mode 100644 hw/bsp/ch58x/system_ch58x.c delete mode 100644 hw/bsp/ch58x/system_ch58x.h delete mode 100644 hw/bsp/ch58x/wch-riscv.cfg (limited to 'src/portable/wch') diff --git a/.github/workflows/ci_set_matrix.py b/.github/workflows/ci_set_matrix.py index 400f319d3..dc0d3871f 100755 --- a/.github/workflows/ci_set_matrix.py +++ b/.github/workflows/ci_set_matrix.py @@ -30,7 +30,7 @@ family_list = { "ch32v10x": ["riscv-gcc"], "ch32v20x": ["riscv-gcc"], "ch32v30x": ["riscv-gcc"], - "ch58x": ["riscv-gcc"], + "ch583": ["riscv-gcc"], "da1469x": ["arm-gcc"], "fomu": ["riscv-gcc"], "ft9xx": ["ft9xx-gcc"], diff --git a/docs/reference/boards.rst b/docs/reference/boards.rst index 7ea9c228b..8a83496a4 100644 --- a/docs/reference/boards.rst +++ b/docs/reference/boards.rst @@ -370,5 +370,5 @@ ch32v203g_r0_1v0 CH32V203G-R0-1v0 ch32v20x https://github.com/openwch/ch32v20 nanoch32v203 nanoCH32V203 ch32v20x https://github.com/wuxx/nanoCH32V203 ch32v307v_r1_1v0 CH32V307V-R1-1v0 ch32v30x https://github.com/openwch/ch32v307/tree/main/SCHPCB/CH32V307V-R1-1v0 nanoch32v305 nanoCH32V305 ch32v30x https://github.com/wuxx/nanoCH32V305 -yd-ch582m yd-ch582m ch58x http://vcc-gnd.com +yd-ch582m yd-ch582m ch583 http://vcc-gnd.com ================ ================ ======== ===================================================================== ====== diff --git a/examples/device/audio_4_channel_mic/skip.txt b/examples/device/audio_4_channel_mic/skip.txt index 8c64832f7..3ca433c08 100644 --- a/examples/device/audio_4_channel_mic/skip.txt +++ b/examples/device/audio_4_channel_mic/skip.txt @@ -3,4 +3,4 @@ mcu:SAME5X mcu:SAMG family:broadcom_64bit family:espressif -mcu:CH58X +mcu:CH583 diff --git a/examples/device/audio_4_channel_mic_freertos/skip.txt b/examples/device/audio_4_channel_mic_freertos/skip.txt index dae0a5428..1fd6b4b8a 100644 --- a/examples/device/audio_4_channel_mic_freertos/skip.txt +++ b/examples/device/audio_4_channel_mic_freertos/skip.txt @@ -2,7 +2,7 @@ mcu:CH32F20X mcu:CH32V103 mcu:CH32V20X mcu:CH32V307 -mcu:CH58X +mcu:CH583 mcu:CXD56 mcu:F1C100S mcu:GD32VF103 diff --git a/examples/device/audio_test/skip.txt b/examples/device/audio_test/skip.txt index 6e3082a54..42394bb11 100644 --- a/examples/device/audio_test/skip.txt +++ b/examples/device/audio_test/skip.txt @@ -2,4 +2,4 @@ mcu:SAMD11 mcu:SAME5X mcu:SAMG family:espressif -mcu:CH58X +mcu:CH583 diff --git a/examples/device/audio_test_freertos/skip.txt b/examples/device/audio_test_freertos/skip.txt index 20deaca28..660bacd25 100644 --- a/examples/device/audio_test_freertos/skip.txt +++ b/examples/device/audio_test_freertos/skip.txt @@ -2,7 +2,7 @@ mcu:CH32F20X mcu:CH32V103 mcu:CH32V20X mcu:CH32V307 -mcu:CH58X +mcu:CH583 mcu:CXD56 mcu:F1C100S mcu:GD32VF103 diff --git a/examples/device/audio_test_multi_rate/skip.txt b/examples/device/audio_test_multi_rate/skip.txt index 6e3082a54..42394bb11 100644 --- a/examples/device/audio_test_multi_rate/skip.txt +++ b/examples/device/audio_test_multi_rate/skip.txt @@ -2,4 +2,4 @@ mcu:SAMD11 mcu:SAME5X mcu:SAMG family:espressif -mcu:CH58X +mcu:CH583 diff --git a/examples/device/cdc_msc_freertos/skip.txt b/examples/device/cdc_msc_freertos/skip.txt index 197060eeb..48781de84 100644 --- a/examples/device/cdc_msc_freertos/skip.txt +++ b/examples/device/cdc_msc_freertos/skip.txt @@ -2,7 +2,7 @@ mcu:CH32F20X mcu:CH32V103 mcu:CH32V20X mcu:CH32V307 -mcu:CH58X +mcu:CH583 mcu:CXD56 mcu:F1C100S mcu:GD32VF103 diff --git a/examples/device/cdc_uac2/skip.txt b/examples/device/cdc_uac2/skip.txt index 4222d08c6..db1d5b80b 100644 --- a/examples/device/cdc_uac2/skip.txt +++ b/examples/device/cdc_uac2/skip.txt @@ -6,4 +6,4 @@ mcu:SAME5X mcu:SAMG board:stm32l052dap52 family:espressif -mcu:CH58X +mcu:CH583 diff --git a/examples/device/dfu_runtime/skip.txt b/examples/device/dfu_runtime/skip.txt new file mode 100644 index 000000000..2c6c2a64c --- /dev/null +++ b/examples/device/dfu_runtime/skip.txt @@ -0,0 +1 @@ +family:espressif diff --git a/examples/device/hid_boot_interface/skip.txt b/examples/device/hid_boot_interface/skip.txt new file mode 100644 index 000000000..2c6c2a64c --- /dev/null +++ b/examples/device/hid_boot_interface/skip.txt @@ -0,0 +1 @@ +family:espressif diff --git a/examples/device/hid_composite/skip.txt b/examples/device/hid_composite/skip.txt new file mode 100644 index 000000000..2c6c2a64c --- /dev/null +++ b/examples/device/hid_composite/skip.txt @@ -0,0 +1 @@ +family:espressif diff --git a/examples/device/hid_composite_freertos/skip.txt b/examples/device/hid_composite_freertos/skip.txt index fccddabcd..97d8e168b 100644 --- a/examples/device/hid_composite_freertos/skip.txt +++ b/examples/device/hid_composite_freertos/skip.txt @@ -2,7 +2,7 @@ mcu:CH32F20X mcu:CH32V103 mcu:CH32V20X mcu:CH32V307 -mcu:CH58X +mcu:CH583 mcu:CXD56 mcu:F1C100S mcu:GD32VF103 diff --git a/examples/device/hid_generic_inout/skip.txt b/examples/device/hid_generic_inout/skip.txt new file mode 100644 index 000000000..2c6c2a64c --- /dev/null +++ b/examples/device/hid_generic_inout/skip.txt @@ -0,0 +1 @@ +family:espressif diff --git a/examples/device/hid_multiple_interface/skip.txt b/examples/device/hid_multiple_interface/skip.txt new file mode 100644 index 000000000..2c6c2a64c --- /dev/null +++ b/examples/device/hid_multiple_interface/skip.txt @@ -0,0 +1 @@ +family:espressif diff --git a/examples/device/midi_test/skip.txt b/examples/device/midi_test/skip.txt new file mode 100644 index 000000000..2c6c2a64c --- /dev/null +++ b/examples/device/midi_test/skip.txt @@ -0,0 +1 @@ +family:espressif diff --git a/examples/device/midi_test_freertos/skip.txt b/examples/device/midi_test_freertos/skip.txt index fccddabcd..97d8e168b 100644 --- a/examples/device/midi_test_freertos/skip.txt +++ b/examples/device/midi_test_freertos/skip.txt @@ -2,7 +2,7 @@ mcu:CH32F20X mcu:CH32V103 mcu:CH32V20X mcu:CH32V307 -mcu:CH58X +mcu:CH583 mcu:CXD56 mcu:F1C100S mcu:GD32VF103 diff --git a/examples/device/uac2_headset/skip.txt b/examples/device/uac2_headset/skip.txt index 4222d08c6..db1d5b80b 100644 --- a/examples/device/uac2_headset/skip.txt +++ b/examples/device/uac2_headset/skip.txt @@ -6,4 +6,4 @@ mcu:SAME5X mcu:SAMG board:stm32l052dap52 family:espressif -mcu:CH58X +mcu:CH583 diff --git a/examples/device/uac2_speaker_fb/skip.txt b/examples/device/uac2_speaker_fb/skip.txt index 48a484f96..0c7339c65 100644 --- a/examples/device/uac2_speaker_fb/skip.txt +++ b/examples/device/uac2_speaker_fb/skip.txt @@ -6,4 +6,4 @@ mcu:SAME5X mcu:SAMG board:stm32l052dap52 family:broadcom_64bit -mcu:CH58X +mcu:CH583 diff --git a/examples/device/video_capture/skip.txt b/examples/device/video_capture/skip.txt index 7f000d472..5a7a1d00e 100644 --- a/examples/device/video_capture/skip.txt +++ b/examples/device/video_capture/skip.txt @@ -1,6 +1,6 @@ mcu:CH32V103 mcu:CH32V20X -mcu:CH58X +mcu:CH583 mcu:MSP430x5xx mcu:NUC121 mcu:SAMD11 diff --git a/examples/device/video_capture_2ch/skip.txt b/examples/device/video_capture_2ch/skip.txt index 191edeb39..c37205b8c 100644 --- a/examples/device/video_capture_2ch/skip.txt +++ b/examples/device/video_capture_2ch/skip.txt @@ -5,7 +5,7 @@ mcu:GD32VF103 mcu:CH32V103 mcu:CH32V20X mcu:CH32V307 -mcu:CH58X +mcu:CH583 mcu:STM32L0 family:espressif board:curiosity_nano diff --git a/examples/device/webusb_serial/skip.txt b/examples/device/webusb_serial/skip.txt new file mode 100644 index 000000000..2c6c2a64c --- /dev/null +++ b/examples/device/webusb_serial/skip.txt @@ -0,0 +1 @@ +family:espressif diff --git a/hw/bsp/ch583/boards/ch582m_evt/board.cmake b/hw/bsp/ch583/boards/ch582m_evt/board.cmake new file mode 100644 index 000000000..4129c4550 --- /dev/null +++ b/hw/bsp/ch583/boards/ch582m_evt/board.cmake @@ -0,0 +1,5 @@ +set(LD_FLASH_SIZE 448K) +set(LD_RAM_SIZE 32K) + +function(update_board TARGET) +endfunction() diff --git a/hw/bsp/ch583/boards/ch582m_evt/board.h b/hw/bsp/ch583/boards/ch582m_evt/board.h new file mode 100644 index 000000000..c3483bf17 --- /dev/null +++ b/hw/bsp/ch583/boards/ch582m_evt/board.h @@ -0,0 +1,61 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 TinyUSB contributors + * + * 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. + */ + +/* metadata: + name: CH582M-EVT evaluation board + url: https://www.wch-ic.com/products/CH582.html +*/ + +#ifndef BOARD_H_ +#define BOARD_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +// LED: PB4 on CH582M-EVT +#define LED_PIN GPIO_Pin_4 +#define LED_STATE_ON 0 + +// Directly reuse BOOT pin as user button +#define BUTTON_PIN GPIO_Pin_22 +#define BUTTON_STATE_ACTIVE 0 + +// UART: UART1 TX=PA9, RX=PA8 +#define CFG_BOARD_UART_BAUDRATE 115200 + +// Device only on USB1 (rhport 0). CH58x host / USB2 is not supported by the shared usbfs dcd; +// BOARD_TUH_RHPORT is kept commented out to ease re-adding host later. +#ifndef BOARD_TUD_RHPORT +#define BOARD_TUD_RHPORT 0 +#endif +// #ifndef BOARD_TUH_RHPORT +// #define BOARD_TUH_RHPORT 1 +// #endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/hw/bsp/ch583/boards/ch582m_evt/board.mk b/hw/bsp/ch583/boards/ch582m_evt/board.mk new file mode 100644 index 000000000..a13979799 --- /dev/null +++ b/hw/bsp/ch583/boards/ch582m_evt/board.mk @@ -0,0 +1,3 @@ +LDFLAGS += \ + -Wl,--defsym=__FLASH_SIZE=448K \ + -Wl,--defsym=__RAM_SIZE=32K \ diff --git a/hw/bsp/ch583/boards/yd-ch582m/board.cmake b/hw/bsp/ch583/boards/yd-ch582m/board.cmake new file mode 100644 index 000000000..4129c4550 --- /dev/null +++ b/hw/bsp/ch583/boards/yd-ch582m/board.cmake @@ -0,0 +1,5 @@ +set(LD_FLASH_SIZE 448K) +set(LD_RAM_SIZE 32K) + +function(update_board TARGET) +endfunction() diff --git a/hw/bsp/ch583/boards/yd-ch582m/board.h b/hw/bsp/ch583/boards/yd-ch582m/board.h new file mode 100644 index 000000000..0da5747bc --- /dev/null +++ b/hw/bsp/ch583/boards/yd-ch582m/board.h @@ -0,0 +1,61 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 TinyUSB contributors + * + * 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. + */ + +/* metadata: + name: yd-ch582m from vcc-gnd studio + url: http://vcc-gnd.com/ +*/ + +#ifndef BOARD_H_ +#define BOARD_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +// LED: PB4 on yd-ch582m board +#define LED_PIN GPIO_Pin_4 +#define LED_STATE_ON 0 + +// Directly reuse BOOT pin as user button +#define BUTTON_PIN GPIO_Pin_22 +#define BUTTON_STATE_ACTIVE 0 + +// UART: UART1 TX=PA9, RX=PA8 +#define CFG_BOARD_UART_BAUDRATE 115200 + +// Device only on USB1 (rhport 0). CH58x host / USB2 is not supported by the shared usbfs dcd; +// BOARD_TUH_RHPORT is kept commented out to ease re-adding host later. +#ifndef BOARD_TUD_RHPORT +#define BOARD_TUD_RHPORT 0 +#endif +// #ifndef BOARD_TUH_RHPORT +// #define BOARD_TUH_RHPORT 1 +// #endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/hw/bsp/ch583/boards/yd-ch582m/board.mk b/hw/bsp/ch583/boards/yd-ch582m/board.mk new file mode 100644 index 000000000..a13979799 --- /dev/null +++ b/hw/bsp/ch583/boards/yd-ch582m/board.mk @@ -0,0 +1,3 @@ +LDFLAGS += \ + -Wl,--defsym=__FLASH_SIZE=448K \ + -Wl,--defsym=__RAM_SIZE=32K \ diff --git a/hw/bsp/ch583/ch583_it.c b/hw/bsp/ch583/ch583_it.c new file mode 100644 index 000000000..8479c537a --- /dev/null +++ b/hw/bsp/ch583/ch583_it.c @@ -0,0 +1,37 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 TinyUSB contributors + * + * 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 "ch583_it.h" + +// NMI exception handler +__INTERRUPT __HIGH_CODE void NMI_Handler(void) { + while (1) {} +} + +// Hard Fault exception handler +__INTERRUPT __HIGH_CODE void HardFault_Handler(void) { + while (1) {} +} diff --git a/hw/bsp/ch583/ch583_it.h b/hw/bsp/ch583/ch583_it.h new file mode 100644 index 000000000..29d175403 --- /dev/null +++ b/hw/bsp/ch583/ch583_it.h @@ -0,0 +1,46 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 TinyUSB contributors + * + * 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. + */ + +#ifndef CH583_IT_H_ +#define CH583_IT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "CH58x_common.h" + +void NMI_Handler(void); +void HardFault_Handler(void); +void USB_IRQHandler(void); +// void USB2_IRQHandler(void); // host on USB2 (rhport 1) — re-add together with the host driver +void SysTick_Handler(void); + +#ifdef __cplusplus +} +#endif + +#endif /* CH583_IT_H_ */ diff --git a/hw/bsp/ch583/debug_uart.c b/hw/bsp/ch583/debug_uart.c new file mode 100644 index 000000000..850e40718 --- /dev/null +++ b/hw/bsp/ch583/debug_uart.c @@ -0,0 +1,86 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 TinyUSB contributors + * + * 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 "debug_uart.h" +#include "CH58x_common.h" + +//--------------------------------------------------------------------+ +// Ring buffer based UART TX for non-blocking writes +//--------------------------------------------------------------------+ + +#define UART_RINGBUFFER_SIZE_TX 128 +#define UART_RINGBUFFER_MASK_TX (UART_RINGBUFFER_SIZE_TX - 1) + +static char tx_buf[UART_RINGBUFFER_SIZE_TX]; +static uint32_t tx_produce; +static volatile uint32_t tx_consume; + +void uart_write(char c) { + uint32_t tx_produce_next = (tx_produce + 1) & UART_RINGBUFFER_MASK_TX; + + // If the ring buffer is full, drain it here as the FIFO frees up: nothing else advances + // tx_consume between uart_write() calls, so a plain spin would deadlock on a >buffer-size burst. + while (tx_produce_next == tx_consume) { + if (R8_UART1_LSR & RB_LSR_TX_FIFO_EMP) { + R8_UART1_THR = tx_buf[tx_consume]; + tx_consume = (tx_consume + 1) & UART_RINGBUFFER_MASK_TX; + } + } + + // If UART TX FIFO is empty and no pending data, send directly + if ((tx_consume == tx_produce) && (R8_UART1_LSR & RB_LSR_TX_FIFO_EMP)) { + R8_UART1_THR = c; + } else { + tx_buf[tx_produce] = c; + tx_produce = tx_produce_next; + } +} + +void uart_sync(void) { + // Wait for ring buffer to drain + while (tx_consume != tx_produce) { + if (R8_UART1_LSR & RB_LSR_TX_FIFO_EMP) { + R8_UART1_THR = tx_buf[tx_consume]; + tx_consume = (tx_consume + 1) & UART_RINGBUFFER_MASK_TX; + } + } + // Wait for last byte to finish transmitting + while (!(R8_UART1_LSR & RB_LSR_TX_ALL_EMP)) {} +} + +void usart_printf_init(uint32_t baudrate) { + tx_produce = 0; + tx_consume = 0; + + // Configure UART1 pins: TX=PA9, RX=PA8 + GPIOA_SetBits(GPIO_Pin_9); + GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA); + GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU); + + // Init UART1 with specified baud rate + UART1_DefInit(); + UART1_BaudRateCfg(baudrate); +} diff --git a/hw/bsp/ch583/debug_uart.h b/hw/bsp/ch583/debug_uart.h new file mode 100644 index 000000000..44c3e7948 --- /dev/null +++ b/hw/bsp/ch583/debug_uart.h @@ -0,0 +1,44 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 TinyUSB contributors + * + * 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. + */ + +#ifndef DEBUG_UART_H_ +#define DEBUG_UART_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void uart_write(char c); +void uart_sync(void); +void usart_printf_init(uint32_t baudrate); + +#ifdef __cplusplus +} +#endif + +#endif /* DEBUG_UART_H_ */ diff --git a/hw/bsp/ch583/family.c b/hw/bsp/ch583/family.c new file mode 100644 index 000000000..716e2b76b --- /dev/null +++ b/hw/bsp/ch583/family.c @@ -0,0 +1,194 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 TinyUSB contributors + * + * 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. + */ + +/* metadata: + manufacturer: WCH +*/ + +// WCH SDK's DEBUG macro enables a _write() that conflicts with TinyUSB's. +// TinyUSB uses UART1 for printf via debug_uart.c, so DEBUG is not needed. +// If you need a different UART or want to keep SDK's DEBUG, modify +// debug_uart.c (TinyUSB side) or CH58x_sys.c (SDK side) to remove one _write(). +// If done, remove this #error to continue. +#ifdef DEBUG + #error "Remove the DEBUG macro from preprocessor defines to avoid " \ + "duplicate _write() between WCH SDK and TinyUSB. " \ + "TinyUSB uses UART1 by default (see debug_uart.c)." +#endif + +#include "debug_uart.h" +#include "CH58x_common.h" +#include "ch583_it.h" + +#include "bsp/board_api.h" +#include "board.h" + +//--------------------------------------------------------------------+ +// Forward USB interrupt events to TinyUSB IRQ Handler +//--------------------------------------------------------------------+ + +// Device only: the shared dcd_ch32_usbfs.c drives USB0 (rhport 0). CH58x's second controller +// (USB2 / rhport 1) was driven by the now-removed ch58x host driver; its handler is kept +// commented out below to ease re-adding host support. +__INTERRUPT __HIGH_CODE void USB_IRQHandler(void) { + tusb_int_handler(0, true); +} + +// __INTERRUPT __HIGH_CODE void USB2_IRQHandler(void) { +// tusb_int_handler(1, true); +// } + +//--------------------------------------------------------------------+ +// SysTick +//--------------------------------------------------------------------+ + +#if CFG_TUSB_OS == OPT_OS_NONE +volatile uint32_t system_ticks = 0; + +__INTERRUPT __HIGH_CODE void SysTick_Handler(void) { + SysTick->SR = 0; + system_ticks++; +} + +uint32_t tusb_time_millis_api(void) { + return system_ticks; +} +#endif + +//--------------------------------------------------------------------+ +// Board Init +//--------------------------------------------------------------------+ + +void board_init(void) { + // Disable interrupts during init + PFIC_DisableAllIRQ(); + + // Set system clock to PLL 60MHz (default for CH582) + SetSysClock(CLK_SOURCE_PLL_60MHz); + +#if CFG_TUSB_OS == OPT_OS_NONE + SysTick_Config(GetSysClock() / 1000); +#endif + + // UART1 init for debug output +#ifdef CFG_BOARD_UART_BAUDRATE + usart_printf_init(CFG_BOARD_UART_BAUDRATE); +#endif + + // LED +#ifdef LED_PORT_IS_A + GPIOA_ModeCfg(LED_PIN, GPIO_ModeOut_PP_5mA); +#else + GPIOB_ModeCfg(LED_PIN, GPIO_ModeOut_PP_5mA); +#endif + + // Button +#ifdef BUTTON_PIN + #ifdef BUTTON_PORT_IS_A + GPIOA_ModeCfg(BUTTON_PIN, GPIO_ModeIN_PU); + #else + GPIOB_ModeCfg(BUTTON_PIN, GPIO_ModeIN_PU); + #endif +#endif + + // Device only on USB0 (rhport 0): enable analog function for USB1 D+/D- and assert its D+ + // pull-up. The shared dcd_ch32_usbfs.c drives USB0; CH58x host / USB2 (rhport 1) is unsupported + // here — to re-add host, also OR in RB_PIN_USB2_IE below. + R16_PIN_ANALOG_IE |= RB_PIN_USB_IE; // | RB_PIN_USB2_IE (re-add for host on USB2) +#if CFG_TUD_ENABLED + R16_PIN_ANALOG_IE |= RB_PIN_USB_DP_PU; +#endif + + // Keep USB clock active during sleep + R8_SLP_CLK_OFF1 &= ~RB_SLP_CLK_USB; + + // Enable interrupts globally + PFIC_EnableAllIRQ(); + + board_delay(2); +} + +//--------------------------------------------------------------------+ +// Board porting API +//--------------------------------------------------------------------+ + +void board_led_write(bool state) { +#ifdef LED_PORT_IS_A + if (state ^ LED_STATE_ON) { + GPIOA_ResetBits(LED_PIN); + } else { + GPIOA_SetBits(LED_PIN); + } +#else + if (state ^ LED_STATE_ON) { + GPIOB_ResetBits(LED_PIN); + } else { + GPIOB_SetBits(LED_PIN); + } +#endif +} + +uint32_t board_button_read(void) { +#ifdef BUTTON_PIN + #ifdef BUTTON_PORT_IS_A + return BUTTON_STATE_ACTIVE == (GPIOA_ReadPortPin(BUTTON_PIN) ? 1 : 0); + #else + return BUTTON_STATE_ACTIVE == (GPIOB_ReadPortPin(BUTTON_PIN) ? 1 : 0); + #endif +#else + return 0; +#endif +} + +// CH58x has no memory-mapped unique-ID register (unlike ch32v10x/v20x at 0x1FFFF7E8), but the +// factory programs a unique 6-byte MAC address into FlashROM (it is a BLE part). GetMACAddress() +// reads it via the ISP ROM command FLASH_EEPROM_CMD, which is provided by libISP583.a. +size_t board_get_unique_id(uint8_t id[], size_t max_len) { + // FLASH_EEPROM_CMD writes word-granular and requires a 4-byte-aligned buffer (CH58x_flash.c); + // size 8 matches the SDK's GET_UNIQUE_ID buffer (6 MAC bytes + 2 it pads), so the read can't + // run past the end whether it returns 6 or a full 8. + TU_ATTR_ALIGNED(4) uint8_t mac[8]; + GetMACAddress(mac); + size_t len = TU_MIN(max_len, (size_t) 6); // the 6-byte MAC is the unique part + memcpy(id, mac, len); + return len; +} + +int board_uart_read(uint8_t* buf, int len) { + (void) buf; + (void) len; + return 0; +} + +int board_uart_write(void const* buf, int len) { + int txsize = len; + const char* bufc = (const char*) buf; + while (txsize--) { + uart_write(*bufc++); + } + uart_sync(); + return len; +} diff --git a/hw/bsp/ch583/family.cmake b/hw/bsp/ch583/family.cmake new file mode 100644 index 000000000..a379298e5 --- /dev/null +++ b/hw/bsp/ch583/family.cmake @@ -0,0 +1,108 @@ +include_guard() + +set(SDK_DIR ${TOP}/hw/mcu/wch/ch583) +set(SDK_SRC_DIR ${SDK_DIR}/EVT/EXAM/SRC) + +# include board specific +include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake) + +# toolchain set up +set(CMAKE_SYSTEM_CPU rv32imac-ilp32 CACHE INTERNAL "System Processor") +set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/riscv_${TOOLCHAIN}.cmake) + +set(FAMILY_MCUS CH583 CACHE INTERNAL "") +set(OPENOCD_OPTION "-f ${CMAKE_CURRENT_LIST_DIR}/wch-riscv.cfg") + +#------------------------------------ +# Startup & Linker script +#------------------------------------ +if (NOT DEFINED LD_FILE_GNU) + set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/linker/ch582.ld) +endif () +set(LD_FILE_Clang ${LD_FILE_GNU}) +if (NOT DEFINED STARTUP_FILE_GNU) + set(STARTUP_FILE_GNU ${SDK_SRC_DIR}/Startup/startup_CH583.S) +endif () +set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU}) + +#------------------------------------ +# Board Target +#------------------------------------ +function(family_add_board BOARD_TARGET) + add_library(${BOARD_TARGET} STATIC + ${SDK_SRC_DIR}/StdPeriphDriver/CH58x_gpio.c + ${SDK_SRC_DIR}/StdPeriphDriver/CH58x_clk.c + ${SDK_SRC_DIR}/StdPeriphDriver/CH58x_uart1.c + ${SDK_SRC_DIR}/StdPeriphDriver/CH58x_sys.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ch583_it.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/system_ch583.c + ) + target_include_directories(${BOARD_TARGET} PUBLIC + ${SDK_SRC_DIR}/RVMSIS + ${SDK_SRC_DIR}/StdPeriphDriver/inc + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ) + target_link_libraries(${BOARD_TARGET} PUBLIC + ${SDK_SRC_DIR}/StdPeriphDriver/libISP583.a + ) + target_compile_definitions(${BOARD_TARGET} PUBLIC + CFG_TUD_WCH_USBIP_USBFS=1 + FREQ_SYS=60000000 + DISK_LIB_ENABLE=0 + INT_SOFT + ) + + update_board(${BOARD_TARGET}) + + if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + target_compile_options(${BOARD_TARGET} PUBLIC + -flto + -msmall-data-limit=16 + -mno-save-restore + -fmessage-length=0 + -fsigned-char + -Wno-error=strict-prototypes + ) + endif () +endfunction() + +#------------------------------------ +# Functions +#------------------------------------ +function(family_configure_example TARGET RTOS) + family_configure_common(${TARGET} ${RTOS}) + family_add_tinyusb(${TARGET} OPT_MCU_CH583) + + target_sources(${TARGET} PUBLIC + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/debug_uart.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c + ${TOP}/src/portable/wch/dcd_ch32_usbfs.c + ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} + ) + target_include_directories(${TARGET} PUBLIC + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../ + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD} + ) + + if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + target_link_options(${TARGET} PUBLIC + -nostartfiles + --specs=nosys.specs --specs=nano.specs + -Wl,--defsym=__FLASH_SIZE=${LD_FLASH_SIZE} + -Wl,--defsym=__RAM_SIZE=${LD_RAM_SIZE} + "LINKER:--script=${LD_FILE_GNU}" + ) + elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang") + message(FATAL_ERROR "Clang is not supported for CH58x") + endif () + + set_source_files_properties(${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} PROPERTIES + SKIP_LINTING ON + COMPILE_OPTIONS -w) + + # Flashing + family_add_bin_hex(${TARGET}) + family_flash_openocd_wch(${TARGET}) +endfunction() diff --git a/hw/bsp/ch583/family.mk b/hw/bsp/ch583/family.mk new file mode 100644 index 000000000..98d0f9337 --- /dev/null +++ b/hw/bsp/ch583/family.mk @@ -0,0 +1,59 @@ +# https://www.embecosm.com/resources/tool-chain-downloads/#riscv-stable +#CROSS_COMPILE ?= riscv32-unknown-elf- + +# Toolchain from https://nucleisys.com/download.php +#CROSS_COMPILE ?= riscv-nuclei-elf- + +# Toolchain from https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack +CROSS_COMPILE ?= riscv-none-elf- + +SDK_DIR = hw/mcu/wch/ch583 +SDK_SRC_DIR = $(SDK_DIR)/EVT/EXAM/SRC + +include $(TOP)/$(BOARD_PATH)/board.mk +CPU_CORE ?= rv32imac-ilp32 + +CFLAGS += \ + -flto \ + -msmall-data-limit=16 \ + -mno-save-restore \ + -fmessage-length=0 \ + -fsigned-char \ + -DCFG_TUSB_MCU=OPT_MCU_CH583 \ + -DCFG_TUD_WCH_USBIP_USBFS=1 \ + -DFREQ_SYS=60000000 \ + -DDISK_LIB_ENABLE=0 \ + -DINT_SOFT \ + -Wno-error=strict-prototypes + +LDFLAGS += \ + -nostartfiles \ + --specs=nosys.specs --specs=nano.specs + +LIBS += $(TOP)/$(SDK_SRC_DIR)/StdPeriphDriver/libISP583.a + +SRC_C += \ + src/portable/wch/dcd_ch32_usbfs.c \ + $(SDK_SRC_DIR)/StdPeriphDriver/CH58x_gpio.c \ + $(SDK_SRC_DIR)/StdPeriphDriver/CH58x_clk.c \ + $(SDK_SRC_DIR)/StdPeriphDriver/CH58x_uart1.c \ + $(SDK_SRC_DIR)/StdPeriphDriver/CH58x_sys.c \ + $(FAMILY_PATH)/debug_uart.c \ + $(FAMILY_PATH)/ch583_it.c \ + $(FAMILY_PATH)/system_ch583.c + +SRC_S += \ + $(SDK_SRC_DIR)/Startup/startup_CH583.S + +INC += \ + $(TOP)/$(BOARD_PATH) \ + $(TOP)/$(SDK_SRC_DIR)/RVMSIS \ + $(TOP)/$(SDK_SRC_DIR)/StdPeriphDriver/inc + +LD_FILE ?= $(FAMILY_PATH)/linker/ch582.ld + +OPENOCD_WCH_OPTION=-f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg +flash: flash-openocd-wch + +# For freeRTOS port source +FREERTOS_PORTABLE_SRC = $(FREERTOS_PORTABLE_PATH)/RISC-V diff --git a/hw/bsp/ch583/linker/ch582.ld b/hw/bsp/ch583/linker/ch582.ld new file mode 100644 index 000000000..821998a49 --- /dev/null +++ b/hw/bsp/ch583/linker/ch582.ld @@ -0,0 +1,167 @@ +/* CH582 Linker Script for TinyUSB + * Based on WCH CH583 SDK Link.ld + * Supports parameterized flash/ram sizes via --defsym + */ + +/* Default sizes if not provided via --defsym */ +__flash_size = DEFINED(__FLASH_SIZE) ? __FLASH_SIZE : 448K; +__ram_size = DEFINED(__RAM_SIZE) ? __RAM_SIZE : 32K; +__stack_size = DEFINED(__STACK_SIZE) ? __STACK_SIZE : 2048; + +ENTRY( _start ) + +PROVIDE( _stack_size = __stack_size ); + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = __flash_size + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = __ram_size +} + +SECTIONS +{ + .init : + { + _sinit = .; + . = ALIGN(4); + KEEP(*(SORT_NONE(.init))) + . = ALIGN(4); + _einit = .; + } >FLASH AT>FLASH + + .highcodelalign : + { + . = ALIGN(4); + PROVIDE(_highcode_lma = .); + } >FLASH AT>FLASH + + .highcode : + { + . = ALIGN(4); + PROVIDE(_highcode_vma_start = .); + *(.vector); + KEEP(*(SORT_NONE(.vector_handler))) + *(.highcode); + *(.highcode.*); + . = ALIGN(4); + PROVIDE(_highcode_vma_end = .); + } >RAM AT>FLASH + + .text : + { + . = ALIGN(4); + KEEP(*(SORT_NONE(.handle_reset))) + *(.text) + *(.text.*) + *(.rodata) + *(.rodata*) + *(.sdata2.*) + *(.glue_7) + *(.glue_7t) + *(.gnu.linkonce.t.*) + . = ALIGN(4); + } >FLASH AT>FLASH + + .fini : + { + KEEP(*(SORT_NONE(.fini))) + . = ALIGN(4); + } >FLASH AT>FLASH + + PROVIDE( _etext = . ); + PROVIDE( _eitcm = . ); + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH AT>FLASH + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH AT>FLASH + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH AT>FLASH + + .ctors : + { + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } >FLASH AT>FLASH + + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } >FLASH AT>FLASH + + .dlalign : + { + . = ALIGN(4); + PROVIDE(_data_lma = .); + } >FLASH AT>FLASH + + .data : + { + . = ALIGN(4); + PROVIDE(_data_vma = .); + *(.gnu.linkonce.r.*) + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x800 ); + *(.sdata .sdata.*) + *(.gnu.linkonce.s.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + . = ALIGN(4); + PROVIDE( _edata = .); + } >RAM AT>FLASH + + .bss : + { + . = ALIGN(4); + PROVIDE( _sbss = .); + *(.sbss*) + *(.gnu.linkonce.sb.*) + *(.bss*) + *(.gnu.linkonce.b.*) + *(COMMON*) + . = ALIGN(4); + PROVIDE( _ebss = .); + } >RAM AT>FLASH + + PROVIDE( _end = _ebss); + PROVIDE( end = . ); + + .stack ORIGIN(RAM) + LENGTH(RAM) - __stack_size : + { + PROVIDE( _heap_end = . ); + . = ALIGN(4); + PROVIDE(_susrstack = . ); + . = . + __stack_size; + PROVIDE( _eusrstack = .); + __freertos_irq_stack_top = .; + } >RAM +} diff --git a/hw/bsp/ch583/system_ch583.c b/hw/bsp/ch583/system_ch583.c new file mode 100644 index 000000000..d3724f0ce --- /dev/null +++ b/hw/bsp/ch583/system_ch583.c @@ -0,0 +1,39 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 TinyUSB contributors + * + * 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 "CH58x_common.h" +#include "system_ch583.h" + +uint32_t SystemCoreClock = FREQ_SYS; + +void SystemInit(void) { + SetSysClock(CLK_SOURCE_PLL_60MHz); + SystemCoreClock = GetSysClock(); +} + +void SystemCoreClockUpdate(void) { + SystemCoreClock = GetSysClock(); +} diff --git a/hw/bsp/ch583/system_ch583.h b/hw/bsp/ch583/system_ch583.h new file mode 100644 index 000000000..c174c9f5e --- /dev/null +++ b/hw/bsp/ch583/system_ch583.h @@ -0,0 +1,43 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 TinyUSB contributors + * + * 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. + */ + +#ifndef SYSTEM_CH583_H_ +#define SYSTEM_CH583_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t SystemCoreClock; // System Clock Frequency (Core Clock) + +extern void SystemInit(void); +extern void SystemCoreClockUpdate(void); + +#ifdef __cplusplus +} +#endif + +#endif /* SYSTEM_CH583_H_ */ diff --git a/hw/bsp/ch583/wch-riscv.cfg b/hw/bsp/ch583/wch-riscv.cfg new file mode 100644 index 000000000..64d595d8e --- /dev/null +++ b/hw/bsp/ch583/wch-riscv.cfg @@ -0,0 +1,17 @@ +adapter driver wlinke +adapter speed 6000 +transport select sdi + +wlink_set_address 0x00000000 +set _CHIPNAME wch_riscv +sdi newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00001 + +set _TARGETNAME $_CHIPNAME.cpu + +target create $_TARGETNAME.0 wch_riscv -chain-position $_TARGETNAME +$_TARGETNAME.0 configure -work-area-phys 0x20000000 -work-area-size 0x8000 -work-area-backup 1 +set _FLASHNAME $_CHIPNAME.flash + +flash bank $_FLASHNAME wch_riscv 0x00000000 0 0 0 $_TARGETNAME.0 + +echo "Ready for Remote Connections" diff --git a/hw/bsp/ch58x/boards/ch582m_evt/board.cmake b/hw/bsp/ch58x/boards/ch582m_evt/board.cmake deleted file mode 100644 index 4129c4550..000000000 --- a/hw/bsp/ch58x/boards/ch582m_evt/board.cmake +++ /dev/null @@ -1,5 +0,0 @@ -set(LD_FLASH_SIZE 448K) -set(LD_RAM_SIZE 32K) - -function(update_board TARGET) -endfunction() diff --git a/hw/bsp/ch58x/boards/ch582m_evt/board.h b/hw/bsp/ch58x/boards/ch582m_evt/board.h deleted file mode 100644 index c3483bf17..000000000 --- a/hw/bsp/ch58x/boards/ch582m_evt/board.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2024 TinyUSB contributors - * - * 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. - */ - -/* metadata: - name: CH582M-EVT evaluation board - url: https://www.wch-ic.com/products/CH582.html -*/ - -#ifndef BOARD_H_ -#define BOARD_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -// LED: PB4 on CH582M-EVT -#define LED_PIN GPIO_Pin_4 -#define LED_STATE_ON 0 - -// Directly reuse BOOT pin as user button -#define BUTTON_PIN GPIO_Pin_22 -#define BUTTON_STATE_ACTIVE 0 - -// UART: UART1 TX=PA9, RX=PA8 -#define CFG_BOARD_UART_BAUDRATE 115200 - -// Device only on USB1 (rhport 0). CH58x host / USB2 is not supported by the shared usbfs dcd; -// BOARD_TUH_RHPORT is kept commented out to ease re-adding host later. -#ifndef BOARD_TUD_RHPORT -#define BOARD_TUD_RHPORT 0 -#endif -// #ifndef BOARD_TUH_RHPORT -// #define BOARD_TUH_RHPORT 1 -// #endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/hw/bsp/ch58x/boards/ch582m_evt/board.mk b/hw/bsp/ch58x/boards/ch582m_evt/board.mk deleted file mode 100644 index a13979799..000000000 --- a/hw/bsp/ch58x/boards/ch582m_evt/board.mk +++ /dev/null @@ -1,3 +0,0 @@ -LDFLAGS += \ - -Wl,--defsym=__FLASH_SIZE=448K \ - -Wl,--defsym=__RAM_SIZE=32K \ diff --git a/hw/bsp/ch58x/boards/yd-ch582m/board.cmake b/hw/bsp/ch58x/boards/yd-ch582m/board.cmake deleted file mode 100644 index 4129c4550..000000000 --- a/hw/bsp/ch58x/boards/yd-ch582m/board.cmake +++ /dev/null @@ -1,5 +0,0 @@ -set(LD_FLASH_SIZE 448K) -set(LD_RAM_SIZE 32K) - -function(update_board TARGET) -endfunction() diff --git a/hw/bsp/ch58x/boards/yd-ch582m/board.h b/hw/bsp/ch58x/boards/yd-ch582m/board.h deleted file mode 100644 index 0da5747bc..000000000 --- a/hw/bsp/ch58x/boards/yd-ch582m/board.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2024 TinyUSB contributors - * - * 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. - */ - -/* metadata: - name: yd-ch582m from vcc-gnd studio - url: http://vcc-gnd.com/ -*/ - -#ifndef BOARD_H_ -#define BOARD_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -// LED: PB4 on yd-ch582m board -#define LED_PIN GPIO_Pin_4 -#define LED_STATE_ON 0 - -// Directly reuse BOOT pin as user button -#define BUTTON_PIN GPIO_Pin_22 -#define BUTTON_STATE_ACTIVE 0 - -// UART: UART1 TX=PA9, RX=PA8 -#define CFG_BOARD_UART_BAUDRATE 115200 - -// Device only on USB1 (rhport 0). CH58x host / USB2 is not supported by the shared usbfs dcd; -// BOARD_TUH_RHPORT is kept commented out to ease re-adding host later. -#ifndef BOARD_TUD_RHPORT -#define BOARD_TUD_RHPORT 0 -#endif -// #ifndef BOARD_TUH_RHPORT -// #define BOARD_TUH_RHPORT 1 -// #endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/hw/bsp/ch58x/boards/yd-ch582m/board.mk b/hw/bsp/ch58x/boards/yd-ch582m/board.mk deleted file mode 100644 index a13979799..000000000 --- a/hw/bsp/ch58x/boards/yd-ch582m/board.mk +++ /dev/null @@ -1,3 +0,0 @@ -LDFLAGS += \ - -Wl,--defsym=__FLASH_SIZE=448K \ - -Wl,--defsym=__RAM_SIZE=32K \ diff --git a/hw/bsp/ch58x/ch58x_it.c b/hw/bsp/ch58x/ch58x_it.c deleted file mode 100644 index 2211e1eda..000000000 --- a/hw/bsp/ch58x/ch58x_it.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2024 TinyUSB contributors - * - * 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 "ch58x_it.h" - -// NMI exception handler -__INTERRUPT __HIGH_CODE void NMI_Handler(void) { - while (1) {} -} - -// Hard Fault exception handler -__INTERRUPT __HIGH_CODE void HardFault_Handler(void) { - while (1) {} -} diff --git a/hw/bsp/ch58x/ch58x_it.h b/hw/bsp/ch58x/ch58x_it.h deleted file mode 100644 index 3e050344d..000000000 --- a/hw/bsp/ch58x/ch58x_it.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2024 TinyUSB contributors - * - * 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. - */ - -#ifndef CH58X_IT_H_ -#define CH58X_IT_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "CH58x_common.h" - -void NMI_Handler(void); -void HardFault_Handler(void); -void USB_IRQHandler(void); -// void USB2_IRQHandler(void); // host on USB2 (rhport 1) — re-add together with the host driver -void SysTick_Handler(void); - -#ifdef __cplusplus -} -#endif - -#endif /* CH58X_IT_H_ */ diff --git a/hw/bsp/ch58x/debug_uart.c b/hw/bsp/ch58x/debug_uart.c deleted file mode 100644 index 850e40718..000000000 --- a/hw/bsp/ch58x/debug_uart.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2024 TinyUSB contributors - * - * 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 "debug_uart.h" -#include "CH58x_common.h" - -//--------------------------------------------------------------------+ -// Ring buffer based UART TX for non-blocking writes -//--------------------------------------------------------------------+ - -#define UART_RINGBUFFER_SIZE_TX 128 -#define UART_RINGBUFFER_MASK_TX (UART_RINGBUFFER_SIZE_TX - 1) - -static char tx_buf[UART_RINGBUFFER_SIZE_TX]; -static uint32_t tx_produce; -static volatile uint32_t tx_consume; - -void uart_write(char c) { - uint32_t tx_produce_next = (tx_produce + 1) & UART_RINGBUFFER_MASK_TX; - - // If the ring buffer is full, drain it here as the FIFO frees up: nothing else advances - // tx_consume between uart_write() calls, so a plain spin would deadlock on a >buffer-size burst. - while (tx_produce_next == tx_consume) { - if (R8_UART1_LSR & RB_LSR_TX_FIFO_EMP) { - R8_UART1_THR = tx_buf[tx_consume]; - tx_consume = (tx_consume + 1) & UART_RINGBUFFER_MASK_TX; - } - } - - // If UART TX FIFO is empty and no pending data, send directly - if ((tx_consume == tx_produce) && (R8_UART1_LSR & RB_LSR_TX_FIFO_EMP)) { - R8_UART1_THR = c; - } else { - tx_buf[tx_produce] = c; - tx_produce = tx_produce_next; - } -} - -void uart_sync(void) { - // Wait for ring buffer to drain - while (tx_consume != tx_produce) { - if (R8_UART1_LSR & RB_LSR_TX_FIFO_EMP) { - R8_UART1_THR = tx_buf[tx_consume]; - tx_consume = (tx_consume + 1) & UART_RINGBUFFER_MASK_TX; - } - } - // Wait for last byte to finish transmitting - while (!(R8_UART1_LSR & RB_LSR_TX_ALL_EMP)) {} -} - -void usart_printf_init(uint32_t baudrate) { - tx_produce = 0; - tx_consume = 0; - - // Configure UART1 pins: TX=PA9, RX=PA8 - GPIOA_SetBits(GPIO_Pin_9); - GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA); - GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU); - - // Init UART1 with specified baud rate - UART1_DefInit(); - UART1_BaudRateCfg(baudrate); -} diff --git a/hw/bsp/ch58x/debug_uart.h b/hw/bsp/ch58x/debug_uart.h deleted file mode 100644 index 44c3e7948..000000000 --- a/hw/bsp/ch58x/debug_uart.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2024 TinyUSB contributors - * - * 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. - */ - -#ifndef DEBUG_UART_H_ -#define DEBUG_UART_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void uart_write(char c); -void uart_sync(void); -void usart_printf_init(uint32_t baudrate); - -#ifdef __cplusplus -} -#endif - -#endif /* DEBUG_UART_H_ */ diff --git a/hw/bsp/ch58x/family.c b/hw/bsp/ch58x/family.c deleted file mode 100644 index 64ae4a903..000000000 --- a/hw/bsp/ch58x/family.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2024 TinyUSB contributors - * - * 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. - */ - -/* metadata: - manufacturer: WCH -*/ - -// WCH SDK's DEBUG macro enables a _write() that conflicts with TinyUSB's. -// TinyUSB uses UART1 for printf via debug_uart.c, so DEBUG is not needed. -// If you need a different UART or want to keep SDK's DEBUG, modify -// debug_uart.c (TinyUSB side) or CH58x_sys.c (SDK side) to remove one _write(). -// If done, remove this #error to continue. -#ifdef DEBUG - #error "Remove the DEBUG macro from preprocessor defines to avoid " \ - "duplicate _write() between WCH SDK and TinyUSB. " \ - "TinyUSB uses UART1 by default (see debug_uart.c)." -#endif - -#include "debug_uart.h" -#include "CH58x_common.h" -#include "ch58x_it.h" - -#include "bsp/board_api.h" -#include "board.h" - -//--------------------------------------------------------------------+ -// Forward USB interrupt events to TinyUSB IRQ Handler -//--------------------------------------------------------------------+ - -// Device only: the shared dcd_ch32_usbfs.c drives USB0 (rhport 0). CH58x's second controller -// (USB2 / rhport 1) was driven by the now-removed ch58x host driver; its handler is kept -// commented out below to ease re-adding host support. -__INTERRUPT __HIGH_CODE void USB_IRQHandler(void) { - tusb_int_handler(0, true); -} - -// __INTERRUPT __HIGH_CODE void USB2_IRQHandler(void) { -// tusb_int_handler(1, true); -// } - -//--------------------------------------------------------------------+ -// SysTick -//--------------------------------------------------------------------+ - -#if CFG_TUSB_OS == OPT_OS_NONE -volatile uint32_t system_ticks = 0; - -__INTERRUPT __HIGH_CODE void SysTick_Handler(void) { - SysTick->SR = 0; - system_ticks++; -} - -uint32_t tusb_time_millis_api(void) { - return system_ticks; -} -#endif - -//--------------------------------------------------------------------+ -// Board Init -//--------------------------------------------------------------------+ - -void board_init(void) { - // Disable interrupts during init - PFIC_DisableAllIRQ(); - - // Set system clock to PLL 60MHz (default for CH582) - SetSysClock(CLK_SOURCE_PLL_60MHz); - -#if CFG_TUSB_OS == OPT_OS_NONE - SysTick_Config(GetSysClock() / 1000); -#endif - - // UART1 init for debug output -#ifdef CFG_BOARD_UART_BAUDRATE - usart_printf_init(CFG_BOARD_UART_BAUDRATE); -#endif - - // LED -#ifdef LED_PORT_IS_A - GPIOA_ModeCfg(LED_PIN, GPIO_ModeOut_PP_5mA); -#else - GPIOB_ModeCfg(LED_PIN, GPIO_ModeOut_PP_5mA); -#endif - - // Button -#ifdef BUTTON_PIN - #ifdef BUTTON_PORT_IS_A - GPIOA_ModeCfg(BUTTON_PIN, GPIO_ModeIN_PU); - #else - GPIOB_ModeCfg(BUTTON_PIN, GPIO_ModeIN_PU); - #endif -#endif - - // Device only on USB0 (rhport 0): enable analog function for USB1 D+/D- and assert its D+ - // pull-up. The shared dcd_ch32_usbfs.c drives USB0; CH58x host / USB2 (rhport 1) is unsupported - // here — to re-add host, also OR in RB_PIN_USB2_IE below. - R16_PIN_ANALOG_IE |= RB_PIN_USB_IE; // | RB_PIN_USB2_IE (re-add for host on USB2) -#if CFG_TUD_ENABLED - R16_PIN_ANALOG_IE |= RB_PIN_USB_DP_PU; -#endif - - // Keep USB clock active during sleep - R8_SLP_CLK_OFF1 &= ~RB_SLP_CLK_USB; - - // Enable interrupts globally - PFIC_EnableAllIRQ(); - - board_delay(2); -} - -//--------------------------------------------------------------------+ -// Board porting API -//--------------------------------------------------------------------+ - -void board_led_write(bool state) { -#ifdef LED_PORT_IS_A - if (state ^ LED_STATE_ON) { - GPIOA_ResetBits(LED_PIN); - } else { - GPIOA_SetBits(LED_PIN); - } -#else - if (state ^ LED_STATE_ON) { - GPIOB_ResetBits(LED_PIN); - } else { - GPIOB_SetBits(LED_PIN); - } -#endif -} - -uint32_t board_button_read(void) { -#ifdef BUTTON_PIN - #ifdef BUTTON_PORT_IS_A - return BUTTON_STATE_ACTIVE == (GPIOA_ReadPortPin(BUTTON_PIN) ? 1 : 0); - #else - return BUTTON_STATE_ACTIVE == (GPIOB_ReadPortPin(BUTTON_PIN) ? 1 : 0); - #endif -#else - return 0; -#endif -} - -// CH58x has no memory-mapped unique-ID register (unlike ch32v10x/v20x at 0x1FFFF7E8), but the -// factory programs a unique 6-byte MAC address into FlashROM (it is a BLE part). GetMACAddress() -// reads it via the ISP ROM command FLASH_EEPROM_CMD, which is provided by libISP583.a. -size_t board_get_unique_id(uint8_t id[], size_t max_len) { - // FLASH_EEPROM_CMD writes word-granular and requires a 4-byte-aligned buffer (CH58x_flash.c); - // size 8 matches the SDK's GET_UNIQUE_ID buffer (6 MAC bytes + 2 it pads), so the read can't - // run past the end whether it returns 6 or a full 8. - TU_ATTR_ALIGNED(4) uint8_t mac[8]; - GetMACAddress(mac); - size_t len = TU_MIN(max_len, (size_t) 6); // the 6-byte MAC is the unique part - memcpy(id, mac, len); - return len; -} - -int board_uart_read(uint8_t* buf, int len) { - (void) buf; - (void) len; - return 0; -} - -int board_uart_write(void const* buf, int len) { - int txsize = len; - const char* bufc = (const char*) buf; - while (txsize--) { - uart_write(*bufc++); - } - uart_sync(); - return len; -} diff --git a/hw/bsp/ch58x/family.cmake b/hw/bsp/ch58x/family.cmake deleted file mode 100644 index a52309276..000000000 --- a/hw/bsp/ch58x/family.cmake +++ /dev/null @@ -1,108 +0,0 @@ -include_guard() - -set(SDK_DIR ${TOP}/hw/mcu/wch/ch583) -set(SDK_SRC_DIR ${SDK_DIR}/EVT/EXAM/SRC) - -# include board specific -include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake) - -# toolchain set up -set(CMAKE_SYSTEM_CPU rv32imac-ilp32 CACHE INTERNAL "System Processor") -set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/riscv_${TOOLCHAIN}.cmake) - -set(FAMILY_MCUS CH58X CACHE INTERNAL "") -set(OPENOCD_OPTION "-f ${CMAKE_CURRENT_LIST_DIR}/wch-riscv.cfg") - -#------------------------------------ -# Startup & Linker script -#------------------------------------ -if (NOT DEFINED LD_FILE_GNU) - set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/linker/ch582.ld) -endif () -set(LD_FILE_Clang ${LD_FILE_GNU}) -if (NOT DEFINED STARTUP_FILE_GNU) - set(STARTUP_FILE_GNU ${SDK_SRC_DIR}/Startup/startup_CH583.S) -endif () -set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU}) - -#------------------------------------ -# Board Target -#------------------------------------ -function(family_add_board BOARD_TARGET) - add_library(${BOARD_TARGET} STATIC - ${SDK_SRC_DIR}/StdPeriphDriver/CH58x_gpio.c - ${SDK_SRC_DIR}/StdPeriphDriver/CH58x_clk.c - ${SDK_SRC_DIR}/StdPeriphDriver/CH58x_uart1.c - ${SDK_SRC_DIR}/StdPeriphDriver/CH58x_sys.c - ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ch58x_it.c - ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/system_ch58x.c - ) - target_include_directories(${BOARD_TARGET} PUBLIC - ${SDK_SRC_DIR}/RVMSIS - ${SDK_SRC_DIR}/StdPeriphDriver/inc - ${CMAKE_CURRENT_FUNCTION_LIST_DIR} - ) - target_link_libraries(${BOARD_TARGET} PUBLIC - ${SDK_SRC_DIR}/StdPeriphDriver/libISP583.a - ) - target_compile_definitions(${BOARD_TARGET} PUBLIC - CFG_TUD_WCH_USBIP_USBFS=1 - FREQ_SYS=60000000 - DISK_LIB_ENABLE=0 - INT_SOFT - ) - - update_board(${BOARD_TARGET}) - - if (CMAKE_C_COMPILER_ID STREQUAL "GNU") - target_compile_options(${BOARD_TARGET} PUBLIC - -flto - -msmall-data-limit=16 - -mno-save-restore - -fmessage-length=0 - -fsigned-char - -Wno-error=strict-prototypes - ) - endif () -endfunction() - -#------------------------------------ -# Functions -#------------------------------------ -function(family_configure_example TARGET RTOS) - family_configure_common(${TARGET} ${RTOS}) - family_add_tinyusb(${TARGET} OPT_MCU_CH58X) - - target_sources(${TARGET} PUBLIC - ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c - ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/debug_uart.c - ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c - ${TOP}/src/portable/wch/dcd_ch32_usbfs.c - ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} - ) - target_include_directories(${TARGET} PUBLIC - ${CMAKE_CURRENT_FUNCTION_LIST_DIR} - ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../ - ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD} - ) - - if (CMAKE_C_COMPILER_ID STREQUAL "GNU") - target_link_options(${TARGET} PUBLIC - -nostartfiles - --specs=nosys.specs --specs=nano.specs - -Wl,--defsym=__FLASH_SIZE=${LD_FLASH_SIZE} - -Wl,--defsym=__RAM_SIZE=${LD_RAM_SIZE} - "LINKER:--script=${LD_FILE_GNU}" - ) - elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang") - message(FATAL_ERROR "Clang is not supported for CH58x") - endif () - - set_source_files_properties(${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} PROPERTIES - SKIP_LINTING ON - COMPILE_OPTIONS -w) - - # Flashing - family_add_bin_hex(${TARGET}) - family_flash_openocd_wch(${TARGET}) -endfunction() diff --git a/hw/bsp/ch58x/family.mk b/hw/bsp/ch58x/family.mk deleted file mode 100644 index ac0443659..000000000 --- a/hw/bsp/ch58x/family.mk +++ /dev/null @@ -1,59 +0,0 @@ -# https://www.embecosm.com/resources/tool-chain-downloads/#riscv-stable -#CROSS_COMPILE ?= riscv32-unknown-elf- - -# Toolchain from https://nucleisys.com/download.php -#CROSS_COMPILE ?= riscv-nuclei-elf- - -# Toolchain from https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack -CROSS_COMPILE ?= riscv-none-elf- - -SDK_DIR = hw/mcu/wch/ch583 -SDK_SRC_DIR = $(SDK_DIR)/EVT/EXAM/SRC - -include $(TOP)/$(BOARD_PATH)/board.mk -CPU_CORE ?= rv32imac-ilp32 - -CFLAGS += \ - -flto \ - -msmall-data-limit=16 \ - -mno-save-restore \ - -fmessage-length=0 \ - -fsigned-char \ - -DCFG_TUSB_MCU=OPT_MCU_CH58X \ - -DCFG_TUD_WCH_USBIP_USBFS=1 \ - -DFREQ_SYS=60000000 \ - -DDISK_LIB_ENABLE=0 \ - -DINT_SOFT \ - -Wno-error=strict-prototypes - -LDFLAGS += \ - -nostartfiles \ - --specs=nosys.specs --specs=nano.specs - -LIBS += $(TOP)/$(SDK_SRC_DIR)/StdPeriphDriver/libISP583.a - -SRC_C += \ - src/portable/wch/dcd_ch32_usbfs.c \ - $(SDK_SRC_DIR)/StdPeriphDriver/CH58x_gpio.c \ - $(SDK_SRC_DIR)/StdPeriphDriver/CH58x_clk.c \ - $(SDK_SRC_DIR)/StdPeriphDriver/CH58x_uart1.c \ - $(SDK_SRC_DIR)/StdPeriphDriver/CH58x_sys.c \ - $(FAMILY_PATH)/debug_uart.c \ - $(FAMILY_PATH)/ch58x_it.c \ - $(FAMILY_PATH)/system_ch58x.c - -SRC_S += \ - $(SDK_SRC_DIR)/Startup/startup_CH583.S - -INC += \ - $(TOP)/$(BOARD_PATH) \ - $(TOP)/$(SDK_SRC_DIR)/RVMSIS \ - $(TOP)/$(SDK_SRC_DIR)/StdPeriphDriver/inc - -LD_FILE ?= $(FAMILY_PATH)/linker/ch582.ld - -OPENOCD_WCH_OPTION=-f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg -flash: flash-openocd-wch - -# For freeRTOS port source -FREERTOS_PORTABLE_SRC = $(FREERTOS_PORTABLE_PATH)/RISC-V diff --git a/hw/bsp/ch58x/linker/ch582.ld b/hw/bsp/ch58x/linker/ch582.ld deleted file mode 100644 index 821998a49..000000000 --- a/hw/bsp/ch58x/linker/ch582.ld +++ /dev/null @@ -1,167 +0,0 @@ -/* CH582 Linker Script for TinyUSB - * Based on WCH CH583 SDK Link.ld - * Supports parameterized flash/ram sizes via --defsym - */ - -/* Default sizes if not provided via --defsym */ -__flash_size = DEFINED(__FLASH_SIZE) ? __FLASH_SIZE : 448K; -__ram_size = DEFINED(__RAM_SIZE) ? __RAM_SIZE : 32K; -__stack_size = DEFINED(__STACK_SIZE) ? __STACK_SIZE : 2048; - -ENTRY( _start ) - -PROVIDE( _stack_size = __stack_size ); - -MEMORY -{ - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = __flash_size - RAM (xrw) : ORIGIN = 0x20000000, LENGTH = __ram_size -} - -SECTIONS -{ - .init : - { - _sinit = .; - . = ALIGN(4); - KEEP(*(SORT_NONE(.init))) - . = ALIGN(4); - _einit = .; - } >FLASH AT>FLASH - - .highcodelalign : - { - . = ALIGN(4); - PROVIDE(_highcode_lma = .); - } >FLASH AT>FLASH - - .highcode : - { - . = ALIGN(4); - PROVIDE(_highcode_vma_start = .); - *(.vector); - KEEP(*(SORT_NONE(.vector_handler))) - *(.highcode); - *(.highcode.*); - . = ALIGN(4); - PROVIDE(_highcode_vma_end = .); - } >RAM AT>FLASH - - .text : - { - . = ALIGN(4); - KEEP(*(SORT_NONE(.handle_reset))) - *(.text) - *(.text.*) - *(.rodata) - *(.rodata*) - *(.sdata2.*) - *(.glue_7) - *(.glue_7t) - *(.gnu.linkonce.t.*) - . = ALIGN(4); - } >FLASH AT>FLASH - - .fini : - { - KEEP(*(SORT_NONE(.fini))) - . = ALIGN(4); - } >FLASH AT>FLASH - - PROVIDE( _etext = . ); - PROVIDE( _eitcm = . ); - - .preinit_array : - { - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP (*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - } >FLASH AT>FLASH - - .init_array : - { - PROVIDE_HIDDEN (__init_array_start = .); - KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) - KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) - PROVIDE_HIDDEN (__init_array_end = .); - } >FLASH AT>FLASH - - .fini_array : - { - PROVIDE_HIDDEN (__fini_array_start = .); - KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) - KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) - PROVIDE_HIDDEN (__fini_array_end = .); - } >FLASH AT>FLASH - - .ctors : - { - KEEP (*crtbegin.o(.ctors)) - KEEP (*crtbegin?.o(.ctors)) - KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - } >FLASH AT>FLASH - - .dtors : - { - KEEP (*crtbegin.o(.dtors)) - KEEP (*crtbegin?.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - } >FLASH AT>FLASH - - .dlalign : - { - . = ALIGN(4); - PROVIDE(_data_lma = .); - } >FLASH AT>FLASH - - .data : - { - . = ALIGN(4); - PROVIDE(_data_vma = .); - *(.gnu.linkonce.r.*) - *(.data .data.*) - *(.gnu.linkonce.d.*) - . = ALIGN(8); - PROVIDE( __global_pointer$ = . + 0x800 ); - *(.sdata .sdata.*) - *(.gnu.linkonce.s.*) - . = ALIGN(8); - *(.srodata.cst16) - *(.srodata.cst8) - *(.srodata.cst4) - *(.srodata.cst2) - *(.srodata .srodata.*) - . = ALIGN(4); - PROVIDE( _edata = .); - } >RAM AT>FLASH - - .bss : - { - . = ALIGN(4); - PROVIDE( _sbss = .); - *(.sbss*) - *(.gnu.linkonce.sb.*) - *(.bss*) - *(.gnu.linkonce.b.*) - *(COMMON*) - . = ALIGN(4); - PROVIDE( _ebss = .); - } >RAM AT>FLASH - - PROVIDE( _end = _ebss); - PROVIDE( end = . ); - - .stack ORIGIN(RAM) + LENGTH(RAM) - __stack_size : - { - PROVIDE( _heap_end = . ); - . = ALIGN(4); - PROVIDE(_susrstack = . ); - . = . + __stack_size; - PROVIDE( _eusrstack = .); - __freertos_irq_stack_top = .; - } >RAM -} diff --git a/hw/bsp/ch58x/system_ch58x.c b/hw/bsp/ch58x/system_ch58x.c deleted file mode 100644 index 068c1a131..000000000 --- a/hw/bsp/ch58x/system_ch58x.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2024 TinyUSB contributors - * - * 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 "CH58x_common.h" -#include "system_ch58x.h" - -uint32_t SystemCoreClock = FREQ_SYS; - -void SystemInit(void) { - SetSysClock(CLK_SOURCE_PLL_60MHz); - SystemCoreClock = GetSysClock(); -} - -void SystemCoreClockUpdate(void) { - SystemCoreClock = GetSysClock(); -} diff --git a/hw/bsp/ch58x/system_ch58x.h b/hw/bsp/ch58x/system_ch58x.h deleted file mode 100644 index e96741ee8..000000000 --- a/hw/bsp/ch58x/system_ch58x.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2024 TinyUSB contributors - * - * 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. - */ - -#ifndef SYSTEM_CH58X_H_ -#define SYSTEM_CH58X_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -extern uint32_t SystemCoreClock; // System Clock Frequency (Core Clock) - -extern void SystemInit(void); -extern void SystemCoreClockUpdate(void); - -#ifdef __cplusplus -} -#endif - -#endif /* SYSTEM_CH58X_H_ */ diff --git a/hw/bsp/ch58x/wch-riscv.cfg b/hw/bsp/ch58x/wch-riscv.cfg deleted file mode 100644 index 64d595d8e..000000000 --- a/hw/bsp/ch58x/wch-riscv.cfg +++ /dev/null @@ -1,17 +0,0 @@ -adapter driver wlinke -adapter speed 6000 -transport select sdi - -wlink_set_address 0x00000000 -set _CHIPNAME wch_riscv -sdi newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00001 - -set _TARGETNAME $_CHIPNAME.cpu - -target create $_TARGETNAME.0 wch_riscv -chain-position $_TARGETNAME -$_TARGETNAME.0 configure -work-area-phys 0x20000000 -work-area-size 0x8000 -work-area-backup 1 -set _FLASHNAME $_CHIPNAME.flash - -flash bank $_FLASHNAME wch_riscv 0x00000000 0 0 0 $_TARGETNAME.0 - -echo "Ready for Remote Connections" diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index f2a2d92a5..b5390a59d 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -659,7 +659,7 @@ #define TUP_DCD_EDPT_CLOSE_API #endif -#elif TU_CHECK_MCU(OPT_MCU_CH58X) +#elif TU_CHECK_MCU(OPT_MCU_CH583) // CH582/583 USBFS: older WCH USBFS IP with a single combined per-endpoint control register // (like CH32V103), driven by the shared dcd_ch32_usbfs.c on USB0 (rhport 0). Device only: // the shared hcd_ch32_usbfs.c is CH32V20x-specific and does not support CH58x, so host / diff --git a/src/portable/wch/ch32_usbfs_reg.h b/src/portable/wch/ch32_usbfs_reg.h index 90a477b79..415a015dc 100644 --- a/src/portable/wch/ch32_usbfs_reg.h +++ b/src/portable/wch/ch32_usbfs_reg.h @@ -130,7 +130,7 @@ #elif CFG_TUSB_MCU == OPT_MCU_CH32V307 #include #define USBHD_IRQn OTG_FS_IRQn -#elif CFG_TUSB_MCU == OPT_MCU_CH58X +#elif CFG_TUSB_MCU == OPT_MCU_CH583 #include "CH58x_common.h" // CH582/583 USBFS device controller: same combined per-endpoint control register as // CH32V103 (IN response bits[1:0], OUT response bits[3:2]) but a different register map - diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 22c7a43fa..ece9cde07 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -37,7 +37,7 @@ // Struct-based EP register access (uniform layout). CH58X has a different register map and // defines EP_DMA/EP_TX_LEN/EP_CTRL itself in ch32_usbfs_reg.h. - #if CFG_TUSB_MCU == OPT_MCU_CH58X + #if CFG_TUSB_MCU == OPT_MCU_CH583 // CH58X EP registers split into a low block (EP0-4) and a high block (EP5-7). Walk from each // block's first slot by the 4-byte slot stride (pointer arithmetic off slot 0, so the unused // ternary branch's index can't trip -Warray-bounds). EP4 has no DMA register of its own (it @@ -220,7 +220,7 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force) { if (xfer->valid) { if (force || xfer->len) { size_t len = TU_MIN(xfer->max_size, xfer->len); -#if CFG_TUSB_MCU == OPT_MCU_CH58X +#if CFG_TUSB_MCU == OPT_MCU_CH583 // Every CH58x endpoint buffer is 64 bytes. Isochronous (which would push max_size up to 1023) // is refused in dcd_edpt_iso_alloc(), but some classes (e.g. video) ignore that result, so cap // the copy here to guarantee we never write past the buffer into a neighbouring endpoint's. @@ -256,7 +256,7 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { struct usb_xfer *xfer = &data.xfer[ep][TUSB_DIR_OUT]; if (xfer->valid) { size_t len = TU_MIN(xfer->max_size, TU_MIN(xfer->len, rx_len)); -#if CFG_TUSB_MCU == OPT_MCU_CH58X +#if CFG_TUSB_MCU == OPT_MCU_CH583 len = TU_MIN(len, 64u); // cap to the 64-byte EP buffer (see update_in) #endif memcpy(xfer->buffer, ep_out_buf(ep), len); @@ -308,7 +308,7 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { // enable other endpoints but NAK everything USBOTG_FS->UEP4_1_MOD = 0xCC; USBOTG_FS->UEP2_3_MOD = 0xCC; -#if CFG_TUSB_MCU == OPT_MCU_CH58X +#if CFG_TUSB_MCU == OPT_MCU_CH583 // CH58X: a single mode register enables EP5/6/7 RX+TX (different bit layout than CH32). USBOTG_FS->UEP567_MOD = RB_UEP5_RX_EN | RB_UEP5_TX_EN | RB_UEP6_RX_EN | RB_UEP6_TX_EN | RB_UEP7_RX_EN | RB_UEP7_TX_EN; @@ -393,7 +393,7 @@ void dcd_int_handler(uint8_t rhport) { USBOTG_FS->INT_FG = USBFS_INT_FG_BUS_RST; } else if (status & USBFS_INT_FG_SUSPEND) { -#if CFG_TUSB_MCU == OPT_MCU_CH58X +#if CFG_TUSB_MCU == OPT_MCU_CH583 // CH58x raises this single interrupt for both suspend and resume; MIS_ST's suspend bit tells // them apart (set while suspended, clear once resumed) so tud_resume_cb() actually fires. dcd_event_t event = {.rhport = rhport, @@ -447,7 +447,7 @@ void dcd_edpt0_status_complete(uint8_t rhport, const tusb_control_request_t *req (void)rhport; if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) { -#if CFG_TUSB_MCU == OPT_MCU_CH58X +#if CFG_TUSB_MCU == OPT_MCU_CH583 // On CH58x R8_USB_DEV_AD bit 7 is a user general-purpose flag; only bits [6:0] are the address. USBOTG_FS->DEV_ADDR = (uint8_t)((USBOTG_FS->DEV_ADDR & 0x80u) | (request->wValue & 0x7Fu)); #else @@ -485,7 +485,7 @@ bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet (void)rhport; (void)ep_addr; (void)largest_packet_size; -#if CFG_TUSB_MCU == OPT_MCU_CH58X +#if CFG_TUSB_MCU == OPT_MCU_CH583 // No isochronous support on CH58x: its 8-bit T_LEN caps a packet at 255B and the endpoints use // plain 64-byte buffers, so accepting an iso max_size (up to 1023) would let update_in()/ // update_out() run off the end of the buffer into neighbouring ones. Refuse it outright. @@ -503,7 +503,7 @@ bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { (void)rhport; (void)desc_ep; -#if CFG_TUSB_MCU == OPT_MCU_CH58X +#if CFG_TUSB_MCU == OPT_MCU_CH583 return false; // CH58x has no isochronous support (see dcd_edpt_iso_alloc) #else return true; diff --git a/src/tusb_option.h b/src/tusb_option.h index 9170d1205..cb8e3f6bd 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -195,7 +195,7 @@ #define OPT_MCU_CH32F20X 2210 ///< WCH CH32F20x #define OPT_MCU_CH32V20X 2220 ///< WCH CH32V20X #define OPT_MCU_CH32V103 2230 ///< WCH CH32V103 -#define OPT_MCU_CH58X 2240 ///< WCH CH58x +#define OPT_MCU_CH583 2240 ///< WCH CH583 #define OPT_MCU_CH582 2240 ///< alias to CH58x series #define OPT_MCU_CH583 2240 ///< alias to CH58x series diff --git a/tools/get_deps.py b/tools/get_deps.py index b31f8a0cb..ebbf9b871 100755 --- a/tools/get_deps.py +++ b/tools/get_deps.py @@ -255,7 +255,7 @@ deps_optional = { 'ch32f20x'], 'hw/mcu/wch/ch583': ['https://github.com/openwch/ch583.git', 'bd508ad7ceed48377619837051412a651952857f', - 'ch58x'], + 'ch583'], 'hw/mcu/artery/at32f403a_407': ['https://github.com/ArteryTek/AT32F403A_407_Firmware_Library.git', 'f2cb360c3d28fada76b374308b8c4c61d37a090b', 'at32f403a_407'], -- cgit v1.3.1