JZ2440 中断分析

裸机系列代码地址:链接:http://pan.baidu.com/s/1pLHOd0v 密码:4x5s

当某事件发生时,硬件会设置某个寄存器;CPU会在每执行完一个指令时,通过硬件查看这个寄存器,如果发现所关注的事件发生

了,则中断当前程序流程,跳转到一个固定的地址处理这事情,事后返回继续执行的程序。
中断的使用步骤:
(1)设置好中断模式下的栈,禁止中断。当发生中断IRQ时,CPU进入中断模式,这时使用中断模式下的栈
(2)准备好中断服务程序(ISR),在中断服务程序中跳转到具体的中断处理程序,在具体的中断处理程序中做想要做的事,并清除中断
(3)进入、退出中断模式时,需要保存、恢复被中断程序的运行环境
HandleIRQ:
	sub lr,lr,#4
	stmdb sp!, {r0-r12,lr}

	ldr lr,=int_return
	ldr pc,=EINT_Handle

int_return:
	ldmia sp!,{r0-r12,pc}^
(4)根据具体的中断,设置相关的外设。比如对于GPIO中断,需要将相应的引脚功能设为“外部中断”,设置中断触发条件,一些中断拥有
自己的屏蔽寄存器,还需要开启它。
(5)对于“Request sources”的中断,将INTSUBMASK寄存器中的相应位设为0
(6)设置中断优先级
(7)将INTMASK寄存器中的相应位设为0
(8)设置CPSR寄存器的中断使能位,使能中断

中断控制寄存器
(1)SUBSRCPND寄存器(SUB SOURCE PENDING)
标示有子中断的中断,在S3C2440中这类有子中断的中断有6个,共对应15个子中断
INT_UART0 : INT_RXD0 , INT_TXD0 , INT_ERR0
INT_UART1 : INT_RXD1 , INT_TXD1 , INT_ERR1
INT_UART2 : INT_RXD2 , INT_TXD2 , INT_ERR2
INT_ADC   : INT_ADC_S , INT_TC
INT_CAM   : INT_CAM_C , INT_CAM_P
INT_WDT_AC97 : INT_WDT , INT_AC97
当这些子中断发生并且没有被INTMASK寄存器屏蔽,则他们中的若干位将“汇集”出现在SRCPND寄存器的一位上
例如,SUBSRCPND中的 INT_RXD0 , INT_TXD0 , INT_ERR0只要有一位只要有一个发生没有被屏蔽,则SRCPND寄存器
上的INT_UART0将被标示。往某位中写1即可令此位为0,写入0无效果,数据保持不变
(2)INTSUBMASK寄存器(INTERRUPT SUB MASK)
INTSUBMASK寄存器用来屏蔽SUBSRCPND寄存器所标示的中断,INTSUBMASK中的某位被置为1时,对应的中断被屏蔽
(3)SRCPND寄存器(SOURCE PENDING)
SRCPND中每一位被用来标示一个(或一类子中断)是否已经发生。若想清除某一位,往此位写1
(4)INTMASK(INTERRUPT MASK)
     INTMASK寄存器被用来屏蔽SRCPND寄存器中所标示的中断。INTMASK某位被设为1时,对应的中断被屏蔽
(5)PRIORITY寄存器
当有多个普通中断同时发生时,中断控制器将选出最高优先级的中断,首先处理它。
(6)INTPND寄存器(INTERRUPT PENDING)
     经过中断优先级仲裁器选出优先级最高的中断后,这个中断在INTPND寄存器中的相应位被置1,随后,CPU将进入
     中断模式处理它。同一时间内,此寄存器只有一位被置1
(7)INFOFFSET寄存器(INTERRUPT OFFSET)
这个寄存器被用来表示INTPND寄存器中哪位被置1了,即INTPND寄存器[x]位为1时,INTOFFSET寄存器的值为x
在清除SRCPND,INTPND寄存器时,INTOFFSET寄存器被自动清除
 
怎样判断具体是哪一个中断发生了
1、对于无子中断的中断类,通过INTOFFSET或INTPND即可知道是哪个中断发生了。
2、对于有子中断的中断类,光通过INFOFFSET无法知道具体发生的中断,还需要通过SUBSRCPND来进一步判断具体发生的中断
3、对于EINT4~EINT23光通过INFOFFSET也无法知道具体发生的中断类型,因为EINT4~EINT7在SRCPND中以EINT4_7标示,通过
INTOFFSET我们只能知道EINT4~EINT7中有一个发生了,EINT9~EINT23是同样的道理。此时我们需要EINTPEND来判断具体发生

的中断类型

下面来看一个具体中断的实例

Makefile文件

objs:= head.o init.o irq.o main.o 

irq.bin: $(objs)
	arm-linux-ld -Ttext 0x00000000 -o irq_elf $^
	arm-linux-objcopy -O binary -S irq_elf $@
	arm-linux-objdump -D -m arm irq_elf > irq.dis

%.o:%.c 
	arm-linux-gcc -Wall -O2 -c -o $@ $<

