(原创)eCos驱动分析 之 ISR是如何与硬件中断联系起来的 ---转载文章

合集下载

外部中断实验原理

外部中断实验原理

外部中断实验原理一、实验原理外部中断是计算机科学中的一个重要概念,它允许程序在特定的事件发生时被唤醒或中断。

外部中断对于实现实时计算、多任务处理、异常处理等重要功能具有关键作用。

本实验旨在深入理解外部中断的工作原理,并通过实例分析来揭示其实际应用中的关键点。

二、详细内容分析1. 中断触发机制外部中断是由特定事件触发的,例如输入输出操作完成、定时器溢出、硬件错误等。

当中断触发条件满足时,硬件会保存当前程序的状态,并将控制权转移到指定的中断处理程序。

2. 中断优先级当多个中断同时发生时,系统需要根据一定的优先级规则来确定执行哪个中断处理程序。

中断优先级的高低取决于具体应用的需求,通常可以根据重要性和实时性要求来设定。

3. 中断处理程序中断处理程序(Interrupt Service Routine, ISR)是一段特定的代码,用于在发生中断时处理事件并做出响应。

ISR通常包括保存寄存器状态、处理中断事件、恢复寄存器状态以及执行相应的操作等步骤。

4. 中断嵌套与处理器状态在多任务操作系统中,可能存在多个中断同时发生的情况。

此时,系统需要根据优先级逐一处理中断,并保存每个中断处理前的处理器状态,以便在处理完中断后恢复到原来的状态。

5. 中断屏蔽与唤醒某些情况下,系统可能需要暂时屏蔽某些中断,以避免干扰关键任务的执行。

同时,某些中断可能需要唤醒睡眠状态的进程或线程。

这些操作需要通过特定的指令或机制来实现。

三、实例分析以一个简单的例子来说明外部中断的工作流程:假设我们有一个基于Linux 系统的嵌入式系统,当某个硬件设备完成一项任务(如数据传输)时,会触发一个外部中断。

系统会保存当前的任务状态,并执行相应的中断处理程序(ISR)。

ISR会读取硬件设备的数据,并执行相应的操作(如数据处理、任务调度等)。

在ISR执行完毕后,系统会恢复之前保存的任务状态,并继续执行之前的任务。

这个例子中,我们看到了外部中断如何被用于实时处理任务、唤醒睡眠状态的进程以及调度任务等操作。

DSPBIOS总结

DSPBIOS总结

DSP/BISO线程调度DSP/BIOS使用户的应用程序可以由一个线程集合构筑起来,每一个线程执行一个模块化的功能。

通过允许高优先级的线程抢占低优先级的线程,以及允许阻塞、同步、通信等各种线程间的交互方式,使得多线程的应用程序可以在一个处理器上运行。

DSP/BIOS支持多种不同优先级的线程,每种线程类型都有不同的执行和抢占特性。

这些线程按照优先级从高到低的顺序排列如下:●硬件中断(HWI),包括CLK函数。

●软件中断(SWI),包括PRD函数。

●任务(TSK)。

●后台线程(IDL)。

在DSP/BIOS中,硬件中断有最高的优先级,然后是软件中断,软件中断可以被高优先权软件中断或硬件中断抢先。

软件中断是不能被阻塞的。

任务的优先权低于软件中断,共有15个任务优先权级别(加上TSK_idle应该16个)。

任务在等待某个资源有效时可以被阻塞。

后台线程idle_loop是优先级最低的线程。

线程优先级如下图表示:下面具体介绍各种线程。

HWI module硬件中断是用来处理应用程序响应外部异步事件时必须执行的关键操作。

在典型的DSP应用中,硬件中断是由片上的外设或者DSP外部的设备触发的。

中断发生后处理器会通过中断向量跳转到相应的ISR地址。

一个中断的跳转由一个DSP/BIOS HWI对象负责,跳转的地址可以是一个用户函数或者是通用的系统HWI调度程序(dispatcher)的入口地址。

硬件中断ISR可以使用汇编语言、C语言或者混合编写。

HWI函数通常使用汇编来提高效率。

如果要完全使用C语言编写,应该使用系统的HWI调度程序,它会在调用用户C函数的前后分别惊醒现场环境保护与恢复。

所有的硬件中断都会一直运行到结束,如果一个硬件中断在其ISR得到运行机会前被多次触发,该ISR也只运行一次。

因此,用户必须尽量和减少HWI执行的代码量。

如果GIE位被使能,一个硬件中断可能被任何其他的被使能的中断抢占。

硬件中断没有优先级的区分;线程调度结果首先取决于该类就绪线程是被使能还是被禁止的。

浅谈linux性能调优之十七:进程绑定与中断绑定

浅谈linux性能调优之十七:进程绑定与中断绑定

浅谈linux性能调优之十七:进程绑定与中断绑定1.使用taskset设置CPU亲和性taskset搜索并设定运行进程的CPU亲和性(根据进程ID)。

它还可用于启动给定CPU亲和性的进程,这样就可将指定的进程与指定的CPU或者一组CPU捆绑CPU 亲和性使用位掩码表示。

最低位对应第一个逻辑 CPU,且最高位对应最后一个逻辑CPU。

这些掩码通常是十六进制,因此0x00000001 代表处理器 1,0x00000003 代表处理器 3 。

要设定运行进程的 CPU 亲和性,请执行以下命令,使用处理器或者您要捆绑到的处理器掩码替换 mask,使用您要更改亲和性的进程的进程 ID 替换 pid。

# taskset -p mask pid要启动给定亲和性的进程,请运行以下命令,使用处理器或者您要捆绑的处理器的掩码替换 mask,使用程序、选项以及您要运行的程序参数替换 program。

# taskset mask -- program与其将处理器指定为位码,您还可以使用 -c 选项提供逗号分开的独立处理器,或者一组处理器列表,类似如下:# taskset -c 0,5,7-9 -- myprogram有关 taskset 的详情请参考 man page:man taskset。

