CPU运行过程中怎么检测外部事件的发生呢,如usb设备插入,按键按下。
1.通过查询的方式,程序循环查询设备的状态,实现比较简单就是占用CPU资源比较高。
2.中断的方式,当事件发生时主动触发一个中断,CPU会终止当前正在执行的任务,响应中断,调用相应的中断处理程序,等中断处理完
继续执行当前的任务。
我们以按键为例,前面有用查询的方式检测按键是否按下,现在看程序以中断方式监测到按键按下要做哪些步骤:
1.设置CPU允许相应中断,通过配置CPSR的I位打开中断
__asm__ __volatile__(
"mrs r0, cpsr\n"
"bic r0, r0, #0x80\n"//设置CPSR的I位,将IRQ位打开
"msr cpsr, r0\n"
::: "r0"
);
或
__asm__ __volatile__ (
"cpsie i\n"
);
2.配置GIC相关寄存器,GIC是4412内部的中断控制器,由GIC来管理中断的响应,分发. 主要配置打开中断,设置中断优先级,设置中断源
配置如下:
ICCICR_CPU0 = 1; //允许CPU0响应中断
ICCPMR_CPU0 = 0xff; //设置各个中断的优先级
// 配置接收按键K1的中断,4412有160个中断号,K1对应64,配置64号中断源相关寄存器
ICDDCR = 1; //需要enable的中断的开关,K1
ICDIPR16_CPU0 = ~(0xff << 0); //配置64号中断优先级
ICDIPTR16_CPU0 = (1 << 0); //选择CPU0处理64号中断
ICDISER2_CPU0 = (1 << 0); //64号中断enable
3.设置控制K1的GPIO口GPX3为中断方式,GPIO可以配置成输入,输出,特殊功能,或作为中断触发的接口。
GPX3CON &= ~(0x7 << 8);
GPX3CON |= (0xf << 8); //从电路图可以看出中断源XEINT26,对应中断号64.
EXT_INT43CON &= ~(0x7 << 8);
EXT_INT43CON &= ~(0x3 << 8); //设置中断触发方式
EXT_INT43_MASK &= ~(0x1 << 2); //打开EINT26中断
4.构建异常向量表,当异常发生时,cpu会跳到相应的地址(基地址0x00000000或0xffff0000)去执行指令,如发生swi异常跳到0x08去执行,发生irq中断
时跳到0x18,所以我们要把发生各种异常时要执行的指令放到相应的地址去,就叫做异常向量表,如下,我们需要把如下代码拷贝到0x00000000或0xffff0000
去,因为4412的0x00处是IROM只读,所以只能拷到0xffff0000,拷之前还要打开MMU,映射0xffff0000,把异常向量表拷贝到0xffff0000。
当上面的步骤配置好按下K1时就会触发irq中断,当发生irq中断时就会执行b irq,大致就是保存相应寄存器,执行中断处理函数do_irq,在do_irq里我们可以根据寄存器状态判断
是哪个中断发生了,中断处理完后需要恢复中断前状态。
void do_irq(unsigned long regs[])
{
if (EXT_INT43_PEND & (1 << 2)) {
printf("ExtInt43_2 \n");
EXT_INT43_PEND = (1 << 2);
}
}
unsigned long *pdo_irq = 0x75000000;
*pdo_irq = do_irq;
__asm__ (
"vectors:\n"
"b reset\n" //0x00: reset的向量地址
"b und\n" //0x04: 未定义指令中止模式的向量地址
"b swi\n" //0x08: 管理模式的向量地址,通过SWI指令进入此模式
"b pre_abt\n" //指令预取终止导致的异常的向量地址
"b dat_abt\n" //数据访问终止导致的异常的向量地址
".word 0\n" //0x14: 保留
"b irq\n" //0x18: 中断模式的向量地址
"b fiq\n" //0x1c: 快中断模式的向量地址
"reset:\n"
"und:\n"
"mov sp, #0x74000000\n"
"stmfd sp!, {r0-r12, lr}\n"
"mov r0, sp\n"
"mov r3, #0x74000000\n"
"ldr r3, [r3]\n"
"blx r3\n"
"mov sp, #0x74000000\n"
"ldmea sp, {r0-r12, pc}^\n"
"swi:\n"
"pre_abt:\n"
"dat_abt:\n"
"fiq:\n"
"irq:\n"
"mov sp, #0x75000000\n"
"sub lr, lr, #4 \n"
"stmfd sp!, {r0-r12, lr}\n" //保存寄存器
"mov r0, sp\n"
"mov r3, #0x75000000\n"
"ldr r3, [r3]\n"
"blx r3\n" //跳到0x75000000处的中断处理函数执行
"mov sp, #0x75000000\n"
"ldmea sp, {r0-r12, pc}^\n" //恢复寄存器
"EOV:\n"
"vectors_start:\n"
".word vectors\n"
"vectors_end:\n"
".word EOV\n"
);
代码位置:https://github.com/cyj1988jyc/luoji4412/