在前几天有客户问了一个问题:如果外部中断来的频率足够快,上一个中断没有处理完成,新来的中断该如何处理?
在研究了arm的官方手册后,了解中断有使能、清除或挂起等实现方式,今天分享给大家。
中断一般是由硬件(例如外设、外部引脚)产生,当某种内部或外部事件发生时,MCU的中断系统将迫使 CPU 暂停正在执行的程序,转而去进行中断事件的处理,中断处理完毕后,又返回被中断的程序处,继续执行下去,所有的Cortex-M 内核系统都有一个用于中断处理的组件NVIC,主要负责处理中断,还处理其他需要服务的事件。嵌套向量式中断控制器(NVIC: Nested Vectored Interrupt Controller)集成在Cortex-M0处理器里,它与处理器内核紧密相连,并且提供了中断控制功能以及对系统异常的支持。
处理器中的NVIC能够处理多个可屏蔽中断通道和可编程优先级,中断输入请求可以是电平触发,也可以是最小的一个时钟周期的脉冲信号。每一个外部中断线都可以独立的使能、清除或挂起,并且挂起状态也可以手动地设置和清除。
主程序正在执行,当遇到中断请求(Interrupt Request)时,暂停主程序的执行转而去执行中断服务例程(Interrupt Service Routine,ISR),称为响应,中断服务例程执行完毕后返回到主程序断点处并继续执行主程序。多个中断是可以进行嵌套的。正在执行的较低优先级中断可以被较高优先级的中断所打断,在执行完高级中断后返回到低级中断里继续执行,采用“咬尾中断”机制。
内核中断(异常管理和休眠模式等),其中断优先级则由SCB寄存器来管理,IRQ的中断优先级是由NVIC来管理。
NVIC的寄存器经过了存储器映射,其寄存器的起始地址为0xE000E100,对其访问必须是每次32bit。
SCB寄存器的起始地址:0xE000ED00,也是每次32bit访问,SCB寄存器主要包含SysTick操作、异常管理和休眠模式控制。
NVIC具有以下特性:
*(volatile unsigned long) (0xE000E100) = 0x4 ; //使能#2中断 *(volatile unsigned long) (0xE000E180) = 0x4 ; //清除#2中断
__asm void Interrupt_Enable() { LDR R0, =0xE000E100 ; //ISER寄存器的地址 MOVS R1, #04 ; //设置#2中断 STR R1, [R0] ; //使能中断#2 } __asm void Interrupt_Disable() { LDR R0, =0xE000E180 ; //ICER寄存器的地址 MOVS R1, #04 ; //设置#2中断 STR R1, [R0] ; //使能中断#2 }
//使能中断#IRQn __STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); } } //清除中断#IRQn __STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); __DSB(); __ISB(); } } //读取使能中断#IRQn __STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { return((uint32_t)(((NVIC->ISER[0U] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); } else { return(0U); } }
*(volatile unsigned long)(0xE000E100) = 0x4 ; //使能中断#2 *(volatile unsigned long)(0xE000E200) = 0x4 ; //挂起中断#2 *(volatile unsigned long)(0xE000E280) = 0x4 ; //清除中断#2的挂起状态
__asm void Interrupt_Set_Pending() { LDR R0, =0xE000E100 ; //设置使能中断寄存器地址 MOVS R1, #0x4 ; //中断#2 STR R1, [R0] ; //使能#2中断 LDR R0, =0xE000E200 ; //设置挂起中断寄存器地址 MOVS R1, #0x4 ; //中断#2 STR R1, [R0] ; //挂起#2中断 } __asm void Interrupt_Clear_Pending() { LDR R0, =0xE000E100 ; //设置使能中断寄存器地址 MOVS R1, #0x4 ; //中断#2 STR R1, [R0] ; //使能#2中断 LDR R0, =0xE000E280 ; //设置清除中断挂起寄存器地址 MOVS R1, #0x4 ; //中断#2 STR R1, [R0] ; //清除#2的挂起状态 }
//设置一个中断挂起 __STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { NVIC->ISPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); } } //清除中断挂起 __STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { NVIC->ICPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); } } //读取中断挂起状态 __STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { return((uint32_t)(((NVIC->ISPR[0U] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); } else { return(0U); } }
原文标题:技术分享 | Cortex-M0中断控制和系统控制(一)
文章出处:【微信公众号:安芯教育科技】欢迎添加关注!文章转载请注明出处。
全部0条评论
快来发表一下你的评论吧 !