ARM Cortex-M4技术问询:PRIMASK置1时SysTick中断变化及自旋锁信号量中SysTick机制
兄弟,先把PRIMASK的底给你抖出来——这货是Cortex-M4内核里管全局中断屏蔽的关键寄存器。当它被置为1的时候,除了NMI(不可屏蔽中断)和HardFault这种连系统都没法忽略的顶级故障中断,所有优先级≥0的可屏蔽中断都会被暂时“压下去”。
而SysTick属于典型的可屏蔽中断,优先级是可以配置的(默认一般是最低优先级)。所以当PRIMASK=1时:
- SysTick的中断请求会被内核挂起来,哪怕它的计数已经到了、触发条件满足,也没法触发对应的中断服务程序(ISR)。
- 只有等到PRIMASK被重新清0(比如执行
CPSIE I指令),内核才会去检查挂起的SysTick中断请求,如果此时请求还在,就会立刻响应它。
咱先对着你给的代码一点点拆解,你就明白SysTick在这儿的作用了:
首先看OS_Wait的逻辑:这是一个自旋锁版本的信号量获取函数,当信号量*s为0时,任务会进入循环“自旋等待”,直到信号量被其他任务释放。
void OS_Wait(int32_t *s){ while( (*s) == 0 ) { EnableInterrupts(); //SysTick是否会等待到这一行? Disableinterrupts(); } (*s) = (*s) - 1; EnableInterrupts(); }
对应的汇编子程序:
EnableInterrupts CPSIE I ; 这条指令是清PRIMASK寄存器,打开全局可屏蔽中断 BX LR
先回答你心里的疑问:SysTick会不会等到EnableInterrupts()这一行?
答案是:会,但得看时机。
当任务进入while循环后,先执行EnableInterrupts()——这行代码会执行CPSIE I,把PRIMASK清0,此时全局可屏蔽中断(包括SysTick)被完全打开。
这时候,如果SysTick的定时周期刚好到了(比如RTOS配置的系统节拍到了),内核就会立刻触发SysTick中断,跳转到SysTick的中断服务程序(RTOS里这个ISR一般是核心调度器的入口,负责上下文切换:把当前这个自旋等待的任务挂起,切换到就绪队列里的其他任务去执行)。
等其他任务执行完、调度器切回当前任务时,会从EnableInterrupts()之后的指令继续执行,也就是Disableinterrupts()——这行又会把PRIMASK置1,重新屏蔽全局中断,然后回到while循环的开头,再次检查信号量*s是否不为0。
为什么要这么设计?
如果自旋等待时一直关中断,那SysTick永远没法触发,RTOS调度器就没法工作,系统会卡死在这个循环里。而每次循环短暂打开一次中断,就是给SysTick一个“触发窗口”,让调度器有机会切换到其他任务——说不定其他任务会释放这个信号量,等切回来的时候,*s就不为0了,当前任务就能跳出循环,继续执行。
说白了,这个自旋锁的实现是在“自旋等待”和“系统调度”之间找了个平衡:既通过自旋避免了任务切换的开销(适合短时间等待),又给SysTick留了口子,保证系统不会因为自旋而彻底卡死。
内容的提问来源于stack exchange,提问作者Fua

