COTEX-M内核中断控制
Cotex-M3 和 M4的 NVIC 最多支持 240个 IRQ(中断请求)、1一个不可屏蔽中断(NMI)、1个Systick(滴答定时器)中断和多个系统异常
ST使用16个优先级
STM32关于中断的寄存器在NVIC 和 SCB中
typedef struct
{
__IOM uint32_t ISER[8U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */
//以上为8个32位寄存器,为240个中断的使能
uint32_t RESERVED0[24U];
__IOM uint32_t ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */
//以上为中断0-31的除能寄存器
uint32_t RSERVED1[24U];
__IOM uint32_t ISPR[8U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */
//以上为中断0-31的悬起寄存器
uint32_t RESERVED2[24U];
__IOM uint32_t ICPR[8U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */
//以上为中断0-31的解悬寄存器
uint32_t RESERVED3[24U];
__IOM uint32_t IABR[8U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */
//中断活动寄存器
uint32_t RESERVED4[56U];
__IOM uint8_t IP[240U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */
//每个外部中断的优先级分组设置寄存器,每个寄存器占用8位,4个相邻的优先级寄存器拼成一个32位寄存器
uint32_t RESERVED5[644U];
__OM uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */
//以上为软件触发中断寄存器
} NVIC_Type;
编号 0,1, 2,3不可更改
STM32只是用高四位表达优先级级数,所以最多16级分组
7对应着STM32的组0
如何设置为哪个优先级分组
上图地址不一定正确
STM32通过这一个寄存器设置中断优先级分组,使用3位控制5个分组
注: FREERTOS中着重设置 PendSV 和 SysTick的优先级
如何设置?
在port.c中,代码如下:
/***************************************************************************************************************/
/* FreeRTOS与中断有关的配置选项 */
/***************************************************************************************************************/
#ifdef __NVIC_PRIO_BITS
#define configPRIO_BITS __NVIC_PRIO_BITS
#else
#define configPRIO_BITS 4
#endif
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 //中断最低优先级
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 //系统可管理的最高中断优先级
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )
#define portNVIC_SYSTICK_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )
#define portNVIC_SYSPRI2_REG ( * ( ( volatile uint32_t * ) 0xe000ed20 ) )
//portNVIC_SYSPRI2_REG的地址对应上图的系统异常优先级 0xE000_ED20(四个八位合成一个32位的寄存器)
//at BaseType_t xPortStartScheduler()
/* Make PendSV and SysTick the lowest priority interrupts. */
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
中断屏蔽寄存器
进入临界段代码保护时,屏蔽其他中断
-
PRIMASK寄存器:用于除能NMI和硬FAULT之外的所有异常
使能://关闭所有中断(但是不包括fault和NMI中断)
__asm void INTX_DISABLE(void)
{
CPSID I
BX LR
}
除能://开启所有中断
__asm void INTX_ENABLE(void)
{
CPSIE I
BX LR
} -
FAULTMASK寄存器:
屏蔽比-1级数更低的中断优先级(硬FAULT也被屏蔽),使用方法和上面的PRIMASK一样,对应的寄存器设1(使能)或者设0(除能) -
BASEPRI寄存器:
屏蔽比优先级没它高的中断(中断0~15,数字越大,优先级越低,0最先,15最后)
比如寄存器的值是 0x30(STM32只是用高四位),所以0~2优先级的不被屏蔽, 3~15级的将被屏蔽,使能和除能的代码如下:
使能:
static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )
{
__asm
{
/* Barrier instructions are not used as this function is only used to
lower the BASEPRI value. */
msr basepri, ulBASEPRI
}
}
除能:
static portFORCE_INLINE void vPortClearBASEPRIFromISR( void )
{
__asm
{
/* Set BASEPRI to 0 so no interrupts are masked. This function is only
used to lower the mask in an interrupt, so memory barriers are not
used. */
msr basepri, #0
}
}
FREERTOS中不能使用0~ 4优先级的中断,只能使用5~15的中断(带ISR的函数可以使用这些优先级)