cortex的异常和中断.docx
《cortex的异常和中断.docx》由会员分享,可在线阅读,更多相关《cortex的异常和中断.docx(15页珍藏版)》请在冰豆网上搜索。
cortex的异常和中断
Cortex-M3异常和中断---基于NXPLPC177x/8x
分类:
我的小问题集2013-04-1008:
26 1805人阅读 评论(0) 收藏 举报
目录(?
)[+]
0.前言
本文想解决的问题有:
∙如何开启、关闭中断
∙如何开启、关闭异常
∙LPC177x/8x支持的中断优先级个数
∙复位后,异常/中断默认的优先级
∙如何设置异常/中断的优先级
∙什么是优先级组,如何设置优先级组,复位后的优先级组
1.Cortex-M3的异常/中断屏蔽寄存器组
注:
只有在特权级下,才允许访问这3个寄存器。
名字
功能描述
PRIMASK
只有单一比特的寄存器。
置为1后,就关掉所有可屏蔽异常,只剩下NMI和硬Fault可以响应。
默认值是0,表示没有关闭中断。
FAULTMASK
只有单一比特的寄存器。
置为1后,只有NMI可以响应。
默认值为0,表示没有关异常。
BASEPRI
该寄存器最多有9位(由表达优先级的位数决定)。
定义了被屏蔽优先级的阈值。
当它被设置为某个值后,所有优先级号大于等于此值的中断都被关。
若设置成0,则不关断任何中断,0为默认值。
注:
寄存器BASEPRI的有效位数受系统中表达优先级的位数影响,如果系统中只使用3个位来表达优先级,则BASEPRI有意义的值仅为0x00、0x20、0x40、0x60、0x80、0xA0、0xC0和0xE0
使用MRS/MSR指令访问这三个寄存器,比如:
MRSR0,BASEPRI;读取BASEPRI到R0中
MSRBASEPRI,R0;将R0数据写入到BASEPRI中
为了快速的开关中断,CM3还专门设置了一条CPS指令,有四种用法:
CPSIDI;PRIMASK=1,关中断
CPSIEI;PRIMASK=0,开中断
CPSIDF;FAULTMASK=1,关异常
CPSIEF;FAULTMASK=0,开异常
CMSIS-M3微控制器软件接口标准中的core_cm3.h给出了开关中断或异常的函数:
1.1开/关中断
1:
/**
2:
*@briefSetthePriorityMaskvalue
3:
*
4:
*@parampriMaskPriMask
5:
*
6:
*Settheprioritymaskbitintheprioritymaskregister
7:
*/
8:
static__INLINEvoid__set_PRIMASK(uint32_tpriMask)
9:
{
10:
registeruint32_t__regPriMask__ASM("primask");
11:
__regPriMask=(priMask);
12:
}
使用__set_PRIMASK
(1)关闭中断;__setPRIMASK(0)开启中断。
一些说明:
__INLINE是宏定义,对应__inline,这是keil编译器自定义关键字,表示这个函数是内联函数,但并不是强制性内联,编译器最终决定是否内联。
__ASM(“primask”):
__ASM也是一个宏,对应__asm,这是keil编译器自定义关键字,关于这个关键字,有相当多的用法,可以在C中内嵌汇编语言、内嵌汇编函数、指定汇编标号以及本代码中的声明一个已命名寄存器变量。
这里,已命名的寄存器是("primask"),也就是说寄存器变量__regPriMask等同于编译器已命名的primask。
语法为:
registertypevar-name__asm(reg);
keil编译器已命名的寄存器变量为:
寄存器
__asm修饰的字符串
处理器
APSR
"apsr"
Allprocessors
CPSR
"cpsr"
Allprocessors
BASEPRI
"basepri"
Cortex-M3,Cortex-M4
BASEPRI_MAX
"basepri_max"
Cortex-M3,Cortex-M4
CONTROL
"control"
Cortex-M0,Cortex-M1,Cortex-M3,Cortex-M4
DSP
"dsp"
Cortex-M0,Cortex-M1,Cortex-M3,Cortex-M4
EAPSR
"eapsr"
Cortex-M0,Cortex-M1,Cortex-M3,Cortex-M4
EPSR
"epsr"
Cortex-M0,Cortex-M1,Cortex-M3,Cortex-M4
FAULTMASK
"faultmask"
Cortex-M3,Cortex-M4
IAPSR
"iapsr"
Cortex-M0,Cortex-M1,Cortex-M3,Cortex-M4
IEPSR
"iepsr"
Cortex-M0,Cortex-M1,Cortex-M3,Cortex-M4
IPSR
"ipsr"
Cortex-M0,Cortex-M1,Cortex-M3,Cortex-M4
MSP
"msp"
Cortex-M0,Cortex-M1,Cortex-M3,Cortex-M4
PRIMASK
"primask"
Cortex-M0,Cortex-M1,Cortex-M3,Cortex-M4
PSP
"psp"
Cortex-M0,Cortex-M1,Cortex-M3,Cortex-M4
PSR
"psr"
Cortex-M0,Cortex-M1,Cortex-M3,Cortex-M4
r0 to r12
"r0" to "r12"
Allprocessors
r14 or lr
"r14" or "lr"
Allprocessors
r13 or sp
"r13" or "sp"
Allprocessors
r15 or pc
"r15" or "pc"
Allprocessors
SPSR
"spsr"
Allprocessors,apartfromCortex-Mseriesprocessors.
XPSR
"xpsr"
Cortex-M0,Cortex-M1,Cortex-M3,Cortex-M4
1.2开/关异常
1:
/**
2:
*@briefSettheFaultMaskvalue
3:
*
4:
*@paramfaultMaskfaultMaskvalue
5:
*
6:
*Setthefaultmaskregister
7:
*/
8:
static__INLINEvoid__set_FAULTMASK(uint32_tfaultMask)
9:
{
10:
registeruint32_t__regFaultMask__ASM("faultmask");
11:
__regFaultMask=(faultMask&1);
12:
}
使用__set_FAULTMASK
(1)来关闭中断和异常;使用__set_FAULTMASK(0)开启中断和异常.
1.3更精确的优先级屏蔽
1:
/**
2:
*@briefSettheBasePriorityvalue
3:
*
4:
*@parambasePriBasePriority
5:
*
6:
*Setthebasepriorityregister
7:
*/
8:
static__INLINEvoid__set_BASEPRI(uint32_tbasePri)
9:
{
10:
registeruint32_t__regBasePri__ASM("basepri");
11:
__regBasePri=(basePri&0xff);
12:
}
比如想屏蔽优先级不高于0x60的中断,则使用代码:
__set_BASEPRI(0x60);如果想取消中断屏蔽,则使用__set_BASEPRI(0)即可。
2.异常/中断和优先级
Cortex-M3的异常包括系统异常和外设中断,系统异常是Cortex-M3内核自带的一些异常,比如复位、总线Fault和SysTick等等(见表2-1),外设中断是指制造CPU的厂家加入的,比如串口、定时器中断等等(见表2-2)。
注:
关于异常和中断,想要分个清清楚楚实在有点困难。
异常和中断都可以“中断”正常执行的代码流,区别在于,异常是Cortex-M3内核产生的“中断”信号,而中断是Cortex-M3内核外部(片上外设或外部中断信号)产生的“中断”信号。
希望你看懂了,有时候你心里明白,但要讲的清清楚楚着实难!
表2-1:
系统异常
编号
类型
优先级
简介
0
N/A
N/A
无
1
复位
-3(最高)
复位
2
NMI
-2
不可屏蔽中断(来自外部NMI输入脚)
3
硬Fault
-1
只要FAULTMASK没有置位,硬Fault服务例程会被强制执行
4
存储器管理Fault
可编程
MPU访问违例以及访问非法位置均可引发。
企图在“非执行区”取址也会引发此Fault。
5
总线Fault
可编程
总线收到了错误响应,原因可以使预取流产或数据流产,企图访问协处理器也会引发此Fault
6
用法Fault
可编程
由于程序错误导致的异常。
通常是使用了一条无效指令,或者是非法的状态转换,例如尝试切换到ARM状态
7~10
保留
保留
保留
11
SVCall
可编程
执行系统服务调用指令(SVC)引发的异常
12
调试监视器
可编程
调试器(断点、数据观察点,或者是外部调试请求)
13
保留
保留
保留
14
PendSV
可编程
为系统设备而设的“可挂起请求”
15
SysTick
可编程
系统节拍时钟定时器(SysTick)
表2-2:
外设中断
编号
类型
优先级
简介
16
IRQ#0
可编程
外设中断#0
17
IRQ#1
可编程
外设中断#1
...
...
可编程
...
255
IRQ#239
可编程
外设中断#239
注:
表2-1和2-2中的“编号”有着特殊的意义,一是特殊功能寄存器IPSR中会记录当前正在服务的异常并给出了它的编号;二是优先级完全相同的多个异常同时挂起时,则先响应异常编号最小的那一个。
一个发生的异常如果不能被立即响应,就称它被“挂起”,值得一提的是,对于被挂起的中断/异常,中断/异常信号不必由其产生者保持,NVIC的挂起状态寄存器会来保持这个信号。
所以哪怕后来挂起的中断源释放了中断请求信号,曾经的中断请求也不会丢失。
除了复位、NMI和硬Fault三个异常具有固定的优先级外,其它所有异常和中断的优先级都是可以编程的。
这就涉及到优先级配置寄存器。
Cortex-M3优先级配置寄存器共8位,所以可以有256级的可编程优先级。
但是大多数Cortex-M3芯片都会精简设计。
LPC177x/8x使用了优先级配置寄存器的5位,所以有32级可编程优先级。
复位后,对于所有优先级可编程的异常,其优先级都被初始化为0(最高优先级)
2.1设置异常/中断的优先级
2.1.1系统异常优先级设置
SHPR1-SHPR3寄存器用于设置有可编程优先级的系统异常,可设置的优先级为0到31。
SHPR1-SHPR3可按字节访问。
为了提高软件效率,CMSIS简化了SCB寄存器的表述。
在CMSIS中,字节数组SHP[0]到SHP[12]对应于寄存器SHPR1至SHPR3。
表2-3:
SHPR1寄存器的位分配
位
名称
功能
[31:
24]
PRI_7
保留
[23:
16]
PRI_6
系统处理程序6的优先级,用法Fault
[15:
8]
PRI_5
系统处理程序5的优先级,总线Fault
[7:
0]
PRI_4
系统处理程序4的优先级,存储器管理Fault
表2-3:
SHPR2寄存器的位分配
位
名称
功能
[31:
24]
PRI_11
系统处理程序11的优先级,SVCall
[23:
0]
-
保留
表2-4:
SHPR3寄存器的位分配
位
名称
功能
[31:
24]
PRI_15
系统处理程序15的优先级,SysTick异常
[23:
16]
PRI_14
系统处理程序14的优先级,PendSV
[15:
0]
-
保留
注:
每个PRI_N域为8位宽,但是处理器仅实现每个域的位[7:
3],位[2:
0]读取值为零并忽略写入值。
2.1.2外设中断优先级设置
LPC177x/8x微处理器的中断优先寄存器IPR0~IPR10用于设置外设中断优先级,控制41个外设中断。
每个IPRx可以按字节访问,在CMSIS中,字节数组IP[0]到IP[40]对应于寄存器IPR0~IPR10。
2.1.3系统异常/外设中断优先级设置C代码
1:
/**
2:
*@briefSetthepriorityforaninterrupt
3:
*
4:
*@paramIRQnThenumberoftheinterruptforsetpriority
5:
*@parampriorityTheprioritytoset
6:
*
7:
*Setthepriorityforthespecifiedinterrupt.Theinterrupt
8:
*numbercanbepositivetospecifyanexternal(devicespecific)
9:
*interrupt,ornegativetospecifyaninternal(core)interrupt.
10:
*
11:
*Note:
Theprioritycannotbesetforeverycoreinterrupt.*/
12:
static__INLINEvoidNVIC_SetPriority(IRQn_TypeIRQn,uint32_tpriority)
13:
{
14:
if(IRQn<0){/*setPriorityforCortex-M3SystemInterrupts*/
15:
SCB->SHP[((uint32_t)(IRQn)&0xF)-4]=((priority<<(8-__NVIC_PRIO_BITS))&0xff);
16:
}
17:
else{/*setPriorityfordevicespecificInterrupts*/
18:
NVIC->IP[(uint32_t)(IRQn)]=((priority<<(8-__NVIC_PRIO_BITS))&0xff);
19:
}
20:
}
其中,参数IRQn为中断ID号,可以为负,也可以为正。
当IRQn为负时,设置系统异常的优先级,当IRQn大于等于0时,设置外设中断优先级。
__NVIC_PRIO_BITS是指使用到的优先级配置寄存器的位数,LPC177x/8x使用了5位。
为什么要使用(8-__NVIC_PRIO_BITS)呢?
这是因为优先级配置寄存器是高位对齐的(MSB),这主要方面不同CPU间的移植。
参数priority为要设置的优先级值,为0~31,数值越低,表示优先级越大。
LPC177x/8x的中断ID为:
系统异常ID:
标号
中断ID
描述
NonMaskableInt_IRQn
-14
不可屏蔽中断
MemoryManagement_IRQn
-12
Cortex-M3内存管理中断
BusFault_IRQn
-11
Cortex-M3总线Fault中断
UsageFault_IRQn
-10
Cortex-M3用法Fault中断
SVCall_IRQn
-5
Cortex-M3SVCall中断
DebugMonitor_IRQn
-4
Cortex-M3调试监视中断
PendSV_IRQn
-2
Cortex-M3PendSV中断
SysTick_IRQn
-1
Cortex-M3系统Tick中断
外设中断ID:
标号
中断ID
描述
标号
中断ID
描述
WDT_IRQn
0
看门狗
EINT3_IRQn
21
外中断3
TIMER0_IRQn
1
定时器0
ADC_IRQn
22
AD转换
TIMER1_IRQn
2
定时器1
BOD_IRQn
23
欠压检测
TIMER2_IRQn
3
定时器2
USB_IRQn
24
USB
TIMER3_IRQn
4
定时器3
CAN_IRQn
25
CAN
UART0_IRQn
5
UART0
DMA_IRQn
26
通用DMA
UART1_IRQn
6
UART1
I2S_IRQn
27
I2S
UART2_IRQn
7
UART2
ENET_IRQn
28
以太网
UART3_IRQn
8
UART3
MCI_IRQn
29
SD/MMC卡I/F
PWM1_IRQn
9
PWM1
MCPWM_IRQn
30
电机控制PWM
I2C0_IRQn
10
I2C0
QEI_IRQn
31
正交编码接口
I2C1_IRQn
11
I2C1
PLL1_IRQn
32
PLL1锁存
I2C2_IRQn
12
I2C2
USBActivity_IRQn
33
USB活动
Reserved0_IRQn
13
保留
CANActivity_IRQn
34
CAN活动
SSP0_IRQn
14
SSP0
UART4_IRQn
35
UART4
SSP1_IRQn
15
SSP1
SSP2_IRQn
36
SSP2
PLL0_IRQn
16
PLL0锁存
LCD_IRQn
37
LCD
RTC_IRQn
17
RTC
GPIO_IRQn
38
GPIO
EINT0_IRQn
18
外中断0
PWM0_IRQn
39
PWM0
EINT1_IRQn
19
外中断1
EEPROM_IRQn
40
EEPROM
EINT2_IRQn
20
外中断2
2.2设置异常/中断的优先级组
Cortex-M3的异常/中断是可以抢占的,高抢占优先级中断可以抢占低抢占优先级中断。
NVIC中有个名字叫做“应用程序中断及复位控制寄存器(AIRCR)”的寄存器,该寄存器的bit[10:
8]称为优先级分组(PRIGROUP)段,表示的值为0~7,分别对应8个不同的抢占优先级设置。
比如优先级分组段为0时,则8位优先级配置寄存器(LPC177x/8x只使用了其中的5位)的bit[7:
1]表示抢占优先级,bit[0:
0]表示非抢占优先级;再比如优先级分组段为1时,则8位优先级配置寄存器的bit[7:
2]表示抢占优先级,bit[1:
0]表示非抢占优先级,依次类推。
复位后,优先级分组(PRIGROUP)段默认值为0,也就是则8位优先级配置寄存器(LPC177x/8x只使用了其中的5位)的bit[7:
1]表示抢占优先级,bit[0:
0]表示非抢占优先级。
而LPC177x/8x只使用了8位优先级配置寄存器其中的bit[7:
3],所以对于LPC177x/8x微处理器而言,复位后默认32级优先级全部为可抢占优先级。
2.2.1设置优先级寄存器组的C代码
1:
/**
2:
*@briefSetthePriorityGroupinginNVICInterruptController
3:
*
4:
*@paramPriorityGroupisprioritygroupingfield
5:
*
6:
*Settheprioritygroupingfieldusingtherequiredunlocksequence.
7:
*Theparameterpriority_groupingisassignedtothefield
8:
*SCB->AIRCR[10:
8]PRIGROUPfield.Onlyvaluesfrom0..7areused.
9:
*Incaseofaconflictbetweenprioritygroupingandavailable
10:
*prioritybits(__NVIC_PRIO_BITS)thesmallestpossibleprioritygroupisset.
11:
*/
12:
static__INLINEvoidNVIC_SetPriorityGrouping(uint32_tPriorityGroup)
13:
{
14:
uint32_treg_value;
15:
/*onlyvalues0..7areused*/
16:
uint32_tPriorityGroupTmp=(PriorityGroup&0x07);
17:
18:
reg_value=SCB->AIRCR;/*readoldregisterconfiguration*/
19:
/*clearbitstochange*/
20:
reg_value&=~(SCB_AIRCR_VECTKEY_Msk|SCB_AIRCR_PRIGROUP_Msk);
21:
/*Insertwritekeyandpriortygroup*/
22:
reg_value=(reg_value|
23:
(0x5FA<24:
(PriorityGroupTmp<<8));
25:
SCB->AIRCR=reg_value;
26:
}
其中,参数PriorityGroup为要设置的优先级分组(PRIGROUP)段的值,取值范围为0~7.由于操作AIRCR寄存器需要访问钥匙,所以要把0x05FA写入到该寄存器的bit[31:
16]中,否则写入的值会被忽