summaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorhathach <[email protected]>2026-06-18 10:58:58 +0700
committerhathach <[email protected]>2026-06-18 10:58:58 +0700
commitad8cbc4668ab8d92e2eebb834c230e9d18ad8e57 (patch)
treeaedbe861afb403114e62d5cd663f5041cfee1a56 /hw
parent52035e2fa3174e85f9c43afdba05097519ae6ea9 (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.c39
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;