2026-06-26 00:57:59 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @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)
|
|
|
|
|
|
|
2026-10-11 02:47:19 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @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)
|
|
|
|
|
|
|
2026-06-26 00:57:59 +08:00
|
|
|
|
#endif /* SYS_CRITICAL_H */
|