@
目录
- 0、思考与回答
- 1、关中断
- 2、开中断
- 3、临界段
- 4、应用
0、思考与回答
0.1、思考一
为什么需要临界段?
有时候我们需要部分代码一旦这开始执行,则不允许任何中断打断,这段代码称为临界段
0.2、思考二
如何实现临界段?
0.3、思考三
对于 Cotex-M4 内核的处理器如何方便的控制其中断开关?
使用 BASEPRI 寄存器,当该寄存器中的值不为 0 时,处理器将不会处理优先级值大于或等于 BASEPRI 的任何异常,该寄存器相关信息可以在 Cortex-M4 Devices Generic User Guide 手册中找到,具体如下图所示
值得注意的是 STM32 的 BASEPRI 寄存器做了一些修改,只使用了其高 4 位,低 4 位的数据没有使用,所以对于 STM32 在使用 BASEPRI 寄存器对中断进行屏蔽时,需要考虑到写入的高 4 位数据才是正确的数据,感兴趣的可以阅读 为何修改BASEPRI寄存器无效? 这篇文章
1、关中断
1.1、带返回值
Keil 版本- /* portMacro.h */
- #define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()
- // 带返回值关中断,将当前中断状态作为返回值返回
- static __inline uint32_t ulPortRaiseBASEPRI(void)
- {
- uint32_t ulReturn,ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
- __asm
- {
- mrs ulReturn,basepri // 保存中断时 BASEPRI 寄存器的值
- msr basepri,ulNewBASEPRI // 屏蔽 优先级值 大于等于 11 的中断
- dsb
- isb
- }
- return ulReturn;
- }
复制代码 CLion 版本- static __inline uint32_t ulPortRaiseBASEPRI(void)
- {
- uint32_t ulReturn,ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
- __asm volatile
- (
- "mrs ulReturn,basepri \n"
- "msr basepri,ulNewBASEPRI \n"
- "dsb \n"
- "isb \n"
- );
- return ulReturn;
- }
复制代码 1.2、不带返回值
Keil 版本- /* portMacro.h */
- #define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()
- // 不带返回值关中断
- static __inline void vPortRaiseBASEPRI(void)
- {
- uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
- __asm
- {
- msr basepri,ulNewBASEPRI
- dsb
- isb
- }
- }
复制代码 CLion 版本- static __inline void vPortRaiseBASEPRI(void)
- {
- uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
- __asm volatile
- (
- "msr basepri, %0 \n"
- "isb \n"
- :
- : "r" (ulNewBASEPRI)
- : "memory"
- );
- }
复制代码 2、开中断
Keil 版本- /* portMacro.h */
- // 设置 BASEPRI 为 0 开所有中断
- #define portENABLE_INTERRUPTS() vPortSetBASEPRI(0)
- // 设置 BASEPRI 为进入中断时的值则恢复原来的中断状态
- #define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x)
- // 开中断
- static __inline void vPortSetBASEPRI(uint32_t ulBASEPRI)
- {
- __asm volatile
- {
- msr basepri,ulBASEPRI
- }
- }
复制代码 CLion 版本- static __inline void vPortSetBASEPRI(uint32_t ulBASEPRI)
- {
- __asm volatile
- (
- "msr basepri, %0 \n"
- : "r" (ulBASEPRI)
- : "memory"
- );
- }
复制代码 3、临界段
- /* task.h */
- #define taskENTER_CRITICAL() portENTER_CRITICAL()
- #define taskEXIT_CRITICAL() portEXIT_CRITICAL()
- #define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()
- #define taskEXIT_CRITICAL_FROM_ISR(x) portCLEAR_INTERRUPT_MASK_FROM_ISR(x)
复制代码- /* portMacro.h */
- extern void vPortEnterCritical(void);
- extern void vPortExitCritical(void);
- #define portENTER_CRITICAL() vPortEnterCritical()
- #define portEXIT_CRITICAL() vPortExitCritical()
复制代码- /* port.c */
- // 中断嵌套计数器
- static UBaseType_t uxCriticalNesting = 0xAAAAAAAA;
- // 进入临界区
- void vPortEnterCritical(void)
- {
- portDISABLE_INTERRUPTS();
- uxCriticalNesting++;
- if(uxCriticalNesting==1)
- {
- // configASSERT((portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK) == 0);
- }
- }
- // 退出临界区
- void vPortExitCritical(void)
- {
- // configASSERT(uxCriticalNesting);
- uxCriticalNesting--;
- if(uxCriticalNesting == 0)
- {
- portENABLE_INTERRUPTS();
- }
- }
复制代码 4、应用
普通场合- // 进入临界区直接屏蔽优先级号大于 11 的中断
- taskENTER_CRITICAL();
- // 退出时直接设置 BASEPRI 寄存器的值为 0
- taskEXIT_CRITICAL();
复制代码 中断场合- uint32_t ulReturn;
- // 进入临界区前保存 BASEPRI 寄存器的值
- ulReturn = taskENTER_CRITICAL_FROM_ISR();
- // 退出临界区时恢复 BASEPRI 寄存器的值
- taskEXIT_CRITICAL_FROM_ISR(ulReturn);
复制代码 来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |