FreeRTOS简单内核实现4 临界段

cnblogs 2024-06-16 14:15:00 阅读 74

本文内容较为简单,主要介绍如何实现临界段以及临界段如何使用

@

目录

  • 0、思考与回答
    • 0.1、思考一
    • 0.2、思考二
    • 0.3、思考三
  • 1、关中断
    • 1.1、带返回值
    • 1.2、不带返回值
  • 2、开中断
  • 3、临界段
  • 4、应用

0、思考与回答

0.1、思考一

为什么需要临界段?

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

0.2、思考二

如何实现临界段?

  1. 关中断
  2. 执行临界区代码
  3. 开中断

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);



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。