/** * @file critical.h * @brief 实时临界区基础设施:基于 BASEPRI 寄存器的中断屏蔽。 * @note EtherCAT 实时架构改造专用。GD32E508 为 Cortex-M4F,支持 BASEPRI 寄存器。 * * @details 设计说明: * - BASEPRI 阈值屏蔽抢占优先级 >= 1 的中断,仅保留 preempt=0(EtherCAT SYNC0 * 周期中断)可立即响应,保证 EtherCAT 周期抖动 <1us。 * - 取代原 PRIMASK 方案(`__disable_irq` / `__set_PRIMASK`),后者会屏蔽全部中断 * (含 preempt=0),无法满足 EtherCAT 实时性要求。 * - NVIC 优先级分组为 `NVIC_PRIGROUP_PRE4_SUB0`(4 位抢占 + 0 位子优先级), * 因此 `__NVIC_PRIO_BITS = 4`,阈值 `(1U << (8U - 4U)) = 0x10`,即屏蔽优先级 * 数值 0x1x 及以上(对应 preempt 1..15),保留 preempt=0(优先级 0x0x)。 * - 阈值定义依赖 `__NVIC_PRIO_BITS`,该宏由 CMSIS 设备头文件提供(GD32E508 = 4)。 * - 项目使用 AC6(armclang) gnu++17,支持 GCC 语句表达式(statement expression), * `RT_CRITICAL_SAVE()` 利用该特性返回保存的 BASEPRI 值,便于嵌套恢复。 */ #ifndef SYS_CRITICAL_H #define SYS_CRITICAL_H #include "RTE_Components.h" #include CMSIS_device_header /** @brief BASEPRI 屏蔽阈值:屏蔽 preempt>=1,保留 preempt=0(EtherCAT SYNC0)。 * 对于 4 位抢占优先级(__NVIC_PRIO_BITS=4),该值为 0x10。 */ #define RT_CRITICAL_BASEPRI_VALUE (1U << (8U - __NVIC_PRIO_BITS)) /** * @brief 进入临界区:屏蔽抢占优先级 >= 1 的中断。 * @note preempt=0 的 EtherCAT SYNC0 周期中断仍可立即抢占执行。 */ #define RT_CRITICAL_ENTER() __set_BASEPRI(RT_CRITICAL_BASEPRI_VALUE) /** * @brief 退出临界区:恢复全部中断响应(BASEPRI 清零)。 */ #define RT_CRITICAL_EXIT() __set_BASEPRI(0U) /** * @brief 保存当前 BASEPRI 并进入临界区,返回进入前的 BASEPRI 值。 * @return 进入临界区前的 BASEPRI 寄存器值(供 RT_CRITICAL_RESTORE 恢复)。 * @note 利用 GCC 语句表达式返回值,用于嵌套临界区场景: * @code * uint32_t save = RT_CRITICAL_SAVE(); * // ... 临界区代码 ... * RT_CRITICAL_RESTORE(save); * @endcode */ #define RT_CRITICAL_SAVE() \ ({ \ uint32_t __basepri_save = __get_BASEPRI(); \ __set_BASEPRI(RT_CRITICAL_BASEPRI_VALUE); \ __basepri_save; \ }) /** * @brief 恢复 BASEPRI 到指定值(用于 RT_CRITICAL_SAVE() 配套的嵌套恢复)。 * @param[in] val RT_CRITICAL_SAVE() 返回的 BASEPRI 值。 */ #define RT_CRITICAL_RESTORE(val) __set_BASEPRI(val) /** * @brief Preempt-0 专用临界区:PRIMASK 全局屏蔽,用于与 preempt=0 中断共享的 * 单字标志(读-改-写)。 * @note 严格限定 O(1) 状态操作(置位/清位/单字赋值)。**严禁**在其中调用 * printf/LOG_*:串口入队实测 36us,TX FIFO 满时可达 123us,会把 EtherCAT * SYNC0 抖动顶出 DC 容差。日志一律放临界区外。 */ #define RT_CRITICAL_PREEMPT0_SAVE() \ ({ \ uint32_t __primask_save = __get_PRIMASK(); \ __disable_irq(); \ __primask_save; \ }) #define RT_CRITICAL_PREEMPT0_RESTORE(val) __set_PRIMASK(val) #endif /* SYS_CRITICAL_H */