作者:SUKHOI27SMK
转自:http://blog.csdn.net/sukhoi27smk/article/details/8572492
在调试CAN总线的时候,遇到了操作系统的中断,为了彻底的弄清楚中断是怎么回事?我先从底层的中断开始研究,在这里我们只讨论外部中断,下面就结合S3C2440TEST测试程序来分析一下中断是怎么执行的:我们研究的是IRQ中断,分析中断过程如下,
在2440init.s中有这样的定义
b
然后有这个定义
HandlerIRQ
我们知道HandlerIRQ
AREA RamData, DATA, READWRITE
HandleReset
HandleUndef
HandleSWI
HandlePabort
HandleDabort
HandleReserved
HandleIRQ
HandleFIQ
在这里我们找到了HandleIRQ标号的入口地址:
接着往下看
HandleEINT0
HandleEINT1
HandleEINT2
HandleEINT3
HandleEINT4_7
HandleEINT8_23
HandleEINT0是IRQ异常的向量存放的地方了,是所有IRQ中断向量表的入口。
下面看2440的中断按键程序,在2440addr.h里找到了这样的定义(中断、IO、LCD等地址分配)
#definepISR_EINT0
#define pISR_EINT1
#define pISR_EINT2
#define pISR_EINT3
#define pISR_EINT4_7
#define pISR_EINT8_23
通过地址对照,我们明白了pISR_EINT0
HandleEINT0
我们知道ARM9的外部中断有5条中断信号线,当外部的中断发生时,就会触发相应的中断信号线,其中pISR_EINT4_7
因此我们知道pISR_EINT0
就是将中断服务程序Key_ISR的地址传送到pISR_EINT0,pISR_EINT2,
/
下面介绍基于WINCE操作系统的外部中断,我现在说一下,WINCE中断的具体过程,
首先我们要把我们设置外部中断函数在我们BSP包里必须定义对应的逻辑中断号,在头文件OALINTR.H中
// These are the 'standard' interrupts
#defineSYSINTR_KEYBOARD
#defineSYSINTR_TOUCH
#defineSYSINTR_ADC
#defineSYSINTR_SERIAL
#defineSYSINTR_AUDIO
#defineSYSINTR_PCMCIA_STATE
#defineSYSINTR_PCMCIA_EDGE
#defineSYSINTR_PCMCIA_LEVEL
…………// 具体查看D:\WINCE500\PLATFORM\SMDK2410\INC\oalintr.h
MapIrq2SysIntr(DWORD_Irq)这个函数我自己理解当我们的中断发生的时候,调用相应的逻辑中断号时,它就返回逻辑中断号的值。_Irq就是(SYSINTR_FIRMWARE+_Irq)中的。_Irq。只要有了这个逻辑中断号我们就可以用这个函数进行关联中断了,InterruptInitialize(SYSINTR_ETHER,g_hInterrupt, 0,0)他的作用就是,把SYSINTR_ETHER逻辑中断号和创建的事件g_hInterrupt关联起来,当有中断发生的时候,这个函数就会使g_hInterrupt这个事件生效,然后我们用这个函数WaitForSingleObject(g_hInterrupt,INFINITE);
这个函数是一个等待函数,当事件g_hInterrupt生效时,就会向下面的程序执行,否则一直在这里等待事件生效。这就是静态中断的过程,动态我还没有研究出来,可能和我们的BSP包有关系,在下面的学习中我会把它研究出来。
注:在EVC编写调用上面的函数时需要包含头文件:ceddk.h(此处用于实验室面板按键用)。
其实添加完对应的逻辑中断号之后我们还的在这几个文件中添加相应的语句才能真正的触发中断,CFW.C中(参考现有中断添加需要的中断如EINT0等)
2 OAL层中断程序汇总
关于WinCE的中断处理,OAL中主要是实现了ISR部分,一般IST会在设备驱动中实现。架构如图:硬件中断产生以后,会导致内核ISR的运行,然后由OAL中的ISR来处理相应的中断,最后导致相对应的IST运行完成真正的中断处理。所以在WinCE中,中断处理由ISR和IST共同完成。ISR主要完成中断源的确定,屏蔽该中断并返回给内核相对应的系统中断号,ISR应该尽量短小。IST则是完成真正的中断处理,比如数据的传输和解析等。当然不是所有的中断处理都需要ISR和IST,看需要,比如WinCE的系统Timer中断就只需要ISR完成。
2.1 在OAL中支持中断,需要实现以下几个中断处理函数a. BOOL OEMInterruptEnable(DWORD sysIntr, VOID* pData, DWORD dataSize)
sysIntr:要被使能的系统中断号
pData:传入的数据指针,该数据由InterruptInitialize函数传入
dataSize:传入数据的大小
该函数用于使能某一个硬件中断。在设备驱动调用InterruptInitialize来初始化一个中断的时候,内核就会调用该函数来使能相应的硬件中断。
b. VOID OEMInterruptDisable(DWORD sysIntr)
sysIntr:要被屏蔽的系统中断号
该函数用于屏蔽一个硬件中断。如果设备驱动调用InterruptDisable函数,则该函数会被调用。
c. VOID OEMInterruptDone(DWORD sysIntr)
sysIntr:要被重新使能的系统中断号
该函数标志着一个中断处理过程的完成。当设备驱动调用InterruptDone函数的时候,该函数会被调用,重新使能相应的硬件中断。
d. ULONG OEMInterruptHandler(ULONG ra)
ra:指令计数,在实际应用中,没有太大意义
当硬件中断产生的时候,该函数就会被调用完成ISR部分的中断处理。一般会在该函数中读取系统的中断标记位,确定中断源并返回相应的系统中断号。
e. void OEMInterruptHandlerFIQ(void)
针对于ARM处理器,该函数用于处理快速中断。
上面5个函数完成了中断的相关处理。这里要提到两个概念:IRQ和SYSINTR。IRQ是指物理中断或者叫硬件中断,而SYSINTR指的是系统中断,也有的地方称为虚拟中断或者逻辑中断,我个人觉得还是叫系统中断比较好。每一个IRQ会和一个系统中断SYSINTR相对应,当硬件中断产生时,ISR实际上是处理IRQ中断,然后返回相应的系统中断SYSINTR给内核,内核会根据相应的SYSINTR触发相应的IST来完成中断处理。
IRQ和SYSINTR之间的对应关系称为映射,分为静态映射和动态映射。静态映射是指在系统编译时IRQ已经和SYSINTR相对应,一般通过OALIntrStaticTranslate函数来实现。而动态映射是指WinCE系统启动后,动态关联IRQ与SYSINTR,一般通过KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR…)来实现。
SYSINTR的类型在nkintr.h中定义,OEMInterruptHandler函数在处理完中断以后,会返回不同类型的SYSINTR给内核,内核会根据返回值进行下一步操作,分为以下几种类型:
SYSINTR_NOP:表示不需要进行任何处理
SYSINTR_RESCHED:表示要进行一次系统调度
SYSINTR_CHAIN:表示不是该中断源产生,在中断链中寻找下一个中断
SYSINTR_RTC_ALARM:表示RTC报警产生
SYSINTR_TIMING:用于ILTiming测试
SYSINTR_PROFILE:用于系统的profile
SYSINTR_FIRMWARE:用于用户自定义系统中断号,所有自定义的系统中断号都应该基于该值进行累加加1,这些自定义的系统中断号用于和IRQ一一对应。