首页 S3C2440的中断学习经验

S3C2440的中断学习经验

举报
开通vip

S3C2440的中断学习经验S3C2440的中断学习经验 一直在看2440的中断处理部分,不懂的实在太多了,百度到这篇文章,实在有听君一席话,胜养十年猪的感觉啊,下面上文章: 中断向量 b HandlerIRQ ;handler for IRQ interrupt 很自然,因为所有的单片机都是那样,中断向量一般放在开头,用过单片机的人都会很熟悉,那就不多说了。 异常服务程序 这里不用中断(interrupt)而用异常(exception),毕竟中断只是异常的一种情况, 下面主要分析的是“中断异常”说白了,就是我们平时单片机里面用的...

S3C2440的中断学习经验
S3C2440的中断学习经验 一直在看2440的中断处理部分,不懂的实在太多了,百度到这篇文章,实在有听君一席话,胜养十年猪的感觉啊,下面上文章: 中断向量 b HandlerIRQ ;handler for IRQ interrupt 很自然,因为所有的单片机都是那样,中断向量一般放在开头,用过单片机的人都会很熟悉,那就不多说了。 异常服务程序 这里不用中断(interrupt)而用异常(exception),毕竟中断只是异常的一种情况, 下面主要分析的是“中断异常”说白了,就是我们平时单片机里面用的中断~~~所有由器件引起的中断,例如TIMER中断,UART中断,外部中断等等,都有一个统一的入口,那就是中断异常 IRQ ! 然后从IRQ的服务函数里面分辨出,当前究竟是什么中断,再跳转到相应的中断服务程序。这样看来,ARM比单片机要复杂一些了,不过原理是不变的。 上面说的就是思路,跟着这个思路来接着分析。 HandlerIRQ 很明显是一个标号,我们找到了 HandlerIRQ HANDLER HandleIRQ 这里是一个宏定义,我们再找到这个宏,看他是怎么定义的: MACRO $HandlerLabel HANDLER $HandleLabel $HandlerLabel sub sp,sp,#4 ;decrement sp(to store jump address) stmfd sp!,{r0} ;PUSH the work register to stack(lr does not push because it return to original address) ldr r0,=$HandleLabel ;load the address of HandleXXX to r0 ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR) MEND 用 HandlerIRQ 将这个宏展开之后得到的结果实际是这样的 HandlerIRQ sub sp,sp,#4 ;decrement sp(to store jump address) stmfd sp!,{r0} ;PUSH the work register to stack(lr does not push because it return to original address) ldr r0,=HandleIRQ ;load the address of HandleXXX to r0 ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR) 至于具体的跳转原理下面再说, 好了,这样的话就容易看的多了,很明显, HandlerIRQ 还是一个 标号,IRQ异常向量就是跳转到这里执行的,这里粗略看一下,应该是 保存现场,然后跳转到真正的处理函数,那么很容易发现了这么一句 ldr r0,=HandleIRQ ,没错,我们又找到了一个标号 HandleIRQ ,看 来真正的处理函数应该是这个 HandleIRQ ,继续寻找 AREA RamData, DATA, READWRITE ^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00 HandleReset # 4 HandleUndef # 4 HandleSWI # 4 HandlePabort # 4 HandleDabort # 4 HandleReserved # 4 HandleIRQ # 4 HandleIRQ ,^ 其实就是 MAP ,这段程序最后我们发现在这里找到了 的意思是,从 _ISR_STARTADDRESS 开始,预留一个变量,每个变量一个标号,预留的空间为 4个字节,也就是 32BIT,其实这里放的是真正的C写的处理函数的地址,说白了,就是函数指针 - - 这样做的话就很灵活了 接着,我们需要安装IRQ处理句柄,说白了,就是设置处理函数的地址,让PC指针可以正确的跳转。 于是我们在接着的找到安装句柄的语句 ; Setup IRQ handler ldr r0,=HandleIRQ ;This routine is needed ldr r1,=IsrIRQ ;if there is not 'subs pc,lr,#4' at 0x18, 0x1c str r1,[r0] IsrIRQ 的地址填到 HandleIRQ对应的地址里面,前面说说白了就是将 了 HandleIRQ 放的是中断处理的函数的入口地址,我们继续找 IsrIRQ IsrIRQ sub sp,sp,#4 ;reserved for PC stmfd sp!,{r8-r9} ldr r9,=INTOFFSET ldr r9,[r9] ldr r8,=HandleEINT0 add r8,r8,r9,lsl #2 ldr r8,[r8] str r8,[sp,#8] ldmfd sp!,{r8-r9,pc} 要理解这个代码,得先学学2440的中断系统了,INTOFFSET存放的是当前中断的偏移号,根据偏移就知道当前是哪个中断源发生的中断。 注意了,我们说的是中断,而不是异常,看看原来的表是啥样子的 ^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00 HandleReset # 4 HandleUndef # 4 HandleSWI # 4 HandlePabort # 4 HandleDabort # 4 HandleReserved # 4 HandleIRQ # 4 HandleFIQ # 4 HandleEINT0 # 4 HandleEINT1 # 4 HandleEINT2 # 4 HandleEINT3 # 4 ....... 可以看到,前面几个是异常,从 HandleEINT0 就是 IRQ异常的向量存放的地方了,这样就可以理解为什么上面 IsrIRQ 里面里面要执行那条指令 ldr r8,=HandleEINT0 add r8,r8,r9,lsl #2 道理很简单, HandleEINT0 就是所有IRQ中断向量表的入口,在这个地址上面,加上一个适当的偏移量,INTOFFSET ,那么我们知道现在,到底是哪个IRQ在申请中断了。 至于具体怎么跳转的, 首先,我们说了,HandleEINT0 开始的一段内存里面,存放的就是中断服务函数的函数指针,ARM的体系的话,每个指针变量就是占4个字节,这里就解释了,为什么这里为每个标号分配了4个字节的空间,里面放的就是函数指针~~~下面再看看怎么跳转,继续看 IsrIRQ 里面就实现了跳转了 str r8,[sp,#8] ldmfd sp!,{r8-r9,pc} 其实最核心就是这两句了,先查找到当前中断服务程序的地址,将他放到 R8 里面,然后出栈,弹出给PC那么PC很自然就跳到中断服务程序了。至于这里的堆栈问题又是一个非常棘手的,需要好好的参透ARM的中断架构,需要了解的可以自己仔细的阅读 《ARM体系结构与编程》里面说的很详细。我们这里的重点是研究怎么跳转。 最后,我们看看在C代码中是怎么安装终端向量的,例如看 按键的外部中断,是怎么具体设置的,参看/src/keyscan.c 里面的代码很简单,里面只有3个函数 KeyScan_Test 是按键测试的主函数 Key_ISR 是按键中断服务函数 KeyScan_Test里面,我们发现了有这么一句 在 pISR_EINT0 = pISR_EINT2 = pISR_EINT8_23 = (U32)Key_ISR; 可以理解否, Key_ISR就是上面提到的按键中断服务函数,函数的名字,代表的就是函数的地址~~~~ 将中断服务函数的地址,注意了,是地址,这是一个 U32型的变量。送到几个变量,我们以pISR_EINT0 作为例子,查看头文件定义,在 2440addr.h 里面找到 // Interrupt vector #define pISR_EINT0 (*(unsigned *)(_ISR_STARTADDRESS+0x20)) _ISR_STARTADDRESS有没有似曾相识的感觉,没错,刚才分析的汇编代码里面就提到了 ^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00 HandleReset # 4 HandleUndef # 4 ...... 对,地址就是这里,然后 _ISR_STARTADDRESS+0x20 就是跳过前面的异常向量,进入IRQ中断向量的入口,所以说到尾 pISR_EINT0 = (U32)Key_ISR; 完成的操作就是,将 Key_ISR 的地址存放到 HandleEINT0 # 4 这个IRQ向量表里面~~~~ 当按键中断发生的时候,发生IRQ异常中断当前PC值-4 保存到LR_IRQ里面,然后执行 b HandlerIRQ 然后是执行 HandlerIRQ sub sp,sp,#4 ; 预留一个用来存放PC地址 stmfd sp!,{r0} ; 保存R0,因为下面使用了 ldr r0,=HandleIRQ ; 将HandleIRQ(服务程序)的地址装载到R0 ldr r0,[r0] str r0,[sp,#4] ; 保存到刚才预留的地方 ldmfd sp!,{r0,pc} ; 弹出堆栈,恢复R0,并且将刚才计算好的 HandleIRQ 地址弹出到 PC堆栈是向下生长的,所以 SUB SP,SP,#4 就 PUSH XX,但是这个XX这个时候并没有用,因为这里用的是强相当于 制移动 SP 指针实现的。然后得到服务程序的地址,再将这个值放回刚才预留的栈的空位上面,最后就是POP出R0恢复,并且将刚才得到的服务程序的地址送到 PC,那么实现的效果就是跳转到 HandleIRQ 里面了。 接着看刚才是怎么安装的HandleIRQ 的 ; Setup IRQ handler ldr r0,=HandleIRQ ;This routine is needed ldr r1,=IsrIRQ ;if there is not 'subs pc,lr,#4' at 0x18, 0x1c str r1,[r0] 可以看出,这里将 IsrIRQ 的地址的值保存到 HandleIRQ 中,也就是说,上面的 IRQ 服务程序,这个时候实际上就是指 IsrIRQ ~ 所以接着的事情就是转移到 IsrIRQ 中执行: IsrIRQ sub sp,sp,#4 ; 预留一个值来保存PC stmfd sp!,{r8-r9} ldr r9,=INTOFFSET ; 计算偏移量,下面解释 ldr r9,[r9] ldr r8,=HandleEINT0 add r8,r8,r9,lsl #2 ldr r8,[r8] str r8,[sp,#8] ; 因为保存了2个寄存器R8 R9 ,所以SP下移了8位 ldmfd sp!,{r8-r9,pc} ; 恢复寄存器,弹出到PC,同上面的一样 怎么保存,操作SP,跟最后弹出到PC的部分和上面的例子一样,下面说说中间的计算部分计算偏移量,其实原理很简单,首先 INTOFFSET 保存着当前是哪个IRQ中断,例如 0代表着 HandleEINT0,1代表HandleEINT1 ..... 等等,这不是乱来,有一个表的,这个是由 S3C2440 的datasheet说的,自己可以去查看。 然后得到 中断处理函数的向量表,这个表的首地址就是 HandleEINT0,那么很自然的想到,怎么查表,那还不简单,HandleEINT0 + INTOFFSET 不就完了,基地址加偏移量就得到表中某项了,当然,因为这里是中断处理向量 每一项占用4个字节,所以用lsl #2处理一下,左移2位相当于乘以4,偏移量乘以4,这应该很好理解的。 我们这个例子找到的就是 HandleEINT0 ,将里面的值读出来,里面放 的是 HandleEINT0 服务函数的地址,这个地址怎么来的,是在C程序里面设置的。我们看 keyscan.c 程序,找到一个 void KeyScan_Test(void) 函数, 里面有这么一句: pISR_EINT0 = pISR_EINT2 = pISR_EINT8_23 = (U32)Key_ISR; 这里是安装了3个按键中断服务程序,我们只关注 0号中断,也就是 pISR_EINT0 = (U32)Key_ISR; 这句话什么意思,先看看pISR_EINT0的定义,在 2440addr.h 中定义 (*(unsigned #define pISR_EINT0 *)(_ISR_STARTADDRESS+0x20)) 看到没有,_ISR_STARTADDRESS 不就是刚才说的那个异常向量的入口地址,加上一个 0x20 之后实际上指向的,就是 HandleEINT0 ~~~这么说来,上面的意思就是,将 Key_ISR 处理函数的入口地址,送到 HandleEINT0 中。 再来看 Key_ISR ,这是一个典型的服务程序,加了_irq 作为编译关键字,告诉编译器,这个函数是中断服务程序 得保存需要的寄存器,免得被破坏。具体可以参考 《ARM体系结构与编程》P283 页的描述。 static void __irq Key_ISR(void) { ....... } 加上 _irq 关键字之后,编译器就会处理好所有的保存动作了,并不需 ARM-CC 编译器的关键字,GCC中并没有这个东要多关心。但是这个是 西,所以GCC处理中断的时候最好还是自己保存一下。 到这里为止,整个中断的过程就解释完毕。分析的过程中确实学习了很多。 中断控制是所示嵌入式系统中不可或缺的一部分。对于不同的处理器,虽然中断控制的原理是基本一致的,但其管理方式往往都有很大的区别。学过51系列单片机的刚开始学ARM人会觉得ARM的中断管理系统很复杂,因为在51中中断向量几乎不用你管。主要是因为在ARM系统中中断源多,且为了实现不同系统对实时性的要求不同而进行多优先级的管理的造成的。 1、ARM7TDMI内核的中断 至于中断的概念这里就说的,下面我来介绍一下ARM7TDMI内核下的中断。 和51单片机只有一种模式不同,ARM7TDMI内核CPU在响应中断后会切换到异常模式下:FIQ中断是进入快中断模式,IRQ中断时进入中断模式(ARM7TDMI内核有7种模式:用户模式,系统模式,快中断模式,中断模式,管理模式,中止模式和未定义模式,其中后5种 被称为异常模式,由程序状态寄存器的M4M3M2M1M0这5位来决定,其实ARM7的模式管理的这5位和51单片机状态寄存器的RS1RS0两位的作用相似)。 1.1、中断处理过程 ARM7进入及退出快中断模式和中断模式的过程(中断响应过程)如下: ? 将下一条指令的地址复制到LR(R14)中(在ARM状态下)。 ? 将CPSR复制到适当的SPSR(各种模式处CPSR是共用一个的,而SPSR在不同异常模式下是不同的)。 ? 根据异常将CPSR模式强制设为快中断模式或中断模式。 ? 强制PC从相关的异常向量处取指。(到此完成进入中断服务程序的动作) ? 执行异常服务程序。 ? 将LR中的值减去偏移量后移入PC。ARM状态快中断模式和中断模式下这个偏移量为4,因为LR保存的是由于FIQ或IRQ占先面没有被执行的指令的地址。 ? 将SPSR的值复制回CPSR中。 ? 清零在入口置位的中断禁止标志。 1.2、异常向量表 一旦产生IRQ中断,微控制器会切换到IRQ模式,并且跳转到向量表0x0000018地址处执行程序。而一旦产生FIQ中断,微控制器会切换到FIQ模式,并且跳转到向量表0x000001C地址处执行程序。所示,在0x00000080处和0x0000001C处必须各有一条跳转指令,分别跳转的 IRQ和FIQ中断处理的代码处。在0x00000000处的一般向量表称为异常向量表,定义如下: ENTRY b ResetHandler for debug b HandlerUndef handlerUndef b HandlerSWI SWI interrupt handler b HandlerPabort handlerPAbort b HandlerDabort handlerDAbort b . handlerReserved b HandlerIRQ 这里是IRQ中断入口处0x00000018 b HandlerFIQ 这里是FIQ中断入口处0x0000001C ResetHandler、HandlerUndef等只是地址标签,是由用户自己在这些异常处理代码的开始处定义的。 2、44b0X的中断 2.1、44b0X的启动时中断的初始化 44B0的初始化程序就是初始化各个关键的寄存器,建立中断向量,然后转移到主函数去执行程序。不过44B0不支持地址映射,所以程序不COPY到RAM种执行。44B0初始化对我们广大初学者来说,比较难理解的是中断的处理和一些少见的操作符号。下面我来一段一段地分析。 2.1.1、44b0的中断子程序地址 就是存放在初始化程序最后的一段: ^ _ISR_STARTADDRESS HandleReset # 4 HandleUndef # 4 HandleSWI # 4 HandlePabort # 4 HandleDabort # 4 HandleReserved # 4 HandleIRQ # 4 HandleFIQ # 4 ;Don't use the label 'IntVectorTable', ;because armasm.exe cann't recognize this label correctly. ;the value is different with an address you think it may be. ;IntVectorTable HandleADC # 4 HandleRTC # 4 HandleUTXD1 # 4 HandleUTXD0 # 4 HandleSIO # 4 … … HandleEINT3 # 4 HandleEINT2 # 4 HandleEINT1 # 4 HandleEINT0 # 4 0xc1(c7)fff84 这段第一行 "^"符号表示在RAM区开辟空间。 ^ _ISR_STARTADDRESS 表示在RAM的_ISR_STARTADDRESS处开辟一段空间。这里开辟的空间是用来存放中断服务程序及其他异常处理程序地址的。每个中断或其他异常都开辟4个字节的空间,这是因为RAM区的程序地址要4个字节才能放得下。而中断程序的地址是应用程序在使用这个中断时,将中断服务程序的地址存入这对应的空间内。_ISR_STARTADDRESS一般是定义在RAM的最后一段空间,可以在一些配置文件中找到这个标签,如:Option.inc。 2.1.2、IRQ中断 44B0的IRQ中断有两种装断模式 一种是非向量IRQ中断,一种是向量IRQ中断。 当有两个中断同时发生时,前者是由软件方式来判断决定先执行那个中断服务,而后者是由硬件逻辑来决定的。 非向量IRQ中断的执行过程 (1) 中断允许并且外部中断请示产生。 ) PC自动跳转一0x00000018处 (2 也就是异常向量表: b ResetHandler b HandlerUndef b HandlerSWI b HandlerPabort b HandlerDabort b . b HandlerIRQ 这里是非向量IRQ中断入口处0x00000018 b HandlerFIQ (3)由 b HandlerIRQ指令跳转到下面的HandlerIRQ HANDLER HandleIRQ宏调用处 LTORG HandlerFIQ HANDLER HandleFIQ HandlerIRQ HANDLER HandleIRQ HandlerUndef HANDLER HandleUndef HandlerSWI HANDLER HandleSWI HandlerDabort HANDLER HandleDabort HandlerPabort HANDLER HandlePabort 这个宏的定义是这样的: MACRO $HandlerLabel HANDLER $HandleLabel $HandlerLabel sub sp,sp,#4 decrement sp(to store jump address) stmfd sp!,{r0} PUSH the work register to stack ;(lr does't push because it return to original address) ldr r0,=$HandleLabel load the address of HandleXXX to r0 ldr r0,[r0] load the contents(service routine start address) of HandleXXX str r0,[sp,#4] store the contents(ISR) of HandleXXX to stack ldmfd sp!,{r0,pc} POP the work register and pc(jump to ISR) MEND 作用是使标签HandleLabel单元的地址数据装载到PC当中,也就是使 程跳转到HandleLabel地址单元中存放的程序地址处。 比如上面执行HandlerIRQ HANDLER HandleIRQ宏调用时是将 如下一段代码的首地址IsrIRQ装入PC,就是下面这段代码在软件上实现在多个中断同时发生时选择一个中断并进入其中断服务程序。 ;One of the following two routines can be used for non-vectored interrupt. IsrIRQ using I_ISPR register. sub sp,sp,#4 reserved for PC stmfd sp!,{r8-r9} IMPORTANT CAUTION if I_ISPC isn't used properly, I_ISPR can be 0 in this routine. ldr r9,=I_ISPR 读中断服务挂起寄存器,存入r9中 ldr r9,[r9] mov r8,#0x0 0 movs r9,r9,lsr #1 从低位向上搜索r9中的第1个为"1"的位 bcs %F1 add r8,r8,#4 b %B0 1 ldr r9,=HandleADC add r9,r9,r8 ldr r9,[r9] str r9,[sp,#8] ldmfd sp!,{r8-r9,pc} 那么为什么说HandleIRQ单元内存放的地址数据是IsrIRQ呢,请看在复位异常处理子程序ResetHanlder里有这样一段代码: ;**************************************************** * Setup IRQ handler * **************************************************** ldr r0,=HandleIRQ ldr r1,=IsrIRQ str r1,[r0] 这就是每次程序复位时将IsrIRQ地址数据装入HandleIRQ单元的。 (4)IsrIRQ子程序的最后一条指令会使程序转入用户的中断服务子程序。 (5)中断返回。 向量IRQ中断的执行过程 IRQ向量模式中断比非向量模式少了一个过程,就是调用IsrIRQ子程序的过程 因为向量模式下,当IRQ中断发生时不是跳转到0x00000018(b HandlerIRQ)处的,而是跳转到0x00000020之后的某个中断向量处。0x00000020之后的代码如下所示: VECTOR_BRANCH ldr pc,=HandlerEINT0 mGA H/W interrupt vector table ldr pc,=HandlerEINT1 ldr pc,=HandlerEINT2 ldr pc,=HandlerEINT3 ldr pc,=HandlerEINT4567 ldr pc,=HandlerTICK mGA b . b . ldr pc,=HandlerZDMA0 mGB ldr pc,=HandlerZDMA1 ldr pc,=HandlerBDMA0 ldr pc,=HandlerBDMA1 ldr pc,=HandlerWDT ldr pc,=HandlerUERR01 mGB b . b . ldr pc,=HandlerTIMER0 mGC ldr pc,=HandlerTIMER1 ldr pc,=HandlerTIMER2 ldr pc,=HandlerTIMER3 ldr pc,=HandlerTIMER4 ldr pc,=HandlerTIMER5 mGC b . b . ldr pc,=HandlerURXD0 mGD ldr pc,=HandlerURXD1 ldr pc,=HandlerIIC ldr pc,=HandlerSIO ldr pc,=HandlerUTXD0 ldr pc,=HandlerUTXD1 mGD b . b . ldr pc,=HandlerRTC mGKA b . b . b . b . b . mGKA b . b . ldr pc,=HandlerADC mGKB b . b . b . b . b . mGKB b . b . 具体跳转到那一句,就看有什么中断产生。如果多个中断同时产生则硬件逻辑可产根据IRQ中断优先级控制寄存器内设定的优先级来决定跳转之处。 比如有两个中断定时器0中断和外部中断1同时产生了,如果外部中断1的优先级比定时器0的中断优先级高,则硬件逻辑会自动使PC转到ldr pc,=HandlerEINT1处,执行这条指令后PC就跳转到宏HandlerEINT1 HANDLER HandleEINT1 而这个会将HandleEINT1单内的地址数据装入PC。与HandleIRQ单元是存放地址IsrIRQ不一样,是直接HandleEINT1存放的外部中断1的服务程序地址的。所以这种模式下是由硬件来中断优先级的,不需要IsrIRQ子程序来处理。 2.1.3 FIQ中断 由于FIQ中断中没有优先级之分,也没有向量模式或非向量模式之分, 因此比起IRQ中断来说要简单得多,它的执行过程与在只有一个中断源的情况下的向量模式IRQ的过程是一样的。 在进入正题之前,我想先把ARM920T的异常向量表(Exception Vectors)做一个简短的介绍。ARM920T的异常向量表有两种存放方式,一种是低端存放(从0x00000000处开始存放),另一种是高端存放(从0xfff000000处开始存放)。关于为什么要分两种方式进行存放这点我将在介绍MMU的文章中进行说明,本文采用低端模式。ARM920T能处理有8个异常,他们分别是: Reset,Undefined instruction,Software Interrupt,Abort (prefetch),Abort (data),Reserved,IRQ,FIQ 下面是某个采用低端模式的系统源码片段: /************************************************************ ***************** _start: b Handle_Reset b HandleUndef b HandleSWI b HandlePrefetchAbort b HandleDataAbort b HandleNotUsed b HandleIRQ b HandleFIQ „.. „ .. other codes „ .. . ************************************************************* ****************/ 上面这部分片段一般出现在一个名叫“head.s”的汇编文件的里,“b Handle_Reset”这条语句就是系统上电之后运行的第一条语句。也就是说这部分代码的二进制码必须位于内存的最开始部分(这正是低端存放模式),因为上电后CPU会从SDRAM的0x00000000处取第一条指令并执行。 Address Instruct 0x00000000: b Handle_Reset 0x00000004: b HandleUndef 0x00000008: b HandleSWI 0x 0000000C: b HandlePrefetchAbort 0x00000010: b HandleDataAbort 0x00000014: b HandleNotUsed 0x00000018: b HandleIRQ 0x0000001C: b HandleFIQ 上面是该程序段在系统上电后加载到内存后的分布情况,我们可以看到每条指令占用了4个字节。 上电后,PC指针会跳转到Handle_Reset处开始运行。以后系统每当有异常出现,则CPU会根据异常号,从内存的0x00000000处开始查表做相应的处理,比如系统触发了一个IRQ异常,IRQ为第6号异常,则CPU将把PC指向0x00000018地址(4*6=24= 0x00000018)处运行,该地址的指令是跳转到“中断异常服务例程”(HandleIRQ)处运行。以上就是我对异常向量表的一个简单介绍。现在可以进入我们文章的主题 ,s3c2410的中断分快中断(FIQ)和普通中断(IRQ),“中断异常处理” 我们讨论的重点是普通中断(IRQ)。 s3c2410的中断异常处理模块总共由以下寄存器构成 SRCPND(SOURCE PENDING REGISTER) INTMOD(INTERRUPT MODE REGISTER) INTMSK(INTERRUPT MASK REGISTER) PRIORITY( PRIORITY REGISTER) INTPND(INTERRUPT PENDING REGISTER) INTOFFSET(INTERRUPT OFFSET REGISTER) SUBSRCPND (INTERRUPT SUB SOURCE PENDING) INTSUBMSK (INTERRUPT SUB MASK REGISTER) 下面我将讲解每个寄存器在一个中断处理流程中所扮演的角色 SRCPND/ SUBSRCPND这两个寄存器在功能上是相同的,它们是中断源引 脚寄存器,在一个中断异常处理流程中,中断信号传进中断异常处理模块后首先遇到的就是SRCPND/ SUBSRCPND,这两个寄存器的作用是用于 SUBSRCPND 的有标示出哪个中断请求被触发。SRCPND的有效位为32, 效位为11,它们中的每一位分别代表一个中断源。SRCPND为主中断源引脚寄存器,SUBSRCPND为副中断源引脚寄存器。 这里列举出SRCPND的各个位信息: 每个位的初始值皆为0。假设现在系统触发了TIMER0中断,则第10bit将被置1,代表TIMER0中断被触发,该中断请求即将被处理(若该中断没有被屏蔽的话)。SUBSRCPND情况与SRCPND相同,这里就不多讲了。 INTMOD寄存器有效位为32位,每一位与SRCPND中各位相对应,它的作用是指定该位相应的中断源处理模式(IRQ还是FIQ)。若某位为0,则该位相对应的中断按IRQ模式处理,为1则以FIQ模式进行处理,该寄存器初始化值为0x00000000,即所有中断皆以IRQ模式进行处理。(详细请参考s3c2410操作手册)。 INTMSK/ INTSUBMSK 寄存器为中断屏蔽寄存器 ,INTMSK为主中断屏蔽寄存器,INTSUBMSK为副中断屏蔽寄存器。INTMSK有效位为32,INTSUBMSK有效位为11,这两个寄存器各个位与SRCPND和SUBSRCPND分别对应。它们的作用是决定该位相应的中断请求是否被处理。若某位被设置为1,则该位相对应的中断产生后将被忽略(CPU不处理该中断请求),设置为0则对其进行处理。这两个寄存器初始化后的值是0xFFFFFFFF和0x7FF,既默认情况下所有的中断都是被屏蔽的。 到目前为止我们总共讲解了SRCPND,INTMOD,INTMSK,SUBSRCPND, INTSUBMSK 五个寄存器,在继续讲解PRIORITY寄存器之前我们先来看一张图。 先弄清楚一点,现在要讨论的是一个中断优先级的判断问题。为什么会有中断有先级的问题呢,我们知道CPU某个时刻只能对一个中断源进行中断处理,如果现在有3个中断同时发生了,那CPU要按什么顺序处理这个3个中断呢,这正是引入优先级判断的原因所在,通过优先级判断,CPU可以按某种顺序逐个处理中断请求。3sc2410的优先级判断分为两级。 如上图所示,SRCPND寄存器对应的32个中断源总共被分为6个组,每 0~5)寄存器对其进行管理。中断必须先由所属组个组由一个ARBITER( 的ARBITER(0~5)进行第一次优先级判断(第一级判断)后再发往ARBITER6进行最终的判断(第二级判断)。ARBITER(0~5)这六个组的优先级已经固定,我们无法改变,也就是说由ARBITER0控制的该组中断优先级最高(该组产生的中断进行第一级判断后永远会以REQ0向ARBITER6传递过去)其次是ARBITER1, ARBITER2, ARBITER4, ARBITER4, ARBITER5.我们能够控制的是某个组里面各个中断的优先级顺序。怎么控制,通过PRIORITY寄存器进行控制:] 以下是PRIORITY寄存器各个位的参数表 从表上我们可以知道PRIORITY寄存器内部各个位被分为两种类型,一种是ARB_MODE,另一种为ARB_SEL, ARB_MODE类型有5组对应ARBITER(2~6),ARB_SEL类型有7组对应ARBITER(0~6)。现在我将以ARBITER2为例,讲解中断组与PRIORITY寄存器中ARB_SEL, ARB_MODE之间的相 互关系。 首先我们看到ARBITER2寄存器管理的该组中断里包括了6个中断,分别是INT_TIMER0,INT_TIMER1,INT_TIMER2,INT_TIMER3,INT_TIMER4, REQ1,REQ2,REQ3,INT_UART2,她们的默认中断请求号分别为REQ0, REQ5。我们先看PRIORITY寄存器中的ARB_SEL2,该参数由两个REQ4, 位组成,初始值为00。从该表可以看出00定义了一个顺序 0-1-2-3-4-5 ,这个顺序就是这组中断组的优先级排列,这个顺序指明了以中断请求号为0(REQ0)的INT_TIMER0具有最高的中断优先级,其 INT_TIMER2„。假设现在ARB_SEL2的值被我们设置次是INT_TIMER1, 为01。则一个新的优先级次序将被使用,01对应的优先级次序为0-2-3-4-1-5,从中可以看出优先级最高和最低的中断请求和之前没有变化,但本来处于第2优先级的INT_TIMER1中断现在变成了第5优先级。从ARB_SEL2被设置为00,01,10,11各个值所出现的情况我们可以看出,除最高和最低的优先级不变以外,其他各个中断的优先级其实是在做一个旋转排列(rotate)。为了达到对各个中断平等对待这一目标,我们可以让优先级次序在每个中断请求被处理完之后自动进行一次旋转,如何自动让它旋转呢,我们可以通过ARB_MODE2达到这个目的,该参数只有1个 bit,置1代表开启对应中断组的优先级次序旋转,0则为关闭。事实上当该位置为1之后,每处里完某个组的一个中断后,该组的ARB_SEL便递增在1(达到11后恢复为00)。 现在我们另ARB_MODE2=1,ARB_SEL2=00 则当前ARBITER2的优先级顺序为0-1-2-3-4-5,假设现在该组的1号中 断请求INT_TIMER1和2号中断请求INT_TIMER2被同时触发,CPU根据优先级判断后决定先把INT_TIMER1中断向ARBITER6进行发送(在ARBITER6做第最终优先级判断),接着再向ARBITER6发送INT_TIMER2中断。请注意,在INT_TIMER1被处理完毕后,该组中段的优先级次序被自动做了一次旋转,旋转后ARBITER2的优先级顺序变为0-2-3-4-1-5。假设之后某个时刻该组的INT_TIMER1和INT_TIMER2又被同时触发,则此时CPU优先处理的会是INT_TIMER2。若我们另ARB_MODE2=0,则改组的中断优先级次序在任何情况下都不做任何改变,除非我们人为地重新设置了ARB_SEL2的值。 呼。。。好累。。。终于说完了麻烦的优先级-_-„ 继续。。。 INTPND 寄存器可能是整个中断处理过程中我们要特别注意的一个寄存器了,他的操作比较特别,怎么特别,请听我慢慢道来.:] 先看一下该寄存器各位详细功能列表 正如你所见的,INTPND 寄存器与SRCPND长得一模一样,但他们在中断异常处理中却扮演着不同的角色,如果说SRCPND是中断信号进入中断处理模块后所经过的第一个场所的话,那么INTPND 则是中断信号在中断处理模块里经历的最后一个寄存器。它的每个位对应一个中断请求,若该位被置1,则表示相应的中断请求被触发,描述到这里你可能会发现它不仅和SRCPND长得一模一样,就连功能都一样,其实不然,他们在功能上有着重大的区别。SRCPND是中断源引脚寄存器,某个位被置1表示相应的中断被触发,但我们知道在同一时刻内系统可以触发若干个 中断,只要中断被触发了,SRCPND的相应位便被置1,也就是说SRCPND 在同一时刻可以有若干位同时被置1,然而INTPND则不同,他在某一时刻只能有1个位被置1,INTPND 某个位被置1(该位对应的中断在所有已触发的中断里具有最高优先级且该中断没有被屏蔽),则表示CPU即将或已经在对该位相应的中断进行处理。于是我们可以有一个 总结 初级经济法重点总结下载党员个人总结TXt高中句型全总结.doc高中句型全总结.doc理论力学知识点总结pdf :SRCPND说明了有什么中断被触发了,INTPND说明了CPU即将或已经在对某一个中断进行处理。 特别注意:每当某一个中断被处理完之后,我们必须手动地把SRCPND/SUBSRCPND , INTPND三个寄存器中与该中断相应的位由1设置为0,刚才我说INTPND的操作很特别,它的特别之处就在于对当我们要把该寄存器中某个值为1的位设置为0时,我们不是往该位置0,而是往该位置1。假设SRCPND=0x00000003,INTPND=0x00000001,该值说明当前0号中断和1号中断被触发,但当前正在被处理的是0号中断,处理完毕后我们应该这样设置INTPND和SRCPND: SRCPND=0x00000002 //位0被置为0 INTPND =0x00000001 //位0被置为0(方法是往该位写入1) INTOFFSET寄存器的功能则很简单,它的作用只是用于表明哪个中断正在被处理。下面是该寄存器各位详细功能列表 若当前INT_TIMER0被触发了,则该寄存器的值为10,以此类推。 现在我把整个中断流程用一个图加以说明 以上这个图清楚地说明了一个中断异常处理流程。 下面我用INT_TIMER0, INT_TIMER2和INT_UART0三个中断完整地介绍一次中断异常处理。首先我们得做几个假设: 假设1:这三个中断的屏蔽被取消。 假设2:PRIORITY寄存器中ARB_MODE2,ARB_MODE5皆为0,既不进行优先级的自动旋转排序,任何时候ARBITER2,ARBITER5控制的中断组优先级次序分别为0-1-2-3-4-5和1-2-3-4。 假设3:这三个中断皆为IRQ类型。 假设4:这三个中断同时被触发。 INT_TIMER0, INT_TIMER2和INT_UART0三个中断被同时触发,此时三个中断信号流向SRCPND寄存器,使该寄存器中的第10位,12位,28位被置为1,中断信号继续向前流经INTMASK 寄存器,这三个中断都没有被屏蔽,于是信号进一步流经INTMODE寄存器,这三个中断皆为IRQ类型,故中断信号继续向前流向PRIORITY寄存器,经过优先级判断,INT_TIMER0中断信号使INTPND 寄存器的第10位置1(INT_TIMER0优先级最高),此时INTOFFSET 寄存器的值为10,CPU转向相应的中断服务例程进行处理。处理完毕后,我们的程序将INTPND和SRCPND的第10置为0,至此INT_TIMER0中断处理完毕。此时SRCPND 的第12位,28位仍为1(这两个中断请求未被处理),故他们会继续被CPU已刚才描述的方式进行处理。 中断异常处理就先讲到这吧 S3C2440的中断寄存器: 1.中断分两大类:内部中断和外部中断。 2.外部中断。24个外部中断占用GPF0-GPF7(EINT0-EINT7),GPG0-GPG15(EINT8-EINT23)。用这些脚做中断输入,则必须配置引脚为中断,并且不要上拉。具体参考datesheet数据手册。 寄存器:EXTINT0-EXTINT2:三个寄存器设定EINT0-EINT23的触发方式。 EINTFLT0-EINTFLT3:控制滤波时钟和滤波宽度。 EINTPEND:这个是中断挂起寄存器,清除时要写1,后面还有几个是写1清除。当一个外部中断(EINT4-EINT23)发生后,那么相应的位会被置1。为什么没有EINT0-EINT3,呵呵,看看SRCPND就知道了,里面没有EINT4-EINT23的位子,所以有了EINTPEND。 EINTMASK:这个简单,是屏蔽中断用的,也就是说位为1时,此次中断无效。 3.内部中断。内部中断有8个寄存器,下面逐一来看。 寄存器:SUBSRCPND:当一个中断发生后,那么相应的位会被置1,表示一个中断发生了。 INTSUBMSK:与上一个是一伙的,中断屏蔽寄存器,具体屏蔽什么,自己看手册去吧。 INTMOD:中断的方式。一个中断可以是普通中断,也可以是快中断,在这里设置,但只能有一个快中断。 PRIORITY :优先级寄存器,不说了。 SRCPND :当一个中断发生后,那么相应的位会被置1,表示一个或一类中断发生了。 INTMSK :中断屏蔽寄存器。 INTPND :中断发生后,SRCPND中会有位置1,可能好几个(因为同时可能发生几个中断),这些中断会由优先级仲裁器选出一个最紧迫的,然后吧把INTPND中相应位置1,所以同一时间只有一位是1。也就是说前面的寄存器置1是表示发生了,只有INTPND置1,CPU才会处理。 INTOFFSET :用来表示INTPND中哪一位置1了,好让你查询,普通中断跳转时查询用。清除、时自动清除。 INTPNDSRCPND 4.各寄存器关系: 下面看图说明: 5.中断过程。 a 如果是不带子中断的内部中断:发生后SRCPND相应位置1,如果没有被INTMSK屏蔽,那么等待进一步处理。 b 如果是带子中断的内部中断:发生后SUBSRCPND相应位置1,如果没有被INTSUBMSK屏蔽,那么SRCPND相应位置1,等待进一步处理,几个SUBSRCPND可能对应同一个SRCPND,对应表如下: SRCPND SUBSRCPND INT_UART0 INT_RXD0,INT_TXD0,INT_ERR0 INT_UART1 INT_RXD1,INT_TXD1,INT_ERR1 INT_UART2 INT_RXD2,INT_TXD2,INT_ERR2 INT_ADC INT_ADC_S, INT_TC INT_CAM INT_CAM_C, INT_CAM_P INT_WDT_AC97 INT_WDT, INT_AC97 c 如果是外部中断:EINT0-EINT3发生后SRCPND相应位置1,如果没有被INTMSK屏蔽,那么等待进一步处理。EINT4-EINT23发生后EINTPEND相应位置1,如果没有被EINTMASK屏蔽,那么SRCPND相应位EINT4-7 或EINT8-23置1,如果没有被INTMSK屏蔽,等待进一步处理,几个EINTPEND对应同一个SRCPND,对应表如下: SRCPND EINTPEND EINT0 EINT0 EINT1 EINT1 EINT2 EINT2 EINT3 EINT3 EINT4-7 EINT4-EINT4 EINT8-23 EINT8-EINT23 三种中断都等待进一步处理了。接下来从SRCPND往下看,看INTMSK。如果中断被屏蔽了,就不用说了(注意:快中断也能被屏蔽)。如果没有被屏蔽,那么会进一步到INTMOD。如果是快中断,那么直接出来,进入FIQ(即CPU进入快中断模式处理)。如果是普通中断,那么SRCPND可以有多为置1(FIQ只能有一个),这时就会经过PRIORITY选出一个优先级高的,然后把根据选出的中断把INTPND相应位置1(注意:只能选出一个),进入IRQ,让CPU处理。 6.中断的开启。 a.如果是不带子中断的内部中断,只需设置INTMSK,让它不屏蔽中断就可以了。 b 如果是带子中断的内部中断,需设置INTSUBMSK和INTMSK,让它门不屏蔽中断就可以了。 c 如果是外部中断,对于EINT8-23需要设置EINTMASK和INTMSK。对于EINT0-EINT3只需设置INTMSK。 7.中断的清除。 a.如果是不带子中断的内部中断,只需清除SRCPND,注意清除需位置1。 b 如果是带子中断的内部中断,需清除SRCPND和SUBSRCPND,注意先清除SUBSRCPND,再清除SRCPND。因为,如果你先清除SRCPND的话,然后在清除SUBSRCPND的过程中,SRCPND会以为又有中断发生,又会置1。也就是说一次中断会响应两次。所以必须先掐断源头。 c 如果是外部中断,对于EINT8-23需要清除EINTPEND和SRCPND(同样注意顺 序)。对于EINT0-EINT3只需清除SRCPND。 本文详细分析了S3C2440的中断寄存器,对arm初学者有一定的帮助
本文档为【S3C2440的中断学习经验】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_721103
暂无简介~
格式:doc
大小:80KB
软件:Word
页数:0
分类:互联网
上传时间:2017-09-26
浏览量:14