《嵌入式linux应用程序开发完全手册》中断控制器操作(外部中断)学习笔记

一.ARM中断体系

当一个“异常”发生时,或者说当收到一个中断触发信号时,ARM9将会自动完成如下一些工作:

(1)在异常工作模式的连接寄存器R14中保存前一个工作模式的下一条指令地址,即是pc+4或者pc+8。

(2)将CPSR的值复制到异常模式的SPSR中。

(3)将CPSR的工作模式位设为这个异常对应的工作模式。

(4)令PC值等于这个异常模式在异常向量表中的地址,即跳转去执行异常向量表中的相应指令。既是执行中断服务程序。

当从异常模式恢复至之前的工作模式时,软件需要完成如下工作:

(1)将前面进入异常时保存在R14中的指令地址减去适当值后赋给PC寄存器。

异常模式

退出异常时PC值

进入异常模式时R14值

Svc

MOVS PC,R14

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

(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的一般处理:

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<

#define GPB6_out (1<

#define GPB7_out (1<

#define GPB8_out (1<

/*

* K1-K4对应GPG11、GPG3、GPF2、GPF0

*/

#define GPG11_eint (2<

#define GPG3_eint (2<

#define GPF2_eint (2<

#define GPF0_eint (2<

/*

* 关闭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<

INTPND = 1<

}

嵌入式linux 添加中断,《嵌入式linux应用程序开发完全手册》中断控制器操作(外部中断)学习笔记...相关推荐

  1. 51单片机外部中断实验 设置中断优先级寄存器,当有外部中断0请求中断时,中断程序执行发光二极管程序,在此过程中,外部中断1也有中断请求,外部中断0的中断程序将被中断去执行外部中断1的中断程序(数码管

    设置中断优先级寄存器,当有外部中断0请求中断时,中断程序执行发光二极管程序,在此过程中,外部中断1也有中断请求,外部中断0的中断程序将被中断去执行外部中断1的中断程序(数码管加1显示程序). #inc ...

  2. STM32CubeMX EC11旋转编码器开发心路历程(encode模式 外部中断模式 普通IO口模式 定时器模式探索)

    文章目录 ENCODE模式探索 普通IO口探索 定时器使用 外部中断探索 编码器开关的理解 最后的实现方案 这篇文章主要还是记录整个过程以及想法的不断改进,对于一些实际的操作还有代码,我准备都分开写到 ...

  3. hal库开启中断关中断_(2)STM32使用HAL库操作外部中断——理论讲解

    1.中断触发过程 对主程序压栈--把中断服务函数的地址写入到程序计数器(PC)--执行中断服务函数 2.中断向量表 中断服务函数的地址在STM32的手册上的中断向量表中(如下是一部分): 如上表所示, ...

  4. gd32f303 设计中断优先级_ALIENTEK 阿波罗 STM32F767 开发板资料连载第九章 外部中断实验...

    1)实验平台:alientek 阿波罗 STM32F767 开发板2)摘自<STM32F7 开发指南(HAL 库版)>关注官方微信号公众号,获取更多资料:正点原子 第九章 外部中断实验 这 ...

  5. ATmega16开发板教程(5)——外部中断

    ​6.外部中断 这里主要编写外部中断0和1的边沿触发,通过LED状态显示. 外部中断0 外部中断我们要知道的是:①如何触发?上升沿.下降沿还是高低电平:②外部中断使能:③中断服务函数的编写. AVR提 ...

  6. php+参考手册,PHP程序开发参考手册

    PHP综合查询参考手册,包含PHPWeb开发中应用的各种语句.函数.类及其方法. 前言 第一篇 PHP基础篇 第1章 语句 第2章 经典类 第3章 数组函数库 第4章 类和对象函数库 第5章 日期时间 ...

  7. 嵌入式linux添加环境变量,Linux环境变量

    前言: 1. 环境变量是操作系统环境设置的变量,适用于整个系统的用户进程: 2. 环境变量可以在命令中设置,但是用户注销的时候将会丢失这些设置值: 3. 若要重复适用,则最好在.profile中定义: ...

  8. 嵌入式开发之Qt-5.9.6应用程序开发环境搭建

    参考文档 嵌入式开发之Qt-5.9.6交叉编译(带WebEngine) Qt-5.9.6 linux安装包官方下载地址 Qt-5.9.6 linux安装包百度云下载地址 开发环境介绍 主机操作系统:U ...

  9. linux添加windows网络打印机,Linux Mint如何添加windows分享的网络打印机?

    1.安装samba sudo apt-get install samba 2.找到系统打印机选项 通过 Menu-->>控制中心-->>系统管理找到 Printers选项,双击 ...

最新文章

  1. springboot视图解析器
  2. mybatis 分页需要的jar包下载_牛逼哄哄的PageHelper分页插件到底牛在哪里?
  3. PacificA: Replication in Log-Based Distributed Storage Systems 论文理解
  4. 25利他行为可以学习和模仿吗
  5. 请求转发与重定向的区别和执行流程
  6. 如何评判在线直播源码优劣?视频直播软件开发经验之谈
  7. 091116 T 维护性
  8. 如何使用libgdx编写一个简单的游戏(一)— 雏形
  9. egg前面加什么,egg前加a还是an?
  10. 云计算学习路线图课件:云计算中的常见的云配置错误
  11. .NET Core的文件系统[2]:FileProvider是个什么东西?
  12. 计算机科学导论定理八,计算机科学导论:思想与方法
  13. 在线答题助手c语言源码,开源的在线答题小程序
  14. 你知道什么是大数据的核心吗?
  15. 【大兴区亦庄亦庄线东晶国际4居室】自如网
  16. 属牛的女孩取名:优美文雅、声声入耳的女孩名字
  17. oracle的账户无法注册表,oracle用户账号在哪注册表ORA-12514问题解决
  18. 凤姐讲述为美国绿卡奋斗的十年
  19. node版本回退,用nvm管理node版本
  20. 浅谈快消品行业的数字化转型

热门文章

  1. _itemmod_day_limit
  2. dataTables基础函数变量
  3. java 企业门户网站 源码 自适应响应式 freemarker 静态引擎 html5 SSM
  4. 小学四则运算练习软件项目报告
  5. [二分][前缀和]洛谷 P1083 借教室
  6. NSArray利用Cocoa框架进行汉字排序
  7. select、poll、poll的比较(转)
  8. ARM Cortex Debug Port Access Port DP AP JTAG-DP SW-DP SWJ-DP JTAG-AP MEM-AP
  9. 字符串MD5加密和产生一个随机密码的方法
  10. 多线程编程之死锁已经死锁产生的原因