libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
ch32_usbcan_shared.hpp
1#pragma once
2#include <atomic>
3#include <cstdint>
4
5#include "ch32_can_caps.hpp"
6
7namespace LibXR::CH32UsbCanShared
8{
12using IrqFn = void (*)();
13
14inline std::atomic_bool usb_inited{false};
15inline std::atomic_bool can1_inited{false};
16inline std::atomic_bool can2_inited{false};
17// 端点对象在 Stop/Start 后仍保留 PMA 地址;分配后不能再增加 CAN 占用。
18// Endpoint objects retain their PMA addresses across Stop/Start.
19inline std::atomic_bool usb_pma_configured{false};
20
21static constexpr uint16_t USBD_PMA_BYTES_SOLO = 512;
22static constexpr uint16_t USBD_PMA_BYTES_WITHCAN = 384;
23static constexpr uint16_t USBD_PMA_BYTES_WITHCAN2 = 256;
24
25// USB/CAN 共享中断拓扑的编译期能力标志。
26// Build-time capability flags for USB/CAN shared interrupt topology.
27#if defined(RCC_APB1Periph_USB)
28inline constexpr bool K_HAS_USB_DEV_FS = true;
29#else
30inline constexpr bool K_HAS_USB_DEV_FS = false;
31#endif
32
33#if defined(CAN1)
34inline constexpr bool K_HAS_CAN1 = true;
35#else
36inline constexpr bool K_HAS_CAN1 = false;
37#endif
38
39#if LIBXR_CH32_HAS_CAN2
40inline constexpr bool K_HAS_CAN2 = true;
41#else
42inline constexpr bool K_HAS_CAN2 = false;
43#endif
44
45inline constexpr bool K_SINGLE_CAN1 = K_HAS_CAN1 && !K_HAS_CAN2;
46// CAN1 在双 CAN 器件上仍使用 USB 命名的共享中断向量。
47// CAN1 uses the USB-named IRQ vectors even on dual-CAN devices.
48inline constexpr bool K_USB_CAN_IRQ_SHARE = K_HAS_USB_DEV_FS && K_HAS_CAN1;
49// 单 CAN、双 CAN 器件上的 FSDEV 都与 CAN 共享 PMA。
50// FSDEV shares PMA with CAN on both single- and dual-CAN devices.
51inline constexpr bool K_USB_CAN_SHARE = K_HAS_USB_DEV_FS && K_HAS_CAN1;
52
53inline constexpr bool usb_can_irq_share_enabled() { return K_USB_CAN_IRQ_SHARE; }
54inline constexpr bool usb_can_share_enabled() { return K_USB_CAN_SHARE; }
55
56inline uint16_t usb_pma_limit_bytes()
57{
58 if constexpr (!K_USB_CAN_SHARE)
59 {
60 return USBD_PMA_BYTES_SOLO;
61 }
62
63 // CAN2 使用高编号过滤器组,即使应用没有创建 CAN1 对象也必须预留。
64 // CAN2 uses the upper filter banks, including when no CAN1 object was created.
65 if constexpr (K_HAS_CAN2)
66 {
67 if (can2_inited.load(std::memory_order_acquire))
68 {
69 return USBD_PMA_BYTES_WITHCAN2;
70 }
71 }
72 return can1_inited.load(std::memory_order_acquire) ? USBD_PMA_BYTES_WITHCAN
73 : USBD_PMA_BYTES_SOLO;
74}
75
76inline std::atomic<IrqFn> usb_irq_cb{nullptr};
77inline std::atomic<IrqFn> can1_rx0_cb{nullptr};
78inline std::atomic<IrqFn> can1_tx_cb{nullptr};
79
80// 非内联注册使静态库链接必须带入共享 ISR 所在的目标文件。
81// Out-of-line registration retains the shared ISR object when linking libxr.a.
82void register_usb_irq(IrqFn fn);
83void register_can1_rx0(IrqFn fn);
84void register_can1_tx(IrqFn fn);
85
86inline bool can1_active()
87{
88 if constexpr (!K_USB_CAN_IRQ_SHARE)
89 {
90 return false;
91 }
92 return (can1_rx0_cb.load(std::memory_order_acquire) != nullptr) ||
93 (can1_tx_cb.load(std::memory_order_acquire) != nullptr);
94}
95} // namespace LibXR::CH32UsbCanShared