S3C2440 按键中断


本文是基于韦东山视频的学习笔记

汇总点这

总汇

根据电路原理图

  • S2 ~ EINT0 //按键2对应中断0
  • S3 ~ EINT2 //按键3对应中断2
  • S4 ~ EINT11 //按键4对应中断11
  • S5 ~ EINT19 //按键5对应中断19

中断也是一种异常,但中断较为复杂一点,除了一般异常的处理流程

  • 保护现场
  • 处理 (handle_irq_c )
    • 判断中断源 [INTOFFSET]
    • 跳到中断处理函数 (key_action)[EINTPEND]
    • 清除中断 [SRCPND] [INTBEND]
  • 恢复现场

当然还有寄存器设置函数 key_enit_init [EXTINTn] [EINTPEND]

更为甚者,我们可以来参考手册上的流程图

这里是引用
对于我们的按键中断来讲,都是without sub-register。

寄存器

使用什么外设,其实都是和寄存器打交道。那么,这次又和哪些寄存器打交道呢。

总中断寄存器

  • [INTMASK] Determine which interrupt source is masked.
    The masked interrupt source will not be
    serviced.(需要设置,在 register_irq 里设置)
  • [INTBEND] Indicate the interrupt request status.(需要清零, handle_irq_c )
  • [INTOFFSET] Indicate the IRQ interrupt request source(只读, handle_irq_c )
  • [SRCPND] Indicate the interrupt request status.(需要清零, handle_irq_c )

INTMSK 寄存器 中断屏蔽寄存器,置1是屏蔽中断源,置0是使能,默认是全部屏蔽,所以需要设置。

  • 地址:0X4A000008
  • [0] : EINT0 = 0x0(S2 - EINT0)
  • [2] : EINT2 = 0x0(S3 ~ EINT2)
  • [5] : EINT8_23 = 0x0(S4 ~ EINT11,S5 ~ EINT19)
  • 即 [0X4A000008] &= ((0<<0) | (0<<2) | (0<<5))

INTPND 寄存器 Indicate the interrupt request status.

  • 地址: 0X4A000010
    表明被请求了的寄存器
  • [0] : EINT0 (S2 - EINT0)
  • [2] : EINT2 (S3 ~ EINT2)
  • [5] : EINT8_23 (S4 ~ EINT11,S5 ~ EINT19)

INTOFFSET 寄存器 Indicate the IRQ interrupt request source

  • 地址:0x4A000014
    只读寄存器
  • 0 : EINT0 (S2 - EINT0)
  • 2 : EINT2 (S3 ~ EINT2)
  • 5 : EINT8_23 (S4 ~ EINT11,S5 ~ EINT19)

SRCPND寄存器 Indicate the interrupt request status.
一共32位代表不同的中断,置0是关闭中断,置1是使能中断

  • 地址: 0X4A000000
  • [0] : EINT0 = 0x1(S2 - EINT0)
  • [2] : EINT2 = 0x1(S3 ~ EINT2)
  • [5] : EINT8_23 = 0x1(S4 ~ EINT11,S5 ~ EINT19)

外部(按键)中断设置

  • [EXTINT0] / [EXTINT1] / [EXTINT2]
    External interrupt control register 0 / 1 / 2(需要设置, key_enit_init )
  • [EINTMASK] External interrupt mask register (需要设置, key_enit_init )
  • [EINTPEND] External interrupt pending register(需要清零, key_action)

EXTINT0 寄存器 External interrupt control register 0

  • 地址:0x56000088
  • [2:0] :EINT0 = 0x111(11x = Both edge triggered)
  • [10:8]:EINT2 = 0x111(11x = Both edge triggered)

EXTINT1 寄存器 External interrupt control register 1
地址:0x5600008c

  • [14:12] :EINT11 = 0x111(11x = Both edge triggered)

EXTINT2 寄存器 External interrupt control register 2
地址:0x56000090

  • [14:12] :EINT19 = 0x111(11x = Both edge triggered)

EINTMASK 寄存器 外部中断屏蔽寄存器,置1是屏蔽中断源,置0是使能,默认是全部屏蔽,所以需要设置。

  • 地址:0x560000a4(External interrupt mask register )
  • [11] :EINT11 = 0x0
  • [19] :EINT19 = 0x0

EINTPEND 寄存器 判断哪个中断发生

  • 地址:0x560000a8(External interrupt pending register)
  • 逐一对应

中断流程

首先是按键中断的各种寄存器初始化,这个真少不了。

/* 初始化按键中断 */
void key_eint_init()

