嵌入式arm(六)关于中断和按键中断示例

零 前言

本文只供参考按键中断程序示例,arm裸机编程始终不是最终的目标,能够完成简单的外设驱动,能理解裸机编程流程即可,要不求甚解,最后的目标还是系统移植,还是在linux下编程,所以不要对学不会裸机编程过于烦躁。
异常的相关概念和响应,到底哪个放在前面好理解呢?我认为先知道异常的相应原理再去看概念容易被接受,但是不知道有哪些概念,又无法知道响应时到底在干嘛。所以本文还是按先概念再相应原理的顺序来安排,但是本文读者应该是有基础的开发者,因此可以自由翻阅,或者先大致浏览概念,仔细看过异常相应之后再来详细看概念。

一 ARM的异常与中断

概述:当异常发生时,处理器会把pc设置为一个特定的地址,即让程序跳转到那个地址去执行那里的指令;这个地址位于中断向量表中,表中是固定好顺序的几个跳转指令;
存储器映射地址0x0是为向量表保留的,很多处理器的向量表都是从0x0地址开始;在某些操作系统如linux中,向量表地址可以选择到其他地址开始;

1 异常有哪些

1.1 七种异常的信息收集表

arm的异常总共有7种。

异常类型 英文名 处理器模式 优先级 返回地址 返回地址的用途 执行地址
复位异常 reset svc特权模式 1 - 复位没有lr 0x0
未定义指令异常 undefined interrupt undefined未定义指令中止模式 7 lr 指向未定义指令的下一条指令 0x04
软中断异常 swi svc特权模式 6 lr 指向swi指令的下一条指令 0x08
预取异常 prefetch abort abort指令预取中止模式 5 lr-4 指向导致预取指令异常的那条指令 0x0c
数据异常 data abort abort数据访问中止模式 2 lr-8 指向导致数据中止异常的指令 0x10
外部中断异常 irq irq外部中断请求模式 4 lr-4 指向发生异常时正在执行的指令 0x18
快速中断异常 fiq fiq快速中断请求模式 3 lr-4 指向发生异常时正在执行的指令 0x1c

注:0x14地址未使用;

1.2 七种异常的产生
1.2.1 复位异常

通常用于系统上电和软硬件导致系统复位两种情况,产生复位异常中断。
复位即从头开始,复位异常中断处理程序进行的是初始化工作。下面列出一些常见的工作:

  • 初始化数据栈和寄存器;
  • 初始化存储系统,如系统的MMU;
  • 初始化关键的I/O设备;
  • 使能中断;
  • 将处理器切换到合适的模式;
  • 初始化C变量,跳转到应用程序执行;
1.2.2 未定义指令异常

见名知意,就是arm遇到了一条未定义的指令,这种情况不是应该报错吗?为啥还有专门的异常。
因为有协处理的存在,arm中有专门的协处理器指令来操作它,如果程序中写了协处理器指令,但是外部的协处理器未响应,或者根本没有协处理器时,无法执行,则发生未定义指令异常;也就是说,这是一种与硬件相关的异常,而不是一种语法错误,与编译器无关;
我们可以利用它的这种特点,来实现指令集的扩展:
协处理器有很多种,选择当前系统中没有的协处理器,运行其相关的指令,使之可以发生未定义指令异常,在异常处理程序中放上自己想要的代码,可以仿真这种协处理器的功能,也可以干别的事。
如果要仿真,步骤如下:
(1) 将仿真程序入口地址链接到向量表中0x4处。(在start.s中)
(2) 读取该未定义指令的bits[27:24]位,判断其是否是一条协处理器指令,0b1110或者0b110x是协处理器指令,然后根据[11:8]位判断具体是哪一条指令,然后实现其功能;
不仿真的话,就在中断处理程序中写自己的代码;

1.2.3 软中断异常

软中断由swi指令产生,即由程序中的代码产生,与硬件电路无关;软中断进入的是svc模式;

1.2.4 预取异常

由系统存储器报告,当处理器去取一条被标记为预取无效的指令时,发生预取异常。
如果系统中不包含MMU,指令预取异常中断处理程序只是简单报告错误并退出,否则引起异常的指令的物理地址被存储到内存中。

1.2.5 数据异常

