You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ARM Cortex-M4技术问询:PRIMASK置1时SysTick中断变化及自旋锁信号量中SysTick机制

问题1:PRIMASK寄存器被置为1时,ARM Cortex-M4的SysTick中断请求会发生什么变化?

兄弟,先把PRIMASK的底给你抖出来——这货是Cortex-M4内核里管全局中断屏蔽的关键寄存器。当它被置为1的时候,除了NMI(不可屏蔽中断)和HardFault这种连系统都没法忽略的顶级故障中断,所有优先级≥0的可屏蔽中断都会被暂时“压下去”。

而SysTick属于典型的可屏蔽中断,优先级是可以配置的(默认一般是最低优先级)。所以当PRIMASK=1时:

  • SysTick的中断请求会被内核挂起来,哪怕它的计数已经到了、触发条件满足,也没法触发对应的中断服务程序(ISR)。
  • 只有等到PRIMASK被重新清0(比如执行CPSIE I指令),内核才会去检查挂起的SysTick中断请求,如果此时请求还在,就会立刻响应它。
问题2:自旋锁信号量中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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:13:11