




已阅读5页,还剩13页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
ARM中断基础知识一、ARM内核工作模式因为中断会设计到ARM内核工作模式的切换,所以先简要介绍一下各个模式:ARM模式的切换要设计到寄存器CPSR,下面是各个位表示的含义,CPSR4:0是工作模式切换控制位。T=0时是ARM指令模式,T=1时是Thumb指令模式。F=0时是允许FIQ,F=1是禁止FIQI=0时是允许IRQ,I=1是禁止IRQ在开发板刚刚启动起来的时候首先得关闭所有中断,等把开发板的硬件初始化,各种参数设置好之后就可以打开中断了。CPSR有4个8位区域:标志域(F)、状态域(S)、扩展域(X)、控制域(C)C控制域屏蔽字节(CPSR7:0)X扩展域屏蔽字节(CPSR15:8)S状态域屏蔽字节(CPSR23:16)F标志域屏蔽字节(CPSR31:24)常用于MRS或MSR指令,用于cpsr中的值转移到寄存器或把寄存器的内容加载到cpsr中.如: MSR CPSR_c,0xd3ARM 内核工作模式的切换是要自己手动切换的, 设置CPSR 寄存器低5位进行切换(第五位始终是1)cpsr4:0处理器模式英文表示1,0000用户模式usr1,0001快速中断模式fiq1,0010中断模式irq1,0011管理模式svc1,0111中止模式abt1,1011未定义und1,1111系统模式sysCPU刚刚复位后的模式是管理模式(SVC),如果我们写纯裸机代码(不使用uboot),刚开始是在stepping stone中运行的,我们在这个里面得完成代码的一些硬件的初始化,比如时钟初始化,sdram初始化,nandflash初始化(从nandflash启动)等等,然后把程序从nandflash中拷贝到sdram中运行,在这段启动代码中我们免不了要初始化各种堆栈,而且是各个模式下的堆栈最好都提前设置好,这里就要考虑各种因素了。比如我们是在OK6410平台上面测试,当复位或者开机后处于8K 大小的stepping stone中,此时我们设置堆栈是SVC下的堆栈,如果我们要设置其他模式下的堆栈的话我们就必须手动的设置CPSR下的模式位,来跳转到各个模式下设定好对应的堆栈。因为以后是要在sdram中运行了,所以这些堆栈应当设定为sdram中的地址。OK6410中的sdram是256M的,所以我们可以从顶部开始设置,比如说切换到irq模式,把堆栈设置为SP = 0x60000000 (因为S3C6410中内存起始地址是从0x50000000开始的,加上256M,即0x10000000,得到栈顶为0x60000000),然后切换到fiq模式下,把堆栈设置为SP = 0x5f000000,一次类推。但是要注意的是,我们还在stepping stone中运行的时候SVC的堆栈还是得保持在片内内存的顶部即SP = 8*1024,直到要跳转到sdram中运行的时候了才把SVC的堆栈设置到sdram中去。有些人喜欢刚开始只设置SVC的堆栈(因为刚开启的时候就是这个模式,所以必须设置一下),而不设置别的模式的堆栈,等到中断发生了之后,在中断函数中设置堆栈的地址。我觉得这样有些不妥,提前都设置好,以后中断进来后就省去了每次设置堆栈的步骤,提高了效率。中断向量表:以下代码就是切换CPU工作模式的示例;* Begin init stact */;在6种模式下切换并设置堆栈指针MRS R0,CPSR;把CPSR读取到R0BIC R0,#0x1f;低5位清零LDR R1,=MODE_Fiq;设置R1 为0b10001,跳转到fiq模式ORR R0,R0,R1;R0和R1相或,设置低5位MSR CPSR_c,R0;把R0的值重新赋值到CPSRLDR SP,=Stact_Fiq;设置fiq的栈指针BIC R0,#0x1f;低5位清零LDR R1,=MODE_Irq;跳转Irq模式ORR R0,R0,R1MSR CPSR_c,R0LDR SP,=Stact_Irq;设置irq的栈指针BIC R0,#0x1fLDR R1,=MODE_Svc;跳转到svc模式ORR R0,R0,R1MSR CPSR_c,R0LDR SP,=Stact_Svc;设置svc的栈指针BIC R0,#0x1fLDR R1,=MODE_Abort;跳转到abort模式ORR R0,R0,R1MSR CPSR_c,R0LDR SP,=Stact_Abort;设置abort的栈指针BIC R0,#0x1fLDR R1,=MODE_Undef;跳转到undef模式ORR R0,R0,R1MSR CPSR_c,R0LDR SP,=Stact_Undef;设置undef栈指针BIC R0,#0x1fLDR R1,=MODE_Sys;跳转到sys模式ORR R0,R0,R1MSR CPSR_c,R0LDR SP,=Stact_Sys;设置sys栈指针与S3C2440相比,S3C6410增加中断向量控制器,这样在S3C2440里需要用软件来跳转的中断处理机制,在S3C6410中可以完全由硬件来跳转。只要把ISR(中断处理函数)地址存在连续向量寄存器空间,而不必像在S3C2440自行分配空间进行管理。换句话说,在S3C2440下是由cpu触发IRQ/FIQ异常,由异常处理函数里再查找相关中断寄存器来跳到指定的ISR,而可以全部由S3C6410的VIC硬件来自动处理。这样就大大简化了中断处理编程。另外一变化是S3C6410外部中断加入了滤波电路,这样原来需要软件去毛刺的地方均可以采用硬件来进行滤波了,这样大大简化了外部中断处理。S3C6410具有187个多功能IO端口,其中有127个用于外部中断。这127个引脚可以分为10组:外部中断分组对应GPIOExternal interrupt Group 0GPN0GPN15 GPL8GPL14 GPM0GPM4(16+7+5=28,所以EINT0PEND有28bit来识别这28个中断)External interrupt Group 1GPA0GPA7 GPB0GPB6External interrupt Group 2GPC0GPC7External interrupt Group 3GPD0GPD5External interrupt Group 4GPF0GPF14External interrupt Group 5GPG0GPG7External interrupt Group 6GPH0GPH9External interrupt Group 7GPO0GPO15External interrupt Group 8GPP0GPP14External interrupt Group 9GPQ0GPQ96410支持64种中断源,即有64个中断号。INT_EINT0仅仅对应0号中断,INT_EINT0又包含几个中断。在VIC中,10组外部中断占用的中断源情况如下:中断号中断源对应外部中断VIC组0INT_EINT0External interrupt 03VIC01INT_EINT1External interrupt411VIC032INT_EINT2External interrupt1219VIC133INT_EINT3External interrupt2027VIC153INT_EINT4External interruptgroup1group9VIC1举个例子(OK6410的6个按键做外部中断):按键对应引脚对应外部中断中断源KEY1GPN0External interrupt 0INT_EINT0KEY2GPN1External interrupt 1INT_EINT0KEY3GPN2External interrupt 2INT_EINT0KEY4GPN3External interrupt 3INT_EINT0KEY5GPN4External interrupt 4INT_EINT1KEY6GPN5External interrupt 5INT_EINT1KEY1KEY4都是属于INT_EINT0,即都是属于中断号为0的中断,这四个按键产生的外部中断所调用的中断处理函数的地址都是存在VIC0VECTADDR0寄存器中的,这四个随便哪个按下都会调用同一个中断处理函数,所以在处理函数里面必须判别是哪个按键所触发的中断。中断相关寄存器的设计演变(寄存器以外部按键中断为例)ICARM7(4510)ICARM9(2440)ICARM11(6410)内核(core)CPSR I-bitCPSR I-bitCPSR I-bitVIC Port(Enable)VIC interface(PC A0A31)中断控制器(IC)INTMODINTPNDINTMSKINTOFFSETINTPRIINTPNDINTMODINTMSKSRCPNDVectADDRESS(32bit - A0A31,中断函数地址的注册 )Vectors(handlers中断处理函数)Priority(优先级的判别)VIC0IRQSTATUS/VIC0FIQSTATUS(IRQ/FIQ的中断悬起位)VIC0INTSELECT(选择是IRQ还是FIQ模式)VIC0INTENABLE(MASK功能)VIC0RAWINTR(显示FIQ中断是否置位,从EINT0PND上传输过来的)中断源控制器(GPIO)EINTCON(F/R/L)GPXCON(EINT)EINTCON(F/R/L)GPXCON(EXIT)INTMASKEINT0PND(需要手动清除)EINT0CON0(Low/High level Falling/Rising/Both edge)GPxCON(EINT)硬件层key/UART/USB/Timerkey/UART/USB/Timerkey/UART/USB/Timer我用的是OK6410,分析一下最后一列:最后一列从下到上,是从最外层一直到内核各个寄存器的顺序,以外部key按键中断为例(GPN0GPN5-key1key6)中断源 GPIO ControllerGPNCON1:0 - key1 Set the pin mux function as Ext.Interrupt000 = Input01 = Output* 10 = Ext. Interrupt011 = Key pad ROW0EINT0CON02:0 - EINT1,0 Sets the signaling method of Ext.Interrupt0000 = Low level001 = High level* 01x = Falling edge triggered10x = Rising edge triggered11x = Both edge triggeredEINT0PEND00 = Not occur1 = Occur interruptEINT0MASK0* 0 = Enables Interrupt1 = Masked我们这里的中断是使用中断向量控制器VIC如何测试和中断相关的各个寄存器到底是怎么工作的,上下层的相互关系是怎么样的?先看下面的关系图(从下到上越来越接近cpu内核):首先我们不采用中断方式来看各个寄存器的变化,我们用查询的方式查看,以按键中断为例,当有按键按下的时候,各个寄存器怎么变化,相互之间的关系如何:准备一个能够在串口输出字符的程序。OK6410的KEY1是接在GPN0上面的,通过GPNCON把它设置成中断方式,且通过EINT0CON0设置成下降沿触发方式,代码如下:01/* set GPNIO to EINT mode , 10 - Eint */02temp = GPNCON ;03temp &= (0x30);04temp |= (0x20);05GPNCON = temp;0607/* set EINT triger mode to falling eage ,01x = Falling edge */08temp = EINT0CON0 ;09temp &= (0x70);10temp |= (0x30);11EINT0CON0 = temp;当按下KEY的时候,会触发中断,并且把这个信号传送到最下层的中断悬起位寄存器EINT0PEND,这个寄存器不同的bit对应不同的中断。EINT0PEND的上层是中断屏蔽寄存器INTMASK,当这个寄存器设置为屏蔽的时候中断触发信号是无法通过它传送到上层去的。我们先来看看当中断发生的时候EINT0PEND是如何变化的,他的变化会带来怎么样的结果。01while(1)0203for(ch=a;ch=z;ch+)04if( (EINT0PEND & 0x1)=0x1)/轮询EINT0PEND有没有被置位05uart_putchar(+);0607uart_putchar(ch);08delay();0910上面的程序是在不停的查询EINT0PEND0,该bit对应的是外部中断0,如果按下KEY产生一个下降沿,对应位会置位,if语句满足,会打印出一个“+”,然后出来打印字母,按键松开后是否还会满足if呢?看现象:发现按下一次之后“+”会不停的打印出来,也就是说if语句都是满足的,这就意味着EINT0PEND置位之后没有被清除,每次查询都还有,所以会不停的打印加号,所以这个寄存器我们必须手动清除,否则触发一次中断后就会不停的响应该中断。清除的方式就是向对应位写1,我们这里是:至于清除中断悬起位的方式:3种清0的写法,只有最后一种是正确的清除。1PEND |= 10; (not good)2PEND = 0xFFFFFFFF; (not good)3PEND = 10; (Good!)如果PEND寄存器某个bit是0,你写一个1进去,那么会变成1。只有当这位是1的时候写个1进去才会变成0.第一种:用或的方式,若PEND = 00011111(二进制),PEND | (10) = 00011111,也就是将00011111写入到值为00011111的PEND中,那么PEND的值变成00000000,所有的位都被清0了,而不是我们原本的意思要清除第一位。第二种:直接赋值,其实和第一种方式是一样的,只不过第一种是先求出或的值然后写进寄存器,如果原本是00011111的PEND,写进0xFFFFFFFF那么PEND中原本是0的位还是0,是1的位全部都清为0 ,还是不是我们想要的结果。第三种:PEND = 1 0 ,加入PEND是00011111,把00000001赋值进来,那么得到PEND的值为00011110,刚好是我们想要的,清除我们想要清除的位。下面我们看看EINT0MASK的屏蔽作用是怎样的效果:首先看看EINT0MASK的描述信息:可以看出哪位置1就是屏蔽对应的中断信号1/* EINT0MASK0 = 1 : Mask EINT0 */2temp = EINT0MASK ;3temp &= (0x10);4temp |= (0x10);5EINT0MASK = temp;屏蔽外部中断0,看中断触发信号能不能通过它传达到上面的寄存器VIC0RAWINTR。看看VIC0RAWINTR的描述:先不屏蔽中断,看看能否在VIC0RAWINTR看到中断信号:01/* EINT0MASK0 = 0 : disMask EINT0 */02temp = EINT0MASK ;03temp &= (0x10);04EINT0MASK = temp;0506uart_init();07while(1)0809for(ch=a;ch=z;ch+)10if( (VIC0RAWINTR & 0x1)=0x1)11uart_putchar(+);1213uart_putchar(ch);14delay();1516按下KEY,触发中断,发现现象如下(没有清理EINT0PEND):说明在VIC0RAWINTR 检测到中断触发信号了。如果把EINT0MASK0设置为1,即屏蔽信号,看看结果:怎么按KEY也检测不到中断触发信号,说明EINT0MASK是这里的一道关卡,中断触发信号能否传到上级要看这里有没有屏蔽掉,它相当于一个开关作用。继续dismask中断触发信号,让它传递到VIC0RAWINTR ,然后清除中断悬起位,看现象是怎样的:01/* EINT0MASK0 = 0 : disMask EINT0 */02temp = EINT0MASK ;03temp &= (0x10);04EINT0MASK = temp;0506uart_init();07while(1)0809for(ch=a;ch Eint */06temp = GPNCON ;07temp &= (0x30);08temp |= (0x20);09GPNCON = temp;1011/* set EINT triger mode to falling eage ,01x = Falling edge */12temp = EINT0CON0 ;13temp &= (0x70);14temp |= (0x30);15EINT0CON0 = temp;1617/* EINT0MASK0 = 0 : disMask EINT0 */18temp = EINT0MASK ;19temp &= (0x10);20/temp |= (0x10);21EINT0MASK = temp;2223/* VIC0INTENABLE0=1 : enable interrupt */24/* clear bit by VIC0INTENCLEAR */25temp = VIC0INTENABLE ;26temp &= (0x10);27temp |= (0x10);28VIC0INTENABLE = temp;2930/* VIC0INTSELECT0 = 0 : set to IRQ */31temp = VIC0INTSELECT ;32temp &= (0x10);33VIC0INTSELECT = temp;3435uart_init();36while(1)3738for(ch=a;ch=z;ch+)39if( (VIC0IRQSTATUS & 0x1)=0x1)40uart_putchar(+);41EINT0PEND = 0x1;4243uart_putchar(ch);44delay();4546按下KEY出现下面的现象:按一次打印一个“+”,说明如果是把VIC0INTENABLE对应位设置成disable,那么就会屏蔽掉中断信号,这里相当于又建立了一道关卡,它没同意就不能把信号传达到上一层。1/* VIC0INTENABLE0=0 : disable interrupt */2/* clear bit by VIC0INTENCLEAR */3temp = VIC0INTENABLE ;4temp &= (0x10);5VIC0INTENABLE = temp;现象:怎么按KEY也不会打印出“+”,说明中断信号被屏蔽了。当信号传达到这里的时候还得继续往上,还需要经过中断优先级的寄存器,判别那个中断优先级最高,这个只影响到中断的顺序,不影响中断信号的有无。但是在cpu内核的最近的地方还有个中断的开关,是个总开关CPSR的I/F-bit,默认是关闭的。这个一打开了就会把中断信号送给cpu内核了。打开最后这个总开关有两个写法,一个是在汇编里面写,一个是在c语言里面的嵌入汇编里面写,我们这里在c语言潜入汇编来写:1/* init CPSR I-bit */2/0101,00113_asm4mov r0,#0x535msr cpsr,r06但是编译的时候有警告,说应该吧这个r0定义成一个变量:解决方法:声明一个变量来代替寄存器1intval;2/* init CPSR I-bit */3/0101,00114_asm56mov val,#0x537msr cpsr,val8编译警告就没有了,这里出现警告是因为R0可能被别的使用的,这里使用会冲突,我们定义一个变量来代替R0就行了。但是编译运行后发现还是按下就有“+”打印出来,没有什么跳转现象啊!cpsr修改成为cpsr_cxsf或者CPSR_cxsf,再次编译运行后,按下按键会发现,不打印了,停下来了:说明cpu检测到了中断信号,跳出了原来运行的主函数,但是按理来说是要重启的,这里可能是VIC没有打开。下面介绍怎么打开VIC打开VIC:1intval2;2/* VIC Enable (cp15) */3_asm45mrc p15,0,val2,c1,c0,06orr val2,val2,#(1PC ,SPSR - CPSR修改start.s,实现IRQ_handler1)IRQ模式下的sp指针需要初始化2)除了清除pending bit之外,还需要清除VIC0ADDRESS =0 ;B)复杂的办法就是不用VIC,自己实现全过程1、当 IRQ 异常发生的时候,cpu 跳转到 0x182、背景知识:reset 0 地址被映射 map 到 iROM (内容不可修改)0 地址 在 iROM 中 (0xD0000000)iRAM (0xD0020000) - 0x20000 (iROM 被映射到了 0x20000)通过 md 命令,查看相关内存单元值,发现 0x18: 0xEA000018经过一系列分析,最终在 iROM 中的跳转指令会加载从 0xD0037400 地址开始的值,作为异常发生后要跳转的地址+offset ,因此只需要修改 0xD0037418 的向量即可。3、(int)IRQ_handler - 0xD0037400 + 0x18如果是 SWI 软件中断,则在 0xD0037408 处填写swi_handler的地址第一种方法当程序有中断且cpu检测到中断的时候轮询就没有意义了,所以去掉轮训。在主函数外面声明一个handler函数:1voidC_IRQ_handler(void)23EINT0PEND = 0x1;4uart_putchar( );5uart_putchar(+);6uart_putchar(
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 建筑拆除项目质量控制与检查方案
- 房屋结构设计优化与施工质量控制方案
- 污水处理厂改扩建工程节能评估报告
- 农副产品批发交易市场建设项目环境影响报告书
- 旅游景区景观改造方案
- 跨境智慧物流枢纽建设项目建筑工程方案
- 氟硅酸钠生产线项目技术方案
- DB54T 0046-2019 糌粑加工技术规程
- 学生心理健康危机干预流程手册
- 小学数学长度单位教学课件
- GB/T 46256-2025生物基材料与制品生物基含量及溯源标识要求
- 社交APP用户社群运营创新创业项目商业计划书
- 2025年互联网医疗市场份额动态趋势研究报告
- 2025至2030铝合金行业市场深度分析及竞争格局与行业项目调研及市场前景预测评估报告
- 医院中医科常见病症诊疗规范
- 2025广东广州市白云区民政局招聘窗口服务岗政府雇员1人笔试备考试题及答案解析
- 《电子商务概论》(第6版) 教案 第11、12章 农村电商;跨境电商
- 车辆改装施工方案模板
- 到梦空间使用讲解
- 大象牙膏教学课件
- 【《老年高血压患者护理措施研究》6600字(论文)】
评论
0/150
提交评论