十.ARM裸机学习之中断系统2(S5PV210的中断系统详解)

                    版权声明:本文为博主原创文章,允许转载请注明。谢谢!                        <a class="copy-right-url" href=" https://blog.csdn.net/wangweijundeqq/article/details/78634146"> https://blog.csdn.net/wangweijundeqq/article/details/78634146</a>
                </div>
                                                <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-3019150162.css">
                                    <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-3019150162.css">
            <div class="htmledit_views" id="content_views">
一.轮询方式处理按键
参考 E:\Linux\8.key_open

  
  
  1. //按键的初始化
  2. void key_init(void)
  3. {
  4. // GPH0CON的bit8~15全部设置为0,即为输入模式
  5. rGPH0CON &=~( 0xff<< 8);
  6. // GPH2CON的bit0~15全部设置为0,即为输入模式
  7. rGPH2CON &= ~( 0xFFFF<< 0);
  8. }

  
  
  1. void key_polling(void)//轮询方式
  2. {
  3. // 依次,挨个去读出每个GPIO的值,判断其值为1还是0.如果为1则按键按下,为0则弹起
  4. // 轮询的意思就是反复循环判断有无按键,隔很短时间
  5. // 对应开发板上标着LEFT的那个按键
  6. while( 1)
  7. {
  8. if (rGPH0DAT & ( 1<< 2))
  9. {
  10. // 为1,说明没有按键
  11. led_off();
  12. printf( "key left.\n");
  13. }
  14. else
  15. {
  16. // 添加消抖
  17. // 第一步,延时
  18. delay20ms();
  19. // 第二步,再次检验按键状态
  20. if (!(rGPH0DAT & ( 1<< 2)))
  21. {
  22. // 为0,说明有按键
  23. led1();
  24. printf( "key down.\n");
  25. }
  26. }
  27. // 对应开发板上标着DOWN的那个按键
  28. if(rGPH0DAT &( 1<< 3)) // 为1,说明没有按键
  29. {
  30. led_off();
  31. printf( "key down.\n");
  32. }
  33. else // 为0,说明有按键
  34. {
  35. // 添加消抖
  36. // 第一步,延时
  37. delay20ms();
  38. // 第二步,再次检验按键状态
  39. if (!(rGPH0DAT & ( 1<< 3)))
  40. {
  41. // 为0,说明有按键
  42. led1();
  43. printf( "key down.\n");
  44. }
  45. }
  46. // 对应开发板上标着UP的那个按键
  47. if (rGPH2DAT & ( 1<< 0))
  48. {
  49. // 为1,说明没有按键
  50. led_off();
  51. printf( "key down.\n");
  52. }
  53. else
  54. {
  55. // 添加消抖
  56. // 第一步,延时
  57. delay20ms();
  58. // 第二步,再次检验按键状态
  59. if (!(rGPH2DAT & ( 1<< 0)))
  60. {
  61. // 为0,说明有按键
  62. led3();
  63. printf( "key down.\n");
  64. }
  65. }
  66. }
  67. }
二.中断系统 2017/11/21 23:30
1.异常向量表分析:

(1)、复位(RESET)
    a、当处理器复位引脚有效时,系统产生复位异常中断,程序跳转到复位异常中断处理程序处执行,包括系统加电和系统复位。
    b、通过设置PC跳转到复位中断向量处执行称为软复位。
    (2)、未定义的指令
    当ARM处理器或者是系统中的协处理器认为当前指令未定义时,产生未定义的指令异常中断,可以通过改异常中断机制仿真浮点向量运算。
     (3)、软件中断
    这是一个由用户定义的中断指令(SWI)。 该异常由执行 SWI 指令产生, 可用于用户模式下的程序调用特权操作指令。在实时操作系统中可以通过该机制实现系统功能调用。
     (4)、指令与取终止(Prefech Abort)
    如果处理器预取的指令的地址不存在,或者该地址不允许当前指令访问,当被预取的指令执行时,处理器产生指令预取终止异常中断。
     (5)、数据访问终止(DATAABORT)
    如果数据访问指令的目标地址不存在,或者该地址不允许当前指令访问,处理器产生数据访问终止异常中断。
     (6)、外部中断请求(IRQ)
    当处理器的外部中断请求引脚有效,而且CPSR的寄存器的I控制位被清除时,处理器产生外部中断请求异常中断。系统中个外设通过该异常中断请求处理服务。
     (7)、快速中断请求(FIQ)
    当处理器的外部快速中断请求引脚有效,而且CPSR的F控制位被清除时,处理器产生外部中断请求异常中断。
一.CPU 自动处理的过程包括如下:
1、   拷贝 CPSR 到 SPSR_
2、   设置适当的 CPSR 位:   改变处理器状态进入 ARM 状态;改变处理器模式进入相应的异常模式;设置中断禁止位禁止相应中断。
3、   更新 LR_ ,这个寄存器中保存的是异常返回时的链接地址
4、   设置 PC 到相应的异常向量
异常中断处理返回
 二. 异常处理完毕之后,ARM微处理器会执行以下几步操作从异常返回:
    (1)、将所有修改过的用户寄存器从处理程序的保护栈中恢复。 
    (2)、将SPSR复制回CPSR中,将连接寄存器LR的值减去相应的偏移量后送到PC中。 
    (3)、若在进入异常处理时设置了中断禁止位,要在此清除。
    复位异常处理程序不需要返回。

当异常发生时,内核会跳转到向量表的相应位置,并执行当中的指令。 对于每一种异常,保存的返回地址都是不一样的,一般都需要我们手动的跳转,当然调整的时机也需要我们选择,是在进入处理前跳转还是返回时调整都是需要我们程序员控制的。

三.中断处理的第一阶段(异常向量表阶段)处理 。 2017/11/23 22:35
第一个阶段的主要任务是从异常发生到响应异常并且保存/恢复现场、跳转到真正的异常处理程序处
1.查210的iROM application ,iRAM中的异常向量表起始地址为0xD0037400

各个异常对应的入口就等于异常向量表的起始地址+上图中入口的偏移地址:如下图

2.中断处理保存现场,包括:第一:设置IRQ栈;第二,保存LR;第三,保存R0~R12,


1)中断处理要注意保护现场(中断从SVC模式来,则保存SVC模式下的必要寄存器的值)和恢复现场(中断处理完成后,准备返回SVC模式前,要将保存的SVC模式下的必要寄存器的值恢复回去,不然到了SVC模式后寄存器的值乱了,SVC模式下原来正在进行的常规任务就被你搞坏了)
(2)保存现场包括:第一:设置IRQ栈;第二,保存LR;第三,保存R0~R12
(3)为什么要保存LR寄存器?要考虑中断返回的问题。中断ISR执行完后如何返回SVC模式下去接着执行原来的代码。中断返回其实取决于我们进入中断时如何保存现场。中断返回时关键的2个寄存器就是PC和CPSR。所以我们在进入IRQ模式时,应该将SVC模式下的下一句指令的地址(中断返回地址)和CPSR保存起来,将来恢复时才可以将中断返回地址给PC,将保存的CPSR给CPSR。
(4)中断返回地址就保存在LR中,而CPSR(自动)保存在(IRQ模式下的)SPSR中

四、中断处理的第二阶段处理过程
第二个阶段就是进入了真正的异常处理程序irq_handler之后,目的是识别多个中断源中究竟哪一个发生了中断,然后调用相应的中断处理程序来处理这个中断。

1.第一阶段: 找到具体是哪个中断:S5PV210中因为支持的中断源很多,所以直接设计了4个中断寄存器,每个32位,每位对应一个中断源。(理论上210最多支持128个中断,实际支持不足128个,有些位是空的);210没有子中断寄存器,每个中断源都是并列的。当中断发生时,在irq_handler中依次去查询4个中断源寄存器,看哪一个的哪一位被置1,则这个位对应的寄存器就发生了中断,即找到了 中断编号 。
2. 第二阶段, 找到对应的中断服务处理isr:2210开拓了一种全新的寻找isr的机制。210提供了很多寄存器来解决每个中断源对应isr的寻找问题,实现的效果是当发生相应中断时,硬件会自动的将相应isr推入一定的寄存器中,程序员在设置中断的时候,把这个中断的isr地址直接放入这个中断对应的VECTADDR寄存器即可。

S5PV210中断处理的主要寄存器:
VIC0INTENABLE:中断使能
VIC0INTENCLEAR:中断禁止
VIC0INTSELECT:中断选择,IRQ/FIQ
VIC0IRQSTATUS:IRQ中断状态寄存器,软件在处理中断第二阶段的第一阶段,就是靠查询这个寄存器来 得到中断编号 的
VIC0FIQSTATUS:FIQ中断状态寄存器
VIC0VECTADDR :中断源对应的ISR地址,中断发生第二阶段如何 获取isr地址 由这个寄存器自动完成,只需要拿出ISR地址,调用即可
VICnVECTPRIORITY31:中断优先级设置寄存器
VIC0ADDRESS :向量地址寄存器,当有中断发生时,硬件上会将当前中断的中断服务例程ISR地址从寄存器VICVECTADDR自动拷贝到寄存器VICDDR中
总结 : S5PV210的中断体系采用如下的ISR确定策略
(1)、将128个中断源分为4组,每组的ISR组成一个数组,以中断号为数组索引。
(2)、4组ISR数组的首地址分别存放在VICVECTADDR0~VICVECTADDR3中。
绑定ISR时,只需将用户自己编写的ISR地址放入ISR数组中以中断号为索引的位置即可

五、中断处理流程( 参考: http://blog.51cto.com/9291927/1787523 ) 2017/11/24 22:51
S5PV210中断处理流程:
1、中断处理前的准备工作
A、 初始化中断控制器。
外部中断的中断控制器的初始化包括:绑定第一阶段异常向量表;外设相应GPIO引脚设置为外部中断模式、外部中断控制寄存器的初始化、中断向量控制寄存器的初始化。
内部中断的中断控制器的初始化包括:中断向量控制寄存器的初始化,
B、 绑定中断源的ISR到向量中断控制器的VICnVECTADDR。
C、 使能中断源中断。
问题1:如何绑定自己实现的isr到VICnVECTADDR
(1)搞清楚2个寄存器的区别:VICnVECTADDR和VICnADDR( 寄存器在上面已经解释 )
(1)VICVECTADDR寄存器一共有4×32个,每个中断源都有一个VECTADDR寄存器,我们应该将自己为这个中断源写的isr地址丢到这个中断源对应的VECTADDR寄存器中即可。

问题二:真正的中断处理程序如何获取isr?
(1) 当发生中断时,硬件会自动把相应中断源的isr地址从VICnVECTADDR寄存器中推入VICnADDR寄存器中,所以我们第二阶段的第二阶段isr_handler中,只需要到相应的VICnADDR中去拿出isr地址,调用执行即可。

思考问题: 中断处理程序与中断服务 ISR的区别:? (截取的网上的资料)
中断处理程序和中断服务例程ISR是两个非常容易混淆的概念,但两者是两个不同的概念。内核中的中断处理程序与中断服务例程的关系如下图:

     每一个触发中断的中断源对应一个中断处理程序,每一个中断处理程序对应多个中断服务例程。对中断服务例程进行注册后中断服务例程就会挂在中断请求队列中。中断处理程序是中断向量的处理程序,如果多个设备共享一个中断源,中断处理程序必须要调用每个设备的中断服务例程ISR。
    在裸机中,由于每个中断源(终端编号)只有一个对应的中断向量地址寄存器VICVECTADDR,所以每一个中断处理程序只有一个中断服务例程。
2、中断处理流程
A、 异常向量表跳转到IRQ入口
CPU处理常规任务时收到中断的通知,于是S5PV210根据iROM固化代码跳转到iRAM的异常向量表的IRQ异常向量地址。一般将负责保护现场、处理中断、恢复现场的汇编代码段的起始地址赋值给IRQ异常向量地址,作为处理中断的入口。
B、 保护中断现场(在start.S中),然后跳入isr_handler
处理中断之前先要保护总线 现场,主要工作是:设置IRQ模式下的栈,将R0-R12,LR压栈保存(由于流水线的原因,LR一般为当前执行的指令地址加8,LR减去4就是下一条要运行指令的地址)。
C、 执行中断处理程序
在isr_handler中先去搞清楚是哪个VIC中断了。查看VICnADDR寄存器是否有ISR函数地址,如果有,执行ISR。一般在中断发生之前已经绑定好ISR到VICnVECTADDR。
D、 恢复现场
执行ISR后,将栈中的R0-R12,LR分别出栈R0-R12,PC,程序将根据PC的值自动跳转会到常规任务执行。

  
  
  1. // 在这个汇编函数中,用来做中断模式下的现场保护和恢复,并且调用真正的中断处理程序
  2. IRQ_handle:
  3. // 设置IRQ模式下的栈
  4. ldr sp, =IRQ_STACK
  5. // 保存LR
  6. // 因为ARM有流水线,所以PC的值会比真正执行的代码+8,
  7. sub lr, lr, #4
  8. // 保存r0-r12和lr到irq模式下的栈上面
  9. stmfd sp!, {r0-r12, lr}
  10. // 在此调用真正的isr来处理中断
  11. bl irq_handler
  12. // 处理完成开始恢复现场,其实就是做中断返回,关键是将r0-r12,pc,cpsr一起回复
  13. ldmfd sp!, {r0-r12, pc}^




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值