2.硬件中断发生频繁,是件很消耗 CPU 资源的事情,在多核 CPU 条件下如果有办法把大量硬件中断分配给不同的 CPU (core) 处理显然能很好的平衡性能。

现在的服务器上动不动就是多 CPU 多核、多网卡、多硬盘,如果能让网卡中断独占1个 CPU (core)、磁盘 IO 中断独占1个 CPU 的话将会大大减轻单一 CPU 的负担、提高整体处理效率。

中断请求(IRQ)是用于服务的请求,在硬件层发出。

可使用专用硬件线路或者跨硬件总线的信息数据包(消息信号中断,MSI)发出中断。

启用中断后,接收IRQ 后会提示切换到中断上下文。

内核中断调度代码会搜索 IRQ 号码机器关联的注册中断服务路由(ISR)列表,并按顺序调用 ISR。

中断实例

中断实例

.sect “.pvecs”
PVECTORS B B B B B B B PHANTOM PHANTOM PHANTOM PHANTOM PHANTOM PHANTOM PHANTOM
;定义各外设子向量段
;子向量的地址偏移为0000h 子向量的地址偏移为 ;子向量的地址偏移为0001h 子向量的地址偏移为 ;子向量的地址偏移为0002h 子向量的地址偏移为 ;子向量的地址偏移为0003h 子向量的地址偏移为 ;子向量的地址偏移为0004h 子向量的地址偏移为 ;子向量的地址偏移为0005h 子向量的地址偏移为 ;子向量的地址偏移为0006h 子向量的地址偏移为
INT5 B INT6 B
PHANTOM ;PMA Int level 5 8 PHANTOM ;PMC Int level 6 9 PHANTOM ;PM10 User S/W int- - PHANTOM ;PM12 User S/W int- - PHANTOM ;PM14 User S/W int- - PHANTOM ;PM16 User S/W in存器PIVR中 CPU获取被装载 中断向量)被装载到外设中断向量寄存器PIVR中,CPU获取被装载 PIVR 到PIVR中的值之后,用这个值来判断是哪一个外设引起的中断,接 PIVR中的值之后,用这个值来判断是哪一个外设引起的中断, 中的值之后 着转移到相应的SISR。 转移到相应的SISR。 SISR 将PIVR中的值装载入累加器时需先左移,再加上一个固定的偏 PIVR中的值装载入累加器时需先左移, 加上一个固定的偏 中的值装载入累加器时需先左移 移量,然后程序转到累加器指定的地址入口,这个地址将指向SISR, 移量,然后程序转到累加器指定的地址入口,这个地址将指向SISR, SISR 从而执行XINT1的中断服务子程序。 从而执行XINT1的中断服务子程序。 XINT1的中断服务子程序 例如: 例如: LACC PIVR,1;读外设中断向量寄存器(PIVR),并左移 位 ),并左移 ;读外设中断向量寄存器( ),并左移1位 ADD #PVECTTORS;加上外设中断入口地址, ;加上外设中断入口地址, BACC ;跳到相应的中断服务子程序入口 T1PINT_ISR:LDP #DP_EVA;通用定时器 中断服务;子程序入 中断服务; : ;通用定时器1中断服务 口

基于eCos操作系统的FLASH驱动程序分析与移植

基于eCos操作系统的FLASH驱动程序分析与移植

基于eCos操作系统的FLASH驱动程序分析与移植0 引言嵌入式系统需要支持的外部设备种类繁多,如何构造运行良好的嵌入式设备的驱动程序,对嵌入式操作系统的实际应用有重要意义。

eCos是一种源代码公开的实时嵌人式操作系统,对嵌入式应用具有良好的支持,内核专门设计了便于设备驱动管理和开发的I/O包和DEV包,开发人员可以方便地将自己开发的驱动程序加入其中,与别的系统组件一起进行配置。

1 系统目标板简介硬件目标板是为无人机系统设计的系统开发板,它是从Arca系统测试板经过功能简化设计而来的满足无人机系统要求的目标板。

硬件目标板如图1所示。

GT2000支持SRAM,FLASH,ROM,VLIO(静态段支持可变等待时间I/O设备)和SDRAM(同步动态RAM)等外部扩展存储器。

GT2000的外部地址空间是按体(bank)划分的,有四个体属于静态存储器区域,由引脚CS0~CS3选择,在将FLASH,SRA M,VLIO(用作其他外设接口)等静态I/O设备地址分别设计在CS0~CS2区域内,由GT2000内部的外部内存访问接口(EMI)控制器中的静态内存访问控制寄存器(SMCR)进行访问控制,分配地址访问接口。

系统目标板选用两片Intel公司的TE28F320的FLASH(16位)并联获得32位总线宽度。

Intel公司的TE28F320是32 Mb(2 M×16 b)多功能FLASH,2.7~3.6 V单电源供电,读取时间为70 ns,封装格式为48-Pin TSoP(12 mm×20 mm)或48-Ball TFB-GA,可被擦写10 000次。

方舟的JTAG仿真器支持TE28F320 FLASH,可以通过JTAG接口进行在线读写和擦除,这给调试程序和硬件提供了方便。

FLASH的电路原理图以及GT2000的引脚“DACK[2..1]/MD_MEM[1..0]”设置如图2所示。

2 eCos驱动程序的体系结构与驱动程序设计模式eCos操作系统的设备驱动程序通常包含以下内容:提供一些底层函数,负责完成设备初始化与配置、注册设备,从设备收发数据、控制设备、处理设备中断等,并进行设备管理。

CE中断详解

CE中断详解

CE中断详解CE中断详解WINCE驱动开发之中断的使用中断的使用1、wince中断简介1: ISR的概念首先搞清楚两个名词意义,IRQ:硬件中断号;SYSINTR_xx:系统中断或者称逻辑中断号。

ISR(interrupt service routine)是处理IRQs(interrupt request line)的程序。

Windows CE用一个ISR来处理所有的IRQ (硬件中断号)请求。

