diff options
| author | hathach <[email protected]> | 2026-06-18 10:58:58 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2026-06-18 10:58:58 +0700 |
| commit | ad8cbc4668ab8d92e2eebb834c230e9d18ad8e57 (patch) | |
| tree | aedbe861afb403114e62d5cd663f5041cfee1a56 /hw | |
| parent | 52035e2fa3174e85f9c43afdba05097519ae6ea9 (diff) | |
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) <[email protected]>
Diffstat (limited to 'hw')
| -rw-r--r-- | hw/bsp/ch32v10x/family.c | 39 |
1 files changed, 18 insertions, 21 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; |
