STM32L4中断系统
STM32L4基于Cortex-M4架构,内部有一个嵌套中断向量控制器(NVIC)来管理异常,并将优先级最高的异常提交给CPU处理。异常的编号范围是1~255,其中编号1~15被归为系统异常(如NMI、SYSTICK等),编号16~255被归为外部异常(也称外部中断,如UART、EXTI等),各个异常源与NVIC和Core的关系如下图,
对于STM32L4系列MCU,除了16个系统异常外,还支持82个中断源,这些中断源的优先级支持16级。
NVIC对异常的管理通过一系列的寄存器进行,如外部中断控制的NVIC寄存器、系统异常控制的SCB寄存器、全局控制的特殊功能寄存器。
1.1、外部中断控制的NVIC寄存器
NVIC寄存器用于控制外部中断IRQ的行为,如中断设置使能、中断清除使能、中断设置挂起、中断清除挂起、中断优先级设置、软件触发中断等。
- 中断使能配置寄存器的操作函数:
void __NVIC_EnableIRQ(IRQn_Type IRQn) //使能中断,IRQn为中断编号,如USART3_IRQN;
void __NVIC_DisableIRQ(IRQn_Type IRQn) //禁止中断,IRQn为中断编号
uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn)//获取中断使能状态,返回1:使能,0:禁止
- 中断挂起寄存器的操作函数:
void __NVIC_SetPendingIRQ(IRQn_Type IRQn) //设置挂起位,IRQn为中断编号
void __NVIC_ClearPendingIRQ(IRQn_Type IRQn)//清除挂起位,IRQn为中断编号
uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) //获取挂起位状态,返回1:挂起,0:未挂起
- 活跃状态寄存器的操作函数:
uint32_t __NVIC_GetActive(IRQn_Type IRQn) //获取活跃位状态,返回1:活跃,0:未活跃
当某个活跃位置1时,表示MCU当前正在处理该中断的服务程序,执行完成后,该活跃位自动被清零;
当低优先级的中断服务程序正在执行时,高优先级中断挂起,则MCU打断低优先级中断,执行高优先级的中断服务程序,此时,低优先级与高优先级的活跃位均置1。
- 优先级配置寄存器
void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
//设置中断优先级,IRQn为中断编号,priority为优先级,STM32L4支持16级,即priority取值为0~15;
uint32_t __NVIC_GetPriority(IRQn_Type IRQn) //获取中断优先级,IRQn为中断编号
- 软件中断设置寄存器
NVIC->STIR = IRQn // IRQn为中断编号
软件中断设置与中断挂起设置寄存器使用的效果一致,都能触发一次软件中断。
1.2、系统异常控制的SCB寄存器
SCB寄存器用于配置系统异常,包含系统异常使能、异常挂起设置与清除、优先级、活跃状态查询等;同时还有错误源状态与系统调试相关的寄存器。
在SCB模块中,与系统异常设置有关的主要是SCB->ICSR、SCB->AIRCR、SCB->SHP[X]、SCB->SHCSR寄存器,相关的异常有NMI、FAULT、SVC、PendSV、SysTick等,对应的使能与挂起位配置如下表所示:
- NMI挂起位设置
SCB->ICSR |= (1 << 31); 或 (*((volatile uint32_t *)0xe000ed04)) |= (1 << 31);
- Memmanage错误
//使能Memmanage异常中断,默认关闭
SCB->SHCSR |= 1 << 16;或(*((volatile uint32_t *)0xe000ed24)) |= (1 << 16);
//设置优先级,IRQn = -12;
__NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
或(*((volatile uint32_t *)0xe000ed18)) = priority;
- 总线错误
//使能总线异常中断,默认关闭
SCB->SHCSR |= 1 << 17; 或(*((volatile uint32_t *)0xe000ed24)) |= (1 << 17);
//设置优先级,IRQn = -11;
__NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
或(*((volatile uint32_t *)0xe000ed19)) = priority;
- 使用错误
//使能使用异常中断,默认关闭
SCB->SHCSR |= 1 << 18; 或(*((volatile uint32_t *)0xe000ed24)) |= (1 << 18);
//设置优先级,IRQn = -10;
__NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
或(*((volatile uint32_t *)0xe000ed1A)) = priority;
- SVC系统调用
//系统调用指令,执行SVC_HANDLER()处理函数;
svc 0
//设置优先级,IRQn = -5;
__NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
或(*((volatile uint32_t *)0xe000ed1F)) = priority;
- PendSV可挂起的系统调用
//设置pendsv挂起位
SCB->ICSR |= (1 << 28); 或 (*((volatile uint32_t *)0xe000ed04)) |= (1 << 28);
//清除pendsv挂起位
SCB->ICSR |= (1 << 27); 或 (*((volatile uint32_t *)0xe000ed04)) |= (1 << 27);
//设置优先级,IRQn = -2;
__NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
或(*((volatile uint32_t *)0xe000ed22)) = priority;
- SysTick定时器
//异常使能
SysTick->CTRL |= (1 << 2); 或 (*((volatile uint32_t *)0xe000e010)) |= (1 << 2);
//设置SYSTICK挂起位
SCB->ICSR |= (1 << 26); 或 (*((volatile uint32_t *)0xe000ed04)) |= (1 << 26);
//清除SYSTICK挂起位
SCB->ICSR |= (1 << 25); 或 (*((volatile uint32_t *)0xe000ed04)) |= (1 << 25);
//设置优先级,IRQn = -1;
__NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
或(*((volatile uint32_t *)0xe000ed23)) = priority;
1.3、全局控制的特殊寄存器
全局中断使能与禁止主要是操作内核CPSR寄存器的I位与F位的置1与清0状态。
A、PRIMASK
用于禁止除了NMI和HardFault外的所有异常和中断,内核提供的操作函数为:
void __set_PRIMASK(uint32_t priMask);
uint32_t __get_PRIMASK(void);
举例:
/* Disable interrupts*/
uint32_t primask_bit = __get_PRIMASK();
__disable_irq();
//…不可中断代码
/* Re-enable the interrupts */
__set_PRIMASK(primask_bit);
B、FAULTMASK
用于禁止除了NUM外的所有异常和中断,包含HardFault也被屏蔽,内核提供的操作函数为:
uint32_t __get_FAULTMASK(void);
void __set_FAULTMASK(uint32_t faultMask);
举例:
/* Disable interrupts*/
uint32_t faultmask_bit = __get_ FAULTMASK ();
__disable_fault_irq ();
//…不可中断代码
/* Re-enable the interrupts */
__set_ FAULTMASK (faultmask_bit);
C、BASEPRI
该寄存器用于禁止优先级低于某特定等级的中断,在内核提供的操作函数如下:
uint32_t __get_BASEPRI(void);//获取当前被屏蔽等级阈值
void __set_BASEPRI(uint32_t basePri);//设置当前被屏蔽的等级阈值
举例:
__set_BASEPRI(0x60); //禁止优先级在0x60~0xFF间的中断。
1.4、Core控制模块的地址空间
ARM Cortex m4地址总线位宽32bit,支持4G的存储器容量,但实际在MCU中最多支持几个M的Flash容量,因此其它的地址位置用于各种外设的访问。
4G的地址空间被分为8个块,每个块512M,代码区域为首块(0x00000000~0x1FFFFFFF),内部SRAM区域为第二块(0x20000000~0x3FFFFFFF),而内核控制模块则位于第8块,如下图所示: