Cortex-M3内核异常与外部中断剖析

本文所有的测试是基于STM32F103测试的,因为STM32F103是Cortex-M3内核的芯片,而且恰好我手里有这个芯片,所以就用它了。为了清晰明了,全部使用寄存器方式测试。
在使用Cortex-M3系列内核芯片的时候必须掌握其中的NVIC中断向量控制器。必须搞清楚其中的每一个细节。
NVIC管理240个外部中断,这里的外部指内核外部,比如看门狗中断,定时器中断等等都叫做外部中断。
那么内核的异常优先级怎么设置呢,比如Sistick,PendSV呢?内核异常优先级由系统控制块管理。
那我们先看一下内核的优先级究竟怎么设置,我们先来看一个函数NVIC_SetPriority

static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
  if(IRQn < 0) {
    SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for Cortex-M3 System Interrupts */
  else {
    NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff);    }        /* set Priority for device specific Interrupts  */
}

参数IRQn代表中断号,参数priority表示优先级。我们知道内核的中断号全部是负数,函数内部对负数的中断号操作是在SCB中的SHP数组里,找到SHP的地址,SHP的起始地址是0xE000ED18,这个大家可以算一下,篇幅原因,这里不推算了。
在这里插入图片描述
M3权威指南中清楚的给出了每个内核异常名字,优先级设置地址,异常使能位。
我们推算出的地址和M3权威指南中的给出的地址相吻合,那我们是不是可以设置一下内核中的优先级了呢,感受一下
把MenManage fault的中断优先级设置为2,试一下。
上代码

SCB->SHP[0] = (0x02<<4);//设置MemoryManagement中断优先级为2

使用STM32F103 测试的,ST使用了高4位表示优先级,所有要左移4位。
上图
在这里插入图片描述
优先级设置完了,使能中断我们也试一下,

SCB->SHCSR = 1<<16;//使能MemoryManagement中断

就不贴图片了,MemoryManagement中断确实是使能了。
其余的内核异常也是同样的设置方法。
外部中断
我们接下来看一下内核之外片上外设的中断,cortex-M3是如何管理的?
在说外部中断之前,我们先来了解一下,cortex-M3优先级分组的概念,
优先级分组在SCB->AIRCR寄存器中
在这里插入图片描述
上图是STM32对cortex的裁剪,只用了4个位表示优先级。
回过头我们看NVIC_SetPriority函数,片上外设的中断优先级是在NVIC的IP寄存器组中设置的,
core_cm3.h文件下对NVIC的结构体如下

typedef struct
{
  __IO uint32_t ISER[8];     	  //中断使能寄存器      偏移地址  0x000        
       uint32_t RESERVED0[24];    //保留                               
  __IO uint32_t ICER[8];          //中断除能寄存器	   偏移地址  0x080         
       uint32_t RSERVED1[24];     //保留                                 
  __IO uint32_t ISPR[8];    	  //中断悬起寄存器      偏移地址  0x100          
       uint32_t RESERVED2[24];	  //保留                                   
  __IO uint32_t ICPR[8];          //中断解悬寄存器      偏移地址  0x180    			
       uint32_t RESERVED3[24];    //保留                               
  __IO uint32_t IABR[8];          //中断活动状态寄存器  偏移地址  0x200           
       uint32_t RESERVED4[56];    //保留                               
  __IO uint8_t  IP[240];          //外部中断优先级寄存器            
       uint32_t RESERVED5[644];   //保留                               
  __O  uint32_t STIR;             //软件触发中断寄存器           
}  NVIC_Type;    

这些寄存器在M3权威指南中都有详细的说明。
中断使能,除能与悬起,解悬都是成对出现的。为什么要搞成一对寄存器而不是一组寄存器,因为这些寄存器只有写1有效,写0是无效的。因此要打开某个中断我们只要相应的位写1其余位写0就可以了。是不是很便捷,如果是一组寄存器,写1使能中断写0关闭中断,那么我们想要使能某一个中断就必须先把寄存器的值读取出来,然后将对应位置1,在将数据写回寄存器,这样就存在一个读,修改,写的过程。搞清楚了成对出现的原因以后我们看下每一组寄存器的含义。
uint32_t ISER[8];中断使能寄存器,写1使能中断,写0无效。
cortex-M3可以管理240个外部中断,每个外部中断用一个bit表示。ISER的类型是 uint32_t类型,数组8个元素,那么就是32*8 = 256位。256个bit完全可以容纳240个中断了,最后一个32bit的数组元素没有用完。
每一个bit和外部中断(片上外设中断)是如何对应的呢?
下面图片是M3权威指南给出的解释,
在这里插入图片描述
也就是说外部中断0对应ISER[0]中的bit0,外部中断1对应ISER[0]中的bit1,外部中断32对应ISER[1]中的bit0.依次类推。
uint32_t ICER[8];外部中断除能寄存器。写1除能,写0无效。用法和含义同上不再赘述。
uint32_t ISPR[8];外部中断悬起寄存器。写1悬起,写0无效。如果中断发生时,正在处理同级或高优先级异常,或者被掩蔽,则中断不能立即得到响应。此时中断被悬起。中断的悬起状态可以通过“中断设置悬起寄存器(SETPEND)”和“中断悬起清除寄存器(CLRPEND)”来读取,还可以写它们来手工悬起中断。
uint32_t ICPR[8];外部中断解悬寄存器,写1解悬。写0无效。
IABR[8];中断活跃寄存器。该寄存器只读。在处理器执行了其 ISR 的第一条指令后,它的活动位就被置 1,并且直到 ISR 返回时才硬件清零。如果该中断被抢占,在执行更高优先级的中断时该为依然为1.直到返回,又硬件自动清0。
uint8_t IP[240];中断优先级寄存器,每个外部中断占用1个字节。
明白了这些我们用代码来测试一下吧,使用TIMER2
设置优先级分组2

SCB->AIRCR = 0x05FA0000 | (0x05<<8);//bit10~bit8    101  分组2

配置TIMER和NVIC

void timer_init(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructre;
	NVIC_InitTypeDef NVIC_InitStructre;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	
	TIM_TimeBaseStructre.TIM_Period = 9999 ; //计10000个数10ms
	TIM_TimeBaseStructre.TIM_Prescaler = 71 ;//PSC对TIMxCLK72分频  72000000/72 = 1000000HZ
	TIM_TimeBaseStructre.TIM_CounterMode = TIM_CounterMode_Up ;//向上计数
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructre);//定时器时基初始化
	
	TIM_Cmd(TIM2,ENABLE);
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	TIM_ClearITPendingBit (TIM2,TIM_IT_Update);
		
	NVIC->ISER[TIM2_IRQn/32] = 1 << (TIM2_IRQn%32);//使能外部中断
	NVIC->IP[TIM2_IRQn] = ((0x03<<2)|(0x00<<0))<<4;	//配置抢占式优先级3  次优先级0
}

在这里插入图片描述
可以看NVIC中外部中断定时器2的中断已经使能了,中断优先级是12。为什么是12呢? 12的二进制是 1100。因为优先级分组设置了组2,即抢占式优先级占2位,次优先级占2位。抢占优先级在高,次优先级在低。我们设置的抢占式优先级是3,次优先级是0。那么恰好就是1100了,即十进制的12.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值