当前位置:首页 > 单片机 > 单片机
[导读] 实验的目的:当TQ2440开发板的按键按下的时候,触发中断,点亮LED灯。实验的源程序:/**************************************************************************************s3c24xx.h************

实验的目的:
当TQ2440开发板的按键按下的时候,触发中断,点亮LED灯。


实验的源程序:
/*************************************************************************************
*s3c24xx.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)



@******************************************************************************
@ 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 @ 进入中断模式
ldr sp, =3072 @ 设置中断模式栈指针


msr cpsr_c, #0xd3 @ 进入管理模式
ldr sp, =4096 @ 设置管理模式栈指针,
@ 其实复位之后,CPU就处于管理模式,
@ 前面的“ldr sp, =4096”完成同样的功能,此句可省略


bl init_led @ 初始化LED的GPIO管脚
bl init_irq @ 调用中断初始化函数,在init.c中
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 @ 调用中断服务函数,在interrupt.c中
int_return:
ldmia sp!, { r0-r12,pc }^ @ 中断返回, ^表示将spsr的值复制到cpsr

======================================================

注:ARM9的异常向量表:


======================================================

/**************************************************************************************************
*%20init.c:%20进行一些初始化
*************************************************************************************************/


#include%20"s3c24xx.h"


/*
*%20LED1,LED2,LED4对应GPB5、GPB6、GPB7、GPB8
*/
#define%20GPB5_out%20(1<<(5*2))
#define%20GPB6_out%20(1<<(6*2))
#define%20GPB7_out%20(1<<(7*2))
#define%20GPB8_out%20(1<<(8*2))


#define%20GPB5_msk%20(3<<(5*2))
#define%20GPB6_msk%20(3<<(6*2))
#define%20GPB7_msk%20(3<<(7*2))
#define%20GPB8_msk%20(3<<(8*2))


/*
*%20K1,K2,K3,K4对应GPF1、GPF4、GPF2、GPF0
*/
#define%20GPF0_int%20%20%20(0x2<<(0*2))
#define%20GPF1_int%20%20%20(0x2<<(1*2))
#define%20GPF2_int%20%20%20(0x2<<(2*2))
#define%20GPF4_int%20%20%20(0x2<<(4*2))


#define%20GPF0_msk%20%20(3<<(0*2))
#define%20GPF1_msk%20%20(3<<(1*2))
#define%20GPF2_msk%20%20(3<<(2*2))
#define%20GPF4_msk%20%20(3<<(4*2))


/*
*%20关闭WATCHDOG,否则CPU会不断重启
*/
void%20disable_watch_dog(void)
{
%20%20WTCON%20=%200;%20//%20关闭WATCHDOG很简单,往这个寄存器写0即可
}


