在开发STM32时,我们经常会遇到一些需要知道系统当前中断信息的情况,比如某个中断是否被使能、是否pending、是否正在执行该中断等。如果是在调试环境,那么可以直接查看中断信息,KEIL中的操作方法如下。所有中断的Enable状态、Pending状态(已经发生但是还没有执行到中断)、Active状态(正在执行中断)、中断优先级等信息都一目了然。
如果想在非调试环境下获取中断信息,那么可以通过NVIC和SCB两个寄存器来查看。官方提供的库中有对这两个寄存器做简单的描述。
typedef struct
{
__IO uint32_t ISER[1]; /* Interrupt Set Enable Register */
uint32_t RESERVED0[31];
__IO uint32_t ICER[1]; /* Interrupt Clear Enable Register */
uint32_t RSERVED1[31];
__IO uint32_t ISPR[1]; /* Interrupt Set Pending Register */
uint32_t RESERVED2[31];
__IO uint32_t ICPR[1]; /* Interrupt Clear Pending Register */
uint32_t RESERVED3[31];
uint32_t RESERVED4[64];
__IO uint32_t IP[8]; /* Interrupt Priority Register */
} NVIC_Type;
typedef struct
{
__I uint32_t CPUID; /* CPUID Base Register */
__IO uint32_t ICSR; /* Interrupt Control and State Register */
#if (__VTOR_PRESENT == 1)
__IO uint32_t VTOR; /* Vector Table Offset Register */
#else
uint32_t RESERVED0;
#endif
__IO uint32_t AIRCR; /* Application Interrupt and Reset Control Register */
__IO uint32_t SCR; /* System Control Register */
__IO uint32_t CCR; /* Configuration Control Register */
uint32_t RESERVED1;
__IO uint32_t SHP[2]; /* System Handlers Priority Registers. [0] is RESERVED */
__IO uint32_t SHCSR; /* System Handler Control and State Register */
} SCB_Type;
这两个寄存器在具体的芯片参考手册上基本没有提到,因为这是内核寄存器,应该查阅的是CortexM系列权威指南,例如Cortex M3与M4权威指南。以下是权威指南里对SCB的所有寄存器的汇总信息。实际上要以手册为准,官方的库提供的并不是很准确,例如库里描述的NVIC没有IABR寄存器,实际上是有的。
从表里我们可以知道,跟中断相关的是SCB->ICSR寄存器,事实上从图1里我们也可以知道KEIL仿真时查看到中Enable、Pending等信息也是根据这个寄存器来的。以下是SCB->ICSR的详细信息。
从图3可以得知,ICSR寄存器的bit 26表示systick中断是否pending,写bit 25可以清除systick中断pending,bit 22表示是否有片内外设中断在pending等。下图是我截取的某一时刻的KEIL中的NVIC信息和SCB->ICSR寄存器,可以看到两边的ICSR的值是一样的,此时systick中断了已经pending了,ICSR的bit26 也是置1的,和手册上描述的相符。
通过查看SCB->SHCSR寄存器可以知道内核的一些中断是否处于active状态,例如bit 11代表了systick中断是否active。
片内外设的中断信息需要看权威手册的NVIC寄存器,例如NVIC的ISER、ISPR、ICPR、IABR等寄存器,这里就不再赘述了,好在官方也帮我们封装了一部分。官方没有封装获取中断active状态的函数,我们可以自行封装,读取IABR寄存器就可以了。
/* 使能某一中断 */
__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
{
NVIC->ISER[0] = (1 << ((uint32_t)(IRQn) & 0x1F));
}
/* 失能某一中断 */
__STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn)
{
NVIC->ICER[0] = (1 << ((uint32_t)(IRQn) & 0x1F));
}
/* 获取某一中断的pending状态 */
__STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn)
{
return((uint32_t) ((NVIC->ISPR[0] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
}
/* 设置某一中断的pending状态 */
__STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn)
{
NVIC->ISPR[0] = (1 << ((uint32_t)(IRQn) & 0x1F));
}
/* 清除某一中断的pending状态 */
__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)
{
NVIC->ICPR[0] = (1 << ((uint32_t)(IRQn) & 0x1F));
}