在上一篇文章(链接:https://bbs.21ic.com/icview-3461486-1-1.html)中作者介绍了SCB功能块及其第一个关键寄存器CPUID,本文章将主要介绍SCB的第二个关键寄存器:ICSR。
ICSR,即Interrupt Control and State Register,翻译为中断控制和状态寄存器,主要用于控制和查询中断状态,比如提供中断的 pending(挂起)、active(活动)状态,以及异常管理的控制位(如手动触发 PendSV和SysTick 等)。
查看core_cm4.h文件,可以看到ICSR是由下面这些位域信息组成的:
接下来我们逐个解释,如下表所示:
字段名 | 位域 | 读写类型 | 功能描述 |
NMIPENDSET | [31] | RW | 写1,表示不可屏蔽中断(NMI)被挂起 |
PENDSVSET | [28] | RW | 写0无效,写1,表示手动挂起PendSV异常 |
PENDSVCLR | [27] | RW | 写0无效,写1,表示清除PendSV的挂起状态 |
PENDSTSET | [26] | RW | 写0无效,写1,表示手动挂起SysTick异常 |
PENDSTCLR | [25] | RW | 写0无效,写1,表示清除SysTick的挂起状态 |
ISRPREEMPT | [23] | R | 只读,表示是否有可抢占的异常正在挂起 |
ISRPENDING | [22] | R | 只读,表示是否有外部中断正在挂起 |
VECTPENDING | [21:12] | R | 只读,表示当前挂起异常的异常编号,0表示无 |
RETTOBASE | [11] | R | 表示当前是否在中断嵌套中(0表示有更高优先级异常活跃,1表示无嵌套) |
VECTACTIVE | [9:0] | R | 表示当前活跃异常的异常编号(0表示线程模式,非异常) |
我们先来看看Keil的仿真运行时ICSR寄存器的值:
运行时,值为0,如下图:
停止运行时,值为0x00C2E000,如下图:
二进制就是:0000 0000 1100 0010 1110 0000 00000000
比如bit22为1表示有外部中断正在挂起,bit23为1表示有可抢占的异常正在挂起。
那我们可以如何应用ICSR呢?
可以用来手动触发或清除PendSV:
在RTOS中,PendSV用来作为RTOS调度器的御用通道,上下文切换和任务调度都是在ISR中实现的,而ISCR寄存器中的PENDSVSET和PENDSVCLR就专为PendSV设置了两个控制位段;我们可以通过下面的代码操作来挂起PendSV或者清除PendSV的挂起状态:
SCB->ICSR |=SCB_ICSR_PENDSVSET_Msk; // 挂起PendSV
SCB->ICSR |=SCB_ICSR_PENDSVCLR_Msk; // 清除PendSV
有一点需要注意,,就是如果同时向这两个控制位写1,可能导致无法预测的行为。
可以查询当前异常状态:
通过 VECTACTIVE 或 VECTPENDING 字段判断当前运行状态。
可以调试中断状态:
通过检查 ISRPENDING 或 NMIPENDSET 位确认中断是否挂起。
可以读取中断编号:
通过读取 VECTACTIVE 可以确定当前执行的异常或中断编号。
由于ISCR寄存器包含了中断和异常等重要的状态信息,如果直接读取可能会导致不可预测的行为,因此,如果你尝试按读取CPUID寄存器的代码来操作,是不可行的:
复制
uint32_t icsr= 0;uint32_t read_icsr(void){icsr = SCB->ICSR;return icsr;}
按以上代码来读取,读取出来的结果与实际值不一样:
也就是说ICSR需要在特权模式下访问,用户模式是无法操作的;那如何访问呢?可以通过间接访问 NVIC 结构体中的 ISER 、 ICER 、 ISPR 和 ICPR 寄存器来实现。
在Keil仿真时其实也可以直接看到NVIC的寄存器值及查看中断信息:
此处也涉及了关于查看中断信息的方法,后续文章会详细阐述。
下一篇文章作者将介绍VTOR(向量表偏移寄存器)。
。
---------------------
作者:dffzh
链接:https://bbs.21ic.com/icview-3463182-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。