1.中断 :向CPU发出请求停止当前任务处理发出请求的外设的事件。另外一种CPU和外设交互的方式是轮询,效率太低了。
2.中断生命周期:
(1)信号产生(中断源)
(2)信号过滤(中断控制器)
(3)信号处理(CPU)
3.不同的CPU可以处理的中断源数目不一样
4关于中断过滤,分为有无子中断,见下图
5.中断处理,2440是采用非向量方式,每次都有固定的入口地址,然后用软件来判断中断源,效率比较低
6.6410和210是采用向量方式,由于在初始化的时候就已经将各种中断源的处理程序的入口地址和硬件的中断标志一一匹配了,所以是有硬件直接决定当某个中断发生的时候执行某个具体的中断处理函数,效率高
7.软件任务
(1)对中断源初始化
(2)对中断控制器初始化(先是子中断控制器,再是中断控制器),打开中断(因为之前屏蔽了)
(3)针对是否是采用向量方式编写相应的CPU处理函数。
(4)中断清0,比较特殊,是写1清0
(5)对中断模式下的SP指针做初始化
8.在start.s里面,跳转到中断处理函数用的是相对跳转,不是绝对跳转
@初始化栈
init_stack:
mrs r0, cpsr@用读-修改-写 的方式设置CPU的工作模式(CPSR寄存器)
bic r0,r0,#0x1F
orr r0,r0,#0xD2
msr cpsr, r0
ldr sp, =0x5F700000 @设置IRQ模式的堆栈
mrs r0, cpsr
bic r0,r0,#0x1F
orr r0,r0,#0xD3
msr cpsr, r0
ldr sp, =0x5F000000@设置SVC模式的堆栈
mov pc, lr
10 .中断源初始化
/****************************
@File:key.c
@
@Tiny6410裸机下学期代码
@按键初始化文件
@Author:小君君
@****************************/
#include "common.h"
/************************
*8颗按键都初始化为中断模式
*
***********************/
void button_init()
{
(vi KEYCON) &= ~((K1_MSK)|(K2_MSK)|(K3_MSK)|(K4_MSK)|(K5_MSK)|(K6_MSK));
(vi KEYCON) |= ((K1_OK)|(K2_OK)|(K3_OK)|(K4_OK)|(K5_OK)|(K6_OK));
(vi KEYCON1) &= ~(K7_MSK | K8_MSK);
(vi KEYCON1) |= (K7_OK | K8_OK);
}
11. 中断控制器初始化
/****************************
@File:common.h
@
@Tiny6410裸机下学期代码
@中断文件
@Author:小君君
@****************************/
#include "common.h"
/*按键1-4处理函数*/
void key1_4handle()
{
printf("x is: %d\ty is : %d\n",1,1);
/*1.现场保护*/
__asm__(
"sub lr, lr, #4\n"
"stmfd sp!, {r0-r12, lr}\n"
:
:
);
/*2.响应中断,中断处理函数*/
switch((vi EXT_INT_0_PEND)){
case (1 << 0 ):
led1_on();
break;
case (1 << 1 ):
led2_on();
break;
case (1 << 2 ):
led3_on();
break;
case (1 << 3 ):
led4_on();
break;
default:
break;
}
/*3.清除中断标志位*/
(vi EXT_INT_0_PEND) = ~0x0;
(vi VIC0ADDRESS) = 0;
(vi VIC1ADDRESS) = 0;
/*4.恢复现场*/
__asm__(
"ldmfd sp!, {r0-r12, pc}^ \n"
:
:
);
}
/*按键5-6处理函数*/
void key5_6handle()
{
printf("x is: %d\ty is : %d\n",1,1);
/*1.现场保护*/
__asm__(
"sub lr, lr, #4\n"
"stmfd sp!, {r0-r12, lr}\n"
:
:
);
/*2.响应中断,中断处理函数*/
if((vi EXT_INT_0_PEND) & (1 << 4))
led5_on();
else if((vi EXT_INT_0_PEND) & (1 << 5))
led6_on();
/*3.清除中断标志位*/
(vi EXT_INT_0_PEND) = ~0x0;
(vi VIC0ADDRESS) = 0;
(vi VIC1ADDRESS) = 0;
/*4.恢复现场*/
__asm__(
"ldmfd sp!, {r0-r12, pc}^ \n"
:
:
);
}
/*按键7处理函数*/
void key7_handle()
{
printf("x is: %d\ty is : %d\n",1,1);
/*1.现场保护*/
__asm__(
"sub lr, lr, #4\n"
"stmfd sp!, {r0-r12, lr}\n"
:
:
);
/*2.响应中断,中断处理函数*/
led7_on();
/*3.清除中断标志位*/
(vi EXT_INT_0_PEND) = ~0x0;
(vi VIC0ADDRESS) = 0;
(vi VIC1ADDRESS) = 0;
/*4.恢复现场*/
__asm__(
"ldmfd sp!, {r0-r12, pc}^ \n"
:
:
);
}
/*按键8处理函数*/
void key8_handle()
{
printf("x is: %d\ty is : %d\n",1,1);
/*1.现场保护*/
__asm__(
"sub lr, lr, #4\n"
"stmfd sp!, {r0-r12, lr}\n"
:
:
);
/*2.响应中断,中断处理函数*/
led8_on();
/*3.清除中断标志位*/
(vi EXT_INT_0_PEND) = ~0x0;
(vi VIC0ADDRESS) = 0;
(vi VIC1ADDRESS) = 0;
/*4.恢复现场*/
__asm__(
"ldmfd sp!, {r0-r12, pc}^ \n"
:
:
);
}
void irq_init()
{
/*1.设置中断触发方式*/
(vi EXT_INT_0_CON) &= ~((0x7 << 0) | (0x7 << 4) | (0x7 << 8));/*K1-K6双边沿触发*/
(vi EXT_INT_0_CON) |= ((0x2 << 0) | (0x2 << 4) | (0x2 << 8));
(vi EXT_INT_1_CON) &= ~((0x7 << 4) | (0x7 << 8));/*K7-K8下降沿触发*/
(vi EXT_INT_1_CON) |= ((0x2 << 4) | (0x2 << 8));
/*2.使能外部中断,要用到VICINT控制寄存器*/
(vi EXT_INT_0_MASK) = 0; /*使能EINT0--EINT27所有的外部中断*/
(vi VIC0INTENABLE) |= 0x3; /* bit0: eint0~3, bit1: eint4~11 */
(vi VIC1INTENABLE) |= 0x3; /* bit0: eint12~19, bit1: eint20~27 */
/*3.注册中断处理函数*/
(vi EINT0_VECTADDR) = (int)key1_4handle; /* 用户按下key时,CPU就会自动的将VIC0VECTADDR0的值赋给VIC0ADDRESS并跳转到这个地址去执 */
(vi EINT1_VECTADDR) = (int)key5_6handle;
(vi EINT19_VECTADDR) = (int)key7_handle;
(vi EINT20_VECTADDR) = (int)key8_handle;
/*4.开启向量中断模式*/
__asm__(
"mrc p15,0,r0,c1,c0,0\n"
"orr r0,r0,#(1<<24)\n"
"mcr p15,0,r0,c1,c0,0\n"
"mrs r0,cpsr\n"
"bic r0, r0, #0x80\n"
"msr cpsr, r0\n"
:
:
);
}
12.测试文件
/****************************
@File:main.c
@
@Tiny6410裸机上学期代码
@按键中断文件
@Author:小君君
@****************************/
#include "common.h"
int main(void)
{
//mmu_init();//MMU初始化,这里不使用MMU
led_init();//LED的GPIO初始化
button_init();//按键初始化
irq_init();//中断初始化
led_on();//点亮4颗LED
while(1)
;
return 0;
}