自己建设网站需要哪些,wordpress 图站,泉州seo托管,做那个的网站谁有以下内容源于朱有鹏嵌入式课程的学习与整理#xff0c;如有侵权请告知删除。
参考博客 s5pv210的中断体系 - biaohc - 博客园 我的RTOS 之一 --S5PV210 异常向量表基址和软中断测试_liujia2100的博客-CSDN博客 从0开始学ARM-异常及中断处理、异常向量表、swi_一口Linux的技术…以下内容源于朱有鹏嵌入式课程的学习与整理如有侵权请告知删除。
参考博客 s5pv210的中断体系 - biaohc - 博客园 我的RTOS 之一 --S5PV210 异常向量表基址和软中断测试_liujia2100的博客-CSDN博客 从0开始学ARM-异常及中断处理、异常向量表、swi_一口Linux的技术博客_51CTO博客 一、异常及中断的简介
1、异常的介绍 在ARM体系结构中存在以下7种异常情况。 异常情况描述FIQ快速中断IRQ一般的中断保留……Data Abort如果一个预取指令试图存取一个非法的内存单元这时异常产生Prefetch Abort当一个指令被从内存中预取时由于某种原因而失败如果它能到达执行状态这个异常才会产生Software Interrupt当一个软中断指令被执行完的时候执行Undefined Instruction当流水线中的某个非法指令到达执行状态时执行Reset上电时执行1复位异常Reset 当CPU刚上电时或按下reset重启键之后会进入该异常。该异常在管理模式下处理。 2未定义指令异常Undefined Instruction 在流水线技术里的译码阶段如果当前指令不能被识别为有效指令则产生未定义指令异常。该异常在未定义异常模式下处理。 3软件中断指令异常Software Interrupt 该异常是应用程序自己调用时产生的用于用户程序申请访问硬件资源时。 例如printf()打印函数要将用户数据打印到显示器上用户程序要想实现打印必须申请使用显示器而用户程序又没有外设硬件的使用权只能通过使用软件中断指令切换到内核态通过操作系统内核代码来访问外设硬件内核态是工作在特权模式下操作系统在特权模式下完成将用户数据打印到显示器上。 这样做是为了保护操作系统的安全和硬件资源的合理使用。该异常在管理模式下处理。 4预取指令中止异常Prefetch Abort 该异常发生在CPU流水线取指阶段如果目标指令地址是非法地址进入该异常。该异常在中止异常模式下处理。 5数据中止访问异常Data Abort 该异常发生在要访问数据地址不存在或者为非法地址时。该异常在中止异常模式下处理。 6一般中断请求异常IRQ、快速中断请求异常FRQ CPU与外部设备相对独立CPU对全部设备进行管理和资源调度处理CPU要想知道外部设备的运行状态可以让CPU定时查看外部设备的特定寄存器轮询或者在需要CPU干涉处理时让外部设备打断CPU中断让CPU来处理外部设备的请求。 显然第二种方式更合理可以让CPU专心工作这里的“打断”操作就叫做中断请求。 根据请求的紧急情况中断请求分一般中断和快速中断。绝大部分外设使用一般中断请求。快速中断具有最高中断优先级和最小的中断延迟通常用于处理高速数据传输及通道的中数据恢复处理如DMA等。 2、中断的介绍 从上面关于“异常”的描述可知中断属于异常的一种分为“快速中断”和“一般中断”。 中断主要用来解决宏观上的并行需求。微观上的并行指的是真正的并行即使精确到每一秒甚至每一刻多个事情还是在同时进行。宏观上的并行并不等于微观上的并行有时候宏观上是并行的微观上是串行的。 单核CPU无法实现微观上的并行但是通过中断机制可以实现宏观的并行。 衡量一个操作系统的实时性的指标包括最短响应中断时间、单位时间内响应中断次数。 3、异常向量表 3.1 异常向量表的定义 CPU事先定义了一些特定地址作为特定异常的入口地址。异常发生时CPU会根据实际情况把PC的值设置为这些特定地址中的某一个则CPU接下来会取出并执行这个地址所对应的存储单元里的指令。这指令一般是跳转指令以跳转到专门处理某个异常的子程序。这些特定异常及其入口地址的对应关键系就称为异常向量表。 比如定义0x00000000这个地址为复位异常向量地址当发生复位异常时CPU会自动跳转到0x00000000地址去执行指令比如定义0x30000008这个地址为外部中断对应的异常向量地址当发生外部中断时CPU会自动跳转到0x30000008地址去执行指令。 所有架构比如51单片机、PIC单片机的CPU的中断都是通过异常向量表实现的但是不同CPU异常向量表的构造比如有哪些异常向量、这些异常向量的相对位置和异常向量表的基地址往往不同。复杂的ARM还可以软件设置异常向量表的基地址。 一个常见的异常向量表设置如下 相对于基地址的偏移量异常情况0x1CFIQ0x18IRQ0x14保留0x10Data Abort0x0CPrefetch Abort0x08Software Interrupt0x04Undefined Instruction0x00Reset3.2 异常向量表的优先级 优先Reset→Data abort→FIQ→IRQ→Prefetch abort→Undefined instruction / SWI。 3.3 s5pv210的异常向量表 上面所列的常见异常向量表也是s5pv210的异常向量表不过要注意以下几点内容。 1s5pv210 的异常向量表的基地址 系统刚启动时SDRAM 还没有初始化程序都在SRAM中运行因此s5pv210在SRAM中设置了异常向量表以供暂时性使用。如下图所示S5PV210在SRAM中设置的异常向量表的起始地址为0xD003_7400。 2s5pv210 的异常向量表的修改 s5pv210 的异常向量表可以修改以适应操作系统的需求。具体见参考博文二。 二、S5PV210的中断处理流程 1、中断处理的2个阶段 第一个阶段是异常向量表跳转第二个阶段是进入异常处理程序。 2、中断处理的第一阶段 第一个阶段依赖于CPU设计时提供的异常向量表机制。 主要任务是从异常发生到响应异常并且保存现场然后跳转到真正的异常处理程序处。 3、中断处理的第二阶段 第二个阶段主要任务是识别哪个中断源发生了中断然后调用相应的中断处理程序。 1S3C2440的第二阶段处理过程 怎么找到具体是哪个中断 S3C2440的中断控制器中有一个32位的寄存器寄存器的每一个位对应一个中断源。为了解决支持更多的中断源2440又设计了一个子中断机制。在一级中断寄存器中有一些中断共用一个bit位比如AC97和WDT。对于共用中断用子中断来区分哪一个发生中断。 怎么找到对应的ISR 首先给每个中断做了个编号进入isr_handler之后先通过查阅中断源寄存器和子中断寄存器中哪一位为1确定中断的编号然后用这个编号去isr数组isr数组是中断初始化时事先设定好的就是把各个中断的isr的函数名组成一个数组用中断对应的编号作为索引来查询这个数组中查阅得到isr地址。 评价好不好 上面第一个过程中使用子中断搞成2级的很麻烦第二个过程中计算中断编号也耗费时间而中断处理的时间是很宝贵的。系统有一个性能指标叫实时性。实时性就是中断发生到响应的时间这个时间越短越好。 2S5PV210的第二阶段处理过程 怎么找到具体是哪个中断 S5PV210因为支持的中断源很多所以直接设计了4个中断寄存器每个32位每位对应一个中断源。理论上210最多支持128个中断实际支持不足128个因为有些位是空的。S5PV210没有子中断寄存器每个中断源都是并列的。当中断发生时在irq_handler中依次去查询4个中断源寄存器看哪一个中断源寄存器的哪一位被置1则这个位对应的寄存器就发生了中断即找到了中断编号。 怎么找到对应的isr S5PV210中支持的中断源很多如果使用2440的那一套来寻找isr的地址实时性就不好了。S5PV210提供了很多寄存器来解决每个中断源对应isr的寻找问题。当发生相应中断时硬件会自动的将相应isr推入一定的寄存器中我们软件只要去这个寄存器中执行函数就行了。 3总结对比 第一阶段2440和210几乎完全相同实际上几乎所有的CPU在第一阶段都是相同的。 第二阶段不同。各个SoC根据自身对实时性的要求、中断源的多少各自发明了寻找中断编号、寻找对应isr地址的方式。 三、S5PV210的中断控制器
这里所说的中断控制器是指与中断有关的寄存器所组成的集合。
1、 中断使能与禁止寄存器VICnINTENABLE、VICnINTENCLEAR 1VICnINTENABLE 和 VICnINTENCLEAR寄存器分别负责中断使能与中断禁止。 2n0,1,2,3对应着四个寄存器每个寄存器都是32bit每个bit对应一个中断源是否使能 。 VIC0INTENABLE VIC0INTCLEARVIC1INTENABLE VIC1INTCLEARVIC2INTENABLE VIC2INTCLEARVIC3INTENABLE VIC3INTCLEAR如果想启用某个中断则需要在此中断编号所对应的VICnINTENABLE寄存器的相应的位上写1如果想禁止某个中断源则需要在VICnINTENCLEAR寄存器的相应的位写1。 注意有些CPU可以在同一个寄存器位进行中断使能和禁止的设置写1使能写0禁止或者反过来而有些CPU的中断使能和禁止分开为2个寄存器要使能中断就写使能寄存器要禁止中断就写禁止寄存器这里就是这种情况。 3代码示例 //使能中断
//传参intnum表示要启动的某个具体的中断源中断号在int.h中定义是物理中断号
void intc_enable(unsigned long intnum)
{unsigned long temp;// 确定intnum在哪个寄存器的哪一位// 32就是031必然在VIC0if(intnum32){temp VIC0INTENABLE;temp | (1intnum); VIC0INTENABLE temp;}else if(intnum64){temp VIC1INTENABLE;temp | (1(intnum-32));VIC1INTENABLE temp;}else if(intnum96){temp VIC2INTENABLE;temp | (1(intnum-64));VIC2INTENABLE temp;}else if(intnumNUM_ALL){temp VIC3INTENABLE;temp | (1(intnum-96));VIC3INTENABLE temp;}// NUM_ALL : enable all interruptelse{VIC0INTENABLE 0xFFFFFFFF;VIC1INTENABLE 0xFFFFFFFF;VIC2INTENABLE 0xFFFFFFFF;VIC3INTENABLE 0xFFFFFFFF;}
} 2、中断模式选择寄存器VICnINTSELECT 1VICnINTSELECT寄存器用来设置各个中断的模式为IRQ还是FIQ。一般都设置成IRQ。 2n0,1,2,3对应着四个寄存器可以设置各个中断的模式。 VIC0INTSELECTVIC1INTSELECTVIC2INTSELECTVIC3INTSELECT3IRQ和FIQ的区别 s5pv210支持2种中断IRQ和FIQIRQ是普通中断FIQ是快速中断。快速中断提供一种更快响应处理的中断通道用于对实时性要求很高的中断源。CPU提供了一些机制保证FIQ可以被快速处理从而保证实时性。但是只能有一个中断源被设置为FIQ其他都是IRQ。 4FIQ比IRQ快的原因 FIQ模式有专用的r8r12因此中断服务程序可以直接使用r8-r12而不用保存这就能节省时间。 另外异常向量表中FIQ是最后一个异常向量入口因此FIQ模式的中断服务程序不需要跳转可以直接写在原地这样就比其他异常少跳转一次节省一些时间。 5代码示例 // 清除需要处理的中断的中断处理函数的地址
void intc_clearvectaddr(void)
{// VICxADDR:当前正在处理的中断的中断处理函数的地址即isr的入口地址VIC0ADDR 0;VIC1ADDR 0;VIC2ADDR 0;VIC3ADDR 0;
}// 初始化中断控制器
void intc_init(void)
{// 禁止所有中断// 为什么在中断初始化之初要禁止所有中断// 因为中断一旦打开因为外部或者硬件自己的原因产生中断后一定就会寻找isr// 而我们可能认为自己用不到这个中断就没有提供isr这时它自动拿到的就是乱码// 则程序很可能跑飞所以不用的中断一定要关掉。// 一般的做法是先全部关掉然后再逐一打开自己感兴趣的中断。一旦打开就必须// 给这个中断提供相应的isr并绑定好。VIC0INTENCLEAR 0xffffffff;VIC1INTENCLEAR 0xffffffff;VIC2INTENCLEAR 0xffffffff;VIC3INTENCLEAR 0xffffffff;// 这里把所有的中断源的中断类型设置为IRQ其实可以具体到设置每一个中断的中断模式 VIC0INTSELECT 0x0;VIC1INTSELECT 0x0;VIC2INTSELECT 0x0;VIC3INTSELECT 0x0;// 清VICxADDRintc_clearvectaddr();
} 3、 中断状态寄存器VICnIRQSTATUS、VICnFIQSTATUS 1当发生中断时硬件会自动将该寄存器的对应位设置为1以表示发生了中断发。软件在处理中断第二阶段的第一阶段就是通过查询这个寄存器来得到中断编号的。 2n0,1,2,3对应着四个寄存器每个寄存器的每个位表征否发生中断。 VIC0IRQSTATUSVIC1IRQSTATUSVIC2IRQSTATUSVIC3IRQSTATUS3代码示例 // 通过读取VICnIRQSTATUS寄存器判断其中哪个有一位为1来得知哪个VIC发生中断了
unsigned long intc_getvicirqstatus(unsigned long ucontroller)
{if(ucontroller 0)return VIC0IRQSTATUS;else if(ucontroller 1)return VIC1IRQSTATUS;else if(ucontroller 2)return VIC2IRQSTATUS;else if(ucontroller 3)return VIC3IRQSTATUS;else{}return 0;
}// 真正的中断处理程序。意思就是说这里只考虑中断处理不考虑保护/恢复现场
void irq_handler(void)
{//printf(irq_handler.\n);// SoC支持很多个在低端CPU例如2440中有30多个在210中有100多个中断// 这么多中断irq在第一个阶段走的是一条路都会进入到irq_handler来// 我们在irq_handler中要去区分究竟是哪个中断发生了然后再去调用该中断// 对应的isr。// 虽然硬件已经自动帮我们把isr放入了VICnADDRESS中但是因为有4个所以我们必须// 先去软件的检查出来到底哪个VIC中断了也就是说isr到底在哪个VICnADDRESS寄存器中unsigned long vicaddr[4] {VIC0ADDR,VIC1ADDR,VIC2ADDR,VIC3ADDR};int i0;void (*isr)(void) NULL;for(i0; i4; i){// 发生一个中断时4个VIC中有3个是全01个的其中一位不是0if(intc_getvicirqstatus(i) ! 0){isr (void (*)(void)) vicaddr[i];break;}}(*isr)(); // 通过函数指针来调用函数
}4、中断优先级设置寄存器VICnVECTPRIORITYm 1中断优先级设置寄存器可以设置多个中断同时发生时先处理谁后处理谁的问题。一般来说高优先级的中断可以打断低优先级的中断从而嵌套处理中断。 2n0,1,2,3m0,1…31 VIC0VECTPRIORITY0VIC0VECTPRIORITY1…VIC0VECTPRIORITY31VIC1VECTPRIORITY0VIC1VECTPRIORITY1…VIC1VECTPRIORITY31VIC2VECTPRIORITY0VIC2VECTPRIORITY1…VIC2VECTPRIORITY31VIC3VECTPRIORITY0VIC3VECTPRIORITY1…VIC3VECTPRIORITY315、存放中断处理函数首地址的寄存器VICnVECTADDRm 1这些寄存器用来存放各个中断所对应的中断处理函数的首地址。 2每一个中断源都有一个VECTADDR寄存器程序员在设置中断的时候把这个中断的中断处理函数的首地址直接放入这个中断所对应的VECTADDR寄存器即可。 3n0,1,2,3m0,1…31 VIC0VECTADDR0VIC0VECTADDR1…VIC0VECTADDR31VIC1VECTADDR0VIC1VECTADDR1…VIC1VECTADDR31VIC2VECTADDR0VIC2VECTADDR1…VIC2VECTADDR31VIC3VECTADDR0VIC3VECTADDR1…VIC3VECTADDR314代码示例 // 绑定我们写的isr到VICnVECTADDR寄存器
// 绑定过之后我们就把isr地址交给硬件了剩下的我们不用管了硬件自己会处理
// 等发生相应中断的时候我们直接到相应的VICnADDR中去取isr地址即可。
// 参数intnum是int.h定义的物理中断号handler是函数指针就是我们写的isr// VIC0VECTADDR定义为VIC0VECTADDR0寄存器的地址就相当于是VIC0VECTADDR031这个
// 数组这个数组就是一个函数指针数组的首地址然后具体计算每一个中断的时候
// 只需要首地址偏移量即可。
void intc_setvectaddr(unsigned long intnum, void (*handler)(void))
{//VIC0if(intnum32){*( (volatile unsigned long *)(VIC0VECTADDR 4*(intnum-0)) ) (unsigned)handler;}//VIC1else if(intnum64){*( (volatile unsigned long *)(VIC1VECTADDR 4*(intnum-32)) ) (unsigned)handler;}//VIC2else if(intnum96){*( (volatile unsigned long *)(VIC2VECTADDR 4*(intnum-64)) ) (unsigned)handler;}//VIC3else{*( (volatile unsigned long *)(VIC3VECTADDR 4*(intnum-96)) ) (unsigned)handler;}return;
} 6、VICnADDRESS寄存器 1当发生中断时硬件自动识别中断编号并且自动找到这个中断所对应的VECTADDR寄存器然后把寄存器的内容复制到VICADDRESS中以供后续使用。这样的设计避免了软件查找中断源和中断处理函数节省了时间提高了s5pv210的中断响应速度。 2代码示例 // 真正的中断处理程序。意思就是说这里只考虑中断处理不考虑保护/恢复现场
void irq_handler(void)
{//printf(irq_handler.\n);// SoC支持很多个在低端CPU例如2440中有30多个在210中有100多个中断// 这么多中断irq在第一个阶段走的是一条路都会进入到irq_handler来// 我们在irq_handler中要去区分究竟是哪个中断发生了然后再去调用该中断// 对应的isr。(函数指针)// 虽然硬件已经自动帮我们把isr放入了VICnADDR中但是因为有4个所以我们必须// 先去软件的检查出来到底哪个VIC中断了也就是说isr到底在哪个VICADDR寄存器中unsigned long vicaddr[4] {VIC0ADDR,VIC1ADDR,VIC2ADDR,VIC3ADDR};int i0;void (*isr)(void) NULL;for(i0; i4; i){// 发生一个中断时4个VIC中有3个是全01个的其中一位不是0if(intc_getvicirqstatus(i) ! 0){isr (void (*)(void)) vicaddr[i];break;}}(*isr)(); // 通过函数指针来调用函数
}7、总结 以上介绍的寄存器中能表征中断流程的寄存器有 1VICnIRQSTATUS4个 VIC0IRQSTATUSVIC1IRQSTATUSVIC2IRQSTATUSVIC3IRQSTATUS2VICnVECTADDRm寄存器4*32128个 VIC0VECTADDR0VIC0VECTADDR1……VIC0VECTADDR31VIC1VECTADDR0VIC1VECTADDR1……VIC1VECTADDR31VIC2VECTADDR0VIC2VECTADDR1……VIC2VECTADDR31VIC3VECTADDR0VIC3VECTADDR1……VIC3VECTADDR313 VICnADDRESS寄存器4个 VIC0ADDRESSVIC1ADDRESSVIC2ADDRESSVIC3ADDRESS它们之间的关系如下