void%20init_led(void)
{
//%20LED1,LED2,LED3,LED4对应的4根引脚设为输出
GPBCON%20&=%20~(GPB5_msk%20"%20GPB6_msk%20|%20GPB7_msk%20|%20GPB8_msk);
GPBCON%20|=%20GPB5_out%20|%20GPB6_out%20|%20GPB7_out%20|%20GPB8_out;
}


/*
*%20初始化GPIO引脚为外部中断
*%20GPIO引脚用作外部中断时,默认为低电平触发、IRQ方式(不用设置INTMOD)
*/
void%20init_irq(%20)
{
//%20K1,K2,K3,K4对应的4根引脚设为中断功能
GPFCON%20&=%20~(GPF0_msk%20|%20GPF1_msk%20|%20GPF2_msk%20|%20GPF4_msk);
GPFCON%20|=%20GPF0_int%20|%20GPF1_int%20|%20GPF2_int%20|%20GPF4_int;


%20%20//%20对于EINT4,需要在EINTMASK寄存器中使能它
%20%20EINTMASK%20&=%20~(1<<4);
%20%20%20%20%20
%20%20/*
%20%20*%20设定优先级:
%20%20*%20ARB_SEL0%20=%2000b,%20ARB_MODE0%20=%200:%20REQ1%20>%20REQ2%20>%20REQ3,即EINT0%20>%20EINT1%20>%20EINT2
%20%20*%20仲裁器1、6无需设置
%20%20*%20最终:
%20%20*%20EINT0%20>%20EINT1>%20EINT2%20>%20EINT4%20即K4%20>%20K1%20>%20K3%20>%20K2
%20%20*/
%20%20PRIORITY%20=%20(PRIORITY%20&%20((~0x01)%20|%20~(0x3<<7)));


%20%20//%20EINT0、EINT1、EINT2、EINT4_7使能
%20%20INTMSK%20%20&=%20(~(1<<0))%20&%20(~(1<<1))%20&%20(~(1<<2))%20&%20(~(1<<4));
}



/*******************************************************************************************
*interrupt.c
*******************************************************************************************/
#include%20"s3c24xx.h"


void%20EINT_Handle()
{
%20%20unsigned%20long%20oft%20=%20INTOFFSET;
%20%20unsigned%20long%20val;


/*
*%20K1,K2,K3,K4对应GPF1、GPF4、GPF2、GPF0
*%20%20%20%20%20%20即%20EINT1,%20ETIN4,%20EINT2,%20EINT0
*%20%20%20%20%20%20oft为%201,%204,%202,%200%20(对应INTMSK寄存器)
*/
%20
%20%20switch(%20oft%20)
%20%20{
%20%20%20%20//%20K1被按下
%20%20%20%20case%201:
%20%20%20%20{%20
%20%20%20%20%20%20GPBDAT%20|=%20(0xF<<5);%20%20//%20所有LED熄灭
%20%20%20%20%20%20GPBDAT%20&=%20~(1<<5);%20%20%20//%20LED1点亮
%20%20%20%20%20%20break;
%20%20%20%20}
%20%20%20
%20%20%20%20//%20K2被按下
%20%20%20%20case%204:
%20%20%20%20{%20
%20%20%20%20%20%20GPBDAT%20|=%20(0xF<<5);%20%20//%20所有LED熄灭
%20%20%20%20%20%20GPBDAT%20&=%20~(1<<6);%20%20%20//%20LED2点亮
%20%20%20%20%20%20break;
%20%20%20%20}


%20%20%20%20//%20K3被按下
%20%20%20%20case%202:
%20%20%20%20{%20
%20%20%20%20%20%20GPBDAT%20|=%20(0xF<<5);%20%20//%20所有LED熄灭
%20%20%20%20%20%20GPBDAT%20&=%20~(1<<7);%20%20%20//%20LED3点亮
%20%20%20%20%20%20break;
%20%20%20%20}


%20%20%20%20//%20K4被按下
%20%20%20%20case%200:
%20%20%20%20{%20
%20%20%20%20%20%20GPBDAT%20|=%20(0xF<<5);%20%20//%20所有LED熄灭
%20%20%20%20%20%20GPBDAT%20&=%20~(1<<8);%20%20%20//%20LED4点亮
%20%20%20%20%20%20break;
%20%20%20%20}


%20%20%20%20default:
%20%20%20%20%20%20break;
%20%20}


%20%20//清中断
%20%20if(%20oft%20==%204%20)
%20%20%20%20EINTPEND%20=%20(1<<4);%20%20//%20EINT4_7合用IRQ4
%20%20SRCPND%20=%201<%20%20INTPND%20=%201<}



/*****************************************************************************
*main.c
*****************************************************************************/
int%20main()
{
%20%20while(1);
%20%20return%200;
}


/************************************************************************************
*Makefile
************************************************************************************/

objs%20:=%20head.o%20init.o%20interrupt.o%20main.o

int.bin:%20$(objs)
arm-linux-ld%20-Ttext%200x00000000%20-o%20int_elf%20$^
arm-linux-objcopy%20-O%20binary%20-S%20int_elf%20$@
arm-linux-objdump%20-D%20-m%20arm%20int_elf%20>%20int.dis

%.o:%.c
arm-linux-gcc%20-Wall%20-O2%20-c%20-o%20$@%20$<


%.o:%.S
arm-linux-gcc%20-Wall%20-O2%20-c%20-o%20$@%20$<


clean:
rm%20-f%20int.bin%20int_elf%20int.dis%20*.o



实验的问题总结:
I.刚开始程序会执行head.S文件,第一条指令是b%20reset指令。在reset中,我们可以知道:
设置了reset模式下的栈,因为我们之后需要调用C语言函数,而C语言函数的局部变量是需要栈来保存的。
然后我们可以看到,执行了这样一条指令:msr%20cpsr_c,%20#0xd2
其原因可以看一下解释:

/***************************MRS%20和%20MSR*********************************
%20%20MRS%20R0,%20CPSR%20%20%20%20%20%20%20%20读取CPSR的内容写入R0
%20%20MSR%20CPSR,%20R0%20%20%20%20%20%20%20%20读取R0的内容写入CPSR
%20%20MSR%20CPSR_f,%20R0%20%20%20%20%20%20%20读取R0的24-31的内容写入CPSR的24-31bit
%20%20MSR%20CPSR_c,%20R0%20%20%20%20%20%20%20读取R0的0-7的内容写入CPSR的0-7bit
%20%20MSR%20CPSR_fc,%20R0%20
%20%20MSR%20CPSR_f,%20#0xf0000000%20%20将0xf写入CPSR的24-31bit
%20%20所有的CPSR可以替换成SPSR
***************************MRS%20和%20MSR*********************************/

/****************************CPSR***********************************
CPSR格式如下所示。SPSR和CPSR格式相同。
31%20%20%2030%20%20%2029%20%2028%20%20%2027%20%20%2026%20%20%20%20%20%20%20%207%20%20%206%20%20%205%20%20%204%20%20%203%20%20%202%20%20%201%20%20%200
N%20%20%20Z%20%20%20C%20%20%20V%20%20%20Q%20%20%20DNM(RAZ)%20%20%20%20%20I%20%20%20F%20%20%20T%20%20%20M4%20%20M3%20%20M2%20%20M1%20%20M0


***条件标志位***
N——本位设置成当前指令运算结果的bit[31]的值。当两个表示的有符号整数运算时,n=1表示运算结果为负数,n=0表示结果为正书或零。
Z——z=1表示运算的结果为零;z=0表示运算的结果不为零。对于CMP指令,Z=1表示进行比较的两个数大小相等。
C——下面分四种情况讨论C的设置方法:
在加法指令中(包括比较指令CMP),当结果产生了进位,则C=1,表示无符号运算发生上溢出;其他情况C=0。
在减法指令中(包括减法指令CMP),当运算中发生错位,则C=0,表示无符号运算数发生下溢出;其他情况下C=1。
对于包含移位操作的非加减运算指令,C中包含最后一次溢出的的位的数值。对于其他非加减运算指令,C位的值通常不受影响。
V——对于加减运算指令,当操作数和运算结果为二进制的补码表示的带符号数时,V=1表示符号为溢出;通常其他指令不影响V位。
***Q标识位***
在ARM%20V5的E系列处理器中,CPSR的bit[27]称为q标识位,主要用于指示增强的dsp指令是否发生了溢出。同样的spsr的bit[27]位也称为q标识位,用于在异常中断发生时保存和恢复CPSR中的Q标识位。
在ARM%20V5以前的版本及ARM%20V5的非E系列的处理器中,Q标识位没有被定义。
***CPSR中的控制位***
CPSR的低八位I、F、T、M[4:0]统称为控制位。当异常中断发生时这些位发生变化。在特权级的处理器模式下,软件可以修改这些控制位。
**中断禁止位I,F:当I=1时禁止IRQ中断,当F=1时禁止FIQ中断
**T控制位:T控制位用于控制指令执行的状态,即说明本指令是ARM指令还是Thumb指令。对于ARM%20V4以更高版本的T系列ARM处理器,T控制位含义如下:
T=0表示执行ARM指令
T=1表示执行Thumb指令
对于ARM%20V5以及更高版本的非T系列处理器,T控制位的含义如下
T=0表示执行ARM指令
T=1表示强制下一条执行的指令产生未定指令中断
***M控制位***
M控制位控制处理器模式,具体含义如下:
M[4:0]%20处理器模式%20%20可访问的寄存器
ob10000%20user%20%20%20pc,r14~r0,CPSR
0b10001%20FIQ%20%20%20PC,R14_FIQ-R8_FIQ,R7~R0,CPSR,SPSR_FIQ
0b10010%20IRQ%20%20%20PC,R14_IRQ-R13_IRQ,R12~R0,CPSR,SPSR_IRQ
0B10011%20SUPERVISOR%20%20PC,R14_SVC-R13_SVC,R12~R0,CPSR,SPSR_SVC
0b10111%20ABORT%20%20%20PC,R14_ABT-R13_ABT,R12~R0,CPSR,SPSR_ABT
0b11011%20UNDEFINEED%20%20PC,R14_UND-R8_UND,R12~R0,CPSR,SPSR_UND
0b11111%20SYSTEM%20%20%20PC,R14-R0,CPSR(ARM%20V4以及更高版本)
*****************************CPSR*************************************/
看完这两点,你就知道为什么要设置的值为#0xd2。接下来是设置中断模式下的栈指针。同上,因为每种模式下的栈寄存器是不共用的。


II.接下来,我们重点看一下ldr%20lr,%20=halt_loop%20这条指令,为什么在调用main函数之前需要设置lr寄存器呢?不设置难道不可以么?
具体解释如下:
在跳转的时候,PC的值会赋给lr寄存器。
在汇编调用C语言的时候,不一定非得配置lr寄存器,这要看你调用完C语言后想再往下执行哪条指令,
若接下来执行的指令刚好是C语言完了之后的这条指令,那么这种情况下可以不用设置,因为CPU会自动将lr%20=%20lr%20-%204,
也就是接下来该执行的一条指令,若你想再调用C语言之后,是跳转到某处的一标号,此时需要设置lr。

III.接下来,若发生中断的时候,CPU会自动让PC跳转到HandleIRQ%20去执行对应的指令。
然后,我们可以看到:sub%20lr,%20lr,%20#4
为什么要将lr的值减4呢?具体解释如下:


/***************************************************************************
我们知道在ARM 架构里,PC值指向当前执行指令的地址加8处,也就是说, 当执行指令A(地址0x8000)时,PC 等于指令C 的地址(0x8008)。
假如指令A 是“BL”指令,则当执行该指令时,会把PC(=0x8008)保存到LR 寄存器里面,但是接下去处理器会马上对LR 进行一个自动的调整动作:
LR=LR-0x4。这样,最终保存在 LR 里面的是 B 指令的地址,所以当从 BL 返回时,LR 里面正好是正确的返回地址。同样的调整机制在所有LR
自动保存操作中都存在,比如进入中断响应时,处理器所做的LR 保存中,也进行了一次自动调整,并且调整动作都是LR=LR-0x4。


下面,我们对不同类型的异常的返回地址依次进行说明:
假设在指令A 处(地址0x8000)发生了异常,进入异常响应后,LR 上经过调整保存的地址值应该是B 的地址0x8004。
1、 如果发生的是软件中断,即A 是“SWI”指令
异常是由指令本身引起的,从 SWI 中断返回后下一条执行指令就是B,正好是LR 寄存器保存的地址, 所以只要直接把LR 恢复给PC。
MOVS pc, lr
2、 发生的是Undefined instruction异常
异常是由指令本身引起的,从异常返回后下一条执行指令就是B,正好是LR 寄存器保存的地址, 所以只要直接把LR 恢复给PC。
MOVS pc, lr
3、 发生的是IRQ或FIQ中断
因为指令不可能被中断打断,所以A指令执行完以后才能响应中断,此时PC已更新,指向指令D的地址(地址0x800C),
LR 上经过调整保存的地址值是C 的地址0x8008。中断返回后应该执行B指令,所以返回操作是:
SUBS pc, lr, #4
4、 发生的是Prefetch Abort异常
该异常并不是处理器试图从一个非法地址取指令时触发,取出的指令只是被标记为非法,按正常处理流程放在流水线上,
在执行阶段触发Prefetch Abort异常,此时LR 上经过调整保存的地址值是B 的地址0x8004。异常返回应该返回到A指令,
尝试重新取指令,所以返回操作是:
SUBS pc, lr, #4
5、 发生的是“Data Abort”
CPU访问存储器时触发该异常,此时PC指向指令D的地址(地址0x800C),LR 上经过调整保存的地址值是C 的地址0x8008。
异常返回后,应回到指令A,尝试重新操作存储器,所以返回操作是:
SUBS pc, lr, #8
****************************************************************************/
这就是为什么我们需要将lr的值减4,具体可以参考我转载的博客。

IV.然后我们可以看得这样一条指令:stmdb sp!, { r0-r12,lr },它是和ldmia sp!, { r0-r12,pc }^ 指令对应起来的。
在跳转到中断服务程序之前,先保存用到的寄存器,在完成中断服务程序之后,又恢复寄存器。其中,lr和pc是对应起来的。
也就是说,恢复寄存器后,pc中保存的值是lr寄存器中的。所以当执行完这条指令之后,就又跳回来了。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

本文中,小编将对车联网予以介绍,如果你想对它的详细情况有所认识,或者想要增进对它的了解程度,不妨请看以下内容哦。

关键字: 车联网 智能交通 体系结构

在下述的内容中,小编将会对智慧物流的相关消息予以报道,如果智慧物流是您想要了解的焦点之一,不妨和小编共同阅读这篇文章哦。

关键字: 智慧物流 体系结构 物流

在这篇文章中,小编将为大家带来智能机器人的相关报道。如果你对本文即将要讲解的内容存在一定兴趣,不妨继续往下阅读哦。

关键字: 智能机器人 机器人 体系结构

摘 要 :针对目前工业大数据体系结构不完善、尚未形成标准统一的理论架构的问题,文中就如何将大数据技术与工业生产场景进行整合,如何建设工业大数据系统等问题展开了讨论。文中阐述了工业大数据的特点与基本体系结构,对相关技术处理...

关键字: 工业大数据 体系结构 处理体系 计算引擎 理论架构 计算分析

摘 要 :文中首先阐述了物联网的起源、概念及其体系结构,接着对物联网中的关键技术进行了介绍,最后列举了物联网技术在日常生活中的应用,让大家对物联网能有更深层次的理解与认识。

关键字: 物联网 体系结构 RFID 应用

摘要:车联网作为物联网技术的重要应用之一,具有十分广阔的应用前景。文章通辻介绍基于位置的车联网通用应用平台概念,分析了车联网通用应用平台的技术构架,并列举了该平台在几个重点领域的典型应用,给出了该平台所具有的通用性与相对...

关键字: 车联网 物联网 体系结构 典型应用

摘 要:随着基于物联网的智能家居系统的出现,人们对物联网的关注逐渐从概念发展到了技术应用。文中从物联网系统的三层体系结构出发,对智能家居系统加以分析,不仅理清了物联网与智能家居系统的关系,而且明确了智能家居系统的体系结构...

关键字: 物联网 智能家居 体系结构 技术路线

摘要:物联网的三层体系结构感知层、传输层和应用层与安防系统的数据采集、传输、应用三个主要部分有诸多相似之处,这种相似为公安院校安全技术防范课程教学实践提供了一个崭新的思路。文中对物联网的基本概念、数据感知、数据传输以及数...

关键字: 物联网 安全技术防范 教学实践 体系结构

摘要:物联网应用的多样性、分散性和缺乏管理等问题制约着物联网的发展。物联网要连接和管理的对象是包括静止和移动的末端设备及各种资产,这些设备连接上传感器等感知设备成为网络中的节点。基于物联网这种网络特点,利用通用网管的思想...

关键字: 物联网 体系结构 网络管理 综合信息管理平台

摘 要:文章对局域网可能受到的安全威胁进行了分析,并针对这些可能受到的威胁设计了一个包含物理安全、网络安全、系统安全、应用安全和数据安全的局域网安全模型,从技术上保证局域网的安全,同时还设计了安全的网络结构并辅以安全管理...

关键字: 局域网 安全 体系结构 管理制度
关闭
关闭