当一个中断发生时,内核的异常处理程序先调用内核ISR,内核ISR禁用所有具有相同优先级和较低优先级的中断,然后调用已经注册的OAL ISR程序,一般ISR有下列特征:1) 执行最小的中断处理,最小的中断处理指能够检验、答复产生中断的硬件,而把更多的处理工作留给IST(interrupt service thread)。

2) 当ISR完成时返回中断ID(逻辑中断,或者说是系统中断,就是SYSINTR_xx)(这个中断ID大部分是预定义的)。

ISR是在OAL层中实现的运行于内核态的程序。

根据执行效率要高和嵌入式实时性的要求,ISR多用汇编或者C语言实现,主要任务就是根据硬件中断返回一个逻辑中断号。

根据CPU是单个中断入口还是多个中断入口,ISR分为单ISR模型和多ISR模型:(1)单ISR模型:CPU只有一个硬件中断IRQ入口(如ARM和XScale处理器),所有的中断只有一个ISR入口,在OAL层中有一个统一的函数名:OEMInterruptHandler,在此函数中识别中断源并返回一个逻辑中断号SYSINTR_ID。

如:在BSP的oalintr.h里定义自定义中断的逻辑中断值#define SYSINTR_MYINTR (SYSINTR_FIRMWARE + 10)在armint.c的OEMInterruptHandler()中OEMInterruptHandler(){…………….else if (IntPendVal == INTSRC_EINT2) // EINT2return(SYSINTR_MYINTR);}(2)多ISR模型:即ISR链(IISR)。

ECos系统驱动程序的编写

ECos系统驱动程序的编写

ECos系统驱动程序的编写介绍Ecos的驱动程序分为两个部分:1./dev目录下,该部分程序同硬件相关2./io目录下,该部分程序同系统相关在IO包中的元件,可以增加当一个驱动程序被认为是静止的时候,她们必须通过一个透明的“handle”来访问。

每一个设备都有一个独特的名字,函数cyg_io_lookup()被用来寻找设备名字和设备号的对应。

而且,cyg_io_lookup()函数为设备驱动程序在使用该设备时进行设备的初始化提供了方便。

所有设备都有一个名字,如:/dev/console、/dev/serial0,等等所有的驱动程序,在Ecos中都是有c写成的设备驱动程序的基本功能是提供对设备的接收和发送数据。

而详细的实现方法有设备类自己实现。

例如:向块设备读写数据同向串口读写数据不同附加的函数为操作设备或硬件设备的状态提供了接口。

不同的设备有不同的附加函数。

Ecos的设备模块支持分层(layering),也就是说,一个设备驱动程序可以创建在另一个设备驱动程序上。

例如:tty就建立在简单的串口驱动上。

上层模块相对底层模块而言,有更好的可塑性,可以增加更多的功能和特征。

如tty设备驱动还提供了队列缓冲和编辑。

有些设备驱动还提供了它们所依赖的下一级驱动的特性。

Tty设备允许通过get/set config 调用来操作实际串口的的信息,并下达到实际串口。

用户API所有相关函数,除了cyg_io_lookup()以外,都需要io句柄。

所有函数都返回一个Cyg_ErrNo值。

若一个错误发生时,该值为负数,且其绝对值代表相应的错误号。

该值在cyg/error/codes.h有定义。

正确返回ENOERR。

任何的函数参数都为指针。

它允许驱动传递效率高。

最应引起注意的是参数length,他将传递给读写函数。

他包含有一个期待返回的数据长度而返回实际长度。

Cyg_ErrNo cyg_io_lookup( const char *name, cyg_io_handle_t *handle )上述函数将设备名字转换成句柄。

中断处理可以分为两部分中断服务b例程bISR

中断处理可以分为两部分中断服务b例程bISR

中断在系统设计中的应用非常广泛,可以说,硬件中断、软件中断无处不在,在WINCE下驱动开发更是如此,比如:按键中断、触摸屏中断、AUDIO中断、DMA中断.....等等,几乎含概每个模块。

因此,了解中断的处理过程对驱动开发极其重要,下面对WINCE下的中断处理过程做一个简单介绍。

中断处理可以分为两部分:中断服务例程-ISR、中断服务线程-IST。

系统在处理中断异常的时候,应该要尽可能快的完成,因此,我们应该ISR中做简短的处理,把中断标识返回给中断处理器,越快越好。

那么就要把大部分的处理留给IST来处理。

我们可以简单的认为,ISR的任务就是完成把硬件中断也就是物理中断转为系统中断并返回。

下面再来了解一下IST,IST就是一个线程,在驱动初始化的时候创建并等待一个事件,当然,在这之前要先创建一个事件,并与中断相关联起来,当中断产生以后该事件触发IST,IST里通常是用户的处理程序。

IST的实现必须先实现两个过程:IST的中断必须和一个事件相关联,IST必须通过WaitForSingleObject来等待这个事件的唤醒,IST的最后要调用INTERRUPTDONE来对注销中断,否则该中断只能用一次,一般我们在驱动的XXX_INIT函数中实现。

IST在BSP/COMMON/INTR/intr.c中,这里面的内容包括init、enable、disable、oeminterrupthandler等函数,主要是对中断的初始化、使能、处理等,其中最关键的是oeminterrupthandler。

