|
/*----------------------------------------------------------------------------------
LPCARM中断非典方法大全圣诞裸奔程序详解(更新)
雁塔菜农HotPower 2006.12.25 更新于菜地
----------------------------------------------------------------------------------*/
#include <LPC213xDEF.H> //ARM菜鸟HotPower创建定义文件(最新为倒塌版)
/*---------------------------------------------------------------------------------
注意:
LPC213XDEF.H文件下载
可将LPC213XDEF.H拷贝到Keil\ARM\INC\PHILIPS目录下
点击下载本裸奔程序完整的工程压缩包
----------------------------------------------------------------------------------*/
void __swi(0) Enable_IRQ(void);
void __SWI_0 (void) {
int tmp;
__asm
{
MRS tmp, SPSR
BIC tmp, tmp, #0x80
MSR SPSR_c, tmp
}
}
void __swi(1) Disable_IRQ(void);
void __SWI_1 (void) {
int tmp;
__asm
{
MRS tmp, SPSR
ORR tmp, tmp, #0x80
MSR SPSR_c, tmp
}
}
void __swi(2) Enable_FIQ(void);
void __SWI_2 (void) {
int tmp;
__asm
{
MRS tmp, SPSR
BIC tmp, tmp, #0x40
MSR SPSR_c, tmp
}
}
void __swi(3) Disable_FIQ(void);
void __SWI_3 (void) {
int tmp;
__asm
{
MRS tmp, SPSR
ORR tmp, tmp, #0x40
MSR SPSR_c, tmp
}
}
void __swi(4) Enable_VIC(void);
void __SWI_4 (void) {
VIC->Protection = 0;//开放对VIC的写入保护
}
/*-------------------------------------------------------------
SWI中断和VICSoftInt软件中断的区别之处
由于VIC->Protection可以在任何级别随意置'1',即关闭
对VIC的写入,故没必要构造Disable_VIC();
以下函数SetVICProtection()只是说明SWI中断和VICSoftInt软件
中断的区别,即前者属于非屏蔽中断,且可带参数和返回值。
而后者和属于可屏蔽中断,与VIC中断一样,无参数和返回值。
但VICSoftInt软件中断有别于模块的VIC中断。它可自组中断,也可
模拟系统模块中断。
两者都很灵活,但用途和方法有很大的差异。
SWI中断改进的注解见SWI.s和SWI_Table.s.否则不能正确开关FIQ/IRQ
--------------------------------------------------------------*/
unsigned int __swi(5) SetVICProtection(unsigned int val);
unsigned int __SWI_5 (unsigned int val) {
VIC->Protection = val;//VIC->Protection可以随意置'1',但清'0'必须在管理模式下
return VIC->Protection;
}
extern void FIQ_EINT0 (void) __irq
{
VIC->SoftIntClr = (1 << VICIntSel_EINT0);//增强安全性
INTCON->EXT_INT = (1 << EINT0); //清除INT0中断标志
VIC->VectAddr = 0;
}
void IRQ_EINT1 (void) __irq
{
VIC->SoftIntClr = (1 << VICIntSel_EINT1);;//增强安全性
while(INTCON->EXT_INT & (1 << EINT1)) {//等待P0_3和P0_14都为高电平
INTCON->EXT_INT = (1 << EINT1);//清除INT1中断标志(电平触发必须读后清除!!!)
}
VIC->VectAddr = 0;
}
void IRQ_SOFT (void) __irq
{
VIC->SoftIntClr = (1 << VICIntSel_SoftInt22);//清除用户软件中断标志
VIC->VectAddr = 0;
}
void IRQ_Default (void) __irq
{
switch(VIC->IRQStatus) {
case (1 << VICIntSel_EINT0)://拦截非法INT0中断
INTCON->EXT_INT = (1 << EINT0);//清除非法INT0中断标志
VIC->SoftIntClr = (1 << VICIntSel_EINT0);//清除非法INT0软件中断标志
break;
case (1 << VICIntSel_EINT1)://拦截非法INT1中断
INTCON->EXT_INT = (1 << EINT1);//清除非法INT1中断标志
VIC->SoftIntClr = (1 << VICIntSel_EINT1);//清除非法INT1软件中断标志
break;
case (1 << VICIntSel_EINT2)://拦截非法INT2中断
INTCON->EXT_INT = (1 << EINT2);//清除非法INT2中断标志
VIC->SoftIntClr = (1 << VICIntSel_EINT2);//清除非法INT2软件中断标志
break;
case (1 << VICIntSel_EINT3)://拦截非法INT3中断
INTCON->EXT_INT = (1 << EINT3);//清除非法INT2中断标志
VIC->SoftIntClr = (1 << VICIntSel_EINT3);//清除非法INT3软件中断标志
break;
case (1 << VICIntSel_SoftInt23)://拦截非法用户软件中断VICIntSel_SoftInt23
VIC->SoftIntClr = (1 << VICIntSel_SoftInt23);//清除非法用户软件中断标志
break;
case (1 << VICIntSel_SoftInt24)://拦截非法用户软件中断VICIntSel_SoftInt24
VIC->SoftIntClr = (1 << VICIntSel_SoftInt24);//清除非法用户软件中断标志
break;
case (1 << VICIntSel_SoftInt25)://拦截非法用户软件中断VICIntSel_SoftInt25
VIC->SoftIntClr = (1 << VICIntSel_SoftInt25);//清除非法用户软件中断标志
break;
case (1 << VICIntSel_SoftInt26)://拦截非法用户软件中断VICIntSel_SoftInt26
VIC->SoftIntClr = (1 << VICIntSel_SoftInt26);//清除非法用户软件中断标志
break;
default:
VIC->SoftIntClr = 0xffffff;//清除所有非法用户软件中断标志
}
VIC->VectAddr = 0;
}
int main(void)
{
unsigned int i;
Disable_IRQ();//关闭向量中断总开关
Disable_FIQ();//关闭快速中断总开关
VIC->IntEnable = 0;//关闭全部中断
VIC->SoftIntClr = 0xffffffff;//清除所有软中断标志
VIC->IntSelect = 0;//全部中断为IRQ中断或默认中断
PINSEL->PIN_SEL0 = 0x00000000;//设置管脚连接GPIO
PINSEL->PIN_SEL1 = 0x00000000;//设置管脚连接GPIO
P0->IODIR = 0x00000000;//设置P0口为输入
P1->IODIR = 0x00000000;//设置P1口为输入
PINSEL->PIN_SEL0 |= (P0_1_EINT0 << P0_1_PINSEL); //选择P0.1为INT0外部中断引脚
PINSEL->PIN_SEL1 |= (P0_16_EINT0 << P0_16_PINSEL); //选择P0.16也可为INT0外部中断引脚
PINSEL->PIN_SEL0 |= (P0_3_EINT1 << P0_3_PINSEL); //选择P0.3为INT1外部中断引脚
PINSEL->PIN_SEL0 |= (P0_14_EINT1 << P0_14_PINSEL); //选择P0.14也可为INT1外部中断引脚
INTCON->EXT_POLAR = ~(1 << EXTPOLAR0); //INT0为低电平有效
INTCON->EXT_POLAR &= ~(1 << EXTPOLAR1); //INT1为低电平有效
INTCON->EXT_MODE = (1 << EXTMODE0); //设置INT0为边沿触发
INTCON->EXT_MODE &= ~(1 << EXTMODE1); //设置INT1为电平触发
/*-------------------------------------------------------------------------------------------
FIQ中断和IRQ中断的区别之处
FIQ中断和IRQ中断都属于可屏蔽中断,他们分别受CPSR的F和I位的控制。
前者不需对VIC->VectAddrs和VIC->VectCntls进行设置,但要想正确地
中断要做几步工作:
1. VIC->IntSelect = (1 << VICIntSel_EINT0); //设置EINT0为FIQ中断
2. VIC->IntEnable |= (1 << VICIntSel_EINT0); //使能EINT0中断
3. 建立FIQ中断函数FIQ_EINT0().
注意要声明为外部的即extern void FIQ_EINT0 (void) __irq
4. 改写Startup.S的内容。(改写后的注解见Startup.S)
后者需对VIC->VectAddrs和VIC->VectCntls进行设置。方法:
1. VIC->IntSelect &= ~(1 << VICIntSel_EINT1); //设置EINT1为IRQ中断
2. VIC->VectCntls[0] = VICIntSel_Enable | VICIntSel_EINT1;//设置外部中断1分配VIC最高优先级
IRQ_EINT1;//设置中断服务程序地址见Startup_Table.S
VIC->IntEnable |= (1 << VICIntSel_EINT1); //使能EINT1中断
3. 建立IRQ中断函数IRQ_EINT1().
注意要声明为内部的即void IRQ_EINT1 (void) __irq
4. 必须改写Startup.S的内容。
5. 当VIC中断向量地址未定义或超出VIC->VectAddrs[15]时,使用默认中断向量VIC->DefVectAddr
向量(数组)向量与默认中断向量最大的不同在于每个向量中断都有1个中断地址,而默认中断向量
只占用1个公共的中断地址但可包含多个中断源。故默认中断向量必须判别是某个具体的中断源。
所以也可以认为默认中断向量是第17个中断向量。
特别注意非典的默认中断向量内不是中断的地址而是序号16~31.
6. 非典与经典的最大不同在于前者的VIC->VectAddrs[x]内不是地址而是向量数组的序号。
非典的中断向量地址需要在Startup_Table.s即FLASH内设置。
而经典的中断向量地址需要在VIC->VectAddrs[x]或VIC->DefVectAddr即RAM内设置真正的中断向量地址。
--------------------------------------------------------------------------------------------*/
VIC->IntSelect = (1 << VICIntSel_EINT0); //设置EINT0为FIQ中断
VIC->VectCntls[0] = VICIntSel_Enable | VICIntSel_EINT1;//设置外部中断1分配VIC最高优先级
; VIC->VectAddrs[0] = (unsigned int)IRQ_EINT1;//设置中断服务程序地址
VIC->IntEnable |= (1 << VICIntSel_EINT1);//使能外部中断1
VIC->VectCntls[1] = VICIntSel_Enable | VICIntSel_SoftInt22;//设置用户软件中断
; VIC->VectAddrs[1] = (unsigned int)IRQ_SOFT;//设置用户软件中断服务程序地址
VIC->IntEnable |= (1 << VICIntSel_SoftInt22);//使能用户软件中断
VIC->DefVectAddr = (unsigned int)31;//16~31都可//定义除VIC->VectAddrs[0]~VIC->VectAddrs[15]外的中断函数
INTCON->EXT_INT = (1 << EINT0) //清除INT0中断标志
| (1 << EINT1) //清除INT1中断标志
| (1 << EINT2) //清除INT2中断标志
| (1 << EINT3);//清除INT3中断标志
VIC->SoftIntClr = (1 << VICIntSel_EINT0) //清除EINT0软中断标志
| (1 << VICIntSel_EINT1) //清除EINT1软中断标志
| (1 << VICIntSel_EINT1) //清除EINT2软中断标志
| (1 << VICIntSel_EINT1);//清除EINT3软中断标志
VIC->IntEnable = (1 << VICIntSel_EINT0) //使能EINT0中断
| (1 << VICIntSel_EINT1);//使能EINT1中断
/*--------------------------------------------------------------------------
下列循环是非典的精华所在,其思路请到菜地的[非典型LPCARM之攻防体系]里寻找。
其他需要Startup_Hot.s支持,以配合非典的拦截工作。
---------------------------------------------------------------------------*/
for (i = 0;i <= 15; i ++) {
VIC->VectAddrs = i;//刷新向量地址寄存器VICVectAddr0~VICVectAddr15
}
VIC->Protection = 1;//关闭在用户级对VIC的一些写操作
VIC->Protection = 0;//试图在用户级打开对VIC的一些写操作的保护
Enable_FIQ();//开放快速中断总开关
VIC->SoftInt = (1 << VICIntSel_EINT0);//软件模拟快速中断0(失败!!!)
__nop();
Enable_VIC();//等效为特权级的VIC->Protection = 0;
VIC->SoftInt = (1 << VICIntSel_EINT0);//软件模拟快速中断0(成功!!!)
__nop();
VIC->SoftInt = (1 << VICIntSel_SoftInt22);//软件模拟用户软件中断(失败!!!)
Enable_IRQ();//注意现在立即进入EINT1硬件中断(因为假定P0.3/P0.14都为高电平)
VIC->SoftInt = (1 << VICIntSel_SoftInt22);//软件模拟用户软件中断(成功!!!)
VIC->SoftInt = (1 << VICIntSel_EINT1);//软件模拟向量中断1(成功!!!)
VIC->Protection = 1;//关闭在用户级对VIC的一些写操作
VIC->Protection = 0;;//在用户级试图写'0'无效!!!应该用Enable_VIC();或SetVICProtection(0);
while(i == 0) {//不会进入死循环
__nop();
}
i = SetVICProtection(0);//进入特权级打开对VIC的一些写操作的保护
VIC->IntEnable |= (1 << VICIntSel_SoftInt23);//使能非法用户软件中断
VIC->IntEnable |= (1 << VICIntSel_SoftInt24);//使能非法用户软件中断
VIC->IntEnable |= (1 << VICIntSel_SoftInt25);//使能非法用户软件中断
VIC->IntEnable |= (1 << VICIntSel_SoftInt26);//使能非法用户软件中断
Disable_IRQ();//关闭向量中断总开关
PINSEL->PIN_SEL0 |= (P0_7_EINT2 << P0_7_PINSEL); //选择P0.7为INT2外部中断引脚
INTCON->EXT_POLAR &= ~(1 << EXTPOLAR2); //INT2为低电平有效
INTCON->EXT_MODE |= (1 << EXTMODE2); //设置INT2为边沿触发
// INTCON->EXT_MODE &= ~(1 << EXTMODE2); //设置INT2为电平触发
VIC->IntEnable |= (1 << VICIntSel_EINT2);//使能非法外部中断2
/*----------------------------------------------------------------------------------------------
以下几句引发非法用户软件中断后VIC->VectAddr值为VIC->DefVectAddr,故程序飞入IRQ_Default()处执行。
-----------------------------------------------------------------------------------------------*/
VIC->SoftInt = (1 << VICIntSel_SoftInt23);//软件模拟非法用户软件中断(程序飞)
VIC->SoftInt = (1 << VICIntSel_SoftInt24);//软件模拟非法用户软件中断(程序飞)
VIC->SoftInt = (1 << VICIntSel_SoftInt25);//软件模拟非法用户软件中断(程序飞)
VIC->SoftInt = (1 << VICIntSel_SoftInt26);//软件模拟非法用户软件中断(程序飞)
VIC->SoftInt = (1 << VICIntSel_EINT2);//软件模拟非法INT2软件中断(程序飞!!!)
INTCON->EXT_INT = (1 << EINT2);//清除非法INT2中断标志
VIC->SoftIntClr = (1 << VICIntSel_EINT2);//清除非法INT2软件中断标志
Enable_IRQ();//开放向量中断总开关
VIC->Protection = 1;//关闭在用户级对VIC的一些写操作,保护在用户级VIC不被以外改写
while(i == 0) {//进入死循环
__nop();
}
} |
|