{
	/* 初始化按键寄存器
	 * 设置GPFCON的GPF0/2、GPG3/11为中断引脚 
	 *  按键寄存器 
	 * C_S2 ~ 0  ~ GPF0 
	 * C_S3 ~ 4  ~ GPF2 
	 * C_S4 ~ 6  ~ GPG3 
	 * C_S5 ~ 22 ~ GPG11 
	 * D_S2 ~ 0  ~ GPF0 
	 * D_S3 ~ 2  ~ GPF2 
	 * D_S4 ~ 3  ~ GPG3 
	 * D_S5 ~ 11 ~ GPG11 
	 */
	GPFCON &= ~((3<<C_S2) | (3<<C_S3)); 	/* 把GPFCON 需要位置清零 */
	GPGCON &= ~((3<<C_S4) | (3<<C_S5)); 	/* 把GPGCON 需要位置清零 */

	
	GPFCON |=  ((2<<C_S2) | (2<<C_S3)); 	/* 把GPFCON 需要位置置位0x10 */
	GPGCON |=  ((2<<C_S4) | (2<<C_S5)); 	/* 把GPGCON 需要位置置位0x10 */

	/* EXTINT0 寄存器 External interrupt control register 0
	 - 地址:0x56000088
	 - [2:0]  :EINT0 = 0x111(11x = Both edge triggered)
	 - [10:8] :EINT2 = 0x111(11x = Both edge triggered)

	 * EXTINT1 寄存器 External interrupt control register 1
	 * 地址:0x5600008c
	 - [14:12] :EINT11 = 0x111(11x = Both edge triggered)

	 * EXTINT2 寄存器 External interrupt control register 2
	 * 地址:0x56000090
	 - [14:12] :EINT19 = 0x111(11x = Both edge triggered)
	 
	 * EINTMASK 寄存器 I/O中断屏蔽寄存器,置1是屏蔽中断源,置0是使能,默认是全部屏蔽,所以需要设置。
	 - 地址:0x560000a4(External interrupt mask register ) 
	 - [11] :EINT11 = 0x0
	 - [19] :EINT19 = 0x0
	 */
	EXTINT0 |= ((7<<0) | (7<<8)); 	/* s2, s3*/
	EXTINT1 |= ((7<<12)); 			/* s4 */
	EXTINT2 |= ((7<<12));			/* s5 */

	EINTMASK &= ~((1<<11) | (1<<19));	/* 使能外部中断,关闭屏蔽信号 */

	register_irq(0, key_irq);
	register_irq(2, key_irq);
	register_irq(5, key_irq);
}

一按下按键,硬件处理,首先就会跳到向量组 vector 0x18,通过汇编跳到 do_irq, 在这里完成保护现场恢复现场处理异常跳到c函数 handle_irq_c 。

do_irq:
	/* 重要!栈未设置,需要重新设置,指向一个不会被用到的地方 */
	ldr sp, =0x33d00000

	/* 保护现场 */
	sub lr, lr, #4					//根据lr恢复规则,异常前的lr-4 = 异常后的lr
	stmdb sp!, {r0-r12, lr}			//目前位置 lr 里面有被打断前的下一条将要执行的指令,所以也要保存
	
	/* 处理异常 */
	bl handle_irq_c

	/* 恢复现场 */
	ldmia sp!, {r0-r12, pc}^		/* ^会把spsr的值恢复到cpsr里 */

来到函数 handle_irq_c,做三个动作,分别是分辨中断源清除中断处理中断通过 irq_array[bit](bit) 语句跳转,这个其实是函数指针,in this case,处理函数是 key_action,里面就可以处理按键按下后的事情,整个中断流程至此。

typedef void(*irq_func)(int);
irq_func irq_array[32];

void handle_irq_c()
{
	/* 分辨中断源 */


	/*INTOFFSET 寄存器** Indicate the IRQ interrupt request source
	 - 地址:0x4A000014
   	 只读寄存器
	 - 0 : EINT0 (S2 - EINT0)
 	 - 2 : EINT2 (S3 ~ EINT2)
 	 - 5 : EINT8_23 (S4 ~ EINT11,S5 ~ EINT19)
 	 */
	int bit = INTOFFSET;	//读出来是哪个中断


	/* 处理中断 */
	irq_array[bit](bit);

	/* 清除中断 */
	SRCPND = (1<<bit);
	INTPND = (1<<bit);	
}

还有一个问题没解决 irq_array[bit](bit) 怎么指向 key_irq ?

我们搞一个函数,注册中断函数 ,在里面顺便设置中断屏蔽

/* 注册中断的指针函数, 附加使能总中断
 * irq - 第几个处理函数,fp - 传入的中断处理函数
 */
void register_irq(int irq, irq_func fp)
{

	irq_array[irq] = fp;

	
/* [INTMSK] 寄存器  中断屏蔽寄存器
	 * 置1是屏蔽中断源,置0是使能,默认是全部屏蔽,所以需要设置。
	 - 地址:0X4A000008
	 - [0] : EINT0 = 0x0(S2 - EINT0)
	 - [2] : EINT2 = 0x0(S3 ~ EINT2)
	 - [5] : EINT8_23 = 0x0(S4 ~ EINT11,S5 ~ EINT19)
	 -  即 [0X4A000008] &= ((0<<0) | (0<<2) | (0<<5))
	 */
	INTMSK &= ~(1<<irq);
}