以下是我在该函数中对EINT的简单处理部分代码:if (irq == IRQ_EINT4_7 || irq == IRQ_EINT8_23) { // 4 or 5// Find external interrupt numbermask = INREG32(&g_pPortRegs->EINTPEND);mask &= ~INREG32(&g_pPortRegs->EINTMASK);mask = (mask ^ (mask - 1)) >> 5;irq2 = IRQ_EINT4;while (mask != 0) {mask >>= 1;irq2++;}// Mask and clear interruptmask = 1 << (irq2 - IRQ_EINT4 + 4);SETREG32(&g_pPortRegs->EINTMASK, mask);OUTREG32(&g_pPortRegs->EINTPEND, mask);// Clear primary interruptmask = 1 << irq;OUTREG32(&g_pIntrRegs->SRCPND, mask);OUTREG32(&g_pIntrRegs->INTPND, mask);// From now we care about this irqirq = irq2;else {// Mask and clear interruptmask = 1 << irq;SETREG32(&g_pIntrRegs->INTMSK, mask);OUTREG32(&g_pIntrRegs->SRCPND, mask);OUTREG32(&g_pIntrRegs->INTPND, mask);}// First find if IRQ is claimed by chainsysIntr = NKCallIntChain((UCHAR)irq);if (sysIntr == SYSINTR_CHAIN || !NKIsSysIntrValid(sysIntr)) {// IRQ wasn't claimed, use static mappingsysIntr = OALIntrTranslateIrq(irq);}而IST的具体实现过程可以参照下面的步骤:1、创建一个事件。

单片机中的中断处理机制详解

单片机中的中断处理机制详解

单片机中的中断处理机制详解中断是单片机系统中一种重要的事件响应机制,它可以在程序执行期间暂停当前任务,切换到执行预先定义的中断服务程序(ISR),处理发生的事件,然后再返回到原来的任务。

中断处理机制可以提高系统的响应速度,实现多任务处理和实时控制。

一、中断的分类根据中断源的不同,中断可以分为外部中断和内部中断两类。

1. 外部中断(外部触发):由单片机外部设备产生的中断请求,如按键、定时器、通信接口等。

外部中断可以通过配置中断触发方式为边沿触发或电平触发来选择中断时机。

2. 内部中断(软件触发):由单片机内部事件产生的中断请求,如定时器溢出、串口接收中断等。

内部中断由硬件自身生成,程序可以设置中断使能位和优先级,通过软件触发来使中断发生。

二、中断的执行过程1. 中断请求:当外部设备产生中断请求或者内部事件满足中断触发条件时,会使中断请求标志位置为1,通知单片机发生了中断请求。

2. 中断响应:单片机在进行指令执行过程中会不断地检测中断请求标志位。

如果中断请求标志位为1,表示有中断请求发生,单片机会立即停止当前任务的执行,保存相关寄存器的值,将中断请求标志位复位,并跳转到相应的中断服务程序(ISR)执行。

3. 中断服务程序(ISR):中断服务程序是为了响应特定中断请求而编写的一段程序代码。

ISR的功能是根据中断源的不同进行相应操作,例如读取外设状态、处理数据等。

在ISR执行过程中,一般需要关闭其他中断,以确保ISR的实时性和正确性。

执行ISR结束后,可以重新开放其他中断,供后续的中断请求使用。

4. 中断返回:ISR执行完毕后,需要通过特定的指令返回到原来的任务继续执行,通常使用“返回指令”(RET)或“中断返回指令”(RETI)完成。

在返回之前,需要恢复保存的寄存器值和标志位的状态。

三、中断优先级当多个中断同时发生时,需要根据实际应用需求设置中断的优先级。

中断优先级决定了中断的执行顺序。

1. 屏蔽优先级:每个中断源都有一个屏蔽位,可以设置为使能中断或屏蔽中断。

eCos和在ARM上的驱动与应用开发

eCos和在ARM上的驱动与应用开发

eCos和在ARM上的驱动与应用开发一、eCos系统介绍摘要:简单介绍eCos的体系结构,详细论述eCos的可配置机制的实现原理,重点介绍eCos 在以AT91M55800为核心的ARM7硬件平台上的移植步骤,结合本系统简要介绍内核的配置方法。

最后给出了基于eCos应用软件的编写方法。

eCos(Embedded Configurable Operating System)最初是由Cygnus Solutions公司为面向嵌入式领域而开发的源码公开、具有很强的可移植性和可配置性的,适合于深度嵌入式开发的实时操作系统。

现在eCos主要由eCosCentric公司和eCos开源社区共同开发维护。

eCos的特性,特别是它的可配置性,能有效缩短嵌入式产品的开发周期并降低成本。

1 eCos的体系结构及可配置性1.1 eCos体系结构eCos采用模块化设计,将不同功能的软件分成不同的组件,使其分别位于系统的不同层次。

这种层次结构实现了eCos的可配置性、可移植性、兼容性和可扩展性。

图1是eCos 系统的层次结构框图。

硬件抽象层(HAL)使其上层次结构不必关心具体的硬件结构,因此只需对HAL进行修改就可以使整个eCos的应用移植到新的硬件平台上。

图1 eCos的层次结构框图内核是eCos的一个核心组件,也是系统的一个可选组件,一些较为复杂的应用需要内核的支持。

内核提供了多个可供选择的调度算法,可以很好地支持多任务处理。

eCos内核提供了一组丰富的同步源语,完全能满足各种嵌入式应用的需求。

内核还负责对中断和例外进行处理,它的中断滞后处理机制保证了系统的实时性。

此外,内核还具有内存分配机制和定时机制,并提供多线程GDB调试支持。

内核为上层软件和应用软件提供了丰富的API接口函数。

RedBoot是一个无内核的系统引导程序,是eCos的一个特殊应用。

RedBoot可以加载eCos应用程序,并提供Debug支持,是开发eCos系统时非常有用的工具。

WinCE中断的使用

WinCE中断的使用

WinCE中断的使用1、wince中断简介1:ISR的概念ISR(interrupt service routine)是处理IRQs(interrupt request line)的程序。

Windows CE用一个ISR来处理所有的IRQ请求。

当一个中断发生时,内核的异常处理程序先调用内核ISR,内核ISR禁用所有具有相同优先级和较低优先级的中断,然后调用已经注册的OAL ISR程序,一般ISR有下列特征:1) 执行最小的中断处理,最小的中断处理指能够检验、答复产生中断的硬件,而把更多的处理工作留给IST(interrupt service thread)。

2) 当ISR完成时返回中断ID(中断ID大部分是预定义的)。

2:中断注册步骤1) 用SETUP_INTERRUPT_MAP宏关联SYSINTR和IRQ。

以“SYSINTR_”为前缀的常量由内核使用,用于唯一标识发生中断的硬件。

