summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhathach <[email protected]>2026-07-09 23:38:48 +0700
committerhathach <[email protected]>2026-07-09 23:38:48 +0700
commit90d48c2a632751c1b38831655e256f1bc1918a47 (patch)
tree5be772503ae8011e9b5bbc0183a4aebf29bfeb1b
parentc97c0a12bc5ab8e79aa3db0a777e0219692b5751 (diff)
bsp(ch32): naked fsdev ISRs so nested USBD IRQs return safely
The three USBD lines nest under QingKe HWSTK; gcc's interrupt prologue corrupts the return, so rely on the hardware stack and bare mret. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
-rw-r--r--hw/bsp/ch32v20x/family.c38
-rw-r--r--hw/bsp/ch32v30x/family.c9
2 files changed, 28 insertions, 19 deletions
diff --git a/hw/bsp/ch32v20x/family.c b/hw/bsp/ch32v20x/family.c
index 76024cfde..8875e4faa 100644
--- a/hw/bsp/ch32v20x/family.c
+++ b/hw/bsp/ch32v20x/family.c
@@ -27,25 +27,25 @@ manufacturer: WCH
* - CFG_TUD_WCH_USBIP_USBFS
*/
-// Port0: USBD (fsdev)
-__attribute__((interrupt)) __attribute__((used)) void USB_LP_CAN1_RX0_IRQHandler(void) {
- #if CFG_TUD_WCH_USBIP_FSDEV
- tud_int_handler(0);
- #endif
-}
-
-__attribute__((interrupt)) __attribute__((used)) void USB_HP_CAN1_TX_IRQHandler(void) {
- #if CFG_TUD_WCH_USBIP_FSDEV
- tud_int_handler(0);
- #endif
-
-}
-
-__attribute__((interrupt)) __attribute__((used)) void USBWakeUp_IRQHandler(void) {
- #if CFG_TUD_WCH_USBIP_FSDEV
- tud_int_handler(0);
- #endif
-}
+// Port0: USBD (fsdev). The USBD raises three IRQ lines (LP/HP/WakeUp) that all funnel into the
+// non-reentrant tud_int_handler and can nest (HP preempts LP) with QingKe HWSTK enabled. The
+// mainline toolchain's plain __attribute__((interrupt)) emits a software prologue that fights the
+// hardware context stack and corrupts the return on nesting. Emit naked handlers that rely on
+// HWSTK for context save/restore (equivalent to WCH's "WCH-Interrupt-fast"), which nests safely.
+#if CFG_TUD_ENABLED && CFG_TUD_WCH_USBIP_FSDEV
+ // The `call dcd_int_handler` below lives inside naked asm where LTO cannot see it; without a
+ // compiler-visible reference, -flto builds (make) internalize/drop the symbol and the link fails.
+ TU_ATTR_USED static void (*const fsdev_isr_keep)(uint8_t) = dcd_int_handler;
+ #define FSDEV_NAKED_ISR(name) \
+ __attribute__((naked)) __attribute__((used)) void name(void) { \
+ __asm volatile("li a0, 0\n\t call dcd_int_handler\n\t mret"); }
+#else
+ #define FSDEV_NAKED_ISR(name) \
+ __attribute__((naked)) __attribute__((used)) void name(void) { __asm volatile("mret"); }
+#endif
+FSDEV_NAKED_ISR(USB_LP_CAN1_RX0_IRQHandler)
+FSDEV_NAKED_ISR(USB_HP_CAN1_TX_IRQHandler)
+FSDEV_NAKED_ISR(USBWakeUp_IRQHandler)
// Port1: USBFS
__attribute__((interrupt)) __attribute__((used)) void USBHD_IRQHandler(void) {
diff --git a/hw/bsp/ch32v30x/family.c b/hw/bsp/ch32v30x/family.c
index aee4e7d4f..02c3c7d44 100644
--- a/hw/bsp/ch32v30x/family.c
+++ b/hw/bsp/ch32v30x/family.c
@@ -29,6 +29,7 @@
*/
#include "stdio.h"
+#include <string.h>
// https://github.com/openwch/ch32v307/pull/90
// https://github.com/openwch/ch32v20x/pull/12
@@ -166,6 +167,14 @@ uint32_t board_button_read(void) {
#endif
}
+size_t board_get_unique_id(uint8_t id[], size_t max_len) {
+ volatile uint32_t* ch32_uuid = ((volatile uint32_t*) 0x1FFFF7E8UL); // ESIG unique ID
+ uint32_t uid[3] = { ch32_uuid[0], ch32_uuid[1], ch32_uuid[2] };
+ const size_t len = max_len < sizeof(uid) ? max_len : sizeof(uid);
+ memcpy(id, uid, len); // byte copy: id[] need not be 4-byte aligned
+ return len;
+}
+
int board_uart_read(uint8_t* buf, int len) {
(void) buf;
(void) len;