一、ARM中断体系结构
arm有7中异常工作模式

用户模式、快中断模式、管理模式、数据访问终止模式、中断模式、系统模式、未定义指令终止模式。

几种模式有什么不同呢,
1、不同的寄存器
2、不同的权限
3、触发条件

对于不同的寄存器,ARM920T有31个通用的32位寄存器和6个程序状态寄存器。这37个寄存器分为7组,进入某个工作模式时就使用他那组的寄存器。有些寄存器,不同的工作模式下有他的副本,当切换到另一个工作模式时,那个工作模式的寄存器副本将被使用:这些寄存器被称为备份寄存器(图中灰色部分的寄存器)

在ARM状态下,每种工作模式都有16个通用的寄存器和一个(或两个,这取决于不同的工作模式)程序状态寄存器。图中R0-R15可以直接访问,这些寄存器除了R15外都是通用寄存器,即他们既可以保存数据又可以保存地址。另外R13-R15稍有特殊。R13是栈指针寄存器,通常被用来保存栈指针。14被称为程序连接寄存器,当执行BL子程序调用指令时,R14中得到R15(程序计数器PC)的备份。而当发生中断或异常时,对应的R14_svc、R14_irq、R14_fiq、R14_abt、R14_und中保存R15的返回值。

快速中断模式有7个备份寄存器R8-R14,这使得进入快速中断模式执行很大部分程序时,只要不改变R0-R7,不用保存任何寄存器。七种工作模式都有自己独占的寄存器副本R13和R14,这使得每个模式都有自己的栈指针寄存器和连接寄存器。

每种工作模式除了R0-R15外,还有第17个寄存器CPSR,即当前程序状态寄存器。CPSR中一些位被用来标识各种状态,一些位被用来标识当前处于什么工作模式。
如图CPSR


CPSR各位的意义:
(1)T位:置位时,CPU处Thumb状态,否则处于ARM状态
(2)中断禁止位:I位和F位属于中断禁止位。他们被置位时IRQ中断和FIQ中断分别被禁止。
(3)工作模式位:标识CPU当前处于什么工作模式。可以编写这些位,使CPU进入指定的工作模式。
除CPSR外,还有快速中断模式、中断模式、管理模式、数据访问终止模式和未定义指令终止魔兽等5中工作模式都有独占的寄存器SPSR,即程序状态保存寄存器。当切换进入这些工作模式时,在SPSR中保存前一个工作模式的CPSR的值,这样,当返回前一个工作模式时,可以将SPSR中的值恢复到CPSR中。

综上所述,当一个异常发生时,将切换进入相应的工作模式,这时ARM920T CPU核将自动完成如下的事情:
(1)、在异常工作模式的连接寄存器R14中保存前一个工作模式的下一条即将执行指令的地址,对于ARM状态,这个值是当前pc值加4或加8。
(2)、将CPSR的值复制到异常模式的SPSR
(3)、将CPSR的工作模式位设置为这个异常模式对应的工作模式。
(4)、令PC值等于这个异常模式在异常向量表的地址。即跳转去执行异常向量表中的相应的指令。
相反地、从异常工作模式退出返回之前的工作模式时,需要通过软件完成以下事情:
(1)、前面进入异常工作模式时,连接寄存器保存了前一工作模式的一个指令地址,将他减去一个适当的值后赋给PC寄存器。
(2)、将SPSR的值复制回CPSR。

CPSR模式位设置如下图:

二、s3c2440的中断控制器

CPU工作的过程中如何知道各类外设发生了某些不预期的事件呢,比如串口接收到了新数据、USB接口插入了设备、按下了某个按键等。主要有两种方法:
(1)是查询方式:程序循环地查询各设备的状态并作出相应的反应。实现比较简单,常用在功能相对单一的系统中,比如在一个温度检测系统对温度的不断检查。缺点是占用CPU资源,不适用于多任务系统。
(2)、中断方式:当某事件发生时,硬件会设置某个寄存器;CPU在每执行完一个指令时,通过硬件查看这个寄存器,如果发现所关注的时
间发生了,则中断当前程序流程,跳转到一个固定的地址处理这件事,最后返回继续执行被中断的程序。他的实现相对复杂,但是效率很高,是常用的方法。

中断体系外设、内部外设与CPU核的硬件框图:

