summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHa Thach <[email protected]>2026-06-18 12:15:40 +0700
committerGitHub <[email protected]>2026-06-18 12:15:40 +0700
commit941d63e39a529593ee86caf7ea85e04839680d59 (patch)
tree6df899db9fe34d9385515cb0a27b905c176e4ea4
parent52035e2fa3174e85f9c43afdba05097519ae6ea9 (diff)
parent133de459505860f6961621b5619f4a4cb6c357c4 (diff)
Merge pull request #3710 from hathach/add-hil-ch32v103
ch32v103: bring up USB device (combined-control USBFS IP) + add to HIL
-rw-r--r--hw/bsp/ch32v10x/family.c39
-rw-r--r--src/portable/wch/ch32_usbfs_reg.h140
-rw-r--r--src/portable/wch/dcd_ch32_usbfs.c95
-rw-r--r--test/hil/tinyusb.json16
4 files changed, 197 insertions, 93 deletions
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 <ch32f20x.h>
#elif CFG_TUSB_MCU == OPT_MCU_CH32V103
#include <ch32v10x.h>
+ // 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 <ch32v20x.h>
#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);
}
}
}
diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json
index ea9342c03..41d94bc00 100644
--- a/test/hil/tinyusb.json
+++ b/test/hil/tinyusb.json
@@ -477,6 +477,22 @@
"uid": "EBCA8F0670AF",
"args": ""
}
+ },
+ {
+ "name": "ch32v103r_r1_1v0",
+ "uid": "CDAB3E8749BC54EF0F410025",
+ "toolchain": "riscv-gcc",
+ "tests": {
+ "device": true,
+ "host": false,
+ "dual": false,
+ "skip": ["device/cdc_msc_throughput"]
+ },
+ "flasher": {
+ "name": "openocd_wch",
+ "uid": "BC4954081051",
+ "args": ""
+ }
}
],
"boards-skip": [