%.o:%.S
	arm-linux-gcc -Wall -O2 -c -o $@ $<

clean:
	rm -f irq_elf irq.dis irq.bin *.o
头文件

/*GPIO registers*/
#define GPBCON              (*(volatile unsigned long *)0x56000010)
#define GPBDAT              (*(volatile unsigned long *)0x56000014)
#define GPFCON              (*(volatile unsigned long *)0x56000050)
#define GPFDAT              (*(volatile unsigned long *)0x56000054)
#define GPFUP               (*(volatile unsigned long *)0x56000058)
#define GPGCON              (*(volatile unsigned long *)0x56000060)
#define GPGDAT              (*(volatile unsigned long *)0x56000064)
#define GPGUP               (*(volatile unsigned long *)0x56000068)

/*interrupt registes*/
#define SRCPND              (*(volatile unsigned long *)0x4A000000)
#define INTMOD              (*(volatile unsigned long *)0x4A000004)
#define INTMSK              (*(volatile unsigned long *)0x4A000008)
#define PRIORITY            (*(volatile unsigned long *)0x4A00000c)
#define INTPND              (*(volatile unsigned long *)0x4A000010)
#define INTOFFSET           (*(volatile unsigned long *)0x4A000014)
#define SUBSRCPND           (*(volatile unsigned long *)0x4A000018)
#define INTSUBMSK           (*(volatile unsigned long *)0x4A00001c)

/*external interrupt registers*/
#define EINTMASK            (*(volatile unsigned long *)0x560000a4)
#define EINTPEND            (*(volatile unsigned long *)0x560000a8)

#define     WTCON           (*(volatile unsigned long *)0x53000000)
head.S
.extern main
.text
.global _start
_start:
	b reset 
HandleUndef:
	b HandleUndef

HandlerSWI:
	b HandlerSWI 

HandlePrefetchAbort:
	b HandlePrefetchAbort

HandleDataAbort:
	b HandleDataAbort

HandleNotUsed:
	b HandleNotUsed

    b HandleIRQ           /*中断向量表的位置必须固定,即 b HandleIRQ运行位置必须在0x18处*/

HandleFIQ:
	b HandleFIQ

reset:
	ldr sp,=4096
	bl disable_watchdog

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

	msr cpsr_c,#0xd3     /*进入系统模式*/
	ldr sp,=4096 		 /*设置系统模式栈指针*/

	bl init_led          /*初始化led,即使得LED对应的GPIO引脚为输出模式*/
	bl init_irq          /*初始化中断,即设置相应外设引脚为中断模式,并设置好屏蔽为,优先级仲裁方法*/
	msr cpsr_c,#0x5f     /*开IRQ中断,这之后程序可以响应中断*/

	ldr lr,=halt_loop
	ldr pc,=main  

halt_loop:
	b halt_loop

HandleIRQ:
	sub lr,lr,#4
	stmdb sp!, {r0-r12,lr}

	ldr lr,=int_return
	ldr pc,=EINT_Handle

int_return:
	ldmia sp!,{r0-r12,pc}^
init.c

#include "s3c2440.h"
void init_irq(void)
{
	#define EINT (0b10)

	/*设置按键相关的端口为中断模式*/
	GPFCON &= ~( (3) | (3<<4));       /*先清除下面要设置的寄存器相关位*/
	GPGCON &= ~(3<<6);
	GPFCON |= ((EINT << 4) | (EINT <<0));   /*设置按键对应的GPIO口为中断模式*/
	GPGCON |= (EINT <<6);

	EINTMASK &= (~(1<<11)) ;          /*S4按键的中断为EINT11,在INTPND中的表示为EINT8_23*/

	INTMSK &= ( (~(1<<0)) & (~(1<<2)) & (~(1<<5)));

	PRIORITY = (PRIORITY & ( (~0x01) | (0x3<<7))) | (0x0<<7);
}

void init_led(void)
{
	GPFCON &= ~( (0b11<<12) | (0b11<<10) | (0b11<<8) );
	GPFCON |= ( (0b01<<12) | (0b01<<10) | (0b01<<8));
	GPFDAT |= (0b111<<4);
}

void disable_watchdog(void)
{
	WTCON=0X00;
}
irq.c

#include "s3c2440.h"

void EINT_Handle(void) 
{
	int val;
	val=INTOFFSET;
	switch(val)
		{
			case 0:     /*EINT0*/
					{
						GPFDAT |= (0x7<<4);
						GPFDAT &= ~(1<<4);
						break;
					}
			case 2:     /*EINT2*/
					{
						GPFDAT |= (0b111<<4);
						GPFDAT &= ~(1<<5);
						break;
					}
			case 5:     /*EINT8_23*/
					{
						GPFDAT |= (0b111<<4);
						GPFDAT &= ~(1<<6);						
						break;
					}
			default:
				        break;
		
		}

	/*清除中断*/
	if (val == 5 )
		EINTPEND = ( (1<<11) );
	SRCPND = 1<<val;
	INTPND = 1<<val;
main.c

int main(void)
{
	while(1);
	return 0;
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值