LPC824的中断系统非常强大,要用好中断,就必须先了解LPC824的整个中断系统。下面来讨论一下NVIC中断系统。
在LPC8xx系列处理器中,有一个部分被称为“私有外设总线”(Private peripheral bus),它位于Memory map中地址为0xE0000000~0xE0100000的地方,包含有下表中的几个核心外设。
其中的NVIC(Nested Vectored Interrupt Contorller)就是中断系统,被称为“内嵌套向量中断控制器”。它与处理器内核紧密耦合,可实现低中断延迟及对新中断的有效处理。
它具有以下特征:
拥有32路向量中断;每个中断的优先级均可编程设置为0~192(步长64),数值越小优先级越高,0级为最高优先级;支持电平和边沿触发中断;支持中断尾链;拥有一个外部不可屏蔽中断NMI。
NVIC所涉及到的寄存器如下表所示。
从表中可以看出,每个寄存器都是32位的结构,都具有可读可写的属性,复位值都为全0。其中ISER0寄存器是设置中断的使能,32位对应32路中断,值为1使能中断,值为0不使能中断。ICER0寄存器是设置中断的禁能,32位对应32路中断,值为1禁能中断,值为0不禁能。ISPR0寄存器是设置中断的挂起,32位对应32路中断,值为1挂起,值为0不挂起。ICPR0寄存器是清除中断的挂起,32位对应32路中断,值为1清除挂起,值为0不清除挂起。IPR0~7寄存器是设置中断优先级。
下面是NVIC寄存器组所对应的结构体形式(位于头文件core_cm0plus.h中)。
typedef struct
{
__IOM uint32_t ISER[1U];
uint32_t RESERVED0[31U];
__IOM uint32_t ICER[1U];
uint32_t RSERVED1[31U];
__IOM uint32_t ISPR[1U];
uint32_t RESERVED2[31U];
__IOM uint32_t ICPR[1U];
uint32_t RESERVED3[31U];
uint32_t RESERVED4[64U];
__IOM uint32_t IP[8U];
} NVIC_Type;
因NVIC寄存器组的基址为0xE000E100,所以要将基址指针强制转换为上述结构体,还必须要加上下面的定义。
#define SCS_BASE (0xE000E000UL)
#define NVIC_BASE (SCS_BASE + 0x0100UL)
#define NVIC ((NVIC_Type *) NVIC_BASE )
接下来给出的是上面NVIC32位寄存器所对应的32路中断向量的中断源。
为了能描述上面的32路中断源,在C语言中运用了枚举类型,代码如下所示(位于头文件lpc82x.h中)。
typedef enum {
/*---Cortex-M0PLUS Processor Exceptions Numbers---*/
Reset_IRQn = -15,
NonMaskableInt_IRQn = -14,
HardFault_IRQn = -13,
SVCall_IRQn = -5,
DebugMonitor_IRQn = -4,
PendSV_IRQn = -2,
SysTick_IRQn = -1,
/*---LPC82x Specific Interrupt Numbers---*/
SPI0_IRQn = 0,
SPI1_IRQn = 1,
UART0_IRQn = 3,
UART1_IRQn = 4,
UART2_IRQn = 5,
I2C1_IRQn = 7,
I2C0_IRQn = 8,
SCT_IRQn = 9,
MRT_IRQn = 10,
CMP_IRQn = 11,
WDT_IRQn = 12,
BOD_IRQn = 13,
FLASH_IRQn = 14,
WKT_IRQn = 15,
ADC_SEQA_IRQn = 16,
ADC_SEQB_IRQn = 17,
ADC_THCMP_IRQn = 18,
ADC_OVR_IRQn = 19,
DMA_IRQn = 20,
I2C2_IRQn = 21,
I2C3_IRQn = 22,
PIN_INT0_IRQn = 24,
PIN_INT1_IRQn = 25,
PIN_INT2_IRQn = 26,
PIN_INT3_IRQn = 27,
PIN_INT4_IRQn = 28,
PIN_INT5_IRQn = 29,
PIN_INT6_IRQn = 30,
PIN_INT7_IRQn = 31
} IRQn_Type;
从上述代码中可以看出,除了32路中断源外,还加入了编号为负数的、优先级更高的7个中断源。这里先不进行说明,在后面用到时再来讨论。定义好上述代码后,就可以来写中断所需要的函数了。下面就是依据CMSIS规范所定义的13个中断操作函数(位于头文件core_cm0plus.h中)。
1.允许某个中断
__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn)
{
if ((int32_t)(IRQn) >= 0)
{
NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));
}
}
2.读取某个中断的使能状态
__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn)
{
if ((int32_t)(IRQn) >= 0)
{
return((uint32_t)(((NVIC->ISER[0U] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL));
}
else
{
return(0U);
}
}
3.禁止某个中断
__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn)
{
if ((int32_t)(IRQn) >= 0)
{
NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));
__DSB();
__ISB();
}
}
4.读取某个中断的挂起状态
__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn)
{
if ((int32_t)(IRQn) >= 0)
{
return((uint32_t)(((NVIC->ISPR[0U] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL));
}
else
{
return(0U);
}
}
5.把某个中断的挂起状态设为1
__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn)
{
if ((int32_t)(IRQn) >= 0)
{
NVIC->ISPR[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));
}
}
6.把某个中断的挂起状态清为0
__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn)
{
if ((int32_t)(IRQn) >= 0)
{
NVIC->ICPR[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));
}
}
7.把某个中断的可配置优先级设为1
__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
if ((int32_t)(IRQn) >= 0)
{
NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
(((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn)));
}
else
{
SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
(((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn)));
}
}
8.读取某个中断的优先级
__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn)
{
if ((int32_t)(IRQn) >= 0)
{
return((uint32_t)(((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS)));
}
else
{
return((uint32_t)(((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS)));
}
}
9.编码优先级
__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority)
{
uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL);
uint32_t PreemptPriorityBits;
uint32_t SubPriorityBits;
PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp);
SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS));
return (
((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) |
((SubPriority & (uint32_t)((1UL << (SubPriorityBits )) - 1UL)))
);
}
10.解码优先级
__STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority)
{
uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL);
uint32_t PreemptPriorityBits;
uint32_t SubPriorityBits;
PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp);
SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS));
*pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL);
*pSubPriority = (Priority ) & (uint32_t)((1UL << (SubPriorityBits )) - 1UL);
}
11.设置中断向量
__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector)
{
#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U)
uint32_t *vectors = (uint32_t *)SCB->VTOR;
#else
uint32_t *vectors = (uint32_t *)0x0U;
#endif
vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET] = vector;
}
12.读取中断向量
__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn)
{
#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U)
uint32_t *vectors = (uint32_t *)SCB->VTOR;
#else
uint32_t *vectors = (uint32_t *)0x0U;
#endif
return vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET];
}
13.复位NVIC
__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void)
{
__DSB();
SCB->AIRCR = ((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | SCB_AIRCR_SYSRESETREQ_Msk);
__DSB();
for(;;)
{
__NOP();
}
}
相关文章