您的位置:首页 > 其它

S3C2440中断体系结构:外部中断实验

2015-03-30 22:24 441 查看
转自:http://blog.chinaunix.net/uid-22182617-id-399397.html

1 SUBSRCPND和SRCPND表明有哪些中断被触发了
INTSUMMSK和INTMSK寄存器用于屏蔽某些中断
2 中断触发→SUBSRCPND相应位置1→INTSUBMSK未屏蔽→SRCPND相应位置1→

中断触发
→若是FIQ中断:INTMOD相应位置1(同一时间,只能有一位置1)
→INTMSK未屏蔽→INTPND相应位置1(同一时间,只能有一位置1)
3 读取INTPND或INTOFFSET可以确定中断源
4 清除中断的顺序:SUBSRCPND(相应位写1)→SRCPND(相应位写1)→INTPND
5 自己觉得重要的几步:将相应引脚的功能设置为“外部中断”,设置中断触发条件,开启外设自己的屏蔽寄存器(若有)→INTSUBMSK中相应位设为0→FIQ:INTMOD相应位设为1
→IRQ:PRIORITY设置优先级
→IRQ:INTMSK相应位设为0→CPSR中的I和F位设为0,使能IRQ或FIQ
6 中断控制寄存器
(1)SUBSRCPND中几位若有一位置位,且未被INTSUBMSK屏蔽,则SRCPND中相应有一位置1(多对1的关系)
(2)INTMOD中设为1的为快速中断,设为0的为普通中断
(3)PRIORITY:中断优先级仲裁器6个输入引脚;PRIORITY中三位控制一个中断优先级仲裁器(总共7个),一位为ARB_MODE(仲裁器工作模式位),两位用于控制输入信号的优先级
具体哪位对应哪位:请查看S3C2440官方手册,上面写的很详细
(4)INTOFFSET:INTPND寄存器位[x]置1时,INTOFFSET寄存器的值为x,在清除SRCPND、INTPND时,INTOFFSET自动清除
7 外部中断实验:(实验用板:mini2440,是S3C2440的处理器,再参照原理图即可作相应调整)完整代码:int.tar.gz
(1)head.S
@******************************************************************************
@ File:head.S
@ 功能:初始化,设置中断模式、系统模式的栈,设置好中断处理函数
@******************************************************************************

.extern main @引用其它文件中的mian标号
.text
.global _start
_start:
@******************************************************************************
@ 中断向量,本程序中,除Reset和HandleIRQ外,其它异常都没有使用
@******************************************************************************
b Reset

@ 0x04: 未定义指令中止模式的向量地址
HandleUndef:
b HandleUndef

@ 0x08: 管理模式的向量地址,通过SWI指令进入此模式
HandleSWI:
b HandleSWI

@ 0x0c: 指令预取终止导致的异常的向量地址
HandlePrefetchAbort:
b HandlePrefetchAbort

@ 0x10: 数据访问终止导致的异常的向量地址
HandleDataAbort:
b HandleDataAbort

@ 0x14: 保留
HandleNotUsed:
b HandleNotUsed

@ 0x18: 中断模式的向量地址
b HandleIRQ

@ 0x1c: 快中断模式的向量地址
HandleFIQ:
b HandleFIQ

Reset:
ldr sp, =4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈
bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启

msr cpsr_c, #0xd2 @ 进入中断模式
ldr sp, =3072 @ 设置中断模式栈指针

msr cpsr_c, #0xdf @ 进入系统模式
ldr sp, =4096 @ 设置系统模式栈指针,
@ 其实复位之后,CPU就处于系统模式,
@ 前面的“ldr sp, =4096”完成同样的功能,此句可省略

bl init_led @ 初始化LED的GPIO管脚
bl init_irq @ 调用中断初始化函数,在init.c中
msr cpsr_c, #0x5f @ 设置I-bit=0,开IRQ中断

ldr lr, =halt_loop @ 设置返回地址
ldr pc, =main @ 调用main函数
halt_loop:
b halt_loop

HandleIRQ:
sub lr, lr, #4 @ 计算返回地址
stmdb sp!, { r0-r12,lr } @ 保存使用到的寄存器
@ 注意,此时的sp是中断模式的sp
@ 初始值是上面设置的3072

ldr lr, =int_return @ 设置调用ISR即EINT_Handle函数后的返回地址
ldr pc, =EINT_Handle @ 调用中断服务函数,在interrupt.c中
int_return:
ldmia sp!, { r0-r12,pc }^ @ 中断返回, ^表示将spsr的值复制到cpsr

(2)init.c
/*
* init.c: 进行一些初始化
*/

#include "s3c24xx.h"

/*
* LED1-4对应GPB5、GPB6、GPB7、GPB8
*/
#define GPB5_out (1<<(5*2)) // LED1
#define GPB6_out (1<<(6*2)) // LED2
#define GPB7_out (1<<(7*2)) // LED3
#define GPB8_out (1<<(8*2)) // LED4

/*
* K1-K4对应GPG0、GPG3、GPG5、GPG6
*/
#define GPG0_eint (2<<0) // K1,EINT8
#define GPG3_eint (2<<(3*2)) // K2,EINT11
#define GPG5_eint (2<<(5*2)) // K3,EINT13
#define GPG6_eint (2<<(6*2)) // K4,EINT14

/*
* 关闭WATCHDOG,否则CPU会不断重启
*/
void disable_watch_dog(void)
{
WTCON = 0; // 关闭WATCHDOG很简单,往这个寄存器写0即可
}

void init_led(void)
{
GPBCON = GPB5_out | GPB6_out | GPB7_out | GPB8_out ;
}

/*
* 初始化GPIO引脚为外部中断
* GPIO引脚用作外部中断时,默认为低电平触发、IRQ方式(不用设置INTMOD)
*/
void init_irq( )
{

GPGCON = GPG0_eint | GPG3_eint |GPG5_eint | GPG6_eint;

//使能EINT8 EINT11 EINT13 EINT14
EINTMASK&=(~(1<<8)) & (~(1<<11)) & (~(1<<13)) & (~(1<<14));

//EINT8 EINT11 EINT13 EINT14中断优先级一样,无需设置

// EINT8、EINT11、EINT13、EINT14使能
INTMSK &=(~(1<<5));
}
(3)interrupt.c
#include "s3c24xx.h"

void EINT_Handle()
{
unsigned long oft = INTOFFSET;
unsigned long val;

if( oft==5)
{
GPBDAT |= (0x0f<<5); // 所有LED熄灭

// 需要进一步判断是K1还是K2,或是K1、K2被同时按下
val = EINTPEND;
if (val & (1<<8))
GPBDAT &= ~(1<<5); // K1被按下,LED1点亮
if (val & (1<<11))
GPBDAT &= ~(1<<6); // K2被按下,LED2点亮
if (val & (1<<13))
GPBDAT &= ~(1<<7); // K3被按下,LED3点亮
if (val & (1<<14))
GPBDAT &= ~(1<<8); // K4被按下,LED4点亮
}

//清中断
if( oft == 5 )
EINTPEND = (1<<8) | (1<<11)| (1<<13)| (1<<14); // EINT8_23合用IRQ5
SRCPND = 1<<oft;
INTPND = 1<<oft;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: