历史上的今天

今天是:2024年10月18日(星期五)

正在发生

2021年10月18日 | 【JZ2440笔记】裸机实验使用中断

发布者:HeavenlySunset 来源: eefocus关键字:JZ2440  裸机实验  使用中断 手机看文章 扫描二维码
随时随地手机看文章

一、前言

中断是打断当前程序执行,快速响应突发事件的一种机制。中断的触发源有很多种,比如外部引脚电平变化以及外设的各种事件中断等等,当中断发生时,S3C2440 CPU的PC指针跳往固定的中断向量地址处,执行中断处理函数,之后再返回到原先的程序断点处继续执行程序。


二、实验目标

采用按键中断的方式,通过JZ2440开发板上的三个独立按键分别控制开发板上的三个LED的亮灭。


三、硬件连线

独立按键连线如下:

独立按键只用了三个,分别连接到了EINT0,EINT2,EINT11,即S3C2440的外部中断0,2和11。对应的真实物理引脚分别是GPF0,GPF2和GPG3。S3C2440的外部中断引脚不是随便选的,是定死了哪个引脚能用哪个外部中断的。这点上就比不上STM32这类单片机了,STM32是任意普通引脚都可以做外部中断的。而且STM32支持引脚功能的重映射,就是一个引脚上的各种功能可以映射到其他引脚上用,S3C2440貌似没看到有这个功能。又想了想,毕竟S3C2440是定位于跑操作系统的,和单片机的定位着重点不同,术业有专攻。


LED连线如下:

三个LED分别连接在GPF4,GPF5和GPF6上。


四、S3C2440中断体系

1、工作模式


ARM体系的CPU有以下7中工作模式:


(1)用户模式(usr):ARM处理器正常的程序执行状态。


(2)快速中断模式(fiq):用于高速数据传输或通道处理。


(3)中断模式(irq):用于通用的中断处理。


(4)管理模式(svc):操作系统使用的保护模式。


(5)数据访问终止模式(abt):当数据或指令预取终止时进入该模式,可用于虚拟存储即存储保护。


(6)系统模式(sys):运行具有特权的操作系统任务。


(7)未定义指令终止模式(und):当未定义的指令执行时进入该模式,可用于支持硬件协处理器的软件仿真。


以上的模式可通过软件来进行切换,发生各类中断的时候CPU也会自动进入相应的模式。除用户模式外,其他6种工作模式都属于特权模式。大多数程序运行于用户模式,进入特权模式是为了处理中断、异常、或者访问被保护的系统资源。

在S3C2440中,这些不同的模式都有一组寄存器(r0到r15,CPSR和SPSR)与各自模式相对应,这些寄存器有些是共用的,有些是某个模式下独有的(如上图带三角阴影的寄存器),虽然寄存器名字都一样,但只是该模式下使用。这些寄存器除r15外都是通用寄存器,其中r13到r15这3个寄存器有特殊的意义,r13称为栈指针寄存器(SP),就是C语言用到的那个堆栈指针;r14称为程序连接寄存器(subroutime Link Register)或连接寄存器,当执行汇编指令BL进行子程序跳转的时候,r14中会得到r15(程序计数器PC)的备份,当子程序返回的时候,r14(lr寄存器)的值会赋给r15(PC指针),这就使得程序能够回到断点位置继续向下执行了。


每个模式都有独立的r13和r14寄存器,即每个模式都有独立的堆栈指针(SP)和连接寄存器(lr)。在不同模式间跳转的时候,需要将上一个模式的所有公用寄存器进行压栈操作,以便在之后可以再出栈恢复这些寄存器的值,达到模式恢复的效果。其中快中断模式fiq从r8到r15都是独立的,在进入该模式的时候需要保存的寄存器数目更少(r0到r7),所以进入该中断会更快。


还有第17个寄存器CPSR,即“当前程序状态寄存器”(Current Program Status Register)。里面保存了各种状态位。如下:

这里挑几个重点说明:


(1)I位和F位:中断禁止位和快中断禁止位,当这些位置位时,CPU不响应这些中断。


(2)T位:置位时CPU处于Thumb状态,运行Thumb指令集;否则为ARM状态,运行ARM指令集,不同指令集这里不详细分析,在JZ2440上做实验基本都是用ARM指令集。


(3)M0到M4:工作模式位,表示CPU处于什么工作模式,修改这些位,可以使CPU进入对应的工作模式。


