第5章附录 S3C2410中断源名称
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
表6-1 中断控制器支持的56个中断源
表6-2 SRCPND寄存器的定义
表5-3 INTMOD寄存器的定义续表
实例6-1
完成一个S3C2410芯片中断源的中断控制程序的编写,需要完成四部分内容。
第一部分的实例在前面已经介绍。
下面介绍后三部分内容的编程实例。
例程中所用到的一些寄存器常量等在头文件reg2410.h和isr.h中定义,详见附录。
这两个头文件必须包含在例程文件中。
#include "../inc/reg2410.h"
#include "../inc/isr.h"
例程中还需要用到下面的结构体。
/* 定义结构体*/
typedef struct{
Interrupt_func_t InterruptHandlers;
void* data;
int valid; //设置中断是否有效1=有效0=无效
mask_func_t mask;
mask_func_t unmask;
mask_func_t ack_irq;
}struct_InterruptFunc;
static struct_InterruptFunc InterruptFunc[NR_IRQS]={NULL,};
static void ack_irq(unsigned int irq)
{
rSRCPND = (1 << irq);
rINTPND = (1 << irq);
}
static void mask_irq(unsigned int irq)
{
rINTMSK |= (1 << irq);
}
static void unmask_irq(unsigned int irq)
{
rINTMSK &= ~(1 << irq);
}
(1)56个中断源中断向量设置
/* 56个中断源的中断向量设置函数*/
void ISR_IrqHandler(void)
{
unsigned int irq=GetISROffsetClr(); //得到中断源的中断号
irq=fixup_irq(irq); //计算子中断源的地址偏移
if(irq>=NR_IRQS)
return;
if(InterruptFunc[irq].InterruptHandlers==NULL){
InterruptFunc[irq].ack_irq(irq); //清中断未决位
return;
}
/* 调用中断服务程序*/
InterruptFunc[irq].InterruptHandlers(irq, InterruptFunc[irq].data);
InterruptFunc[irq].ack_irq(irq); //清中断未决位
}
上述程序中,GetISROffsetClr()、fixup_irq()是用来计算中断源号及子中断源地址偏移的函数。
程序代码如下:
// GetISROffsetClr()函数
int GetISROffsetClr()
{
//计算中断的偏移地址,高位优先
int i,ispr=rI_ISPR,tmp=1<<(MAXHNDLRS-1);
for(i=MAXHNDLRS;i>0;i--){
if(ispr&tmp){
return i-1;
}
tmp>>=1;
}
return -1;
}
// fixup_irq()函数
static unsigned int fixup_irq(int irq) {
unsigned int ret;
unsigned long sub_mask, ext_mask;
switch (irq) {
case IRQ_UART0:
sub_mask = rSUBSRCPND & ~rINTSUBMSK;
ret = get_subIRQ(sub_mask, 0, 2, irq);
break;
case IRQ_UART1:
sub_mask = rSUBSRCPND & ~rINTSUBMSK;
ret = get_subIRQ(sub_mask, 3, 5, irq);
break;
case IRQ_UART2:
sub_mask = rSUBSRCPND & ~rINTSUBMSK;
ret = get_subIRQ(sub_mask, 6, 8, irq);
break;
case IRQ_ADCTC:
sub_mask = rSUBSRCPND & ~rINTSUBMSK;
ret = get_subIRQ(sub_mask, 9, 10, irq);
break;
case IRQ_EINT4_7:
ext_mask = rEINTPEND & ~rEINTMASK;
ret = get_extIRQ(ext_mask, 4, 7, irq);
break;
case IRQ_EINT8_23:
ext_mask = rEINTPEND & ~rEINTMASK;
ret = get_extIRQ(ext_mask, 8, 23, irq);
break;
default:
ret = irq;
}
return ret;
}
(2)中断控制初始化
中断控制器初始化程序主要完成具体中断源的中断模式、中断屏蔽位、子中断屏蔽位的设置。
根据5.2.3中介绍的寄存器格式,选择对应该中断源的寄存器位是设置为1,还是设置为0。
void ISR_Init(void)
{
int irq;
/* 设置所有中断源为IRQ模式,并首先屏蔽所有中断源*/
rINTMOD = 0x0; //所有中断源为IRQ模式
rINTMSK = BIT_ALLMSK; // BIT_ALLMSK =0xffffffff
rINTSUBMSK = BIT_SUB_ALLMSK; // BIT_SUB_ALLMSK= 0x7ff
/* 初始化结构体中的成员*/
for (irq=0; irq < NORMAL_IRQ_OFFSET; irq++) {
InterruptFunc[irq].valid = 1;
InterruptFunc[irq].ack_irq = ack_irq;
InterruptFunc[irq].mask = mask_irq;
InterruptFunc[irq].unmask = unmask_irq;
}
InterruptFunc[IRQ_RESERVED6].valid = 0;
InterruptFunc[IRQ_RESERVED24].valid = 0;
InterruptFunc[IRQ_EINT4_7].valid = 0;
InterruptFunc[IRQ_EINT8_23].valid = 0;
InterruptFunc[IRQ_EINT0].valid = 0;
InterruptFunc[IRQ_EINT1].valid = 0;
InterruptFunc[IRQ_EINT2].valid = 0;
InterruptFunc[IRQ_EINT3].valid = 0;
for (irq=NORMAL_IRQ_OFFSET; irq < EXT_IRQ_OFFSET; irq++) {
InterruptFunc[irq].valid = 0;
InterruptFunc[irq].ack_irq = EINT4_23ack_irq;
InterruptFunc[irq].mask = EINT4_23mask_irq;
InterruptFunc[irq].unmask = EINT4_23unmask_irq;
}
for (irq=EXT_IRQ_OFFSET; irq < SUB_IRQ_OFFSET; irq++) {
InterruptFunc[irq].valid = 1;
InterruptFunc[irq].ack_irq = SUB_ack_irq;
InterruptFunc[irq].mask = SUB_mask_irq;
InterruptFunc[irq].unmask = SUB_unmask_irq;
}
}
上述例程中,对中断源的控制寄存器进行初始设置,是每个I/O端口或部件采用中断方式控制时必须编写的程序。
但根据不同的用户需求,寄存器设置的值是不同的。
对于初始化结构体中的成员,不是必须的。
初始化工作还需要完成中断句柄的设置。
下面一段程序是完成该功能的例程。
int SetISR_Interrupt(int vector, void (*handler)(int, void*), void* data)
{
if(vector>NR_IRQS || vector<0)
return -1;
if(!InterruptFunc[vector].valid)
return -1;
InterruptFunc[vector].ack_irq(vector); //清除未决位
InterruptFunc[vector].InterruptHandlers = handler;
InterruptFunc[vector].data = data;
InterruptFunc[vector].unmask(vector); //开放中断
return 0;
}
(3)中断服务程序
中断服务程序是根据I/O端口或部件具体要完成的功能来编写的,没有一个具体的格式。
下面是一个用于键盘的中断服务程序,是通过IIC中断源产生的。
static void Key_ISR(int vector, void* data)
{
static int framecnt=0;
U8 status ,kdata;
status = rIICSTA T ;
if( (status & IICSTA T_MODE_MSK) != IICSTA T_MODE_SR)
return;
kdata = rIICDS;
switch(framecnt){
case 0:
if(status & IICSTA T_SLA VEADDR){
framecnt++;
}
break;
case 1:
if(GetI2C_Devtype(kdata) != DTYPE_MKEYB){
framecnt=0;
}
framecnt++;
break;
case 2:
mcukey = kdata;
if(mcukey&0x80)
{framecnt=0;
break;}
else if(!(mcukey&0x80)){
up=1;
count=1;
tempmcukey=mcukey;
}
framecnt=0;
break;
}
rIICCON &= ~IICCON_INTPEND;
}
上面中断服务程序具体完成的功能细节,我们在此暂不考虑。
若对应中断源产生中断请求信号后,系统能进入该段程序运行,设计者还需要在主程序段中加上下面一条语句:…
SetISR_Interrupt(IRQ_KBD, Key_ISR, NULL);
…
语句中,IRQ_KBD是中断源的偏移量值,因为此处使用的中断源是INT_IIC,因此,IRQ_KBD=27;Key_ISR是上面中断服务程序的函数名。