在Nkintr.h文件中预定义了一些SYSINTR,OEM可以在Oalintr.h文件中自定义SYSINTR。

2) 用HookInterrupt函数关联硬件中断号和ISR。

这里的硬件中断号为物理中断号,而非逻辑中断号IRQ。

2、驱动中IST使用ISR是中断最小处理函数,因此各个驱动的中断处理函数称为IST。

系统中保留16个虚拟中断号,ak3224_intr.h已经定义好各个ISR的虚拟中断号28个。

因此,驱动中的中断处理函数,只要与定义好的28个虚拟中断映射上即可。

例子:首先,我们创建一个事件pGPIOInfo->hGPIOEvent1 = CreateEvent(0,FALSE,FALSE,NULL);其次创建一个处理事件的线程(IST)pGPIOInfo->hGPIOThread1 = CreateThread(NULL, 0, GPIOFuncThread1, pGPIOInfo, 0, NULL);然后使用InterruptInitialize让虚拟中断号pGPIOInfo->dwIntID1与创建的事件pGPIOInfo->hGPIOEvent1挂钩。

eCos ARM体系结构的IRQ情景分析

eCos ARM体系结构的IRQ情景分析

eCos ARM體系結構的IRQ情景分析之一已有6686 次閱讀2009-5-6 00:07最近定位一個問題,把eCos的IRQ代碼走讀了一下,順便做下筆記,共享之。

下圖為Massa的《Embedded Software Development with eCos》的對中斷的解析,這裡我們就從源代碼走一遍這個流程圖。

ARM中斷髮生時,ARM核會做下面一些工作:1、下一條將要執行的指令地址+4賦值給r14(lr)2、CPSR複製到SPSR3、CPSR的模式更改為IRQ模式4、如果原來是thumb狀態,則CPSR更改為ARM狀態5、CPSR的bit7設置為0,即關閉IRQ6、PC指針跳轉到IRQ的中斷向量地址(大多數情況為0x00000018)因此如果從中斷服務中返回,只要將lr減4複製給PC,同時恢復SPSR到CPSR 即可。

這樣被中斷的代碼可以繼續運行下去。

另外在大多數的ARM實現中,線程運行的模式大都為SVC模式,下文以此為假設。

好了,這樣就從hal/arm/arch/current/src/vectors.S 開始IRQ之旅。

784 IRQ:785 // Note: I use this exception stack while saving the context because786 // the current SP does not seem to be always valid in this CPU mode.中斷髮生時,首先需要保存現場,所謂保存現場,就是將一大堆寄存器保存在一個地方,當中斷返回時,重新恢復這些寄存器,以恢復原來的CPU運行狀態。

eCos將現場定義為一個數據結構,並將該數據結構保存在中斷髮生時的上下文的堆棧。

比如說中斷髮生在thread的上下文,則該數據結構保存在thread的堆棧裡。

在「hal/arm/arch/current/include/hal_arch.h」定義了該數據結構。

sisr寄存器原理

sisr寄存器原理

sisr寄存器原理
SISR(Slave-Initiated Selective Reset)寄存器是一种在计算机系统中用于控制复位操作的寄存器。

它通常用于处理器或其他
集成电路中,是一种用于实现系统级复位的重要组成部分。

SISR寄存器的原理是在系统中的每个从设备都有一个对应的SISR寄存器,主设备可以向这些从设备发送复位信号,以实现对特
定从设备的复位操作。

当主设备向某个从设备的SISR寄存器写入特
定的复位命令时,该从设备将执行复位操作,使其恢复到初始状态。

SISR寄存器通常包括一些特定的位字段,用于表示不同的复位
状态或命令。

例如,可能包括一个位用于表示硬件复位,另一个位
用于表示软件复位,还可能包括一些位用于表示不同的复位级别或
范围。

这些位字段的组合可以实现对系统中不同部件的有选择性的
复位操作。

另外,SISR寄存器还可以与系统中的其他控制逻辑相结合,例
如中断控制器或时钟控制器,以实现复杂的系统级复位操作。

通过
与其他控制逻辑的协同工作,SISR寄存器可以确保系统在复位过程
中的正确顺序和时序,以避免出现不可预测的系统行为。

总之,SISR寄存器通过对系统中的从设备进行有选择性的复位操作,实现了对系统复位过程的精细控制,是计算机系统中重要的一部分。

它的原理涉及到对特定位字段的设置和与其他控制逻辑的协同工作,以实现系统级的复位操作。

[宝典]中断资料

[宝典]中断资料

中断资料Wince6.0 中断的产生及响应收藏摘抄自- 程序设计实战一书各种外设时通过中断和wince核心进行通信的。

过程是:1)硬件设备产生硬件中断2)OAL完成硬件中断到逻辑中断(SYSINTR)的转换(OEMinit函数实现)3)系统识别逻辑中断,同时进行处理。

分两步:中断服务例程(ISR)和中断服务线程(IST)。

ISR主要负责中断响应,一般要求短小精干,对执行效率有很高的要求,只负责最简单的工程,即响应设备并返回一个中断标示给核心。

而对中断的实际处理则在IST中。

ISR的主要作用:1 如果数据可能丢失或者被下一个中断改写,则ISR将数据从设备读到缓冲区2 ISR清除设备上的中断条件3 ISR向内核返回一个SYSINTR4 内核设置供IST等待的中断事件5 调度程序调度等待的IST以执行后续的中断服务操作。

ISR分为静态ISR和可安装的ISR。

静态ISR只能静态被编译到核心,在运行时不能改变,和IST通信是单向的,ISR-IST,支持中断嵌套,可以使用核心的堆栈。

可安装的ISR由内核管理程序从DLL中动态加载,是由IST-ISR,多个ISR可以同一个中断请求相连,按加载驱动的顺序进行调度,共享内存的使用比较灵活。

IST是运行在用户空间的中断服务线程,负责接到系统逻辑中断号之后的处理,使用中首先要注册自己,再与一个系统事件关联。

一般来说,使用InterruptInitialize函数注册自己,使用WaitForSingleObject函数来等待终端请求事件。

系统调度器会调度这个线程来进行中断的处理。

流接口驱动一般在XXX_Init里面做这些事情,IST是Device。

exe 的一个附属线程。

具体实现过程是:1 创建一个事件2 得到系统的中断号3 创建一个挂起的中断服务线程(IST)4设置中断服务线程的优先级别5调用函数InterruptInitialize通知系统注册中断6回复中断服务线程IST,IST开始服务最后总结下WINCE6的中断发生和处理过程:1硬件设备产生中断信号2中断信号被异常处理程序(ExceptionHandle)捕获3异常处理程序激活挂载中断服务例程ISR4ISR响应硬件,并操作硬件设备5ISR将中断映射6ISR设置相应的核心中断标示7中断服务调度程序与OAL例程合作,设置中断事件,操纵在特定中断事件上的等待队列8 OAL操作硬件,改变硬件的中断状态,将其设置为开中断9 中断事件激活系统调度程序,在相隔一段时间以后调度中断服务线程10 IST处理中断的相关事件,并调用系统的支持库11 系统支持库访问硬件设备,完成对硬件设备的操作本文来自CSDN博客,转载请标明出处:/jw212/archive/2011/03/17/6255848.aspxWINCE6.0中断默认分类 2010-11-19 16:00:10 阅读53 评论1 字号:大中小订阅 .硬件设备一般通过发送中断信号向操作系统申请服务请求,如PC卡、定时器、音频设备、键盘、触摸屏等。

中断ISR分析

中断ISR分析

中断ISR分析b HandlerIRQ ;handler for IRQ interrupt很自然,因为所有的单片机都是那样,中断向量一般放在开头,用过单片机的人都会很熟悉那就不多说了。

异常服务程序这里不用中断(interrupt)而用异常(exception),毕竟中断只是异常的一种情况,呵呵下面主要分析的是“中断异常”说白了,就是我们平时单片机里面用的中断所有有器件引起的中断,例如TIMER中断,UART 中断,外部中断等等,都有一个统一的入口,那就是中断异常IRQ ! 然后从IRQ的服务函数里面分辨出,当前究竟是什么中断,再跳转到相应的中断服务程序。

这样看来,ARM比单片机要复杂一些了,不过原理是不变的。

上面说的就是思路,跟着这个思路来接着分析。

HandlerIRQ 很明显是一个标号,我们找到了HandlerIRQ HANDLER HandleIRQ这里是一个宏定义,我们再找到这个宏,看他是怎么定义的:MACRO$HandlerLabel HANDLER $HandleLabel$HandlerLabelsub 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 originalldr r0,=$HandleLabel ;load the address of HandleXXX to r0 ldr r0,[r0] ;load the contents(service routine start address) of HandleXXXstr 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 将这个宏展开之后得到的结果实际是这样的HandlerIRQsub 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 originaladdress)ldr r0,=HandleIRQ ;load the address of HandleXXX to r0ldr r0,[r0] ;load the contents(service routine start address) of HandleXXXstr 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 # 4HandleUndef # 4HandleSWI # 4HandlePabort # 4HandleDabort # 4HandleReserved # 4HandleIRQ # 4最后我们发现在这里找到了HandleIRQ ,^ 其实就是MAP ,这段程序的意思是,从_ISR_STARTADDRESS开始,预留一个变量,每个变量一个标号,预留的空间为4个字节,也就是32BIT,其实这里放的是真正的C写的处理函数的地址,说白了,就是函数指针- -这样做的话就很灵活了接着,我们需要安装IRQ处理句柄,说白了,就是设置处理函数的地址,让PC指针可以正确的跳转。

学习笔记(六)——ISR范例

学习笔记(六)——ISR范例

学习笔记(六)——ISR范例 上⼀篇随笔中对中断进⾏了简要的总结,这⼀篇将结合程序加深对ISR的理解。

⼀、使⽤中断 ISR执⾏之前将进⾏以下初始化⼯作。

1.1 建⽴堆栈 前⾯讲到堆栈容量过⼩将导致栈溢出,因此计算容量很重要。

较为简单的程序使⽤MSP,此时只需要开辟⼀个容量够⼤的堆栈,将MSP初始化到其顶即可。

对于⼤型⾼性能程序,则需要两个堆栈配合使⽤,此时就需要谨慎计算两个堆栈的容量。

(开发中⼀般在调试阶段把堆栈进程⽤过的最⼤的量输出,最终作为主堆栈的容量,以免浪费内存)1.2 建⽴向量表 ⼤多数情况下,程序只给每个中断固定的ISR,此时把向量表放在ROM中即可。

有时候,为了应付复杂情况,需要动态改变ISR,就需要重定位向量表了,此时向量表需保存在R/W寄存器中。

重定位钱,⾸先将现有的向量表往新的位置复制⼀份,需要拷贝的主要是各种fault、NMI、SVC的服务例程。

将所有必要向量填好之后,就可以启⽤新的向量表了。

