最新帖子 精华区 社区服务 会员列表 统计排行
主题 : Tiny4412裸机程序之中断
admin 离线
级别: 管理员
UID: 1
精华: 1
发帖: 1000
金币: 526 个
银元: 488 个
铜钱: 7883 个
技术分: 601 个
在线时间: 743(时)
注册时间: 2010-04-21
最后登录: 2018-11-21
楼主  发表于: 2015-11-04   

Tiny4412裸机程序之中断

管理提醒: 本帖被 admin 从 阶段1讨论区 移动到本区(2016-11-20)
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"
);
描述
快速回复

如果您在写长篇帖子又不马上发表,建议存为草稿
认证码:

验证问题:
printf("%d",93)
按"Ctrl+Enter"直接提交