历史上的今天
今天是:2024年09月06日(星期五)
2021年09月06日 | S3C2440 按键中断
2021-09-06 来源:eefocus
中断也是一种异常,但中断较为复杂一点,除了一般异常的处理流程
保护现场
处理 (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< GPFCON |= ((2< /* 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< 还有一个问题没解决 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< 相关代码 中断初始化(总/外部中断) /* 初始化中断控制器 */ 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< else{ GPFDAT &= ~(1< } /* S3控制LED2 */ else if (irq == 2) { if (GPFDAT&(1< else{ GPFDAT &= ~(1< } /* S4控制LED1 */ else if (irq == 5) { if (val & (1<<11)) { if (GPGDAT&(1< else{ GPFDAT &= ~(1< } else if (val & (1<<19)) { if (GPGDAT&(1< else{ GPFDAT &= ~((1< } } 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< 汇编 _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里 */
上一篇:S3C2440中的异常与中断
史海拾趣
|
如果用ads开发 是不是每个程序都要用到44b0的启动代码 不同程序启动代码都一样吗 我听说用iar开发不用启动代码 和用keil一样 44b0+iar+jtag 可以吗… 查看全部问答> |
|
一. 波特率 并行通信中,传输速率是以每秒传送多少字节(B / S)来表示。而串行通信中,传输速率在基波传输的情况下(不加调制,以其固有的频率传送)是用每秒钟传送的位数(bit/s)即波特率来表示。因此,1波特=1位/秒。 最常用的标 ...… 查看全部问答> |
|
RELEASETYPE is not set. Using default settings. 今天编译CE5.0内核遇到这么个警告: RELEASETYPE is not set. Using default settings. 结果导致编译出错,而用同样的BSP在我同事的机子上却没事,所以我怀疑是PB出了问题,哪位大侠给指点一下… 查看全部问答> |
|
程序实现功能如下: 通过clk的脉冲,在recive=0时统计clk的跳变数,达到计时的目的,再把时间通过4个七段数码管显示出来。 程序代码如下: library ieee; use ieee.std_logic_1164.all; entity device is port(clk   ...… 查看全部问答> |
|
今天兴高采烈的在调 PWM程序 弄示波器探头接触引脚的时候 貌似出现了点火花 我也没太在意 出现了波形 可是频率差了点 于是乎准备重新载程序 突然就出现了 我想估计芯片毁了… 查看全部问答> |
|
请教各位: 在BIOS中,我用TSK0调用函数test(),硬件中断INT1调用T0ISR().运行程序后,程序一直进入T0ISR(),而不调用\\"任务\\"对象.不应该是在两次中断之间的时间里,会调用TSK0吗?或者是需要什么API函数调用? 部分程序 ...… 查看全部问答> |




