中断也是一种异常,但中断较为复杂一点,除了一般异常的处理流程
保护现场
处理 (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中的异常与中断
下一篇:S3C2440—6.串口的printf实现
推荐阅读最新更新时间:2024-11-11 14:49
推荐帖子
- 第一次发帖:用MSP430 LaunchPad做了个心率仪
- 在团购的群里看到有人给了一个用PIC单片机制作心率仪链接,做得很不错,是外国人做的!拿到MSP430LaunchPad本来是想做一块触摸板的,可是图不好画,后面又补发了触摸板,所以原来计划作罢。前段时间比较闲,看看有网友翻译了那篇用PIC单片机制作心率仪,就模仿做了一个。水平有限,请大家拍砖!在原来的基础上我做了一些该进,我的是四位数的,最高位是时间提示位-----------也就是提示被测的人已经按住多少时间按了。15秒一到,显示被测者的心率。显示部分我本来想用段码液晶的,可手头上
- IC爬虫 微控制器 MCU
- TI2017年发布超低相噪锁相环LMX2594
- 前几天老板让调试一下TI新发布不久的锁相环,先看看性能。性能是相当优越了,写了一个点频的程序测试了一下效果,输出12G的情况下,100M鉴相在10k可以达到102dbc/hz,基本上满足芯片手册上的指标,测试结果就不贴出来了,但这个效果一般的锁相环采用内插混频才能达到,可以说是相当厉害了。现在在调试扫频功能,但是这个锁相环功能感觉有些强大,有112个寄存器需要配置,扫频功能调试了几天还没有调试成功,如有调试的同道中人,一起讨论一下~此内容由EEWORLD论坛网友logitech66
- logitech66 RF/无线
- EMI噪声耦合的机理?
- 产生噪声的机理有如下几种:(1)阻抗不匹配和阻抗不连续;(2)共模阻抗不匹配引起差模信号;(3)容性耦合产生噪声电流;(4)感性耦合引起噪声电压;第一种阻抗不匹配和阻抗不连续会导致信号反射会导致信号的叠加、过冲、振铃;第二种共模阻抗不匹配导致差模信号,这个我想起的一个例子就是在同相加法器中,共模阻抗不匹配,但是怎么引起的差模信号?第三种第四种容性耦合和感性耦合,是指分开的两个导体之间存在电容,如果存在一个导体的电压相对另一个导体发生变化,就会产生所谓的位移电流,Ic=Cdu/dt,
- 乱世煮酒论天下 模拟电子
- Viterbi核的调用
- 最近在搞Viterbi译码器,不知道哪位大佬有viterbi核的使用手册,另外我调用的时候出现好多Error(204009):Can'tgeneratenetlistoutputfilesbecausethelicenseforencryptedfileF:/QuartusII13.0/biyesheji/viterbi_IP/viterbi-library/auk_vit_hyb_bmp_atl_ent.vhdisnotavailable这类错误哪位能解释下
- 'Friday Altera SoC
- 在altium designer中能不能挖一个凹槽?
- 在altiumdesigner中能不能挖一个凹槽?比如2.0mm厚的板子,要求凹槽深度1.2mm,就是不透的槽,如何挖?在altiumdesigner中能不能挖一个凹槽?走过路过的,帮个忙!就是一个凹槽不透,这个在keepoutlayer层放上槽的外框,最好是不要90°直角,即直角处稍微有点圆弧图上明确表明此处半槽,深度1.2mm,并发板图的时候,要和制板厂沟通能做否qwqwqw2088发表于2014-8-618:26就是一个凹槽不透,这个在keepoutl
- OldChief PCB设计
- CMOS集成电路设计手册
- CMOS集成电路设计手册CMOS集成电路设计手册赞一个非常好的电子书,英文原版,下载保存了,谢谢分享
- liva2022 电路观察室
设计资源 培训 开发板 精华推荐
- LT8494IUF 低静态电流、5V 至 300V、250kHz 反激式转换器的典型应用电路
- DC1554A-A,使用 LTM2882-3 RS232 模块隔离器 @ 3.3V 电源的演示板
- L78L24C正压稳压器Edit boost电路的典型应用
- ZR431F005TA 可调精密齐纳并联稳压器的典型应用
- TCR6DA1825、200mA、1.8V 和 2.5V 输出电压双路输出 CMOS 低压降稳压器的典型应用
- 用于 15V 模拟隔离放大器的电机控制电流检测应用
- 具有固定输出电压、1.8V ADP163 超低静态电流、150mA CMOS 线性稳压器的典型应用电路
- ADR435B 5 Vout 超低噪声 XFET 电压基准的典型应用,具有灌电流和拉电流能力
- 用于电池充电指示器的 NCP301LSN16T1 1.6V 电压检测器的典型应用
- 基于ST1S40IPUR的、具有使能开/关功能的、4A峰值800kHz固定频率PWM同步降压演示板