相关代码

中断初始化(总/外部中断)



/* 初始化中断控制器 */
void interrput_init()
{
	
/* SRCPND寄存器 Indicate the interrupt request status.
	 * 一共32位代表不同的中断,置0是关闭中断,置1是使能中断
	 - 地址: 0X4A000000
	 - [0] : EINT0 = 0x1(S2 - EINT0)
	 - [2] : EINT2 = 0x1(S3 ~ EINT2)
	 - [5] : EINT8_23 = 0x1(S4 ~ EINT11,S5 ~ EINT19)
	 
	 * INTMSK 寄存器  中断屏蔽寄存器
	 * 置1是屏蔽中断源,置0是使能,默认是全部屏蔽,所以需要设置。
	 - 地址:0X4A000008
	 - [0] : EINT0 = 0x0(S2 - EINT0)
	 - [2] : EINT2 = 0x0(S3 ~ EINT2)
	 - [5] : EINT8_23 = 0x0(S4 ~ EINT11,S5 ~ EINT19)
	 -  即 [0X4A000008] &= ((0<<0) | (0<<2) | (0<<5))
	 */

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





按键中断处理

/* 按键处理函数,包括按键处理
irq - 0 : EINT0 (S2 - EINT0)
irq - 2 : EINT2 (S3 ~ EINT2)
irq - 5 : EINT8_23 (S4 ~ EINT11,S5 ~ EINT19)

*/
int key_action(int irq)
{
	unsigned int val = EINTPEND;


	/* S2-GPF0 、 S3-GPF2 、 S4 - GPG3
	 * S2~GPF6、S3~GPF5、S4~GPF4
	 * 如果按键对应DAT寄存器是零,即按键按下,反之 
	 */

	/* S2控制LED3 */
	if (irq == 0)
	{
		if (GPFDAT&(1<<D_S2)){
			GPFDAT |=  (1<<D_LED3);
		}
		else{
			GPFDAT &= ~(1<<D_LED3);
		}
	}
	
	
	/* S3控制LED2 */
	else if (irq == 2)
	{
		if (GPFDAT&(1<<D_S3)){
			GPFDAT |=  (1<<D_LED2);
		}
		else{
			GPFDAT &= ~(1<<D_LED2);
		}
	}

	
	/* S4控制LED1 */
	else if (irq == 5)
	{
		if (val & (1<<11))
		{
			if (GPGDAT&(1<<D_S4)){
				GPFDAT |=  (1<<D_LED1);
			}
			else{
				GPFDAT &= ~(1<<D_LED1);
			} 
		}
		
		else if (val & (1<<19))
		{

			if (GPGDAT&(1<<D_S5)){
				GPFDAT |=  ((1<<D_LED1) | (1<<D_LED2) | (1<<D_LED3));
			}
			else{
				GPFDAT &= ~((1<<D_LED1) | (1<<D_LED2) | (1<<D_LED3));
			} 	
		}
		

	}
	EINTPEND = val;			//清除外部中断
}



void handle_irq_c()
{
	/* 分辨中断源 */


	/*INTOFFSET 寄存器** Indicate the IRQ interrupt request source
	 - 地址:0x4A000014
   	 只读寄存器
	 - 0 : EINT0 (S2 - EINT0)
 	 - 2 : EINT2 (S3 ~ EINT2)
 	 - 5 : EINT8_23 (S4 ~ EINT11,S5 ~ EINT19)
 	 */
	int bit = INTOFFSET;	//读出来是哪个中断


	/* 处理中断 */
	if(bit == 0 || bit == 2 || bit == 5)
		key_action(bit);

	/* 清除中断 */
	SRCPND = (1<<bit);
	INTPND = (1<<bit);	
}



汇编

_start:
	b reset	/* 0x30000000 */
//	ldr pc, =do_und	/* 0x30000004 */
	ldr pc, und_addr	
	ldr pc, swi_addr
	b halt			 /* vector 0x0c : prefetch aboot */
	b halt			 /* vector 0x10 : data abort */
	b halt			 /* vector 0x14 : reserved */
	ldr pc, irq_addr /* vector 0x18 : irq */
	b halt			 /* vector 0x1c : fiq */
……
do_irq:
	/* 重要!栈未设置,需要重新设置,指向一个不会被用到的地方 */
	ldr sp, =0x33d00000

	/* 保护现场 */
	sub lr, lr, #4					//根据lr恢复规则,异常前的lr-4 = 异常后的lr
	stmdb sp!, {r0-r12, lr}			//目前位置 lr 里面有被打断前的下一条将要执行的指令,所以也要保存
	
	/* 处理异常 */
	bl handle_irq_c

	/* 恢复现场 */
	ldmia sp!, {r0-r12, pc}^		/* ^会把spsr的值恢复到cpsr里 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值