数据异常:当存储器访问指令load/store执行,但目标地址不存在或者该地址不允许访问时,由存储器发出数据终止信号。

1.2.6 外部中断异常

当处理器的外部中断请求引脚有效,而且CPSR的I位被清0,产生外部中断异常。

1.2.7 快速中断异常

当快速中断请求引脚有效且CPSR寄存器的F位被清0,发生快速中断异常。

2 异常的优先级

优先级高的优先执行;

3 异常与处理器模式

每种异常都会进入一种特定的模式。
用户模式和系统模式不可通过异常进入,只能通过编程来切换。也就是说,在中断处理程序的最后要切换回用户模式;

4 异常的响应与返回

4.1编程时需要知道的:
4.1.1 异常发生时
4.1.1.1 系统做了什么?

(1) 用spsr保存cpsr;
(2) 改CPSR寄存器:

  • 改工作模式;
  • 让处理器模式为:arm;
  • 禁止中断;(如果需要)
    (3) 保存返回地址到lr;
    (4) 设置pc为相应的中断向量;
4.1.1.2 程序需要做什么?

保存现场到栈区:
用连续地址访问指令ldrm把用到的寄存器和lr一次性保存到栈区我们自己申请的空间内;

4.1.2 当中断程序执行完之后, 程序需要做什么?

(1) 恢复现场–》恢复寄存器的值:用连续地址访问指令strm把栈区我们自己申请的空间内的数据放回到异常之前的寄存器和lr中;
(2) 将spsr的值恢复到cpsr–》恢复工作模式,工作模式不会自动回复,需要我们手动恢复;
(3) 恢复lr到pc—》继续执行之前的代码;那不如直接把栈中的数据返回到pc中,不要中间经过lr;

4.2 来看详细的
4.2.1 arm响应流程

1.判断处理器状态
上述4.1.1.1中的切换处理器状态,异常发生时,处理器自动切换到arm状态,所以在异常处理函数中要判断,在异常发生前,是arm还是thumb状态,通过spsr的T位可以判断。
一般只在swi处理函数中才需要知道异常发生前处理器的状态,所以在thumb状态下,调用swi软中断异常需要注意:发生异常的指令地址是lr-2而不是lr-4;thumb是16位指令,用LDRH指令来判断中断向量号;
2.向量表
每个异常发生时,程序都会从异常向量表中开始跳转,一般向量表中放的就是跳转指令;
其中FIQ向量地址是0x1c,也就是最后一个向量,那么,FIQ_Handler()可以直接从0x1c开始,省下一条跳转指令;

4.2.2 关于返回地址

1.1表中列出了每种异常在返回时需要跳转的地址;
解释:
根据三级流水线,假设有连续的三条指令a; b; c; d; 当处理器将要执行a指令时,pc已经在c指令的地址即pc+8,所以pc-8是a的地址,pc-4是b的地址;
当异常发生时,处理器会把正在执行的指令的下一条指令的地址保存在lr中,也就是pc-4;所有异常都是如此,但是根据不同异常的发生方式,在返回时,还需要对lr上的地址做一点处理;
(1) swi和未定义指令异常,在执行指令时处理异常,返回地址就是lr;
(2) IRQ和FIQ,处理器会把当前指令执行完再处理异常,处理中断时pc已经指到了d指令,所以保存在lr中的pc-4指的是c指令;而我们要返回到b指令,在返回时,需要再补-4才能回到b指令,所以返回地址是lr-4;
(3) 指令预取中止异常,比如b指令是一个无效指令,在预取b指令的时候,b会被标记为预取无效,同时b之前的指令仍然正常运行,当执行到b,pc指d,预取中止异常发生,pc-4也就是c的地址被写入lr,好像跟(1)中一样,但是预取中止异常时程序要返回到b指令那里取读b指令,要返回到b处,对lr补-4;所以返回地址是lr-4;
(4) 数据中止异常,实在访问数据出错时候产生的,也就是在数据访问指令执行结束后才发生异常,而所以返回地址应该为lr-4,但中止异常返回时,需要返回到导致异常的指令,因此再补-4;所以最后返回地址是lr-8;例如执行a访问数据,pc指c,访问出错发生异常是在a执行后,pc指d,而异常返回要求返回到a,所以lr-4指向b,所以要用lr-8返回a;
(5) 复位异常不需要返回地址;

</

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值