找回密码
 立即注册
首页 业界区 安全 FreeRTOS简单内核实现4 临界段

FreeRTOS简单内核实现4 临界段

遇玷 2025-6-8 13:21:04
@
目录

  • 0、思考与回答

    • 0.1、思考一
    • 0.2、思考二
    • 0.3、思考三

  • 1、关中断

    • 1.1、带返回值
    • 1.2、不带返回值

  • 2、开中断
  • 3、临界段
  • 4、应用

0、思考与回答

0.1、思考一

为什么需要临界段?
有时候我们需要部分代码一旦这开始执行,则不允许任何中断打断,这段代码称为临界段
0.2、思考二

如何实现临界段?

  • 关中断
  • 执行临界区代码
  • 开中断
0.3、思考三

对于 Cotex-M4 内核的处理器如何方便的控制其中断开关?
使用 BASEPRI 寄存器,当该寄存器中的值不为 0 时,处理器将不会处理优先级值大于或等于 BASEPRI 的任何异常,该寄存器相关信息可以在 Cortex-M4 Devices Generic User Guide 手册中找到,具体如下图所示
1.png

值得注意的是 STM32 的 BASEPRI 寄存器做了一些修改,只使用了其高 4 位,低 4 位的数据没有使用,所以对于 STM32 在使用 BASEPRI 寄存器对中断进行屏蔽时,需要考虑到写入的高 4 位数据才是正确的数据,感兴趣的可以阅读 为何修改BASEPRI寄存器无效? 这篇文章
1、关中断

1.1、带返回值

Keil 版本
  1. /* portMacro.h */
  2. #define portSET_INTERRUPT_MASK_FROM_ISR()       ulPortRaiseBASEPRI()
  3. // 带返回值关中断,将当前中断状态作为返回值返回
  4. static __inline uint32_t ulPortRaiseBASEPRI(void)
  5. {
  6.         uint32_t ulReturn,ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
  7.         __asm
  8.         {
  9.                 mrs ulReturn,basepri        // 保存中断时 BASEPRI 寄存器的值
  10.                 msr basepri,ulNewBASEPRI    // 屏蔽 优先级值 大于等于 11 的中断
  11.                 dsb
  12.                 isb
  13.         }
  14.         return ulReturn;
  15. }
复制代码
CLion 版本
  1. static __inline uint32_t ulPortRaiseBASEPRI(void)  
  2. {  
  3.     uint32_t ulReturn,ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;  
  4.     __asm volatile  
  5.     (  
  6.         "mrs ulReturn,basepri        \n"  
  7.         "msr basepri,ulNewBASEPRI    \n"  
  8.         "dsb                         \n"  
  9.         "isb                         \n"  
  10.     );  
  11.     return ulReturn;  
  12. }
复制代码
1.2、不带返回值

Keil 版本
  1. /* portMacro.h */
  2. #define portDISABLE_INTERRUPTS()                vPortRaiseBASEPRI()
  3. // 不带返回值关中断
  4. static __inline void vPortRaiseBASEPRI(void)
  5. {
  6.         uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
  7.         __asm
  8.         {
  9.                 msr basepri,ulNewBASEPRI
  10.                 dsb
  11.                 isb
  12.         }
  13. }
复制代码
CLion 版本
  1. static __inline void vPortRaiseBASEPRI(void)  
  2. {  
  3.     uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;  
  4.     __asm volatile  
  5.     (  
  6.         "msr basepri, %0    \n"
  7.         "isb                \n"
  8.         :
  9.         : "r" (ulNewBASEPRI)
  10.         : "memory"
  11.     );  
  12. }
复制代码
2、开中断

Keil 版本
  1. /* portMacro.h */
  2. // 设置 BASEPRI 为 0 开所有中断
  3. #define portENABLE_INTERRUPTS()                 vPortSetBASEPRI(0)
  4. // 设置 BASEPRI 为进入中断时的值则恢复原来的中断状态
  5. #define portCLEAR_INTERRUPT_MASK_FROM_ISR(x)    vPortSetBASEPRI(x)
  6. // 开中断
  7. static __inline void vPortSetBASEPRI(uint32_t ulBASEPRI)
  8. {
  9.         __asm volatile
  10.         {
  11.                 msr basepri,ulBASEPRI      
  12.         }
  13. }
复制代码
CLion 版本
  1. static __inline void vPortSetBASEPRI(uint32_t ulBASEPRI)  
  2. {
  3.     __asm volatile  
  4.     (
  5.         "msr basepri, %0    \n"
  6.         : "r" (ulBASEPRI)
  7.         : "memory"
  8.     );
  9. }
复制代码
3、临界段
  1. /* task.h */
  2. #define taskENTER_CRITICAL()           portENTER_CRITICAL()
  3. #define taskEXIT_CRITICAL()            portEXIT_CRITICAL()
  4. #define taskENTER_CRITICAL_FROM_ISR()  portSET_INTERRUPT_MASK_FROM_ISR()
  5. #define taskEXIT_CRITICAL_FROM_ISR(x)  portCLEAR_INTERRUPT_MASK_FROM_ISR(x)
复制代码
  1. /* portMacro.h */
  2. extern void vPortEnterCritical(void);
  3. extern void vPortExitCritical(void);
  4. #define portENTER_CRITICAL()         vPortEnterCritical()
  5. #define portEXIT_CRITICAL()          vPortExitCritical()
复制代码
  1. /* port.c */
  2. // 中断嵌套计数器
  3. static UBaseType_t uxCriticalNesting = 0xAAAAAAAA;
  4. // 进入临界区
  5. void vPortEnterCritical(void)
  6. {
  7.         portDISABLE_INTERRUPTS();
  8.         uxCriticalNesting++;
  9.         if(uxCriticalNesting==1)
  10.         {
  11.                 // configASSERT((portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK) == 0);
  12.         }
  13. }
  14. // 退出临界区
  15. void vPortExitCritical(void)
  16. {
  17.         // configASSERT(uxCriticalNesting);
  18.         uxCriticalNesting--;
  19.         if(uxCriticalNesting == 0)
  20.         {
  21.                 portENABLE_INTERRUPTS();
  22.         }
  23. }
复制代码
4、应用

普通场合
  1. // 进入临界区直接屏蔽优先级号大于 11 的中断
  2. taskENTER_CRITICAL();
  3. // 退出时直接设置 BASEPRI 寄存器的值为 0
  4. taskEXIT_CRITICAL();
复制代码
中断场合
  1. uint32_t ulReturn;
  2. // 进入临界区前保存 BASEPRI 寄存器的值
  3. ulReturn = taskENTER_CRITICAL_FROM_ISR();
  4. // 退出临界区时恢复 BASEPRI 寄存器的值
  5. taskEXIT_CRITICAL_FROM_ISR(ulReturn);
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册