《嵌入式linux应用程序开发完全手册》中断控制器操作(外部中断)学习笔记
2009-10-28 22:31
302 查看
《嵌入式linux应用程序开发完全手册》中断控制器操作(外部中断)学习笔记
一.ARM中断体系
当一个“异常”发生时,或者说当收到一个中断触发信号时,ARM9将会自动完成如下一些工作:
(1) 在异常工作模式的连接寄存器R14中保存前一个工作模式的下一条指令地址,即是pc+4或者pc+8。
(2) 将CPSR的值复制到异常模式的SPSR中。
(3) 将CPSR的工作模式位设为这个异常对应的工作模式。
(4) 令PC值等于这个异常模式在异常向量表中的地址,即跳转去执行异常向量表中的相应指令。既是执行中断服务程序。
当从异常模式恢复至之前的工作模式时,软件需要完成如下工作:
(1) 将前面进入异常时保存在R14中的指令地址减去适当值后赋给PC寄存器。
(2) 将SPSR的值复制回CPSR。
二. S3C2440中断控制器
其实,无论哪种CPU,中断处理过程都是类似的:
1. 中断控制器汇集各类外设发出的中断信号,然后告诉CPU。
2. CPU保存当前程序的运行环境,调用中断服务程序来处理中断。
3. 在ISR(interrupt Service Routine)中通过读取中断控制器,外设的相关寄存器来识别这是哪个中断,并进行相应的处理。
4. 清除中断:通过读写中断控制器和外设的相关寄存器来实现。
5. 最后恢复被中断程序的运行环境,继续执行中断前的程序。
当然,对于不同的CPU体系结构,具体的寄存器操作自然就不同了。
对于S3C2440,寄存器SUBSRCPND和SRCPND表明有哪些中断被触发了,正在等待处理(pending),INTSUMMSK和INTMSK寄存器用于屏蔽某些中断
基本中断处理过程如下:
中断源被触发过后,SUBSRCPND寄存器中的相应位会被置位,如果此中断没有被INTMSK寄存器屏蔽掉,它将会进一步处理。在SRCPND寄存器中,被触发的中断相应位被置1,等待处理。如果被触发的中断源中有FIQ,则CPU进入FIQ Mode进行处理。如果被触发的是一般的IRQ,可能同时有几个中断被触发,未被INTMSK寄存器屏蔽的中断经过比较,选出优先级最高的中断,此中断在INTPND寄存器中的相应位被置1,然后CPU进入IRQ Mode进行处理。中断服务程序可以通过读取INTPND寄存器或者 INTOFFSET寄存器来确定中断源。
综上,使用中断的步骤如下:
1. 设置好中断模式和快速中断模式下的栈。
2. 准备好中断处理函数。包括异常向量表,ISR,清除中断。
清除中断的方法:
(1) 操作具体外设清除中断信号。
(2) 清除SUBSRCPND,SRCPND寄存器中的相应位。
(3) 清除INTPND寄存器中的相应位。
3. 进入和退出时需要对中断程序的运行环境进行保护和恢复。
(1)进入和退出IRQ的一般处理:
(2)进入和退出FIQ的一般处理:
4. 根据具体中断,设置相关外设,比如对于GPIO中断,需要将相应引功能设置为“外部中断”,设置中断触发条件等等。
5. 将INTSUBMSK寄存器相应位设为0,如果需要的话。
6. 确定使用中断的方式:FIQ或者 IRQ
7. 如果是FIQ,则INTMOD寄存器中设置相应位为1;如果是IRQ,则在PRIORITY寄存器中设置优先级。
8. 如果是IRQ,将INTMSK寄存器相应位设为0,FIQ不受INTMSK寄存器控制。
9. 设置CPSR寄存器中的I 位(IRQ)或者 F位(FIQ),全能IRQ或者FIQ。
中断控制寄存器:
(1) 子中断源未决寄存器SUBSRCPND,地址:0x4A000018
(2) 子中断屏蔽寄存器INTSUBMSK,地址:0x4A00001C
(3) 中断源未决寄存器SRCPND,地址:0x4A000000
(4) 中断屏蔽寄存器INTMSK,地址:0x4A000008
(5) 中断模式寄存器INTMOD,地址:0x4A000004
(6) 优先级寄存器PRIORITY,地址:0x4A00000C
(7) 中断未决寄存器INTPND,地址:0x4A000010
(8) 中断偏移寄存器INTOFFSET,地址:0x4A000014
各个寄存器的具体操作说明请参考S3C2440的datasheet。
三.KEY对应的中断连接
EINT19(GPG11)-------K1
EINT11(GPG3)-------K2
EINT2GPF2)-------K3
EINT0GPF0)-------K4
将这几个I/O口设置成外部中断功能。如果某个key按下时就产生中断,点亮对应的led。
四. 按键中断实验代码
(1)初始化,设置中断模式、系统模式的栈,设置好中断处理函数
(2)初始化,关闭watchdog,,初始化GPIO引脚为外部中断。
(3) 真正的ISR
一.ARM中断体系
当一个“异常”发生时,或者说当收到一个中断触发信号时,ARM9将会自动完成如下一些工作:
(1) 在异常工作模式的连接寄存器R14中保存前一个工作模式的下一条指令地址,即是pc+4或者pc+8。
(2) 将CPSR的值复制到异常模式的SPSR中。
(3) 将CPSR的工作模式位设为这个异常对应的工作模式。
(4) 令PC值等于这个异常模式在异常向量表中的地址,即跳转去执行异常向量表中的相应指令。既是执行中断服务程序。
当从异常模式恢复至之前的工作模式时,软件需要完成如下工作:
(1) 将前面进入异常时保存在R14中的指令地址减去适当值后赋给PC寄存器。
异常模式 | 退出异常时PC值 | 进入异常模式时R14值 |
Svc | MOVS PC,R14 | PC+4 |
Und | MOVS PC,R14 | PC+4 |
Fiq | SUBS PC,R14,#4 | PC+4 |
Irq | SUBS PC,R14,#4 | PC+4 |
Abt | 指令预取终止 SUBS PC,R14,#4 | PC+4 |
指令读取终止 SUBS PC,R14,#8 | PC+8 |
二. S3C2440中断控制器
其实,无论哪种CPU,中断处理过程都是类似的:
1. 中断控制器汇集各类外设发出的中断信号,然后告诉CPU。
2. CPU保存当前程序的运行环境,调用中断服务程序来处理中断。
3. 在ISR(interrupt Service Routine)中通过读取中断控制器,外设的相关寄存器来识别这是哪个中断,并进行相应的处理。
4. 清除中断:通过读写中断控制器和外设的相关寄存器来实现。
5. 最后恢复被中断程序的运行环境,继续执行中断前的程序。
当然,对于不同的CPU体系结构,具体的寄存器操作自然就不同了。
对于S3C2440,寄存器SUBSRCPND和SRCPND表明有哪些中断被触发了,正在等待处理(pending),INTSUMMSK和INTMSK寄存器用于屏蔽某些中断
基本中断处理过程如下:
中断源被触发过后,SUBSRCPND寄存器中的相应位会被置位,如果此中断没有被INTMSK寄存器屏蔽掉,它将会进一步处理。在SRCPND寄存器中,被触发的中断相应位被置1,等待处理。如果被触发的中断源中有FIQ,则CPU进入FIQ Mode进行处理。如果被触发的是一般的IRQ,可能同时有几个中断被触发,未被INTMSK寄存器屏蔽的中断经过比较,选出优先级最高的中断,此中断在INTPND寄存器中的相应位被置1,然后CPU进入IRQ Mode进行处理。中断服务程序可以通过读取INTPND寄存器或者 INTOFFSET寄存器来确定中断源。
综上,使用中断的步骤如下:
1. 设置好中断模式和快速中断模式下的栈。
2. 准备好中断处理函数。包括异常向量表,ISR,清除中断。
清除中断的方法:
(1) 操作具体外设清除中断信号。
(2) 清除SUBSRCPND,SRCPND寄存器中的相应位。
(3) 清除INTPND寄存器中的相应位。
3. 进入和退出时需要对中断程序的运行环境进行保护和恢复。
(1)进入和退出IRQ的一般处理:
sub lr, lr, #4 @ 计算返回地址 stmdb sp!, { r0-r12,lr } @ 保存使用到的寄存器 …… @中断处理 ldmia sp!, { r0-r12,pc }^ @ 中断返回, ^表示将spsr的值复制到cpsr
(2)进入和退出FIQ的一般处理:
sub lr, lr, #4 @ 计算返回地址 stmdb sp!, { r0-r7,lr } @ 保存使用到的寄存器 …… @快速中断处理 ldmia sp!, { r0-r7,pc }^ @ 中断返回, ^表示将spsr的值复制到cpsr
4. 根据具体中断,设置相关外设,比如对于GPIO中断,需要将相应引功能设置为“外部中断”,设置中断触发条件等等。
5. 将INTSUBMSK寄存器相应位设为0,如果需要的话。
6. 确定使用中断的方式:FIQ或者 IRQ
7. 如果是FIQ,则INTMOD寄存器中设置相应位为1;如果是IRQ,则在PRIORITY寄存器中设置优先级。
8. 如果是IRQ,将INTMSK寄存器相应位设为0,FIQ不受INTMSK寄存器控制。
9. 设置CPSR寄存器中的I 位(IRQ)或者 F位(FIQ),全能IRQ或者FIQ。
中断控制寄存器:
(1) 子中断源未决寄存器SUBSRCPND,地址:0x4A000018
(2) 子中断屏蔽寄存器INTSUBMSK,地址:0x4A00001C
(3) 中断源未决寄存器SRCPND,地址:0x4A000000
(4) 中断屏蔽寄存器INTMSK,地址:0x4A000008
(5) 中断模式寄存器INTMOD,地址:0x4A000004
(6) 优先级寄存器PRIORITY,地址:0x4A00000C
(7) 中断未决寄存器INTPND,地址:0x4A000010
(8) 中断偏移寄存器INTOFFSET,地址:0x4A000014
各个寄存器的具体操作说明请参考S3C2440的datasheet。
三.KEY对应的中断连接
EINT19(GPG11)-------K1
EINT11(GPG3)-------K2
EINT2GPF2)-------K3
EINT0GPF0)-------K4
将这几个I/O口设置成外部中断功能。如果某个key按下时就产生中断,点亮对应的led。
四. 按键中断实验代码
(1)初始化,设置中断模式、系统模式的栈,设置好中断处理函数
@****************************************************************************** @ File:head.S @ 功能:初始化,设置中断模式、系统模式的栈,设置好中断处理函数 @****************************************************************************** .extern main .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 @ 进入中断模式,M[4:0]=10010 , [IFT]=110 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中断,[IFT]=010 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)初始化,关闭watchdog,,初始化GPIO引脚为外部中断。
* 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对应GPG11、GPG3、GPF2、GPF0 */ #define GPG11_eint (2<<(11*2)) // K1,EINT19 #define GPG3_eint (2<<(3*2)) // K2,EINT11 #define GPF2_eint (2<<(2*2)) // K3,EINT2 #define GPF0_eint (2<<(0*2)) // K4,EINT0 /* * 关闭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( ) { GPFCON = GPF0_eint | GPF2_eint; GPGCON = GPG3_eint | GPG11_eint; // 对于EINT11、19,需要在EINTMASK寄存器中使能它们 EINTMASK &= (~(1<<11)) & (~(1<<19)); /* * 设定优先级: * ARB_SEL0 = 00b, ARB_MODE0 = 0: REQ1 > REQ3,即EINT0 > EINT2 * 仲裁器1、6无需设置 * 最终: * EINT0 > EINT2 > EINT11,EINT19,即K4 > K3 > K1,K2 * EINT11和EINT19的优先级相同 */ PRIORITY = (PRIORITY & ((~0x01) | (0x3<<7))) | (0x0 << 7) ; // EINT0、EINT2、EINT8_23使能 INTMSK &= (~(1<<0)) & (~(1<<2)) & (~(1<<5)); }
(3) 真正的ISR
void EINT_Handle() { unsigned long oft = INTOFFSET; unsigned long val; switch( oft ) { // K4被按下 case 0: { GPBDAT |= (0x0f<<5); // 所有LED熄灭 GPBDAT &= ~(1<<8); // LED4点亮 break; } // K3被按下 case 2: { GPBDAT |= (0x0f<<5); // 所有LED熄灭 GPBDAT &= ~(1<<7); // LED3点亮 break; } // K1或K2被按下 case 5: { GPBDAT |= (0x0f<<5); // 所有LED熄灭 // 需要进一步判断是K1还是K2,或是K1、K2被同时按下 val = EINTPEND; if (val & (1<<11)) GPBDAT &= ~(1<<6); // K2被按下,LED2点亮 if (val & (1<<19)) GPBDAT &= ~(1<<5); // K1被按下,LED1点亮 break; } default: break; } //清中断 if( oft == 5 ) EINTPEND = (1<<11) | (1<<19); // EINT8_23合用IRQ5 SRCPND = 1<<oft; INTPND = 1<<oft; }
相关文章推荐
- STM8L探索套件学习笔记-EXTI外部中断
- cortex_m3_stm32嵌入式学习笔记(十五):待机唤醒实验(WK_UP外部中断)
- 单片机学习笔记--外部中断,定时器,串口中断
- 嵌入式学习笔记: Cortex-A8 外部中断
- STM32学习笔记之EXTI(外部中断)
- STM32学习笔记——外部中断EXTI
- stm32学习笔记——外部中断的使用
- STM32学习笔记之EXTI(外部中断)
- Tq2440学习笔记之外部中断
- STM32学习笔记-外部中断
- STM32学习笔记:外部中断的使用
- zigbee学习笔记3----cc2530 外部中断实验
- STM32学习笔记:外部中断的使用
- STM32学习笔记:外部中断EXTI的使用
- STM32-外部中断学习笔记
- STM32学习笔记整理之(2)——外部中断
- stm32学习笔记 F1系列外部中断EXTI
- CC2530学习笔记の外部中断——按键控制LED
- stm32学习笔记:GPIO外部中断的使用
- stm32学习笔记——外部中断的使用