并往其中加⼊新的中断向量,程序如下:;该⼦程序根据异常类型建⽴了相应的异常向量;⼊⼝条件:R0=异常类型编号,R1=向量地址PUSH {R2, LR}LDR R2, =0xE000ED08 ;向量表偏移寄存器的地址LDR R2, [R2] ;获取向量表的⾸地址STR R1, [R2,RO,LSL #4] ;在偏移地址vectblOffset(偏移;量)+ExcpType(异常类型)*4地;址处写⼊向量ExcpType*4POP {R2, PC} 另外,向量表写⼊的RAM是写缓冲的,那向量表更新可能会被延迟,因此建⽴所有向量后必须追加DSB指令。

1.3 分配各中断的优先级 找到寄存器直接写⼊即可。

若要确定优先级位数,可以在寄存器中写⼊0xFF,读出1的个数即是位数。

(可以采⽤RBIT和CLZ来配合读出1的个数)1.4 使能和除能中断 使⽤SETENA/CLRENA,程序如下所⽰。

由于4字节对齐,因此程序的主要内容需要计算位于8个寄存器中的哪⼀个32位寄存器和该32位寄存器中的哪⼀位。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

(原创)eCos驱动分析之ISR是如何与硬件中断联系起来的---转载文章要想知道ecos的中断ISR是怎么与硬件中断向量联系起来的,是怎么被调用的?那就要看下面这两个关键的函数:cyg_drv_interrupt_create()cyg_drv_interrupt_attach()这两个函数都声明在cyg/kernel/kapi.h中,其形式如下:void cyg_interrupt_create( cyg_vector_t vector, /* Vector to attach to */ cyg_priority_t priority, /* Queue priority */ cyg_addrword_t data, /* Data pointer*/ cyg_ISR_t *isr, /* Interrupt Service Routine */ cyg_DSR_t *dsr, /* Deferred Service Routine */ cyg_handle_t *handle, /* returned handle */ cyg_interrupt *intr /* put interrupt here */) __THROW;void cyg_interrupt_attach( cyg_handle_t interrupt )__THROW;(注: __THROW是在C++中用的,是用来抛出异常的,详见我的博文/blog/static/888807432011611193510/ 这里可以视而不见.)其中文意义对照如下:cyg_interrupt_create( 中断号, 中断优先级, 传递的中断参数, ISR函数,DSR函数, 被返回的中断句柄, 存放与此中断相关的内核数据的变量空间);cyg_interrupt_attach(中断句柄);这样实际上去研究一下cyg_interrupt_create函数的定义内容,应该就能搞明白我们的问题了!由于其函数声明在kapi.h中,很自然的就想到其定义应在kapi.c文件中,找到....\ecos\ecos-current\packages\kernel\current\src\common\kapi.cxx文件,找到这两个函数的定义如下:/*---------------------------------------------------------------------------*//* Interrupt handling*/externC void cyg_interrupt_create( cyg_vector_t vector, /* Vector to attach to */ cyg_priority_t priority, /* Queue priority*/ cyg_addrword_t data, /* Data pointer */ cyg_ISR_t*isr, /* Interrupt Service Routine */ cyg_DSR_t *dsr, /* Deferred Service Routine */ cyg_handle_t *handle,/* returned handle */ cyg_interrupt *intr /* put interrupt here */) __THROW{ CYG_ASSERT_SIZES( cyg_interrupt,Cyg_Interrupt );Cyg_Interrupt *t = new((void *)intr) Cyg_Interrupt( (cyg_vector)vector, (cyg_priority)priority, (CYG_ADDRWORD)data, (cyg_ISR *)isr,(cyg_DSR *)dsr ); t=t;CYG_CHECK_DATA_PTR( handle, "Bad handle pointer" ); *handle = (cyg_handle_t)intr;}voidcyg_interrupt_attach( cyg_handle_t interrupt )__THROW{ ((Cyg_Interrupt *)interrupt)-&gt;attach();}函数内容比想象中的简单,所有的操作又都传给了Cyg_Interrupt这个类来完成,那就来对Cyg_Interrupt探个究竟吧:(注意Cyg_Interrupt是个C++类, 可不要找成了struct cyg_interrupt,注意哟,cyg_interrupt_create函数的最后一个参数就是这个cyg_interrupt struct类型的,在cyg/kernel/kapidata.h中有个struct cyg_interrupt定义,虽然名字和内容都很相似,但实际上不是.)真正的class Cyg_Interrupt定义在cyg/kernel/intr.hxx中,这个头文件没干别的,就是声明这个class了,可见这是一个很大的class,如下:// -------------------------------------------------------------------------// Interrupt class. This both represents each interrupt and provides a static// interface for controlling the interrupt hardware.class Cyg_Interrupt{friend class Cyg_Scheduler; friend voidinterrupt_end( cyg_uint32,Cyg_Interrupt *,HAL_SavedRegisters *); friend voidcyg_interrupt_post_dsr( CYG_ADDRWORD intr_obj );friend void cyg_interrupt_call_pending_DSRs( void );cyg_vector vector; // Interrupt vector cyg_priority priority; // Queuing priority cyg_ISR *isr; // Pointer to ISR cyg_DSR *dsr; // Pointer to DSRCYG_ADDRWORD data; // Data pointer // DSR handling interface called by the scheduler// Check for pending DSRs static cyg_bool DSRs_pending();// Call anypending DSRs static void call_pending_DSRs(); static void call_pending_DSRs_inner();// DSR handling interface called by the scheduler and HAL // interrupt arbiters.void post_dsr(); // Post the DSR for this interrupt // Data structures for handling DSR calls. We implement two DSR // handling mechanisms, a list based one and a table based // one. The list based mechanism is safe with respect to temporary // overloads and will not run out of resource. However it requires // extra data per interrupt object, and interrupts must be turned // off briefly when delivering the DSR. The table based mechanism // does not need unnecessary interrupt switching, but may be prone // to overflow on overload. However, since a correctly programmed // real time application should not experience such a condition, // the table based mechanism is more efficient for real use. The // list based mechainsm is enabled by default since it is safer to// use during development.#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE static Cyg_Interrupt *dsr_table[CYGNUM_KERNEL_CPU_MAX][CYGNUM_KERNEL_INTERRUPTS_DSRS_TABLE_SIZE] CYGBLD_ANNOTATE_VARIABLE_INTR;static cyg_ucount32dsr_table_head[CYGNUM_KERNEL_CPU_MAX]CYGBLD_ANNOTATE_VARIABLE_INTR;static volatile cyg_ucount32dsr_table_tail[CYGNUM_KERNEL_CPU_MAX]CYGBLD_ANNOTATE_VARIABLE_INTR;#endif#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIST // Number of DSR posts made volatilecyg_ucount32 dsr_countCYGBLD_ANNOTATE_VARIABLE_INTR;// next DSR in list Cyg_Interrupt* volatile next_dsr CYGBLD_ANNOTATE_VARIABLE_INTR;// static list of pending DSRs static Cyg_Interrupt* volatile dsr_list[CYGNUM_KERNEL_CPU_MAX]CYGBLD_ANNOTATE_VARIABLE_INTR;#endif#ifdef CYGIMP_KERNEL_INTERRUPTS_CHAIN// The default mechanism for handling interrupts is to attach just // one Interrupt object to each vector. In some cases, and on some // hardware, this is not possible, and each vector must carry a chain // ofinterrupts.Cyg_Interrupt *next; // Next Interrupt in list// Chaining ISR inserted in HAL vector staticcyg_uint32 chain_isr(cyg_vector vector, CYG_ADDRWORD data);// Table of interrupt chains static Cyg_Interrupt*chain_list[CYGNUM_HAL_ISR_TABLE_SIZE];#endif// Interrupt disable data. Interrupt disable can be nested. On // each CPU this is controlled bydisable_counter[cpu]. When the // counter is first incremented from zero to one, the //interrupt_disable_spinlock is claimed using spin_intsave(), the // original interrupt enable state being saved in// interrupt_disable_state[cpu]. When the counter is decremented // back to zero the spinlock is cleared using clear_intsave().// The spinlock is necessary in SMP systems since a thread // accessing data shared with an ISR may be scheduled on a // different CPU to the one that handles the interrupt. So, merely // blocking local interrupts would be ineffective. SMP aware // device drivers shouldeither use their own spinlocks to protect // data, or use the API supported by this class, via //cyg_drv_isr_lock()/_unlock(). Note that it now becomes// essential that ISRs do this if they are to be SMP-compatible.// In a single CPU system, this mechanism reduces to just // disabling/enabling interrupts.// Disable level counter. This counts the number of times // interrupts have been disabled. static volatile cyg_int32 disable_counter[CYGNUM_KERNEL_CPU_MAX] CYGBLD_ANNOTATE_VARIABLE_INTR;// Interrupt disable spinlock. This is claimed by any CPU that has // disabled interrupts via the Cyg_Interrupt API. static Cyg_SpinLock interrupt_disable_spinlockCYGBLD_ANNOTATE_VARIABLE_INTR;// Saved interrupt state. When each CPU first disables interrupts // the original state of the interrupts are saved here to be // restored later. staticCYG_INTERRUPT_STATEinterrupt_disable_state[CYGNUM_KERNEL_CPU_MAX] CYGBLD_ANNOTATE_VARIABLE_INTR;public:Cyg_Interrupt // Initialize interrupt ( cyg_vector vector, // Vector to attach to cyg_priority priority,// Queue priority CYG_ADDRWORD data,// Data pointer cyg_ISR *isr,// Interrupt Service Routine cyg_DSR *dsr // Deferred Service Routine );~Cyg_Interrupt(); // ISR return values enum { HANDLED = 1, // Interrupt was handled CALL_DSR = 2// Schedule DSR };// Interrupt management void attach();// Attach to vector void detach();// Detach from vector // Static Interrupt management functions// Get the current service routine static voidget_vsr(cyg_vector vector, cyg_VSR **vsr);// Install a vector service routine static voidset_vsr( cyg_vector vector, // hardware vector to replace cyg_VSR *vsr,// my new service routine cyg_VSR **old = NULL// pointer to old vsr, if required ); // Staticinterrupt masking functions// Disable interrupts at the CPU static voiddisable_interrupts();// Re-enable CPU interrupts static voidenable_interrupts();// Are interrupts enabled at the CPU? static inline cyg_bool interrupts_enabled() { return (0 == disable_counter[CYG_KERNEL_CPU_THIS()]); } // Get the vector for the following calls inline cyg_vectorget_vector() { return vector; } // Static PIC control functions // Mask a specific interrupt in a PIC static void mask_interrupt(cyg_vector vector); // The same but not interrupt safe static voidmask_interrupt_intunsafe(cyg_vector vector);// Clear PIC mask static voidunmask_interrupt(cyg_vector vector); // The same but not interrupt safe static voidunmask_interrupt_intunsafe(cyg_vector vector);// Acknowledge interrupt at PIC static void acknowledge_interrupt(cyg_vector vector);// Change interrupt detection at PIC static void configure_interrupt( cyg_vector vector,// vector to control cyg_bool level,// level or edge triggered cyg_bool up// hi/lo level, rising/falling edge );#ifdef CYGPKG_KERNEL_SMP_SUPPORT// SMP support for associating an interrupt with a specific CPU. static void set_cpu( cyg_vector,HAL_SMP_CPU_TYPE cpu ); static HAL_SMP_CPU_TYPE get_cpu( cyg_vector );#endif };这只是声明了这个class,这个class的构造/析构函数和成员函数的实现,还要找cyg/kernel/intr.hxx头文件相对应的C文件,在这里....\packages\kernel\current\src\intr\intr.cxx 找到了intr.cxx文件,因为cyg_interrupt_create函数实际上调用了classCyg_Interrupt的构造函数,我们就来看看这个构造函数: Cyg_Interrupt::Cyg_Interrupt( cyg_vector vec,// Vector to attach to cyg_priority pri,// Queue priority CYG_ADDRWORD d,// Data pointer cyg_ISR *ir,// Interrupt Service Routine cyg_DSR *dr// Deferred ServiceRoutine ){ CYG_REPORT_FUNCTION();CYG_REPORT_FUNCARG5("vector=%d, priority=%d,data=%08x, isr=%08x, ""dsr=%08x", vec, pri, d, ir, dr); vector = vec; priority = pri; isr = ir; dsr = dr; data = d;#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LISTdsr_count = 0; next_dsr = NULL;#endif#ifdef CYGIMP_KERNEL_INTERRUPTS_CHAINnext = NULL;#endifCYG_REPORT_RETURN();};也就是分配了一下成员变量,把cyg_interrupt_create函数传进来的中断号、ISR、DSR等分配给类的成员变量,好像也没什么特别的。

相关文档
最新文档