不论何种CPU,中断的处理是相似的。
(1)、中断控制器汇集各类外设发出的中断信号,然后告诉CPU。
(2)、CPU保存当前程序的运行环境,调用中断服务程序来处理这些中断。
(3)、在ISR中通过读取中断控制器,外设的相关寄存器来识别这是哪个中断,并进行相应的处理。
(4)、清楚中断:通过读写中断控制器和外设的相关寄存器来实现。
(5)、最后恢复被中断程序的运行环境(即上面保存的各个寄存器等),继续执行。

对于不同的CPU而言,中断的处理只是细节的不同。

中断处理框图:

从中断控制器结构图看出
SUBSRCPND和SRCPND寄存器表明有哪些中断被触发,正在等待处理;SUBMASK(INTSUBMASK寄存器)和MASK(INTMASK寄存器)用于屏蔽某些中断。
图中的“Request sources(with sub-register)”表示INT_RXD0、INT_TXD0等中断源(这类中断源S3C2440有15个)。他们不同于“Request sources(without sub-register”。

附图s3c2440异常向量表:

综上所述,使用中断的步骤如下:
(1)设置好中断模式和快速中断模式下的栈:当发生中断IRQ时,CPU进入中断模式,这时使用中断模式下的栈;当发生快速中断时,CPU进入快速中断模式,这时使用快速中断模式下的栈。
(2)准备好中断处理函数。
a、异常向量:
在异常向量表中设置好进入中断模式或快速中断模式时的跳转函数,他们的异常向量分别是0x00000018、0x0000001c。
b、中断服务程序(ISR)
IRQ、FIQ的跳转函数,具体将调用具体中断的服务函数、

对于IRQ,读取INTPND寄存器或INTOFFSET寄存器的值来判断中断源,然后分别处理。
对FIQ,由于只有一个中断可以设为FIQ,无需判断中断源。

c、清除中断:如果不清除中断,则CPU会误以为这个中断又一次发生。

清除中断时从源头开始:首先,需要的话,操作具体外设清除中断信号,比如EINTPEND;其次,清除SUBSRCPND(用到的话)、SRCPND寄存器中的相应的位;最后清除INTPND寄存器中相应的位。
(3)、进入、退出中断模式或快速中断模式时,需要保存、恢复被中断程序的运行环境。
(4)、根据具体中断设置相关外设,比如GPIO中断,需要将相应的引脚功能设置为外部中断、设置中断触发条件等,一些中断有自己的屏蔽寄存器,还要开启它,比如,GPIO的外设中断,EINTMASK。
(5)、对于“Request sources(without sub-register)”的中断,将INTSUBMASK寄存器中相应的位设为0.
(6)、确定使用中断的方式:FIQ或IRQ
a、如果是FIQ,则在INTMOD寄存器中设置相应位为1
b、如果是IRQ,则在RIORITY寄存器中设置优先级
(7)、如果是IRQ,将INTMAK寄存器中相应的位设为0(FIQ不受INITMSK寄存器的控制)。
(8)、设置CPSR寄存器中的I位(对于IRQ)或F位(对于FIQ)为0,使能IRQ或FIQ、

在s3c2440中中断控制器相关的8个寄存器:

1、SUBSRCPND
SUBSRCPND被用来标识INT_RXD0、INT_TXD0等中断是否已经发生,每位对应一个中断。当这些中断发生且没有被INTSUBMSK寄存器屏蔽,则他们的若干位将汇集出现在SRCPND寄存器的一位上,比如、只要INT_RXD0、INT_TXD0或INT_ERR0一个发生且没有被屏蔽,则SRCPND寄存器INT_UART0位被置1.
要清除中断时,往SUBSRCPND中相应的位写1

2、INTSUBMSK
用来屏蔽SUBSRCPND寄存器所标识的中断
3、SRCPND
SRCPND寄存器每一位用来标识一个或一类中断是否已经发生,清除中断时与SUBSRCPND类似。
4、INTMSK
INTMSK寄存器用来屏蔽SRCPND寄存器所标识的中断。
5、INTMOD
当INTMOD寄存器中某位写入1时,它对应的中断被设为FIQ,同一时间里,INTMOD寄存器中只能有一位写入1。
6、PRIORITY
优先级寄存器,有多个中断同时发生时,中断控制器将选出优先级最高的中断源

7、INTPND
经过优先级仲裁器选出优先级最高的中断后,这个中断在INTPND寄存器中相应的位被置1,随后,CPU将进入中断模式处理它。同一时间段里,此寄存器只有一位被置1:在ISR中,可以根据这个位确定是哪个中断。清除中断时,往这个位写1.
8、INTOFFSET寄存器
这个寄存器被用来表示INTPND寄存器中哪个位被置1了,即INTPND寄存器中位【x】位1时,INTOFFSET寄存器的值为x(x为0-31)。
在清除SRCPND、INTPND寄存器时,INTOFFSET寄存器被自动清除。

三、实现按键中断,led灯亮程序

head.S

@******************************************************************************
@ 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, = @ 设置栈指针,以下都是C函数,调用前需要设好栈
bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启 msr cpsr_c, #0xd2 @ 进入中断模式
ldr sp, = @ 设置中断模式栈指针 msr cpsr_c, #0xd3 @ 进入管理模式
ldr sp, = @ 设置管理模式栈指针,
@ 其实复位之后,CPU就处于管理模式,
@ 前面的“ldr sp, =”完成同样的功能,此句可省略 bl init_led @ 初始化LED的GPIO管脚
bl init_irq @ 调用中断初始化函数,在init.c中
msr cpsr_c, #0x5f @ 设置I-bit=,开IRQ中断 ldr lr, =halt_loop @ 设置返回地址
ldr pc, =main @ 调用main函数
halt_loop:
b halt_loop HandleIRQ:
sub lr, lr, # @ 计算返回地址
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 init.c /*
* init.c: 进行一些初始化
*/ #include "s3c24xx.h" /*
* LED1,LED2,LED4对应GPF4、GPF5、GPF6
*/
#define GPF4_out (1<<(4*2))
#define GPF5_out (1<<(5*2))
#define GPF6_out (1<<(6*2)) #define GPF4_msk (3<<(4*2))
#define GPF5_msk (3<<(5*2))
#define GPF6_msk (3<<(6*2)) /*
* S2,S3,S4对应GPF0、GPF2、GPG3
*/
#define GPF0_eint (0x2<<(0*2))
#define GPF2_eint (0x2<<(2*2))
#define GPG3_eint (0x2<<(3*2)) #define GPF0_msk (3<<(0*2))
#define GPF2_msk (3<<(2*2))
#define GPG3_msk (3<<(3*2)) /*
* 关闭WATCHDOG,否则CPU会不断重启
*/
void disable_watch_dog(void)
{
WTCON = ; // 关闭WATCHDOG很简单,往这个寄存器写0即可
} void init_led(void)
{
// LED1,LED2,LED4对应的3根引脚设为输出
GPFCON &= ~(GPF4_msk | GPF5_msk | GPF6_msk);
GPFCON |= GPF4_out | GPF5_out | GPF6_out;
} /*
* 初始化GPIO引脚为外部中断
* GPIO引脚用作外部中断时,默认为低电平触发、IRQ方式(不用设置INTMOD)
*/
void init_irq( )
{
// S2,S3对应的2根引脚设为中断引脚 EINT0,ENT2
GPFCON &= ~(GPF0_msk | GPF2_msk);
GPFCON |= GPF0_eint | GPF2_eint; // S4对应的引脚设为中断引脚EINT11
GPGCON &= ~GPG3_msk;
GPGCON |= GPG3_eint; // 对于EINT11,需要在EINTMASK寄存器中使能它
EINTMASK &= ~(<<); /*
* 设定优先级:
* ARB_SEL0 = 00b, ARB_MODE0 = 0: REQ1 > REQ3,即EINT0 > EINT2
* 仲裁器1、6无需设置
* 最终:
* EINT0 > EINT2 > EINT11即K2 > K3 > K4
*/
PRIORITY = (PRIORITY & ((~0x01) | (0x3<<))) | (0x0 << ) ; // EINT0、EINT2、EINT8_23使能
INTMSK &= (~(<<)) & (~(<<)) & (~(<<));
}
s3c2440.h
/* WOTCH DOG register */
#define WTCON (*(volatile unsigned long *)0x53000000) /* SDRAM regisers */
#define MEM_CTL_BASE 0x48000000
#define SDRAM_BASE 0x30000000 /* NAND Flash registers */
#define NFCONF (*(volatile unsigned int *)0x4e000000)
#define NFCMD (*(volatile unsigned char *)0x4e000004)
#define NFADDR (*(volatile unsigned char *)0x4e000008)
#define NFDATA (*(volatile unsigned char *)0x4e00000c)
#define NFSTAT (*(volatile unsigned char *)0x4e000010) /*GPIO registers*/
#define GPBCON (*(volatile unsigned long *)0x56000010)
#define GPBDAT (*(volatile unsigned long *)0x56000014) #define GPFCON (*(volatile unsigned long *)0x56000050)
#define GPFDAT (*(volatile unsigned long *)0x56000054)
#define GPFUP (*(volatile unsigned long *)0x56000058) #define GPGCON (*(volatile unsigned long *)0x56000060)
#define GPGDAT (*(volatile unsigned long *)0x56000064)
#define GPGUP (*(volatile unsigned long *)0x56000068) #define GPHCON (*(volatile unsigned long *)0x56000070)
#define GPHDAT (*(volatile unsigned long *)0x56000074)
#define GPHUP (*(volatile unsigned long *)0x56000078) /*UART registers*/
#define ULCON0 (*(volatile unsigned long *)0x50000000)
#define UCON0 (*(volatile unsigned long *)0x50000004)
#define UFCON0 (*(volatile unsigned long *)0x50000008)
#define UMCON0 (*(volatile unsigned long *)0x5000000c)
#define UTRSTAT0 (*(volatile unsigned long *)0x50000010)
#define UTXH0 (*(volatile unsigned char *)0x50000020)
#define URXH0 (*(volatile unsigned char *)0x50000024)
#define UBRDIV0 (*(volatile unsigned long *)0x50000028) /*interrupt registes*/
#define SRCPND (*(volatile unsigned long *)0x4A000000)
#define INTMOD (*(volatile unsigned long *)0x4A000004)
#define INTMSK (*(volatile unsigned long *)0x4A000008)
#define PRIORITY (*(volatile unsigned long *)0x4A00000c)
#define INTPND (*(volatile unsigned long *)0x4A000010)
#define INTOFFSET (*(volatile unsigned long *)0x4A000014)
#define SUBSRCPND (*(volatile unsigned long *)0x4A000018)
#define INTSUBMSK (*(volatile unsigned long *)0x4A00001c) /*external interrupt registers*/
#define EINTMASK (*(volatile unsigned long *)0x560000a4)
#define EINTPEND (*(volatile unsigned long *)0x560000a8)
interrupt.c
#include "s3c24xx.h"

void EINT_Handle()
{
unsigned long oft = INTOFFSET;
unsigned long val; switch( oft )
{
// S2被按下
case :
{
GPFDAT |= (0x7<<); // 所有LED熄灭
GPFDAT &= ~(<<); // LED1点亮
break;
} // S3被按下
case :
{
GPFDAT |= (0x7<<); // 所有LED熄灭
GPFDAT &= ~(<<); // LED2点亮
break;
} // K4被按下
case :
{
GPFDAT |= (0x7<<); // 所有LED熄灭
GPFDAT &= ~(<<); // LED4点亮
break;
} default:
break;
} //清中断
if( oft == )
EINTPEND = (<<); // EINT8_23合用IRQ5
SRCPND = <<oft;
INTPND = <<oft;
}
main.c
int main()
{
while();
return ;
}
Makefile
objs := head.o init.o interrupt.o main.o

int.bin: $(objs)
arm-linux-ld -Ttext 0x00000000 -o int_elf $^
arm-linux-objcopy -O binary -S int_elf $@
arm-linux-objdump -D -m arm int_elf > int.dis %.o:%.c
arm-linux-gcc -Wall -O2 -c -o $@ $< %.o:%.S
arm-linux-gcc -Wall -O2 -c -o $@ $< clean:
rm -f int.bin int_elf int.dis *.o
	


												

s3c2440中断控制器操作的更多相关文章

  1. ARM9的中断控制器

    简要复习一下ARM9中断控制器的控制过程: 1.首先能识别触发的中断(对应中断源必须打开,然后查询当前中断状态寄存器),硬件会操控PC跳到中断向量入口(IRQ_HANDLE,硬件控制的只要是IRQ中断 ...

  2. S3C2440中断

    韦东山老师一期中断课程学习: 总结: 程序启动后工作流程,程序从0地址开始执行Reset  --> 重定位  -->ldr pc,=main [绝对跳转到SDRAM中执行main()函数] ...

  3. 【原创】Linux中断子系统(一)-中断控制器及驱动分析

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  4. x86架构中的外部中断结构-Part 1:中断控制器的演化

    本文主要讲解了x86体系架构从外部设备接受中断的过程,本文是系列文章的第一部分,试图回答以下问题: 什么是PIC以及它的用途是什么? 什么是APIC以及它的用途是什么?LAPIC和I/O APIC的目 ...

  5. ASP.NET Core 中文文档 第四章 MVC(4.2)控制器操作的路由

    原文:Routing to Controller Actions 作者:Ryan Nowak.Rick Anderson 翻译:娄宇(Lyrics) 校对:何镇汐.姚阿勇(Dr.Yao) ASP.NE ...

  6. thinkphp使用模块/控制器/操作访问时出现No input file specified.解决方式

    thinkphp使用 http://serverName/index.php/模块/控制器/操作 访问时,出现了 No input file specified. 的错误 解决办法: 一: 开启cgi ...

  7. Linux中断子系统:级联中断控制器驱动

    Linux中断子系统 Linux中断子系统是个很大的话题,如下面的思维导图所示,包含硬件.驱动.中断上半部.中断下半部等等.本文着眼于中断控制器(PIC),特别是级联中断控制器驱动部分,对驱动的设计和 ...

  8. 关于ck中断控制器

    一.中断控制器 中断控制器模块包括 其使能寄存器,状态寄存器等. 中断使能寄存器为32bit,每一个bit 对应一个中断源,具体对应到硬件上线的连接 二.cpu怎样调用到中断 (1). 前置工作 首先 ...

  9. threejs绕轴转,粒子系统,控制器操作等(二)

    前言:threejs系列的第二篇文章,也是一边学习一边总结: 1,一个物体绕着另一个物体转动 上一篇文中主要是物体自转,为了描述一个一个物体绕另一个物体转,这里我描述了一个月球绕地球公转,并且自转的场 ...

随机推荐

  1. Tomcat中server.xml文件内各节点详解

    由于 Tomcat 基于 Java,实际上在各种 Linux 发行版里的配置方法都大同小异,只是我看见在 Arch Linux 环境里搭建 Tomcat 的文章比较少,所以在 Arch Linux 实 ...

  2. Studying TCP's Congestion Window using NS

    Studying TCP's Congestion Window using NS How to obtain TCP's CWND value The most important value th ...

  3. CXPACKET等待事件

    今天收到数据库预警,发现连接数较多.于是立马登录查看机器的基本情况: select * from sys.sysprocesses 查看了一下连接数,发现有两个进程都处于CXPACKET状态,而且看得 ...

  4. 【Leetcode】【Medium】Binary Tree Zigzag Level Order Traversal

    Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to ...

  5. MEGER sentence in oracle

    MEGE Sentence This oracle tutorial explains how to use the oralce MEGER sentence with syntax and sam ...

  6. 薄弱的交互页面之新浪微博到博客的储存型xss漏洞

    首先分享一片博文到微博,然后 在微博评论xss code 最后回到博客点击举报就触发xss了 点击举报 Xss之2 首先还是分享一片博文到微博,然后评论xsscode 回到我的博客个人中心,查看评论 ...

  7. (一)安装Linux时的磁盘划分

    Linux安装中的磁盘划分 安装Ctentos6.3的版本,它使用的默认文件系统类型是ext4. Linux的安装至少要划分为根分区/和swap分区这个两个分区才能正常安装使用. 一般来说应该分为四个 ...

  8. 自动下单tomcat版本问题

    \xalan\xalan,jar找不到是因为spring boot 中使用的是tomcat8.5,从platform依赖进来的运行时环境是tomcat8,导致覆盖原来的依赖,在platform中移除S ...

  9. 【DP】:CF #319 (Div. 2) B. Modulo Sum

    [题目链接]:http://codeforces.com/contest/577/problem/B [相似题目]:http://swjtuoj.cn/problem/2383/ [题意]:给出n个数 ...

  10. git branch 进入编辑状态

    命令行输入git branch,发现进入编辑状态,都要:wq,非常不方便,这样配置 git config --global core.pager ''