还有一个寄存器叫SPSR寄存器(Saved Program Status Register),功能是保存前一个工作模式的CPSR值,这样当要返回一个工作模式时,可以将SPSR的值恢复到CPSR中。


2、中断响应流程

有两类中断请求源:


(1)“Request sources(without sub register)”中的中断源被触发之后,SRCPND(中断请求状态)寄存器中相应位被置1,如果INTMSK(中断屏蔽控制)寄存器未将相应中断屏蔽的话,判断该中断是否是快速中断,如果且快速中断模式是使能的,CPU响应快速中断;如果是普通的中断,PRIORITY(IRQ优先级控制)寄存器的相应位被置1表示产生了该中断,之后INTPND(中断请求状态)寄存器挑出PRIORITY寄存器中的优先级最高的中断进行响应,注意,PRIORITY中可能标记了很多的中断需要处理,但是INTPND一次只挑出一个优先级最高的进行处理,在一个中断没处理完的时候,不响应其他的中断,


(2)“Request sources(with sub register)”这个中断源和(1)的区别可以理解为(1)的中断源是那些大模块比如DMA、定时器,串口等等的某个模块的总的中断请求,而串口模块又存在了RX或者TX中断,这些中断称为中断次级源。该类中断源发生时SUBSRCPND的相应位置位,如果SUBMASK的对应位没有置位来屏蔽这个中断,那么会引发SRCPND的对应位置位,之后的处理流程和(1)中一样。


注意点:


(1)S3C2440的快速中断(fiq)可以打断普通中断(irq),反之不行,普通中断不可以打断普通中断,快速中断也不可以打断快速中断,快速中断(fiq)只能设置一个,即不存在中断嵌套。快速中断(fiq)不引起INTPND和INTOFFSET寄存器的变化,所以这两个寄存器只在IRQ中断中有效。


(2)SUBSRCPND、SRCPND、PRIORITY、INTPND中相应位被置位后,CPU响应了对应的中断过后并不会自动清除这些位,所以需要我们在程序中人为清除对应的位,清除的方法是往对应位写1清除,简单的写法是“INTPND = INTPND”不清除的话该次中断结束之后会立刻进入相同的中断。


(3)不论SUBMASK或者MASK寄存器的相应位有没有置位屏蔽,只要产生了对应的中断,中断请求状态寄存器中都会置位表示有这个中断产生了,上不上报是后续流程的事。


(4)fiq中断由于只能设置一个,一旦产生用户就必定知道是哪个中断源引发的。irq中断有很多个,可以通过读取INTPND寄存器或者INTOFFSET寄存器来确定中断源。


3、中断优先级

S3C2440的中断优先级设置是要遵循固定的模式的,并不像STM32那样可以随意设置。这里的中断优先级设置只是对IRQ中断而言的,FIQ中断不受这个规则限制。


中断优先级通过7个仲裁器完成(ARBITER0到ARBITER6),包括6个一级仲裁器(ARBITER0到ARBITER5)和1个二级仲裁器(ARBITER6),说白了就是二级仲裁器从6个一级仲裁器中挑一个优先级最高的中断报上去给CPU处理,其中REQ0和QEQ5的优先级顺序是固定的,一个最高,一个最低,REQ1到REQ4可以通过配置更改它们的内部优先级顺序,下面贴上一张PRIORITY寄存器的定义表来说明:

通过设置ARB_SELn可以设置REQ1到REQ4的内部顺序,通过设置ARB_MODEn可以设置是否需要自动更改排序,就是处理完该组的一次中断请求后,把对应ARB_SELn的值加1取余4,自动轮换一下优先级顺序。为什么要搞个这个功能呢?我猜应该是解决某些中断长期占用导致另外一些中断难以响应的问题,试想一下如果开始优先级是REQ1到REQ4,用户把这四个中断同等重要来看待,然后REQ1有个中断一直都有请求,REQ2这时也来了个中断请求,但是由于REQ1优先级更高霸占了中断请求的处理资源,然后REQ2就一直得不到响应了。


接下来还是要提一点,REQ0到REQ5的优先级顺序只有4种排列方式,个人感觉还是不太灵活,能像STM32那样自由配置就好了。


 


4、中断处理代码


在进入或者退出中断时需要保存和恢复程序的运行环境。示例代码如下:


(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,恢复之前的工作模式

 


五、代码编写

接下来是具体的实验代码,分为以下几个文件:


head.S:启动文件。


main.c:初始化及各种C函数。


Makefile:编译代码。


各个文件的具体内容如下:


head.S


@*************************************************************************

@ File:head.S

@*************************************************************************       

.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               @关WATCH DOG

 

    msr cpsr_c, #0xd2       @ 进入中断模式

    ldr sp, =3072           @ 设置中断模式栈指针

 

    msr cpsr_c, #0xd3       @ 进入管理模式

    ldr sp, =4096           @ 设置管理模式栈指针,

                            @ 其实复位之后,CPU就处于管理模式,

                            @ 前面的“ldr sp, =4096”完成同样的功能,此句可省略

 

    bl  init_led            @ 初始化LED的GPIO管脚

    bl  init_irq            @ 调用中断初始化函数

    msr cpsr_c, #0x53       @ 设置I-bit=0,开IRQ中断

 

    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            @ 调用中断服务函数

 

int_return:

    ldmia   sp!,    { r0-r12,pc }^  @ 中断返回, ^表示将spsr的值复制到cpsr

main.c


 

#define BYTE unsigned char

#define WORD unsigned short

#define DWORD unsigned int 

 

/* WOTCH DOG register */

#define REG_WTCON               (*(volatile unsigned long *)0x53000000)

 

 

/* GPIO Configure*/

#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 REG_EXTINT0 (*(volatile unsigned long *)0x56000088)

#define REG_EXTINT1 (*(volatile unsigned long *)0x5600008C)

 

/* interrupt Configure */

 

#define REG_EINTMASK (*(volatile unsigned long *)0x560000A4)

#define REG_INTMSK (*(volatile unsigned long *)0X4A000008)

#define REG_INTOFFSET (*(volatile unsigned long *)0x4A000014)

 

#define REG_EINTPEND (*(volatile unsigned long *)0x560000A8)

#define REG_SRCPND (*(volatile unsigned long *)0X4A000000)

#define REG_INTPND (*(volatile unsigned long *)0X4A000010)

 

// #define REG_INTSUBMSK (*(volatile unsigned long *)0x560000A8)

// #define REG_SUBSRCPND (*(volatile unsigned long *)0X4A000018)

 

void disable_watch_dog();

void init_led();

void init_irq();

void EINT_Handle();

 

/*上电后,WATCH DOG默认是开着的,要把它关掉 */

void disable_watch_dog()

{

REG_WTCON = 0;

}

 

void init_led()

{

GPFCON &= ~((DWORD)(3 << (2 * 4)) | (3 << (2 * 5)) | (3 << (2 * 6)));

GPFCON |= ((DWORD)(1 << (2 * 4)) | (1 << (2 * 5)) | (1 << (2 * 6))); //GPF4、GPF5、GPF6输出模式

 

GPFDAT |= (1 << 4) | (1 << 5) | (1 << 6);   //输出高电平,LED全灭

}

 

void init_irq()

{

//配置为外部中断模式

GPFCON &= ~((DWORD)(3 << (2 * 0)) | (3 << (2 * 2)));

GPFCON |= ((DWORD)(2 << (2 * 0)) | (2 << (2 * 2)));

 

GPGCON &= ~((DWORD)(3 << (2 * 3)));

GPGCON |= ((DWORD)(2 << (2 * 3)));

 

//上拉

GPFUP |=  (1 << 0) | (1 << 2);

GPGUP |= (1 << 3);

 

//设置下降沿触发

REG_EXTINT0 &= ~((DWORD)(7 << 0) | (7 << 8));

REG_EXTINT0 |= ((DWORD)(2 << 0) | (2 << 8));

 

REG_EXTINT1 &= ~((DWORD)(7 << 12));

REG_EXTINT1 |= ((DWORD)(2 << 12));

 

//使能EINT11中断

REG_EINTMASK &= ~((DWORD)1<<11);

 

//使能EINT0、EINT2、EINT11中断

REG_INTMSK &= ~((DWORD)(1 << 0) | (1 << 2) |  (1 << 5));

}

 

void EINT_Handle()

{

BYTE bIntOffset = REG_INTOFFSET;

 

switch(bIntOffset)

{

case 0:

GPFDAT ^= ((DWORD)1 << 4); //电平翻转

[1] [2]
关键字:JZ2440  裸机实验  使用中断 引用地址:【JZ2440笔记】裸机实验使用中断

上一篇:S3C2440裸机实验之timer(定时器)
下一篇:ARM中断基础知识

推荐阅读

1、业界|协作机器人:Universal Robots机器人在纽约证券交易所敲响闭市钟声Universal Robots公司的协作机器人在纽约证券交易所敲响闭市钟声,响起的钟声特别纪念第一个机器人和工业自动化指数ROBOGlobal五周年。根据国际机器人联合会的数据,机器人可以在工厂地板和工业生产线上安全地在笼子外安全操作,预计到2025年将占所有工业机器人销售的34%。环球...
本文主要讨论天线串扰损害、相位噪声和定时误差对MIMO下行链路系统性能的影响,以及采用了时间相干多通道示波器和89600矢量信号分析仪(VSA)软件的故障诊断技术,希望能够帮助工程师深入了解误差机制对硬件误差矢量幅度(EVM)性能和系统级射频发射机性能的影响。本文将以LTE作为研究对象,其概念也可应用到其他信号格式中,例如 Mobile WiMAX。  LTE MIM...
IT之家 10 月 16 日消息 10月14日,华为消费者业务手机产品线总裁何刚公布了 Mate 40 系列全球发布会的最新海报,展示了 Mate40 系列的更多细节。海报中,新机的多边形轮廓鲜明,红色的电源键十分惹眼。现在 Twitter 用户 Teme (特米)曝光了一款搭载后置六摄镜头的华为手机,预计就是这款预热海报中的相机模组真正的样子。六个摄像头疑似组...
广告摘要声明广告FlexBuffer™ABB全新推出FlexBuffer™应用单元,为传统的自动化存储和检索系统提供附加功能,旨在应对消费者对多样选择和快速交付日益增长的需求。机器人为该系统的核心部分,从而使该系统成为可靠且维护成本低的解决方案。FlexBuffer™为物流、食品和饮料、医疗保健、消费性包装品、餐厅和零售商带来了更高的柔性,提供了适应能力强、具...

史海拾趣

问答坊 | AI 解惑

继电器的应用

我现在用的是固态继电器,需要用单片机控制继电器驱动交流电机 ,哪里有单片机控制继电器的电路图啊,请帮帮忙吧,谢谢了…

查看全部问答∨

《FPGA三国志》(二)CPLD的时代

我在12年前,偶然接触PLD,没有想到自己居然就在这个行当里安身下来。可是这个行业也的确是个飞速发展的行业,十多年过去后,从当初的接近十家主要供应商,到今天已经激烈搏杀后,只有差不多如论坛题目一样的,成为了今天三足鼎立的局面。想来想去, ...…

查看全部问答∨

求助:关于微带线,共面线和带状线等传输线的工作原理

各位大侠们,麻烦介绍一下,微带线,共面线和带状线等几种传输线的工作原理呀,最好详细一点..谢谢了先…

查看全部问答∨

一些公司IC设计方向面试题

一些公司IC设计方向面试题1、我们公司的产品是集成电路,请描述一下你对集成电路的认识,列举一些与集成电路 相关的内容(如讲清楚模拟、数字、双极型、CMOS、MCU、RISC、CISC、DSP、ASIC、FPGA 等的概念)。(仕兰微面试题目) 2、FPGA和ASIC的 ...…

查看全部问答∨

regedit.exe程序为什么不能运行?

在CE下运行regedit.exe失败,提示找不到REGEDTI或某一个组件?regedit还依赖其他的什么库文件吗?…

查看全部问答∨

WinCE上如何获得指定进程当前所用的内存是多少?

WinCE上如何获得指定进程当前所用的内存是多少? 有没有什么函数可以直接获得某个已知进程当前所用内存?谢谢…

查看全部问答∨

计算机认出USB虚拟串口设备了,但驱动安装不上?

                                 将自作的USB虚拟串口设备插入计算机后,计算机提示安装设备驱动,找到STM32 Virtual COM Port,但我刚在ST网站上下 ...…

查看全部问答∨

关于将外部正弦信号导入音频MIC接口的问题

从信号发生器输出的一个正弦信号,通过什么方法能将其导入MIC接口,作为输入信号,将信号在ARM6410上编写的一个android的模拟示波器上显示出来。求知道的大侠们帮我一下 &nbsp;感激不尽!!…

查看全部问答∨

请问哪位大神有keil c51的语法文件吗?

最近学习单片机编译器,但是却一直未能找到完整的c51的grammar file 。求大神分享!!(flex&bison描述的最好)预先谢谢大家啦…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved