• 中断


    什么是中断?

    • (1)中断的发明是用来解决宏观上的并行需要,宏观就是整体上看,并行就是多个事情同时完成了。
    • (2)微观上的并行,就是指的真正的并行。就是精确到每1s甚至每1ms每一刻,所以宏观上的并行并不等于微观上的并行

    为什么需要中断?

    • 因为单核CPU实际无法并行的,但是可以通过中断机制实现假并行(宏观上并行,微观上实际还是串行的)

    SoC对中断的实现机制:异常向量表

    • 异常两项表是CPU中某些特定地址的特使定义。当中断发生的时,中断要想办法通知CPU去处理中断,怎么做到?这就要靠异常向量表
    • 在CPU设计师,就实现定义了CPU中一些特定位作为特定异常的入口地址(譬如0x00000000地址为复位异常向量地址,则发生复位异常时,CPU会自动跳转到0x00000000地址去执行复位命令。又譬如说外部中断对应的异常向量地址位0x30000008,则发生外部中断后硬件会自动跳转到0x30000008地址去执行指令。)
    • 以上我们讲的是CPU硬件设计时对异常向量表的支持,那么下面要做的就是把处理这个异常的代码地址填入这个异常向量地址

    s5pv210的异常向量表

    • 异常向量表中相对位置是固定的,但是他们的其实位置却是各个SoC不一样的。而且复杂ARM还可以让用户来软件设置这个异常向量表的基地址
    • 扩展到所有架构的CPU中:所有架构(譬如51单片机、PIC单片机)的CPU实现中断都是通过异常向量表实现的,这个机制是不变的,但是不同的CPU的异常向量表的构造和位置是不变的。

    异常和中断的区别和联系

    • 针对SoC来说,发生复位、软终端、中断、快速中断、取指令异常、数据异常等,我们都统一叫异常。所以说:中断其实是异常的一种
    • 异常的定义就是突发事件,打断了CPU正常的常规业务,CPU不得不跳转到异常向量表中去执行异常处理程序。中断是异常的一种一般特指SoC内部外设产生的打断SoC常规业务,或者外部中断(SoC的GPIO引脚传回来的中断)

    异常向量表的编程处理

    像访问内存一样访问异常向量表

    • S5PV210的异常向量表可以改变(在CP15协处理器中),以适应操作系统要求。但是目前系统刚启动时,此时DRAM尚未初始化,程序运行都在SRAM中。210在iRAM中设置异常向量表,供暂时性使用。
    • 查210的iROM application note文档中的iROM的地址分配,可以知道,iRAM中异常向量表的其实地址是0xD0037400,知道了异常向量表的起始地址后,各个异常对应的入口就很好知道了 。

     函数名的是指就是函数的首地址

    • 函数名在C语言中的理解方法和变量名其实没有区别,编译器会把这个函数的函数体对应的代码段和这个函数的函数名(实质是符号)对应起来,等我们使用这个函数名符号时,编译器会将这个函数的函数体实际上做替换。因为函数一般都比较长一般会超过4字节,而函数名这个符号只能对应1个地址,所以实际对应的是函数体那一段代码的首地址
    • 拿C语言中的语法来讲,函数名就是这个函数的函数指针。

    总结:当我们将异常处理程序的首地址和异常向量表绑定起来后,异常处理初步阶段就完成了,到目前可以保证相应异常发生后,硬件自动跳转到对应异常向量表入口去执行时,可以执行到我们事先绑定的函数。

    为什么中断处理要实现在汇编中进行

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

     汇编保存现场和恢复现场

    • 保存现场:关键是保存中断处理程序的返回地址,r0-r12(CPSR是自动的)
    • 恢复现场:主要是恢复r0~r12,pc,cpsr

    S5PV210的向量中断控制器

    可以将异常处理分为2个阶段来理解。第一个阶段是异常向量表跳转;第二个阶段就是进入了真正的异常处理程序irq_hander之后的部分

    中断处理的第一阶段:异常向量表处理

    (1)第一阶段之所以能够进行,主要依赖于CPU设计时提供异常向量表机制。第一阶段主要任务是从异常发生到响应异常并且保存/恢复现场

    (2)第二个阶段的目的是识别多个中断源中究竟是哪一个发生了中断,然后调用相应的中断处理程序来处理这个中断

    S3C2440第二阶段处理过程

    • 第一个问题:怎么找到具体是哪个中断?

    S3C2440的中断控制器有一个寄存器(32位),寄存器的每一位对应着一个中断(为了解决支持更多中断源,2440又设计了一个子中断机制。在一级中断寄存器中,有一些)

    • 第二个问题,怎么找到对应的isr的问题?

    首先给每个中断做一个编号,进入isr_handler之后先通过查阅中断源寄存器和自中断寄存器(中哪一位位1)确定编号。然后用编号去isr数组(isr数组是事先设定好的,就是把各个中断的isr的函数名组成一个数组,用中断对应的编号作为索引来查询这个数组)中查阅找到isr地址

    评价:2440的中断处理设计不是特别优秀,第一个过程使用中断使用2级的很麻烦,第二个过程计算中断编号也很麻烦。而中断处理的时间是很宝贵的(系统有一个性能指标叫做实时性,实时性就是中断发生到响应时间,这个时间越短越好)

    S5PV210的第二个阶段处理过程

    • 第一个问题,怎么找到具体是哪个中断?

    S5PV210中,因为支持的中断源很多,所以直接设计了4个中断寄存器,每个32位,每位对应一个中断源理论上210最多支持32*4=128个中断,实际上支持不足128个,即有些位是空的。210没有子中单寄存器,每个中断源都是并列的。当中断发生时,在irq_hander中依次去查询4个中断寄存器,看哪一个的哪一位被置1,则这个位对应的寄存器就发生了中断,即找到了中断编号。

    • 第二个问题,怎么找到对应的isr问题?

    210中支持的中断源多了很多,如果继续使用2440的方法来寻找isr地址就太慢了,太影响实时性了。于是210开拓了一种全新的寻找isr机制。210提供了很多寄存器来解决每个中断源对应isr的寻址问题。具体的效果是当发生中断时,硬件会自动将相应的isr推入到一定的寄存器中,我们软件只要去这个寄存器中执行函数就行了。

    总结:第一阶段都相同,第二阶段各不同

    第一阶段(异常向量表)2440和210几乎完全相同。实际上几乎所有的cpu在第一阶段都是相同的

    第二阶段就彼此不同了。各个CPU根据自己对实时性的要求和支持的中断源的多少,各自发明了各自处理中断,找到编号,进一步找到isr地址的方式。

    S5PV210中断处理的主要寄存器

    • VICnINTENABLE和VICnINTENCLEAR

    VICnINTNABLE对应interrupt enable ,该寄存器负责相应的中断的使能

    VICnINTENCLEAR对应interrupt enable clear,负责相应的中断的禁止

    当我们想使能(意思就是启用)某个中断时,只要在这个中断编号对应的VICnINTENABLE的相应bit位写1即可(注意这个位写1,其他位写0对其他位没影响)。

    如果我们想禁止某个中断源,只要向VICnINTENCLEAR中相应的位写入1即可。

    注意:这里的设计一共有2种:有些CPU是中断使能和禁止是一个寄存器位,写1就使能写0就禁止(或者反过来写1禁止,写0使能),这样的设计就要非常小心,要使用我们之前说过的读改写的操作方法。另外一种就是使能和禁止是分开的两个寄存器,要禁止就写禁止寄存器,要使能就写使能寄存器,这样的好处就是我们禁止和使能时不需要读改写,只需要写就可以了。

    • VICnINTSELECT

    设置各个中断的模式为IRQ还是FIQ。一般都设置成IRQ

    IRQ和FIQ到底有什么区别?

    210中支持2种中断,IRQ和FIQ。irq是普通中断,fiq是快速中断,从而保证实时性。fiq的限制就是只能有一个中断源被设置位fiq,其他都是irq。

    CPU如何保证fiq比irq快?

    有两个原因:第一fiq有专用的r8~r12,因此在fiq的isr中可以直接使用r8~r12而不用保存,这样就能节省时间。第二,异常向量表中fiq是最后一个异常向量入口。因此fiq的isr不需要跳转,可以直接写在原地,这样就比其他遗产钢箱梁少跳转一次。省了一些时间

    • VICnIRQSTATUS和VICnFIQSTATUS

    中断状态寄存器,是只读的。当发生中断时,硬件会自动将该寄存器的对应位置置1,表示中断发生了。

    软件在处理中断第二阶段时,就是靠查询这个寄存器来得到中断编号的

    • VICnVECTPRIORITY0~VICVECTPRIORITY31

    中断优先级设置寄存器,设置多个中断同时发生时,先处理谁后处理谁的问题。一般来说高优先级的中断可以打断低优先级的中断,从而嵌套处理中断。当然了,有些硬件和软件可以设置不支持中断嵌套。

    • VICnVECTADDR0~VICnVECTADDR31、VICnADDR

    这些寄存器和210中断处理第二阶段的第二阶段有关

    VICnVECTADDR0到31这32个寄存器分别用来存放真正的各个中断对应的isr的函数地址,相当于每一个中断源都有一个VECTADDR寄存器,程序员在设置中断时,把这个中断的isr地址直接放入这个中断对应的VECTADDR寄存器中即可。

    VICnADDR这个寄存器是只需要读的。它里面的内容是硬件自动设置的。当发生了相应的中断时,硬件会自动识别中断编号,然后将其复制到VICnADDR中,供我们使用。

    S5PV210中断处理的编程实践

    中断控制器初始化

    • 主要工作有:第一阶段绑定异常向量表到异常处理程序;禁止所有中断源,选择所有中断类型位IRQ;清理VICnADDR寄存器位0。

    中断的使能与禁止

    • 思路就是先根据中断号判断这个中断属于VIC几,然后再用中断源减去这个VIC的偏移量,得到这个终端号在本VIC中的偏移量,然后1<<x位,写入相应的VIC的VIC的INTENABLE/INTENCLEAR寄存器即可。

    绑定自己实现的isr到VICnVECTADDR

    • 搞清楚这两个寄存器的区别:VICnVECTADDR和VICnADDR
    • VICVECTADDR寄存器一共有4*32个,每个中断源都有一个VICADDR寄存器,我们应该将自己为这个中断源写的isr地址丢到这个中断源对应的VECTADDR寄存器中即可。

    真正的中断处理程序如何获取isr

    当发生中断是,硬件会自动把相应的中断源的isr地址从VICnVECTADDR寄存器推入到寄存器中,所以我们第二阶段的第二阶段isr_hander中只需要到相应的VICnADD中拿出isr地址,调用即可。

    总结:第4步绑定isr地址到VICnVECTADDR和第5步中断发生时第二阶段的第二阶段如何获取isr地址,这两步是相关的。这两个的结合技术就是我们一直在说的S5PV210的硬件自动寻找isr机制

    整个中断的工作分为两个部分:

    第一部分是我们位中断相应而做的预备工作

    • 初始化中断控制器
    • 绑定好isr到中断控制器
    • 相应中断的所有条件使能

    第二部分是当硬件产生中断后如何自动执行isr

    • 第一步:经过异常向量表跳转到IRQ/FIQ的入口
    • 第二步:在start.s中做中断的现场保护,然后跳入isr_hander
    • 第三步:在isr_hander中先去搞清楚是哪个VIC中断了,然后直接去这个VIC和ADDR寄存器中取isr来执行即可
    • 第四步:isr执行完,中断现场恢复,直接返回继续做常规任务

    外部中断

    什么是外部中断?数据手册在哪里?

    • (1)SoC支持的中断类型中有一类叫外部中断。内部中断就是指的中断源来自于SoC内部(一般是内部外设),譬如串口、定时器等部件产生的中断;外部中断是SoC外部的设备,通过外部中断对应的GPIO引脚产生的中断。
    • (2)按键在SoC中就使用外部中断来实现。具体实现方法是:将按键电路接在外部中断的GPIO上,然后将GPIO配置为外部中断模式。此时人通过按按键改变按键电路的电压高低,这个电压高低会触发GPIO对应的外部中断,通过引脚传进去给CPU处理。
    • (3)外部中断相关的介绍和寄存器在2.2.6章节(属于GPIO部分)

    电平触发和边沿触发

    外部中断的触发模式主要有2种:电平触发和边沿触发。

    • (1)电平触发就是说GPIO上的电平只要满足条件,就会不停触发中断。电平触发分为高电平触发和低电平触发。电平触发的特点是,只要电平满足条件就会不停触发中断。
    • (2)边沿触发分为上升沿触发、下降沿触发和双边沿触发三种。边沿触发不关心电平常规状态,只关心电平变化的瞬间(边沿触发不关心电平本身是高还是低,只关心变化是从高到低还是从低到高的这个过程)。

    分析按键的工作:如果我们关注的是按键按下和弹起这两个事件本身,那么应该用边沿触发来处理按键;如果我们关心的是按键按下/弹起的那一段时间,那么应该用电平触发。

    关键寄存器:CON、PEND、MASK

    • (1)外部中断的主要配置寄存器有3个:EXT_CON、EXT_PEND、EXT_MASK
    • (2)EXT_CON配置外部中断的触发方式。触发方式就是说外部电平怎么变化就能触发中断,也就是说这个外部中断产生的条件是什么
    • (3)EXT_PEND寄存器是中断挂起寄存器。这个寄存器中每一位对应一个外部中断,平时没有中断时值为0。当发生了中断后,硬件会自动将这个寄存器中该中断对应的位置1,我们去处理完这个中断后应该手工将该位置0。这个PEND寄存器的位就相当于是一个标志,如果发生了中断但是我们暂时忙来不及去处理时,这个位一直是1(这就是挂起),直到我有空了去处理了这个中断才会手工清除(写代码清除)这个挂起位表示这个中断被我处理了。
    • (4)EXT_MASK寄存器就是各个外部中断的使能/禁止开关。

    分析X210开发板的按键对应的EINT编号:

    • EINT2、EINT3、EINT16、EINT17、EINT18、EINT19

    中断方式处理按键编程实践1

    • 外部中断对应的GPIO模式设置
    • 中断触发模式设置
    • 中断允许、清挂起
    • 中断处理程序isr编写
    • 总结对比:轮询方式处理按键和中断方式的差异

    中断方式处理按键编程实践2

  • 相关阅读:
    BTC比特币全节点部署
    redis缓存层实现redission
    thinkphp5日志文件权限的问题
    MYSQL查两个经纬度之间的直线距离,计算出的单位:米
    thinkphp 建单独的日志目录
    VSCode远程连接Linux服务器
    Linux smb 的挂载和取消挂载及解决类似umount target is busy挂载盘卸载不掉问题
    System limit for number of file watchers reached
    JavaScript 字符串方法
    Linux下常用压缩 解压命令和压缩比率对比
  • 原文地址:https://www.cnblogs.com/jxjl/p/7095528.html
Copyright © 2020-2023  润新知