ARM指令系统

2020年06月10日 阅读数:149
这篇文章主要向大家介绍ARM指令系统,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

3 ARM指令系统

3.1  ARM处理器的指令格式

3.1.1  ARM指令集的特色

3 ARM指令系统

3 ARM指令系统

3.1  ARM处理器的指令格式

3.1.1  ARM指令集的特色

ARM内核属于RISC结构,因此其指令集有着一些独特的特色:指令长度固定,指令格式的种类少,寻址方式简单。因为ARM处理器采用固定长度的32位指令,所以处理器内部硬件设计可以被简化。ARM处理器内部的指令译码采用硬布线逻辑,不使用微程序控制,以减小指令的译码时间,大部分指令能够在一个时钟周期内完成。程序员

ARM处理器的指令按功能可分为七大类:加载/存储指令、数据处理指令、乘法指令、跳转指令、程序状态寄存器处理指令、协处理器指令和异常中断指令。算法

须要特别指出的是,ARM处理器的指令集是加载/存储型的,也即指令集仅能处理寄存器中的数据,并且处理结果都要放回寄存器中,而对系统存储器的访问则须要经过专门的加载/存储指令来完成。编程

按照操做数的特色分,ARM指令能够分为无操做数指令、单操做数指令、双操做数指令和三操做数指令。每条指令都由操做码域、条件码域、条件码设置域、目标操做数、第一操做数寄存器和第二操做数组成。数组

3.1.2  ARM指令的格式

每条ARM指令都是32位的,其格式以下:安全

31   28  27     25 24      21 20  19         16 15        12  11          0 数据结构

条件码app

类别码异步

操做码函数

S工具

目的寄存器

第一操做数

第二操做数

ARM指令助记符表示为:

<opcode> {<cond>} {S} <Rd>, <Rn>, <shift_op2>

每一个域的含义以下:

1) <opcode>:操做码域,指令编码的助记符;

2) {<cond>}:条件码域,指令容许执行的条件编码。花括号表示此项可缺省。

ARM指令的一个重要特色是能够条件执行,每条ARM指令的条件码域包含4位条件码,共16种。几乎全部指令均根据CPSR中条件码的状态和指令条件码域的设置有条件的执行。当指令执行条件知足时,指令被执行,不然被忽略。指令条件码及其助记符后缀表示参见表3.1。

每种条件码可用两个字符表示,这两个字符能够做为后缀添加在指令助记符的后面和指令同时使用。例如,跳转指令B能够加上后缀EQ变为BEQ,表示“相等则跳转”,即当CPSR中的Z标志置位时发生跳转。

3.1 指令的条件码

条件码

助记符后缀

标 志

含 义

0000

EQ

Z置位

相等

0001

NE

Z清零

不相等

0010

CS

C置位

无符号数大于或等于

0011

CC

C清零

无符号数小于

0100

MI

N置位

负数

0101

PL

N清零

正数或零

0110

VS

V置位

溢出

0111

VC

V清零

未溢出

1000

HI

C置位Z清零

无符号数大于

1001

LS

C清零Z置位

无符号数小于或等于

1010

GE

N等于V

带符号数大于或等于

1011

LT

N不等于V

带符号数小于

1100

GT

Z清零且(N等于V

带符号数大于

1101

LE

Z置位或(N不等于V

带符号数小于或等于

1110

AL

忽略

无条件执行

3) {S}:条件码设置域。这是一个可选项,当在指令中设置{S}域时,指令执行的结果将会影响程序状态寄存器CPSR中相应的状态标志。

例如:

ADD R0R1R2 R1R2的和存放到R0寄存器中,不影响状态寄存器

ADDS R0R1R2 执行加法的同时影响状态寄存器

指令中比较特殊的是CMP指令,它不须要加S后缀就默认地根据计算结构更改程序状态寄存器。

4) <Rd>:目的操做数。ARM指令中的目的操做数老是一个寄存器。若是<Rd>与第一操做数寄存器<Rn>相同,也必需要指明,不能缺省。

5) <Rn>:第一操做数。ARM指令中的第一操做数也必须是个寄存器。

6) <shift_op2>:第二操做数。在第二操做数中能够是寄存器、内存存储单元或者当即数。

因为第二操做数只有12bit,用第二操做数表示当即数时,其取值范围为0~212-1,要表示超出这个范围的当即数,一般要依靠伪指令实现。

3.2  ARM指令的寻址方式

所谓寻址方式就是处理器根据指令中给出的地址信息来寻找物理地址的方式。目前ARM指令系统支持以下几种常见的寻址方式。

3.2.1  当即寻址

当即寻址也叫当即数寻址,这是一种特殊的寻址方式,操做数自己就在指令中给出,只要取出指令也就取到了操做数。这个操做数被称为当即数,对应的寻址方式也就叫作当即寻址。例如如下指令:

ADD R0R0,#1 R0R01

ADD R0R0,#0x3f R0R00x3f

在以上两条指令中,第二操做数即为当即数,要求以“#”为前缀,对于以十六进制表示的当即数,还要求在“#”后加上“0x”,以二进制表示的当即数,要求在“#”后加上“%”。

当当即数大于第二操做数的表示范围时,一般用如下伪指令实现:

LDR R0,=#0xffff0000

3.2.2  寄存器寻址

寄存器寻址就是利用寄存器中的数值做为操做数,这种寻址方式是各种微处理器常常采用的一种方式,也是一种执行效率较高的寻址方式。如下指令:

ADD R0R1R2 R0R1R2

该指令的执行效果是将寄存器R1R2的内容相加,其结果存放在寄存器R0中。

3.2.3  寄存器间接寻址

寄存器间接寻址就是以寄存器中的值做为操做数的地址,而操做数自己存放在存储器中。例如如下指令:

ADD R0R1[R2] R0R1[R2]

LDR R0[R1] R0[R1]

STR R0[R1] [R1]R0

在第一条指令中,以寄存器R2的值做为操做数的地址,在存储器中取得一个操做数后与R1相加,结果存入寄存器R0中。

第二条指令将以R1的值为地址的存储器中的数据传送到R0中。

第三条指令将R0的值传送到以R1的值为地址的存储器中。

3.2.4  基址变址寻址

基址变址寻址就是将寄存器(该寄存器通常称做基址寄存器)的内容与指令中给出的地址偏移量相加,从而获得一个操做数的有效地址。变址寻址方式经常使用于访问某基地址附近的地址单元。采用变址寻址方式的指令常见有如下几种形式,以下所示:

LDR R0[R1,#4] R0[R14]

LDR R0[R1,#4] R0[R14]R1R14

LDR R0[R1] ,#4 R0[R1]R1R14

LDR R0[R1R2] R0[R1R2]

在第一条指令中,将寄存器R1的内容加上4造成操做数的有效地址,从而取得操做数存入寄存器R0中。

在第二条指令中,将寄存器R1的内容加上4造成操做数的有效地址,从而取得操做数存入寄存器R0中,而后,R1的内容自增4个字节。

在第三条指令中,以寄存器R1的内容做为操做数的有效地址,从而取得操做数存入寄存器R0中,而后,R1的内容自增4个字节。

在第四条指令中,将寄存器R1的内容加上寄存器R2的内容造成操做数的有效地址,从而取得操做数存入寄存器R0中。

3.2.5  多寄存器寻址

多寄存器寻址是ARM处理器特有的一种寻址方式。因为ARM内核有较多的通用寄存器,采用多寄存器寻址方式,一条指令能够一次完成多个寄存器值的传送。这种寻址方式能够用一条指令完成传送最多16个通用寄存器的值。例如如下指令:

LDMIA R0{R1R2R3R4} R1[R0]

R2[R04]

R3[R08]

R4[R012]

该指令的后缀IA表示在每次执行完加载/存储操做后,R0按字长度增长,所以,指令可将连续存储单元的值传送到R1R4

多个连续的寄存器能够用-”符号链接;不连续的寄存器用“,”分隔书写,如上例可写成:

LDMIA R0{R1-R4}

LDMIA R0{R1-R3R4}

3.2.6  寄存器移位寻址

寄存器移位寻址是ARM指令集特有的寻址方式。ARM处理器内嵌桶型移位器(Barrel Shifter),支持数据的各类移位操做。当第二操做数为寄存器时,能够加入移位操做选项对它进行各类移位操做。

移位操做包括以下6种类型:

一、LSL(或ASL)逻辑(算术)左移

寻址格式:

通用寄存器,LSL(或ASL) 操做数      

完成对通用寄存器中的内容进行逻辑(或算术)的左移操做,按操做数所指定的数量向移位低位用零来填充。其中,操做数能够是通用寄存器,也能够是当即数(031)。

如:

   MOV    R0, R1, LSL#2 ;将R1中的内容左移两位后传送到R0中。

二、LSR逻辑右移

寻址格式:

通用寄存器,LSR 操做数      

完成对通用寄存器中的内容进行右移的操做,按操做数所指定的数量向移位,左端用零来填充。其中,操做数能够是通用寄存器,也能够是当即数(031)。

如:

   MOV    R0, R1, LSR#2 ;将R1中的内容右移两位后传送到R0中,左端用零来填充

三、ASR算术右移

寻址格式:

通用寄存器,ASR 操做数      

完成对通用寄存器中的内容进行右移的操做,按操做数所指定的数量向移位,左端31位的值来填充。其中,操做数能够是通用寄存器,也能够是当即数(031)。

如:

   MOV    R0, R1, ASR#2 ;将R1中的内容右移两位后传送到R0中,左端31位的值来填充

四、ROR循环右移

寻址格式:

通用寄存器,ROR 操做数      

完成对通用寄存器中的内容进行循环右移的操做,按操做数所指定的数量向右循环移位,左端右端移出的位来填充。其中,操做数能够是通用寄存器,也能够是当即数(031)。显然,当进行32位的循环右移操做时,通用寄存器中的值不改变。

如:

   MOV    R0, R1, ROR#2 ;将R1中的内容循环右移两位后传送到R0中。

五、RRX带扩展的循环右移

寻址格式:

通用寄存器,RRX 操做数      

完成对通用寄存器中的内容进行带扩展的循环右移的操做,按操做数所指定的数量向右循环移位,左端进位标志位C来填充。其中,操做数能够是通用寄存器,也能够是当即数(031)。

如:

   MOV    R0, R1, RRX#2 ;将R1中的内容进行带扩展的循环右移两位后传送到R0中。

3.2.7  相对寻址

与基址变址寻址方式相相似,相对寻址以程序计数器PC的当前值为基地址,指令中的地址标号做为偏移量,将二者相加以后获得操做数的有效地址。如下程序段完成子程序的调用和返回,跳转指令BL采用了相对寻址方式:

BL NEXT ;跳转到子程序NEXT处执行

……

NEXT

……

MOV PCLR ;从子程序返回

3.2.8  堆栈寻址

堆栈是一种数据结构,按先进后出(First In Last OutFILO)的方式工做,使用一个称做堆栈指针的专用寄存器指示当前的操做位置,堆栈指针老是指向栈顶。

当堆栈指针指向最后压入堆栈的数据时,称为满堆栈(Full Stack),而当堆栈指针指向下一个将要放入数据的空位置时,称为空堆栈(Empty Stack)。

同时,根据堆栈的生成方式,又能够分为递增堆栈(Ascending  Stack)和递减堆栈(Decending Stack)。当堆栈由低地址向高地址生成时,称为递增堆栈,当堆栈由高地址向低地址生成时,称为递减堆栈。这样就有四种类型的堆栈工做方式,ARM微处理器支持这四种类型的堆栈工做方式,即:

1. 满递增堆栈(FA):堆栈指针指向最后压入的数据,且由低地址向高地址生成。

2. 满递减堆栈(FD):堆栈指针指向最后压入的数据,且由高地址向低地址生成。

3. 空递增堆栈(EA):堆栈指针指向下一个将要放入数据的空位置,且由低地址向高地址生成。

4. 空递减堆栈(ED):堆栈指针指向下一个将要放入数据的空位置,且由高地址向低地址生成。

3.3  ARM指令集

本节对ARM指令集的七大类指令进行详细的描述。

3.3.1  加载/存储指令

ARM处理器支持加载/存储指令用于在寄存器和存储器之间传送数据,加载指令用于将存储器中的数据传送到寄存器,存储指令则完成相反的操做。经常使用的加载存储指令以下:

一、LDR指令

LDR指令的格式为:

LDR{条件} 目的寄存器,<存储器地址>

LDR指令用于从存储器中将一个32位的字数据传送到目的寄存器中。该指令一般用于从存储器中读取32位的字数据到通用寄存器,而后对数据进行处理。当程序计数器PC做为目的寄存器时,指令从存储器中读取的字数据被看成目的地址,从而能够实现程序流程的跳转。该指令在程序设计中比较经常使用,且寻址方式灵活多样,请读者认真掌握。

如:

LDR  R0[R1]            ;将存储器地址为R1的字数据读入寄存器R0

LDR  R0[R1R2]       ;将存储器地址为R1+R2的字数据读入寄存器R0

LDR  R0[R1,#8]       ;将存储器地址为R1+8的字数据读入寄存器R0

LDR  R0[R1R2]       ;将存储器地址为R1+R2的字数据读入寄存器R0,并将

;新地址R1R2写入R1

LDR  R0[R1,#8]       ;将存储器地址为R1+8的字数据读入寄存器R0,并将新

;地址R18写入R1

LDR  R0[R1]R2       ;将存储器地址为R1的字数据读入寄存器R0,并将新地

;址R1R2写入R1

LDR  R0[R1R2LSL2] ;将存储器地址为R1R2×4的字数据读入寄存器R0

;并将新地址R1R2×4写入R1

LDR  R0[R1]R2LSL2 ;将存储器地址为R1的字数据读入寄存器R0,并将新地

;址R1R2×4写入R1

二、STR指令

STR指令的格式为:

STR{条件} 源寄存器,<存储器地址>

STR指令用于从源寄存器中将一个32位的字数据传送到存储器中。该指令在程序设计中比较经常使用,且寻址方式灵活多样,使用方式可参考指令LDR

如:

STR R0[R1],#8 ;将R0中的字数据写入以R1为地址的存储器中,并将新地址R18写入R1

STR R0[R1,#8] ;将R0中的字数据写入以R18为地址的存储器中。

LDR/STR指令均可以加BHSBSH的后缀,分别表示加载/存储字节、半字、带符号的字节、带符号的半字。如LDRB指令表示从存储器加载一个字节进寄存器。当使用这些后缀时,要注意所使用的存储器要支持访问的数据宽度。

三、LDM(或STM)批量数据加载/存储指令

LDM(或STM)指令的格式为:

LDM(或STM){条件}{类型} 基址寄存器{!},寄存器列表{}

LDM(或STM)指令用于从由基址寄存器所指示的一片连续存储器到寄存器列表所指示的多个寄存器之间传送数据,该指令的常见用途是将多个寄存器的内容入栈或出栈。其中,{类型}为如下几种状况:

IA 每次传送后地址加1

IB 每次传送前地址加1

DA 每次传送后地址减1

DB 每次传送前地址减1

FD 满递减堆栈;

ED 空递减堆栈;

FA 满递增堆栈;

EA 空递增堆栈;

{}为可选后缀,若选用该后缀,则当数据传送完毕以后,将最后的地址写入基址寄存器,不然基址寄存器的内容不改变。

基址寄存器不容许为R15,寄存器列表能够为R0R15的任意组合。

{}为可选后缀,当指令为LDM且寄存器列表中包含R15,选用该后缀时表示:除了正常的数据传送以外,还将SPSR复制到CPSR。同时,该后缀还表示传入或传出的是用户模式下的寄存器,而不是当前模式下的寄存器。

如:

STMFD  R13!,{R0R4-R12LR} ;将寄存器列表中的寄存器(R0R4R12LR)存入堆栈。

LDMFD  R13!,{R0R4-R12PC} ;将堆栈内容恢复到寄存器(R0R4R12LR)。

四、SWP数据交换指令

SWP指令的格式为:

SWP{条件} 目的寄存器,源寄存器1,[源寄存器2]

SWP指令用于将源寄存器2所指向的存储器中的字数据传送到目的寄存器中,同时将源寄存器1中的字数据传送到源寄存器2所指向的存储器中。显然,当源寄存器1和目的寄存器为同一个寄存器时,指令交换该寄存器和存储器的内容。

如:

SWP  R0,R1[R2]      ;将R2所指向的存储器中的字数据传送到R0,同时将R1中的字数据传送到R2所指向的存储单元。

SWP  R0,R0[R1]      ;该指令完成将R1所指向的存储器中的字数据与R0中的字数据交换。

3.3.2  数据处理指令

数据处理指令可分为数据传送指令、算术逻辑运算指令和比较指令等。

数据传送指令用于在寄存器和存储器之间进行数据的双向传输。

算术逻辑运算指令完成经常使用的算术与逻辑的运算,该类指令不但将运算结果保存在目的寄存器中,同时更新CPSR中的相应条件标志位。

比较指令不保存运算结果,只更新CPSR中相应的条件标志位。

一、 MOV指令

MOV指令的格式为:

MOV{条件}{S} 目的寄存器,源操做数

MOV指令可完成从另外一个寄存器、被移位的寄存器或将一个当即数加载到目的寄存器。其中S选项决定指令的操做是否影响CPSR中条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值。

如:

MOV R1R0 ;将寄存器R0的值传送到寄存器R1

MOV PCR14 ;将寄存器R14的值传送到PC,经常使用于子程序返回

MOV R1R0LSL3 ;将寄存器R0的值左移3位后传送到R1

二、 MVN指令

MVN指令的格式为:

MVN{条件}{S} 目的寄存器,源操做数

MVN指令可完成从另外一个寄存器、被移位的寄存器、或一个当即数加载到目的寄存器。与MOV指令不一样之处是在传送以前位被反了,把一个被取反的值传送到目的寄存器中。其中S决定指令的操做是否影响CPSR中条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值。

如:

MVN R0,#0 ;将当即数0取反传送到寄存器R0中,完成后R0=-1

三、 CMP指令

CMP指令的格式为:

CMP{条件} 操做数1,操做数2

CMP指令用于把一个寄存器的内容和另外一个寄存器的内容或当即数进行比较,同时更新CPSR中条件标志位的值。该指令进行一次减法运算,但不存储结果,只更改条件标志位。标志位表示的是操做数1与操做2的关系(大、小、相等),例如,当操做数1大于操做操做数2,则此后的有GT 后缀的指令将能够执行。

如:

CMP R1R0 ;将寄存器R1的值与寄存器R0的值相减,并根据结果设置CPSR的标志位

CMP R1,#100 ;将寄存器R1的值与当即数100相减,并根据结果设置CPSR的标志位

 

四、 CMN指令

CMN指令的格式为:

CMN{条件} 操做数1,操做数2

CMN指令用于把一个寄存器的内容另外一个寄存器的内容或当即数取反后进行比较,同时更新CPSR中条件标志位的值该指令实际完成操做数1和操做数2相加并根据结果更改条件标志位。

如:

CMN R1R0 ;将寄存器R1的值与寄存器R0的值相加,并根据结果设置CPSR的标志位

CMN R1,#100 ;将寄存器R1的值与当即数100相加,并根据结果设置CPSR的标志位

五、 TST指令

TST指令的格式为:

TST{条件} 操做数1,操做数2

TST指令用于把一个寄存器的内容和另外一个寄存器的内容或当即数进行按位的与运算,并根据运算结果更新CPSR中条件标志位的值。操做数1是要测试的数据,而操做数2是一个位掩码,该指令通常用来检测是否设置了特定的位。

如:

TST R1,#%1 ;用于测试在寄存器R1中是否设置了最低位(%表示二进制数)

TST R1,#0xffe ;将寄存器R1的值与当即数0xffe按位与,并根据结果设置CPSR的标志位

六、 TEQ指令

TEQ指令的格式为:

TEQ{条件} 操做数1,操做数2

TEQ指令用于把一个寄存器的内容和另外一个寄存器的内容或当即数进行按位的异或运算,并根据运算结果更新CPSR中条件标志位的值。该指令一般用于比较操做数1和操做数2是否相等。

如:

TEQ R1R2 ;将寄存器R1的值与寄存器R2的值按位异或,并根据结果设置CPSR的标志位

七、 ADD指令

ADD指令的格式为:

ADD{条件}{S} 目的寄存器,操做数1,操做数2

ADD指令用于把两个操做数加,并将结果存放到目的寄存器中操做数1应是一个寄存器,操做数2能够是一个寄存器,被移位的寄存器,或一个当即数。

如:

ADD R0,R1,R2          ; R0 = R1 + R2

ADD R0,R1,#256            ; R0 = R1 + 256

ADD R0,R2,R3,LSL#1      ; R0 = R2 + (R3 << 1)

八、 ADC指令

ADC指令的格式为:

ADC{条件}{S} 目的寄存器,操做数1,操做数2

ADC指令用于把两个操做数相加,再加上CPSR中的C条件标志位的值,并将结果存放到目的寄存器中。它使用一个进位标志位,这样就能够作比32位大的数的加法,注意不要忘记设置S后缀来更改进位标志。操做数1应是一个寄存器,操做数2能够是一个寄存器,被移位的寄存器,或一个当即数。

如下指令序列完成两个128位数的加法,第一个数由高到低存放在寄存器R7~R4,第二个数由高到低存放在寄存器R11~R8,运算结果由高到低存放在寄存器R3~R0:

ADDS  R0,R4R8          ; 加低端的字

ADCS  R1R5R9            ; 加第二个字,带进位

ADCS  R2R6R10      加第三个字,带进位

ADC  R3R7R11      加第四个字,带进位

九、 SUB指令

SUB指令的格式为:

SUB{条件}{S} 目的寄存器,操做数1,操做数2

SUB指令用于把操做数1减去操做数2并将结果存放到目的寄存器中操做数1应是一个寄存器,操做数2能够是一个寄存器,被移位的寄存器,或一个当即数。该指令可用于有符号数或无符号数的减法运算。

如:

SUB  R0,R1,R2          ; R0 = R1 - R2

SUB  R0,R1,#256            ; R0 = R1 - 256

SUB  R0,R2,R3,LSL#1      ; R0 = R2 - (R3 << 1)

十、SBC指令

SBC指令的格式为:

SBC{条件}{S} 目的寄存器,操做数1,操做数2

SBC指令用于把操做数1减去操做数2再减去CPSR中的C条件标志位的反码,并将结果存放到目的寄存器中操做数1应是一个寄存器,操做数2能够是一个寄存器,被移位的寄存器,或一个当即数。该指令使用进位标志来表示借位,这样就能够作大于32位的减法,注意不要忘记设置S后缀来更改进位标志。该指令可用于有符号数或无符号数的减法运算。

如:

SUBS  R0,R1,R2          ; R0 = R1 - R2 - C,并根据结果设置CPSR的进位标志位

11RSB指令

RSB指令的格式为:

RSB{条件}{S} 目的寄存器,操做数1,操做数2

RSB指令称为逆向减法指令,用于把操做数2减去操做数1并将结果存放到目的寄存器中操做数1应是一个寄存器,操做数2能够是一个寄存器,被移位的寄存器,或一个当即数。该指令可用于有符号数或无符号数的减法运算。

如:

RSB  R0,R1,R2          ; R0 = R2 – R1

RSB  R0,R1,#256            ; R0 = 256 – R1

RSB  R0,R2,R3,LSL#1      ; R0 = (R3 << 1) - R2

十二、RSC指令

RSC指令的格式为:

RSC{条件}{S} 目的寄存器,操做数1,操做数2

RSC指令用于把操做数2减去操做数1再减去CPSR中的C条件标志位的反码,并将结果存放到目的寄存器中操做数1应是一个寄存器,操做数2能够是一个寄存器,被移位的寄存器,或一个当即数。该指令使用进位标志来表示借位,这样就能够作大于32位的减法,注意不要忘记设置S后缀来更改进位标志。该指令可用于有符号数或无符号数的减法运算。

如:

RSC  R0,R1,R2          ; R0 = R2 – R1 - C

1三、AND指令

AND指令的格式为:

AND{条件}{S} 目的寄存器,操做数1,操做数2

AND指令用于在两个操做数上进行逻辑与运算把结果放置到目的寄存器中操做数1应是一个寄存器,操做数2能够是一个寄存器,被移位的寄存器,或一个当即数。该指令经常使用于屏蔽操做数1的某些位

如:

AND  R0,R0,#3          ; 该指令保持R001位,其他位清零。

1四、ORR指令

ORR指令的格式为:

ORR{条件}{S} 目的寄存器,操做数1,操做数2

ORR指令用于在两个操做数上进行逻辑或运算把结果放置到目的寄存器中操做数1应是一个寄存器,操做数2能够是一个寄存器,被移位的寄存器,或一个当即数。该指令经常使用于设置操做数1的某些位

如:

ORR  R0,R0,#3          ; 该指令设置R001位,其他位保持不变。

1五、EOR指令

EOR指令的格式为:

EOR{条件}{S} 目的寄存器,操做数1,操做数2

EOR指令用于在两个操做数上进行逻辑异或运算把结果放置到目的寄存器中操做数1应是一个寄存器,操做数2能够是一个寄存器,被移位的寄存器,或一个当即数。该指令经常使用于反转操做数1的某些位

如:

EOR  R0,R0,#3          ; 该指令反转R001位,其他位保持不变。

1六、BIC指令

BIC指令的格式为:

BIC{条件}{S} 目的寄存器,操做数1,操做数2

BIC指令用于清除操做数1的某些位把结果放置到目的寄存器中操做数1应是一个寄存器,操做数2能够是一个寄存器,被移位的寄存器,或一个当即数。操做数232位的掩码,若是在掩码中设置了某一位,则清除这一位。未设置的掩码位保持不变。

如:

BIC  R0,R0,#%1011         ; 该指令清除 R0 中的位 01、和 3,其他的位保持不变。

3.3.3  乘法指令与乘加指令

ARM微处理器支持的乘法指令与乘加指令共有6条,可分为运算结果为32位和运算结果为64位两类。与前面的数据处理指令不一样,指令中的所有操做数、目的寄存器必须为通用寄存器不能对操做数使用当即或被移位的寄存器,同时,目的寄存器和操做数1必须是不一样的寄存器。 

一、 MUL指令

MUL指令的格式为:

MUL{条件}{S} 目的寄存器,操做数1,操做数2

MUL指令完成将操做数1与操做数2的乘法运算,并把结果放置到目的寄存器中,同时能够根据运算结果设置CPSR中相应的条件标志位。其中,操做数1和操做数2均为32位的有符号数或无符号数。

如:

MUL R0R1R2 R0 = R1 × R2

MULS R0R1R2 R0 = R1 × R2,同时设置CPSR中的相关条件标志位

二、 MLA指令

MLA指令的格式为:

MLA{条件}{S} 目的寄存器,操做数1,操做数2,操做数3

MLA指令完成将操做数1与操做数2的乘法运算,再将乘积加上操做数3,并把结果放置到目的寄存器中,同时能够根据运算结果设置CPSR中相应的条件标志位。其中,操做数1和操做数2均为32位的有符号数或无符号数。

如:

MLA R0R1R2R3 R0 = R1 × R2 + R3

MLAS R0R1R2R3 R0 = R1 × R2 + R3,同时设置CPSR中的相关条件标志位

三、 SMULL指令

SMULL指令的格式为:

SMULL{条件}{S} 目的寄存器Low,目的寄存器低High,操做数1,操做数2

SMULL指令完成将操做数1与操做数2的乘法运算,并把结果的低32放置到目的寄存器Low结果的高32放置到目的寄存器High,同时能够根据运算结果设置CPSR中相应的条件标志位。其中,操做数1和操做数2均为32位的有符号数。

如:

SMULL R0R1R2R3 R0 = R2 × R3)的低32

R1 = R2 × R3)的高32

四、 SMLAL指令

SMLAL指令的格式为:

SMLAL{条件}{S} 目的寄存器Low,目的寄存器低High,操做数1,操做数2

SMLAL指令完成将操做数1与操做数2的乘法运算,并把结果的低32位同目的寄存器Low中的值相加后又放置到目的寄存器Low结果的高32位同目的寄存器High中的值相加后又放置到目的寄存器High,同时能够根据运算结果设置CPSR中相应的条件标志位。其中,操做数1和操做数2均为32位的有符号数。

对于目的寄存器Low,在指令执行前存放64位加数的低32位,指令执行后存放结果的低32位。

对于目的寄存器High,在指令执行前存放64位加数的高32位,指令执行后存放结果的高32位。

如:

SMLAL R0R1R2R3 R0 = R2 × R3)的低32位 + R0

R1 = R2 × R3)的高32位 + R1

五、 UMULL指令

UMULL指令的格式为:

UMULL{条件}{S} 目的寄存器Low,目的寄存器低High,操做数1,操做数2

UMULL指令完成将操做数1与操做数2的乘法运算,并把结果的低32放置到目的寄存器Low结果的高32放置到目的寄存器High,同时能够根据运算结果设置CPSR中相应的条件标志位。其中,操做数1和操做数2均为32位的无符号数。

如:

UMULL R0R1R2R3 R0 = R2 × R3)的低32

R1 = R2 × R3)的高32

六、 UMLAL指令

UMLAL指令的格式为:

UMLAL{条件}{S} 目的寄存器Low,目的寄存器低High,操做数1,操做数2

UMLAL指令完成将操做数1与操做数2的乘法运算,并把结果的低32位同目的寄存器Low中的值相加后又放置到目的寄存器Low结果的高32位同目的寄存器High中的值相加后又放置到目的寄存器High,同时能够根据运算结果设置CPSR中相应的条件标志位。其中,操做数1和操做数2均为32位的无符号数。

对于目的寄存器Low,在指令执行前存放64位加数的低32位,指令执行后存放结果的低32位。

对于目的寄存器High,在指令执行前存放64位加数的高32位,指令执行后存放结果的高32位。

如:

UMLAL R0R1R2R3 R0 = R2 × R3)的低32位 + R0

R1 = R2 × R3)的高32位 + R1

3.3.4  跳转指令

跳转指令用于实现程序流程的跳转,在ARM程序中有两种方法能够实现程序流程的跳转:使用专门的跳转指令、直接向程序计数器PC写入跳转地址值。

直接向PC写入跳转地址值,能够实如今4GB的地址空间中任意跳转,在跳转以前结合使用MOV LRPC等相似指令,能够保存未来的返回地址值,从而实如今4GB连续的线性地址空间的子程序调用。

使用跳转指令能够完成从当前指令向前或向后的32MB的地址空间的跳转。

一、 B指令

B指令的格式为:

B{条件} 目标地址

B指令是最简单的跳转指令。一旦遇到一个指令,ARM 处理器将当即跳转到给定的目标地址,从那里继续执行。注意存储在跳转指令中的实际值是相对当前PC值的一个偏移量,而不是一个绝对地址,它的值由汇编器来计算(参考寻址方式中的相对寻址)。它是 24 位有符号数,左移两位后有符号扩展为 32 位,表示的有效偏移为 26 位(先后32MB的地址空间)。

如:

B Label ;程序无条件跳转到标号Label处执行

CMP R1,#0 ;当CPSR寄存器中的Z条件码置位时,程序跳转到标号Label处执行

BEQ Label

二、 BL指令

BL指令的格式为:

BL{条件}  目标地址

BL 是另外一个跳转指令,但跳转以前,会在寄存器R14中保存PC的当前内容,所以,能够经过将R14 的内容从新加载到PC中,来返回到跳转指令以后的那个指令处执行。该指令是实现子程序调用的一个基本但经常使用的手段。

如:

BL Label ;当程序无条件跳转到标号Label处执行时,同时将当前的PC值保存到R14

Label标号处能够是一个子程序,在子程序的最后能够使用MOV PC,LR指令跳回BL Label指令处的下一条指令继续执行。

三、 BLX指令

BLX指令的格式为:

BLX  目标地址

BLX指令从ARM指令集跳转到指令中所指定的目标地址,并将处理器的工做状态由ARM状态切换到Thumb状态,该指令同时将PC的当前内容保存到寄存器R14中。所以,当子程序使用Thumb指令集,而调用者使用ARM指令集时,能够经过BLX指令实现子程序的调用和处理器工做状态的切换。同时,子程序的返回能够经过将寄存器R14值复制到PC中来完成。

四、 BX指令

BX指令的格式为:

BX{条件}  目标地址

BX指令跳转到指令中所指定的目标地址,目标地址处的指令既能够是ARM指令,也能够是Thumb指令。

3.3.5  程序状态寄存器访问指令

ARM指令不容许直接操做程序状态寄存器CPSRSPSR。能够经过程序状态寄存器访问指令,在程序状态寄存器和通用寄存器之间传送数据,而后在通用寄存器中进行处理。

一、 MRS指令

MRS指令的格式为:

MRS{条件} 通用寄存器,程序状态寄存器(CPSR或SPSR)

MRS指令用于将程序状态寄存器的内容传送到通用寄存器中。该指令通常用在如下几种状况:

1) 当须要改变程序状态寄存器的内容时,可用MRS将程序状态寄存器的内容读入通用寄存器,修改后再写回程序状态寄存器。

2) 当在异常处理或进程切换时,须要保存程序状态寄存器的值,可先用该指令读出程序状态寄存器的值,而后保存。

如:

MRS R0CPSR ;传送CPSR的内容到R0

MRS R0SPSR ;传送SPSR的内容到R0

二、 MSR指令

MSR指令的格式为:

MSR{条件} 程序状态寄存器(CPSR或SPSR)_<域>,操做数

MSR指令用于将操做数的内容传送到程序状态寄存器的特定域中。其中,操做数能够为通用寄存器或当即数。<域>用于设置程序状态寄存器中须要操做的位,32位的程序状态寄存器可分为4个域:

[31:24]为条件标志位域,用f表示;

[23:16]为状态位域,用s表示;

[15:8]为扩展位域,用x表示;

[7:0]为控制位域,用c表示;

该指令一般用于恢复或改变程序状态寄存器的内容,在使用时,通常要在MSR指令中指明将要操做的域。

如:

MSR CPSRR0 ;传送R0的内容到CPSR

MSR SPSRR0 ;传送R0的内容到SPSR

MSR CPSR_cR0 ;传送R0的内容到SPSR,但仅仅修改CPSR中的控制位域

3.3.6  协处理器指令

ARM微处理器可支持多达16个协处理器,用于各类协处理操做,在程序执行的过程当中,每一个协处理器只执行针对自身的协处理指令,忽略ARM处理器和其余协处理器的指令。

ARM的协处理器指令主要用于ARM处理器初始化ARM协处理器的数据处理操做,以及在ARM处理器的寄存器和协处理器的寄存器之间传送数据,和在ARM协处理器的寄存器和存储器之间传送数据。

一、CDP指令

CDP指令的格式为:

CDP{条件} 协处理器编码,协处理器操做码1,目的寄存器,源寄存器1,源寄存器2,协处理器操做码2。

CDP指令用于ARM处理器通知ARM协处理器执行特定的操做,若协处理器不能成功完成特定的操做,则产生未定义指令异常。其中协处理器操做码1和协处理器操做码2为协处理器将要执行的操做,目的寄存器和源寄存器均为协处理器的寄存器,指令不涉及ARM处理器的寄存器和存储器。

如:

CDP  P32C12C10C34      ;该指令完成协处理器P3的初始化

二、LDC指令

LDC指令的格式为:

LDC{条件}{L} 协处理器编码,目的寄存器,[源寄存器]

LDC指令用于将源寄存器所指向的存储器中的字数据传送到目的寄存器中,若协处理器不能成功完成传送操做,则产生未定义指令异常。其中,{L}选项表示指令为长读取操做,如用于双精度数据的传输。

如:

LDC  P3C4[R0]      ;将ARM处理器的寄存器R0所指向的存储器中的字数据传送到协处理器P3的寄存器C4中。

三、STC指令

STC指令的格式为:

STC{条件}{L} 协处理器编码,源寄存器,[目的寄存器]

STC指令用于将源寄存器中的字数据传送到目的寄存器所指向的存储器中,若协处理器不能成功完成传送操做,则产生未定义指令异常。其中,{L}选项表示指令为长读取操做,如用于双精度数据的传输。

如:

STC  P3C4[R0]      ;将协处理器P3的寄存器C4中的字数据传送到ARM处理器的寄存器R0所指向的存储器中。

四、MCR指令

MCR指令的格式为:

MCR{条件} 协处理器编码,协处理器操做码1,源寄存器,目的寄存器1,目的寄存器2,协处理器操做码2。

MCR指令用于将ARM处理器寄存器中的数据传送到协处理器寄存器中,若协处理器不能成功完成操做,则产生未定义指令异常。其中协处理器操做码1和协处理器操做码2为协处理器将要执行的操做,源寄存器为ARM处理器的寄存器,目的寄存器1和目的寄存器2均为协处理器的寄存器。

如:

MCR  P33R0C4C56    ;该指令将ARM处理器寄存器R0中的数据传送到协处理器P3的寄存器C4C5中。

五、MRC指令

MRC指令的格式为:

MRC{条件} 协处理器编码,协处理器操做码1,目的寄存器,源寄存器1,源寄存器2,协处理器操做码2。

MRC指令用于将协处理器寄存器中的数据传送到ARM处理器寄存器中,若协处理器不能成功完成操做,则产生未定义指令异常。其中协处理器操做码1和协处理器操做码2为协处理器将要执行的操做,目的寄存器为ARM处理器的寄存器,源寄存器1和源寄存器2均为协处理器的寄存器。

如:

MRC  P33R0C4C56    ;该指令将协处理器P3的寄存器中的数据传送到ARM处理器寄存器中。

3.3.7  异常中断指令

一、SWI指令

SWI指令的格式为:

SWI{条件} 24位的当即数

SWI指令用于产生软件中断,以便用户程序能调用操做系统的系统例程。操做系统在SWI的异常处理程序中提供相应的系统服务,指令中24位的当即数指定用户程序调用系统例程的类型,相关参数经过通用寄存器传递,当指令中24位的当即数被忽略时,用户程序调用系统例程的类型由通用寄存器R0的内容决定,同时,参数经过其余通用寄存器传递。 

如:

SWI  0x02     ;该指令调用操做系统编号位02的系统例程。

二、BKPT指令

BKPT指令的格式为:

BKPT   16位的当即数

BKPT指令产生软件断点中断,可用于程序的调试

3.4  Thumb指令集

为兼容数据总线宽度为16位的应用系统,ARM体系结构除了支持执行效率很高的32ARM指令集之外,同时支持16位的Thumb指令集。Thumb指令集是ARM指令集的一个子集,容许指令编码为16位的长度。与等价的32位代码相比较,Thumb指令集在保留32位代码优点的同时,大大的节省了系统的存储空间。

全部的Thumb指令都有对应的ARM指令,并且Thumb的编程模型也对应于ARM的编程模型,在应用程序的编写过程当中,只要遵循必定调用的规则,Thumb子程序和ARM子程序就能够互相调用。当处理器在执行ARM程序段时,称ARM处理器处于ARM工做状态,当处理器在执行Thumb程序段时,称ARM处理器处于Thumb工做状态。

ARM指令集相比较,Thumb指令集中的数据处理指令的操做数仍然是32位,指令地址也为32位,但Thumb指令集为实现16位的指令长度,舍弃了ARM指令集的一些特性,如大多数的Thumb指令是无条件执行的,而几乎全部的ARM指令都是有条件执行的;大多数的Thumb数据处理指令的目的寄存器与其中一个源寄存器相同。

因为Thumb指令的长度为16位,即只用ARM指令一半的位数来实现一样的功能,因此,要实现特定的程序功能,所需的Thumb指令的条数较ARM指令多。在通常的状况下,Thumb指令与ARM指令的时间效率和空间效率关系为:

— Thumb代码所需的存储空间约为ARM代码的60%~70%

— Thumb代码使用的指令数比ARM代码多约30%~40%

— 若使用32位的存储器,ARM代码比Thumb代码快约40%

— 若使用16位的存储器,Thumb代码比ARM代码快约40%~50%

— ARM代码相比较,使用Thumb代码,存储器的功耗会下降约30%

显然,ARM指令集和Thumb指令集各有其优势,若对系统的性能有较高要求,应使用32位的存储系统和ARM指令集,若对系统的成本及功耗有较高要求,则应使用16位的存储系统和Thumb指令集。固然,若二者结合使用,充分发挥其各自的优势,会取得更好的效果。

3.5  伪指令

ARM编译器通常都支持汇编语言的程序设计和C/C++语言的程序设计,以及二者的混合编程。在ARM汇编语言程序,有一些特殊指令助记符,这些助记符与指令系统的助记不一样,没有相对应的操做码,一般称这些特殊指令助记符为伪指令,他们所完成的操做称为伪操做。伪指令在源程序中的做用是为完成汇编程序做各类准备工做的,这些伪指令仅在汇编过程当中起做用,一旦汇编结束,伪指令的使命就完成。

ARM的汇编程序中,有以下几种伪指令:ARM伪指令、符号定义伪指令数据定义伪指令、段定义伪指令、模块控制伪指令、汇编控制伪指令处理伪指令等等

须要特别指出的是,除了几条ARM伪指令之外,其它的伪指令依赖于编译器。也就是说,不一样的ARM编译器的伪指令集是不相同的。例如,ADS编译器的段定义伪指令为AREA,而IAR编译器的段定义伪指令为RSEGASEG。这种状况使得不一样编译器下编出的ARM汇编程序是不一样的。读者在阅读不一样学习材料时应注意分辨在不一样编译器下ARM汇编程序的区别。

本书介绍的是IAR EWARM编译器支持的ARM汇编伪指令。

3.5.1  ARM伪指令

ARM伪指令不是ARM指令集中的指令。它能够象其它ARM指令同样使用,但在编译时这些指令将被等效的ARM指令所取代。

一、LDR-大范围地址读取

LDR伪指令的格式为:

LDR{条件} reg,=expr/label_expr

reg为加载的目的寄存器;expr32位当即数;label_expr为地址表达式或外部表达式。

LDR伪指令将32位常量或一个32位地址加载到指定寄存器。

如:

LDR  R0=#0x12345         ;加载32位当即数0x12345到寄存器R0

LDR  R0=DATA_BUF+60     ;加载DATA_BUF地址+60

二、ADR-小范围地址读取

ADR伪指令的格式为:

ADR{条件} reg,expr

reg为加载的目的寄存器;expr为相对偏移表达式,非字对齐时取值范围为-255~255字节,字对齐时取值范围为-1020~1020字节。

ADR伪指令将基于当前PC相对偏移的地址值读取到寄存器中。

如:

Start: MOV R0#10

ADR R4start ;至关于SUB R4PC#0x0c

三、ADRL-中范围地址读取

ADRL伪指令与ADR相似,不一样在expr的取值范围,非字对齐时取值范围为64KB,字对齐时取值范围为256KB

四、NOP-空操做

3.5.2  数据定义伪指令

一、DCB和DC8

该伪指令的格式为:

标号 DCB或DC8 表达式

DCBDC8伪指令用于分配一片连续的8位字节存储单元,并用伪指令中指定的表达式初始化。其中表达式能够为0255的数字或字符串。

如:

Str DCB “This is a test!” ;分配一个字符串,每一个字符8位字节

二、DCW和DC1六、DCD和DC32

DCBDC8用法相同,不一样的是分别分配16位半字节单元和32位字单元。

三、DF32和DF64

分别表示32位的单精度浮点数和64位的双精度浮点数。

四、DS八、DS1六、DS24和DS32

分别用于保留8位字节、16位半字、24位字和32位字的存储器空间。

如:

Dataspace DS8 100 ;保留1008位字节的存储器空间

3.5.3  符号定义伪指令

一、=、ALIAS和EQU

该伪指令的格式为:

标号 = 表达式

标号 ALIAS 表达式

标号 EQU 表达式

伪指令EQU和=可用于为程序模块中的常量、标号等赋值,定义的局部符号仅在其所在的模块内有效。伪指令ALIAS为符号起个别名。定义的符号采用PUBLIC伪指令声明其属性可以使之被其它模块引用,引用其它模块内符号时必须采用EXTERN伪指令声明其属性。

如:

Test EQU 50 ;定义符号Test的值为50

二、ASSIGN、SET、SETA和VAR

用法与EQU等相似,可用于定义一个变量符号。采用VAR定义的变量符号不能用PUBLIC声明其属性。

三、DEFINE

用于定义在整个程序文件内都有效的全局符号。该符号能够被文件内的全部程序模块引用,但不能在同一文件内从新定义。

四、LIMIT

该伪指令的格式为:

LIMIT 表达式, 最小值, 最大值, 提示信息

用于检查表达式的值是否位于给定范围以内。若是表达式值的范围超限,则输出提示信息。

如:

Speed VAR 23 ;定义符号speed的值为23

LIMIT speed1030…speed out of range… ;检查speed的值是否超限

五、EXTERN(或IMPORT)

该伪指令的格式为:

EXTERN 符号,[符号]……

EXTERN伪指令用于通知汇编器,要使用的符号在其它源文件中定义,但要在当前源文件中引用。

如:

Name Start ;程序模块Start

EXTERN Main ;告诉汇编器Main符号在其它源文件中定义

……

BL Main ;在本模块中引用Main符号

END

六、PUBLIC(或EXPORT)

该伪指令的格式为:

PUBLIC 符号,[符号]……

PUBLIC伪指令用于在程序中声明一个全局符号,该符号可在其它文件中引用。

七、REQUIRE

PUBLIC伪指令用于将一个符号标记为已经被引用。

3.5.4  段定义伪指令

一、ASEG和ASEGN

该伪指令的格式为:

ASEG [起始地址[(对齐)]]

ASEGN 段名[:存储器类型],地址

ASEG伪指令用于定义一个绝对段,并设置段的起始地址。不指定地址值时第一个段默认起始地址为0,后续段地址依次递增。ASEGN伪指令用于设置指定段的绝对起始地址,并容许规定段类型。存储器类型能够为CODE(代码段)、DATA(数据段)、STACK(堆栈段)。

如:

ASEG 0 ;定义一个绝对段,起始地址0

ASEGN CODECODE0 ;定义一个名为CODE的代码段,起始地址0

二、RSEG

该伪指令的格式为:

RSEG 段名[:存储器类型][:(NO)ROOT|(NO)REORDER|SORT][(对齐)]

RSEG伪指令用于定义一个可重定位段,段的起始地址由汇编器临时分配。单个模块中最多可定义65536个可重定位段。

如:

RSEG CODECODEROOT(2) ;定义一个名为CODE的可重定位代码段,用户权限为ROOT(可读写),段内存储器对齐方式为4字节对齐

三、DATA

该伪指令的格式为:

DATA 段名[:存储器类型][(对齐)]

DATA伪指令能够在代码段内定义一个数据区。

如:

RSEG CODECODEROOT(2)

DATA

f1:    DC32 subrtn

四、STACK

该伪指令的格式为:

COMMON 段名[:存储器类型][(对齐)]

STACK伪指令用于定义一个堆栈段,用做堆栈的存储器地址从高向低变化,而用做可重定位段的存储器地址是从低向高变化。

五、COMMON

该伪指令的格式为:

COMMON 段名[:存储器类型][(对齐)]

COMMON伪指令用于定义公共段,各源文件中同名的COMMON段共享同一段内存。它的典型应用是多个不一样子程序共享一段数据存储区。中断向量表也可安排在COMMON段,以便容许从多个服务子程序访问。

六、CODE16和CODE32

CODE16伪指令用于告诉汇编器,其后的指令序列为16位的Thumb指令;CODE32伪指令用于告诉汇编器,其后的指令序列为32位的ARM指令。所以,在使用ARM指令和Thumb指令混合编程的代码中,可用这两条伪指令进行切换。但须要注意的是,它们只通知汇编器其后指令的类型,并不能对处理器进行状态切换。

七、ORG

该伪指令的格式为:

ORG 地址表达式

ORG伪指令用于设置段的起始地址。地址表达式的计算结果应与当前段的类型保持一致,如在RSEG(可重定位段)中,不要使用“ORG 10”,由于10是一个绝对地址,而应当使用“ORG +10”,表示当前段偏移量为10的地址。另外,地址表达式中不能包括任何前向和外部引用。

八、ALIGNRAM和ALIGNROM

该伪指令的格式为:

ALIGNRAM 对齐

ALIGNROM 对齐[,填充值]

用于设置存储器地址边界的对齐方式,“对齐”是一个值为230的常数,并按2230设定对齐地址。ALIGNRAM以数据增量方式对齐,ALIGNROM以填充0字节方式对齐。

九、EVEN和ODD

该伪指令的格式为:

EVEN [填充值]

ODD [填充值]

EVEN伪指令用于将程序计数器PC以偶数地址对齐(等价于ALIGNROM 1),ODD伪指令用于将程序计数器PC以奇数地址对齐。

3.5.5  模块控制伪指令

一、NAME和PROGRAM

该伪指令的格式为:

NAME 模块名

PROGRAM 模块名

NAMEPROGRAM伪指令用于定义一个程序模块。程序模块相似于C语言中的函数,是程序中相对独立的一个部分。程序模块即便没有被调用也会被无条件连接。

如:

NAME Main ;定义一个名为Main的程序模块

二、END和ENDMOD

END伪指令用于结束整个汇编语言程序,ENDMOD用于结束当前程序模块。每一个汇编语言程序最后必须使用END伪指令通知汇编器已经到了源程序结尾,以结束汇编。

三、LIBRARY和MODULE

伪指令用于定义多模块文件中的小模块,其中每一个小模块表明一段子程序,从而能够方便地建立库模块文件。与NAMEPROGRAM不一样的是,用LIBRARYMODULE定义的模块只有在被调用时才会复制到连接代码中。

四、RTMODEL

该伪指令的格式为:

RTMODEL 关键字字符串,值字符串

该伪指令用于声明模块的运行模式属性,以强制模块之间的一致性。全部能被连接在一块儿的模块必须具备相同的关键字;值字符串要么具备相同的值,要么其值为星号*”。

3.5.6  汇编控制伪指令

一、$和INCLUDE

该伪指令的格式为:

$ 文件名

INCLUDE 文件名

该伪指令用于给当前源文件加载头文件。

二、CASEOFF和CASEON

该伪指令用于源程序文件中禁止和容许大小写字符敏感。

三、LTORG

在使用ARM伪指令LDR加载地址数据时,要在适当的位置加入LTORG声明一个数据区,把要加载的数据保存在数据区内,再用LDR读出数据。LTORG伪指令一般放在无条件分支或子程序返回指令后面,这样处理器就不会错误的将数据区中的数据看成指令执行。

四、RADIX

该伪指令用于声明当前使用的数制形式。如:

RADIX 16D ;声明当前使用十六进制数

MOV R0#12 ;此处#120x12

五、IF、ELSE和ENDIF

该伪指令的格式为:

IF 逻辑表达式

指令序列1

ELSE

指令序列2

ENDIF

条件汇编伪指令能根据设定条件的成立与否决定是否对指令序列进行汇编生成目标代码。若逻辑表达式为真,则对指令序列1汇编生成目标代码;不然对指令序列2汇编。其中还能够用ELSEIF伪指令设定新条件。

如:

DEFINE Test ;定义一个全局变量Test

……

IF Test TRUE

指令序列1

ELSE

指令序列2

ENDIF

3.5.7  宏处理伪指令

一、MACRO和ENDM

该伪指令的格式为:

宏名 MACRO [,参数][ ,参数]……

指令序列

ENDM

MACRO伪指令用于定义一个宏,引用宏时必须使用定义的宏名,并可向宏中传递参数。ENDM伪指令用于结束宏定义。

如:

errmac MACRO  text

BL abort

DATA

DC8 text,0

ENDM

包含在MACROENDM之间的指令序列称为宏定义体。在宏定义体的第一行应声明宏的原型(包括宏名和所需的参数),而后就能够在汇编程序中经过宏名来调用该指令序列。在源程序被编译时,汇编器将宏调用展开,用宏定义中的指令序列代替程序中的宏调用,并将实际参数值传递给宏定义中的形式参数。

二、REPT和ENDR

该伪指令的格式为:

REPT 表达式

指令序列

ENDR

伪指令用于指示汇编器将指定的指令序列进行重复汇编,重复次数由表达式的值肯定。若是表达式的值为0,则不进行任何操做。

三、REPTC和ENDR

该伪指令的格式为:

REPTC 符号,替换字符串

指令序列

ENDR

该伪指令用于在宏展开时用替换字符串中的单个字符逐次替换符号。

四、REPTI和ENDR

该伪指令的格式为:

REPTI 符号,替换字符串[,替换字符串]……

指令序列

ENDR

该伪指令用于在宏展开时用整个替换字符串替换符号。

3.6  ARM汇编语言的语句格式

3.6.1  ARM汇编语言的语句格式

ARMThumb)汇编语言的语句格式为:

[标号[:]] 指令或伪指令 操做数 [;注释]

其中,方括号内的内容为可选项。

标号顶格书写时后面可不用冒号,非顶格书写时后面必须用冒号。

标号前加一个问号?”前缀,表示该标号为外部标号,且仅能经过汇编语言访问;标号前加两个下划线“__”前缀,表示该标号为外部标号,能经过C语言和汇编语言访问;没有前缀的标号为局部标号,仅能在本模块内访问。

IAR汇编器对大小写字符敏感,通常指令和伪指令助记符使用大写,标号使用大小写混杂的方式以示区分。

同时,若是一条语句太长,可将该长语句分为若干行来书写,在行的末尾用\”表示下一行与本行为同一条语句。

IAR汇编器规定汇编语言程序文件的默认扩展名为“.s79”,也能够用“.s”或“.asm”做为扩展名。

3.6.2  符号

在汇编语言程序设计中,常用各类符号代替地址、变量和常量等,以增长程序的可读性。尽管符号的命名由编程者决定,但并非任意的,必须遵循如下的约定:

1.符号由大小写字母、数字及下划线组成,符号不能用数字开头。

2.符号区分大小写,同名的大、小写符号会被编译器认为是两个不一样的符号。

3.符号在其做用范围内必须惟一。

4.自定义的符号名不能与系统的保留字相同。

5.符号名不该与指令或伪指令同名。

6IAR汇编器内部预约义符号以双下划线开头和结尾。如:__IAR_SYSTEMS_ASM__

3.6.3  常量和变量

一、 常量

程序中的常量是指其值在程序的运行过程当中不能被改变的量。ARMThumb)汇编程序所支持的常量有数字常量、逻辑常量和字符串常量。

数字常量通常为32位的整数,看成为无符号数时,其取值范围为0232-1,看成为有符号数时,其取值范围为-231231-1。数字常量有4种表示形式:十进制数如123、-456等;十六进制数如0x1230FFFFH等;八进制数如1234q等;二进制数如1010b等。

逻辑常量只有两种取值状况:TRUEFALSE

字符串常量为一个固定的字符串,通常用于程序运行时的信息提示。用法与标准C语言相同。

二、 变量

程序中的变量是指其值在程序的运行过程当中能够改变的量。ARMThumb)汇编程序所支持的变量有数字变量、逻辑变量和字符串变量。

数字变量用于在程序的运行中保存数字值,但注意数字值的大小不该超出数字变量所能表示的范围。

逻辑变量用于在程序的运行中保存逻辑值,逻辑值只有两种取值状况:真或假。

字符串变量用于在程序的运行中保存一个字符串,但注意字符串的长度不该超出字符串变量所能表示的范围。

3.7  ARM汇编语言的程序结构

3.7.1  汇编语言的程序结构

ARMThumb)汇编语言程序中,以程序段为单位组织代码。段是相对独立的指令或数据序列,具备特定的名称。段能够分为代码段和数据段,代码段的内容为执行代码,数据段存放代码运行时须要用到的数据。一个汇编程序至少应该有一个代码段,当程序较长时,能够分割为多个代码段和数据段,多个段在程序编译连接时最终造成一个可执行的映象文件。

可执行映象文件一般由如下几部分构成:

11个或多个代码段,代码段的属性为只读。

20个或多个包含初始化数据的数据段,数据段的属性为可读写。

30个或多个不包含初始化数据的数据段,数据段的属性为可读写。

连接器根据系统默认或用户设定的规则,将各个段安排在存储器中的相应位置。所以源程序中段之间的相对位置与可执行的映象文件中段的相对位置通常不会相同。

3.7.2  一个简单的ARM汇编语言程序

如下是一个汇编语言源程序的基本结构:

代码清单3.1

NAME ASM_EXAMPL ;定义一个名为ARM_EXAMPL的程序模块

RSEG CODE:CODE:ROOT(2) ;定义一个可重定位的代码段

CODE32 ;执行32ARM指令

ORG 0x1000 ;定义程序起始地址为0x1000

Start: LDR R0,=0x3FF5000 Start处的地址即为0x1000

LDR R1,=0xff

STR R1,[R0]

MOV R0,#0x10

MOV R1,#0x20

ADD R0,R0,R1

Stop: B Stop ;跳转到指令自己,程序中止运行

ENDMOD ;本程序模块结束

END ;本程序结束

程序很简单,它完成的功能并不重要,但它已经表示出了一个ARM汇编语言程序的基本结构。

3.8  ARM程序设计举例

3.8.1  分支程序

程序设计中的三种基本结构是:顺序结构、分支结构和循环结构。在C语言中能够使用if-else语句实现单分支和双分支结构,也能够经过switch-case语句实现多分支结构。可是在汇编语言中,分支结构通常是经过跳转指令结合标号来实现的。

ARM汇编语言程序中,因为ARM指令支持条件执行,从而大大减小了分支程序的复杂程度。

例如:用两个整数展转相减的方法求它们的最大公约数。注意体会B指令加条件码的执行方式。程序中使用的main标号是由于IAR汇编器通常默认从main标号处开始执行。

代码清单3.2

NAME GCD

PUBLIC  main                         ;声明外部引用标号main

B      main ;main标号处开始执行

RSEG CODE:CODE                           

CODE32                              

main: MOV R0,#120

MOV R1,#96

Gcd: CMP R0,R1 ;比较两数的大小

BEQ Stop ;若是两数相等则跳到结束处

BLT Less ;若是R0<R1则跳到Less标号处

SUB R0,R0,R1 ;不然R0=R0-R1

B Gcd

Less: SUB R1,R1,R0 R1=R1-R0

 B Gcd

Stop: B Stop ;跳转到指令自己,程序中止运行

ENDMOD ;本程序模块结束

END ;本程序结束

3.8.2  循环程序

经过跳转指令还能够实现程序的循环结构。

例如:求n=1+2+…+10累加的和。

代码清单3.3

NAME SUM

PUBLIC  main                        

B       main

RSEG CODE                           

CODE32                              

main: MOV R0,#10

MOV R1,R0 ;利用R1寄存器作循环计数器

Loop: SUBS R1,R1,1 ;循环次数减1

ADD   R0,R0,R1

BNE Loop ;循环次数为0则结束循环

Stop: B Stop

ENDMOD

END

3.8.3  子程序调用

经过BL指令能够实现子程序调用,语法:BL子程序名。

在子程序的结束处,能够经过MOV  PCLR返回到主程序中。一般能够使用寄存器R0R3完成传递参数到子程序和从子程序返回运算的结果。

如下是使用BL指令调用子程序的汇编语言源程序的例子,该程序编写了一个在内存里拷贝字符串的子程序,而后在主程序里调用它。

代码清单3.4

       NAME  STRCPY                         

        PUBLIC  main                        

        B       main

        RSEG CODE                           

        CODE32                              

main LDR R1,=srcstr       ;R1指向源字符串

       LDR R0,=dststr  ;R0指向目标字符串

  BL strcopy  ;调用strcopy子程序

stop:   B stop  ;程序中止

strcopy:  ;子程序定义

        LDRB R2,[R1],#1   ;读一个字符到R2,并更新源字符地址

        STRB R2,[R0],#1   ;写一个字符,并更新目的字符地址

        CMP R2,#0  ;是否结束。以数字0为标志

        BNE strcopy   ;循环执行

 

        DATA  ;数据区

srcstr DCB "First string - source ",0

dststr DCB "Second string - destination ",0

        ENDMOD                               

        END        

3.8.4  查表法

查表法是编程中经常使用的一种技巧。当程序涉及到较多的数据、数据串或数据表格时,能够经过地址来对它们进行访问。一般有两种方法装载地址:(1)经过ADRADRL伪指令直接装载地址;(2)经过伪指令LDR Rd,=Label从数据表格中装载地址。

下面的程序设置了3个参数,arithfunc根据3个参数返回一个R0值。当R0=0时,R0=R1+R2;当R0=1时,R0=R1-R2;当R0>1时,R0=R1+R2。:

代码清单3.5

      NAME  JUMP                         

        PUBLIC  main                        

        B       main

   Num  EQU 2 ;跳转表格的入口数

        RSEG CODE                           

        CODE32                              

main  MOV  R0,#0        ;如下设置3个参数

        MOV R1,#3  

   MOV R2,#2

   BL arithfunc   ;调用子程序

stop:    B stop ;程序中止

arithfunc:  

        CMP R0,#Num   ;比较参数

        BHS Doadd  ;R0>=2,则执行加法

        ADR R3,jumptable   ;装载跳转表格标号地址

        LDR PC,[R3,R0,LSL #2]   ;跳到相应子程序入口地址处

Jumptable:

        DCD Doadd   ;Doadd子程序的入口地址

        DCD Dosub   ;Dosub子程序的入口地址

Doadd:  ADD R0,R1,R2   ;=0>1时执行的操做

   MOV PC,LR

Dosub:  SUB R0,R1,R2   ;=1时执行的操做

   MOV PC,LR

        ENDMOD                               

        END        

3.8.5  汇编语言与C/C++的混合编程

在应用系统的程序设计中,若全部的编程任务均用汇编语言来完成,其工做量是可想而知的,同时,不利于系统升级或应用软件移植,事实上,ARM体系结构支持C/C+以及与汇编语言的混合编程,在一个完整的程序设计的中,除了初始化部分用汇编语言完成之外,其主要的编程任务通常都用C/C++ 完成。

汇编语言与C/C++的混合编程一般有如下几种方式:

1. 在C/C++代码中嵌入汇编指令。

ARM C中,能够使用关键字__arm来标识一段汇编指令程序。格式以下:

 __asm

{

  汇编指令序列

}

便可在C语言源程序中直接执行ARM汇编指令。

2. 在汇编程序和C/C++的程序之间进行变量的互访。

3. 汇编程序、C/C++程序间的相互调用。

能够把汇编程序和C/C++程序中须要共享的变量或函数用PUBLICextern关键字分别声明为全局变量或全局函数,而后在其它程序文件中便可进行访问和调用。可是从好的编程风格来讲,最好尽可能减小全局变量和全局函数的使用。

混合编程中,必须遵照必定的调用规则,如物理寄存器的使用、参数的传递等。ARM专门为此制定了一个标准ATPCS(ARM-Thumb Procedure Call StandardARM-Thumb过程调用标准)。对于初学者来讲,这是很是烦琐的,在实际工做中也没有太多必要。

在实际的编程应用中,使用较多的方式是:系统程序的初始化部分用汇编语言完成,而后用C/C++完成主要的编程任务,程序在执行时首先完成初始化过程,而后跳转到C/C++程序代码中。汇编程序和C/C++程序之间通常没有参数的传递,也没有频繁的相互调用,所以,整个程序的结构显得相对简单,容易理解。

如下是一个这种结构程序的基本示例。该程序很是简单,创建一个工程asm_c.eww,工程中包括一个汇编语言程序文件init.s79和一个C语言程序文件hello.c

代码清单3.6——init.s79文件

        NAME INIT

        PUBLIC  main                                          

        EXTERN  Main                           ;声明引入C程序的Main()函数

   B main

        RSEG CODE                                     

        CODE32                                         

main:

        NOP               ;此处能够插入用户本身编写的系统初始化代码

 

        B Main                                 ;转向C语言程序

        ENDMOD                                                  

        END     

代码清单3.7——hello.c文件:

#include <stdio.h>

/*注意此处C语言程序的入口函数是大小写敏感的Main()函数,而不是经常使用的main()函数。这是为了跟汇编程序中的main入口区别开,以避免形成工程有两个程序入口。*/

int Main(void)

{

   printf("Hello, world!\n");

}

3.9  ARM汇编语言编写系统启动程序

基于ARM内核的芯片多数为复杂的片上系统,这种复杂系统里的多数硬件模块都是能够配置的,须要由软件来设置其须要的工做状态。因为C语言具备模块性和可移植性的特色,大部分基于ARM的应用系统程序都采用C语言编写。可是当系统复位启动时,在进入C语言的main函数以前,须要有一段启动程序来完成对存储器配置、地址重映射和ARM芯片内部集成外围功能初始化等工做。这类工做直接面对处理器内核和硬件控制器进行编程,用C语言较难实现,所以通常采用汇编语言编写。

3.9.1  编写启动程序的通常规则

ARM内核的处理器在复位后,从0x00000000地址处开始读取指令。实现启动最简单的方法是将应用程序放在映射空间地址为0ROM中。这样当执行第1条指令时,应用程序就从0x00000000处开始执行。但这种方法有不少缺点:ROM的存储宽度较小且速度较慢,会下降系统启动和处理器对异常处理的速度;异常向量表放在ROM中,程序将没法修改向量表,所以常将地址为0的空间映射成RAM,但RAM中的程序掉电没法保存,所以必须将ROM映射为0地址,以保证有效的复位向量,而后再使用重映射命令将RAM映射为0地址,ROM映射到其余地址空间,并将异常向量从ROM复制到RAM中。

编写启动程序应遵循如下通常规则:

1. 设置入口指针

启动程序首先必须定义入口指针,并且整个应用程序只有一个入口指针,一般应用程序的入口地址为0

2. 设置异常向量

基于ARM7TDMI内核的处理器共支持7种异常,异常处理地址存放在地址0处的异常向量表中,共8×4字节的空间。异常向量表的内容参见2.4.2节。

异常向量表一般放在存储器底部,每一个异常分配4个字节的空间。每一个向量入口包含一条跳转指令或加载PC的指令,以执行适当的转移到具体的异常处理程序。若是ROM定位于0地址,则向量表由一系列固定的用以指向每一个异常的指令组成;不然向量必须被动态初始化。能够在启动程序中添加一段代码,使其在运行时将向量表拷贝到0地址开始的存储器空间。对于没有使用的异常,使其指向一个只含返回指令的哑函数,以防止错误异常引发系统混乱。

3. 初始化片内集成外围功能

因为ARM公司仅设计内核并出售给其它半导体厂商,不一样的厂商购买内核受权后加入本身的外围功能,从而致使ARM核处理器芯片丰富多样,但也使得不一样芯片的启动代码在这一部分差异很大。编写这一部分时应根据芯片和应用系统要求对它们进行合适的初始化。比较重要的操做通常有:外部总线接口的初始化、配置时钟锁相环、配置中断控制器、禁用看门狗电路等。

4. 初始化存储系统

有些ARM核芯片可经过对寄存器编程来初始化系统存储器,而对于较复杂系统一般由存储管理单元MMU来管理内存空间。为正确运行应用程序,在初始化期间应将系统须要读写的数据和变量从ROM拷贝到RAM中;一些要求快速响应的程序,例如中断处理程序,也须要在RAM中运行;若是使用Flash,对Flash的擦除和写入操做也必定要在RAM中运行。

5. 初始化堆栈寄存器

系统堆栈初始化取决于用户使用了哪些中断,以及系统须要处理哪些错误类型。通常来讲管理模式堆栈必须初始化。若是使用IRQ中断,则IRQ堆栈必须初始化,而且必须在容许中断以前进行。若是使用FIQ中断,则FIQ堆栈也必须初始化,而且必须在容许中断以前进行。通常在简单的嵌入式系统中不使用停止状态堆栈和未定义指令堆栈,但为了调试方便仍是将其初始化。若是系统使用DRAM或其它外设,还须要设置相关寄存器,以肯定其刷新频率、数据总线宽度等信息。

6. 改变处理器模式和状态

此时能够经过清除CPSR寄存器中的中断控制位来容许中断,这里是安全开启中断的最先地方。这个阶段处理器仍处于管理模式下。若是程序须要在用户模式下运行,能够在此处切换到用户模式并初始化用户模式堆栈指针。

7. 跳转到C语言主程序

在从启动程序跳转到C语言程序的main函数以前,还须要初始化数据存储空间。一般是加入一段循环代码对数据存储空间清0。这样作的主要缘由是C语言中没有初值的变量默认值均为0。已经初始化变量的初值必须从ROM中复制到RAM中,其它变量的初值必须为0

3.9.2  IAR EWARM软件包给出的通常启动程序

下面给出了IAR EWARM软件包提供的通常启动程序代码,实际应用中能够根据具体芯片及应用系统要求进行适当修改,以适应不一样场合的须要。

代码清单3.8——IAR EWARM启动代码

;-----------------------------------------------------------------------------

; 文件中标号的命名规则:

;  ?xxx   - 仅能由汇编语言访问的外部标号

;  __xxx  - 可由C语言访问或定义的外部标号

;  xxx   - 单个模块中的局部标号(注意,本文件包含多个模块)

;  main   - 用户程序的起点

;---------------------------------------------------------------

; 适用于整个文件的宏和模式定义

;---------------------------------------------------------------

; 模式,对应于CPSR寄存器的05

MODE_BITS DEFINE 0x1F ; 用于CPSR模式的位屏蔽

USR_MODE DEFINE 0x10 ; 用户模式

FIQ_MODE DEFINE 0x11 ; FIQ模式

IRQ_MODE DEFINE 0x12 ; IRQ模式

SVC_MODE DEFINE 0x13 ; 管理模式

ABT_MODE DEFINE 0x17 ; 停止模式

UND_MODE DEFINE 0x1B ; 未定义指令模式

SYS_MODE DEFINE 0x1F ; 系统模式

;---------------------------------------------------------------

; ?RESET

; 复位向量。一般INTVEC段被连接到地址0。为程序调试方便,也能够放在其它地址

;---------------------------------------------------------------

MODULE ?RESET

COMMON INTVEC:CODE:NOROOT(2)

PUBLIC  __program_start

EXTERN ?cstartup

EXTERN undef_handler, swi_handler, prefetch_handler

EXTERN data_handler, irq_handler, fiq_handler

        CODE32 ; 复位后始终为ARM模式

org 0x00

__program_start

ldr pc,[pc,#24] ; 绝对跳转地址范围为4GB

; ldr b,?cstartup ; 相对跳转容许重映射,限于32MB

; 能够去掉如下指令前的注释分号来容许异常向量

; 也能够在C语言中采用预编译命令“#pragma vector”

org 0x04

; ldr pc,[pc,#24] ; 跳转到undef_handler

org 0x08

; ldr pc,[pc,#24] ; 跳转到swi_handler

org 0x0c

; ldr pc,[pc,#24] ; 跳转到prefetch_handler

org 0x10

; ldr pc,[pc,#24] ; 跳转到data_handler

org 0x18

; ldr pc,[pc,#24] ; 跳转到irq_handler

org 0x1c

; ldr pc,[pc,#24] ; 跳转到fiq_handler

; 用于ldr pc”指令的常数表入口定位于0x20

; 异常向量能够用C语言的预编译命令“#pragma vector”指定,也能够

; 在如下dc32指令后面填入向量地址。向量地址为ARM向量号+20

org 0x20

         dc32 ?cstartup

org 0x24

;         dc32 undef_handler

org 0x28

;         dc32 swi_handler

org 0x2c

;         dc32 prefetch_handler

org 0x30

;         dc32 data_handler

org 0x38

;         dc32 irq_handler

org 0x3c

;         dc32 fiq_handler

LTORG

; ENDMOD __program_start

        ENDMOD

;---------------------------------------------------------------

; ?CSTARTUP

;---------------------------------------------------------------

MODULE ?CSTARTUP

RSEG IRQ_STACK:DATA(2)

RSEG ABT_STACK:DATA:NOROOT(2)

RSEG UND_STACK:DATA:NOROOT(2)

RSEG FIR_STACK:DATA:NOROOT(2)

RSEG SVC_STACK:DATA:NOROOT(2)

RSEG CSTACK:DATA(2)

RSEG ICODE:CODE:NOROOT(2)

PUBLIC ?cstartup

EXTERN ?main

; 从这里开始执行

; 复位后为ARM管理模式,禁止中断

CODE32

?cstartup

; 须要时在这里加入创建堆栈指针以前的初始化指令

; 初始化堆栈指针

; 如下方式可用于任何异常堆栈:FIQ, IRQ, SVC, ABT, UND, SYS.

; 用户模式使用与SYS模式相同的堆栈

; 堆栈段必须在连接器命令文件中定义,而且已经在上面声明

        mrs r0,cpsr             ; 原PSR值

        bic r0,r0,#MODE_BITS  ; 清除模式位

        orr   r0,r0,#IRQ_MODE   ; 置IRQ模式位

        msr   cpsr_c,r0           ; 改变模式

        ldr sp,=SFE(IRQ_STACK)&0xFFFFFFF8 ; IRQ_STACK结束

        bic   r0,r0,#MODE_BITS  ; 清除模式位

        orr   r0,r0,#ABT_MODE  ; 置Abort模式位

        msr   cpsr_c,r0          ; 改变模式

        ldr sp,=SFE(ABT_STACK)&0xFFFFFFF8  ; ABT_STACK结束

        bic   r0,r0,#MODE_BITS  ; 清除模式位

        orr   r0,r0,#SVC_MODE   ; 置Supervisor模式位

        msr   cpsr_c,r0           ; 改变模式

        ldr sp,=SFE(SVC_STACK) & 0xFFFFFFF8  ; SVC_STACK结束

        bic   r0,r0,#MODE_BITS   ; 清除模式位

        orr   r0,r0,#UND_MODE   ; 置Undefined模式位

        msr   cpsr_c,r0            ; 改变模式

        ldr sp,=SFE(UND_STACK) & 0xFFFFFFF8   ; FIR_STACK结束

        bic   r0,r0,#MODE_BITS    ; 清除模式位

        orr   r0,r0,#FIQ_MODE      ; 置FIR模式位

        msr   cpsr_c,r0              ; 改变模式

        ldr sp,=SFE(FIR_STACK) & 0xFFFFFFF8     ; FIR_STACK结束

        bic   r0,r0,#MODE_BITS     ; 清除模式位

        orr   r0,r0,#SYS_MODE     ; 置System模式位

        msr   cpsr_c,r0              ; 改变模式

        ldr sp,=SFE(CSTACK) & 0xFFFFFFF8      ; CSTACK结束

#ifdef __ARMVFP__

; 容许VFP协处理器

        mov   r0, #0x40000000     ; VFPEN位

        fmxr   fpexc, r0             ; FPEXC, 清除其它

; 将缓冲区清0以禁止下溢出。为知足IEEE 754标准,应删除该指令并安装合适的异常句柄

        mov   r0, #0x01000000  ; VFPFZ位

        fmxr   fpscr, r0               ; FPSCR, 清除其它

#endif

; 在这里能够添加更多的用户自定义初始化指令

; 跳转到?main标号的地方,继续IAR系统的启动程序

         ldr    r0,=?main

         bx    r0

         LTORG

         ENDMOD

         END

习题

3.1  ARM7TDMI有几种寻址方式?LDR R1,[R0,#0x04]属于哪一种寻址方式?

3.2  ARM指令的条件码有多少个?默认条件码是什么?

3.3  ARM指令中第二个操做数有哪几种形式?

3.4  请指出MOV指令与LDR加载指令的区别及用途.

3.5  CMP指令的功能是什么?写一个程序,判断R1的值是否大于0x30,是则将R1减去0x30

3.6  调用子程序是用B仍是用BL指令?请写出返回子程序的指令。

3.7  ARM状态与Thumb状态的切换指令是什么?请举例说明。

3.8  Thumb状态与ARM状态的寄存器有区别吗?Thumb指令对哪些寄存器的访问受到必定限制?

3.9  Thumb指令集的堆栈入栈、出栈指令是哪两条?

3.10 把下面的C代码转换成汇编代码。数组ab分别存放在以0x40000x5000为起始地址的存储区内,类型为long型(32位)。

fori=0;i<8;i++

{

  a[i] = b[7-i];

}

3.11 编写程序,将R1的高8位传送到R2的低8

3.12 编写一段64位加法运算的程序,要求知足:[R1:R0]+[R3:R2],结果存入[R1:R0]

3.13 编写程序将地址0x0000 10000x0000 1030的数据所有搬迁到0x0000 20000x0000 2030的区域中,并将源数据区清零。


4LPC2400系列处理器原理

处理器的“体系结构”指从程序员角度观察到的处理器的组织方式,因此又称为处理器的编程模型。其主要内容为处理器内的寄存器组织、对存储器的寻址方式、指令系统等。本章将介绍ARM7TDMI程序员模型、工做状态与工做模式、ARM和Thumb状态的寄存器组织、存储器组织结构、异常及协处理器接口等一些基本概念。本章还要讲述ARM的编程基础,如ARM微处理器的基本工做原理、与程序设计相关的基本技术细节等。

4.1  LPC2400系列处理器简介

4.1.1  LPC2400系列处理器特性

LPC2400系列处理器包括LPC2468/LPC2470/LPC2478等多款芯片,是基于支持实时仿真和跟踪的16/32位ARM7TDMI-S内核的微控制器,它与全部NXP LPC 2000处理器具备相同的存储器映射、中断向量控制、Flash编程和更新机制,以及调试和仿真功能。LPC2468/LPC2478的512KB大容量嵌入式高速Flash存储器具备128位宽度的存储器接口和独特的加速结构,使得32位代码可以在最高时钟频率72MHz下运行。16位Thumb模式能够将代码规模下降30%以上,而性能损失却很小。LPC2470/LPC2478芯片内部还集成了LCD接口支持(最高1024×768像素、15阶灰度单色和每像素24位真彩色TFT面板),使得这两款芯片能够普遍应用于各类手持式设备中

LPC2400系列处理器拥有丰富的片上资源和外设接口。这一系列芯片的共同特性有:

-ARM7TDMI-S内核,最高72MHz主频;

-98KB的片内静态存储器,其中64KB的片内SRAM,16KB SRAM用于以太网,16KB SRAM用于DMA控制器(也可用于USB控制器),2KB SRAM用于RTC实时时钟;

-512KB片内Flash程序存储器,片内Boot实现IAP和ISP片内Flash编程;

-可配置的外部存储器接口,最多支持8个Bank,支持外部RAM、ROM和Flash存储器扩展,每一个Bank最大可支持到256MB,可支持8/16/32位字宽;

-高级向量中断控制器,支持32个向量中断,可配置优先级和向量地址;

-通用AHB DMA控制器(GPDMA)能够用于支持SSP、I2S和SD/MMC接口;

-10/100M以太网MAC接口;

-多个串行接口,包括4路UART、3路I2C串行总线接口和1个SPI接口;

-10位A/D和D/A转换器,转换时间低至2.44微秒;

-USB device/host/OTG接口;

-2个CAN总线接口;

-4个32位的定时器、2个PWM脉冲调制单元(每一个6路输出)、实时时钟和看门狗;

-160个高速GPIO端口(可承受5V电压),4个独立外部中断引脚;

-标准ARM调试接口,兼容各类现有的调试工具;

-片内晶振频率范围1~24MHz;

-4个低功耗模式:空闲、睡眠、掉电和深度掉电模式;

-供电电压3.3V(3.0V~3.6V)。

LPC2400系列芯片中,LPC2468是LPC2478的无LCD控制器版本,LPC2470是LPC2478的无片内Flash版本,芯片的大多数特性是彻底相同的。因此在后面的章节中,本书一概采用LPC2478芯片为例进行讲解,请读者在实际工做中注意具体芯片的差异。

4.1.2 LPC2400系列处理器结构

LPC2400系列处理器包含一个支持仿真的ARM7TDMI-S CPU、与片内存储器控制器接口的ARM7局部总线、与中断控制器接口的AMBA高性能总线(AHB总线)和链接片内外设功能的AMBA外设总线(APB总线)。存储模式为小端模式。

AHB总线和APB总线都是ARM公司推出的AMBA片上总线规范的一部分。AHB(Advanced High performance Bus)系统总线主要用于高性能模块(如CPU、DMA和DSP等)之间的链接,通常用于片内高性能高速度的外设,如:外部存储器、USB接口、DMA控制器、以太网控制器、LCD液晶屏控制器以及高速GPIO控制器等。LPC2400中的AHB外设一共分配了2MB的地址范围,它位于4GB ARM存储器空间的最顶端。每一个AHB外设都分配了16KB的地址空间。

LPC2400的外设功能模块都链接到APB总线。APB(Advanced Peripheral Bus)外围总线主要用于低带宽的周边外设之间的链接,如:UART、I2C、SPI、I2S、A/D、D/A、CAN等等。APB总线与AHB总线之间经过AHB到APB的桥相连。APB外设也分配了2MB的地址范围,每一个APB外设在APB地址空间内都分配了16KB的地址空间。

片内外设与器件引脚的链接由引脚链接模块控制。软件能够经过控制该模块让引脚与特定的片内外设相链接。

LPC2400的结构框图如图4.1所示。


4.1 LPC2400结构框图

4.2  处理器引脚配置

4.2.1引脚配置

LPC2400系列处理器共有208个引脚,通常提供两种封装形式:LQFP208和TFBGA208。其管脚封装如图4.2所示。

 

LQFP208 FBGA208

4.2 LPC2400系列处理器管脚封装图

LQFP指封装本体厚度为1.4mm的薄型QFP(四侧引脚扁平封装quad flat package),它是一种表面贴装型封装,引脚从四个侧面引出呈L型,每一个侧面52个引脚,引脚号分别为1~5二、53~10四、105~15六、157~208。FBGA是塑料封装的BGA(Ball Grid Array Package),即球栅阵列封装,其引脚都在芯片底部,用英文字母行和数字列标识。因为LPC2400系列处理器在实际使用中更多使用QFP封装,本节引脚介绍以QFP封装为准。

从功能上,LPC2400的208个引脚分为P0口、P1口、P2口、P3口、P4口,以及电源、复位、晶振和其它管脚几部分。下面对这几个部分分别进行介绍。

1. P0口:  P0口是一个32位的双向多功能I/O口,每位的方向可单独控制,且每位的功能取决于管脚链接模块的管脚功能选择。LPC2400的P0口管脚描述如表4.1所示。

4.1 LPC2400的P0口管脚描述

管脚名称

引脚号

类型

描  述

 

P0[0]

 

94

I/O

P0[0]:GPIO口

I

RD1:CAN1接收器输入

O

TXD3:UART3发送输出端

I/O

SDA1:I2C1数据输入/输出

 

P0[1]

 

96

I/O

P0[1]:GPIO口

O

TD1:CAN1发送器输出

I

RXD3:UART3接收输入端

I/O

SCL1:I2C1时钟输入/输出

 

P0[2]

 

202

I/O

P0[2]:GPIO口

O

TXD0:UART0发送输出端

 

P0[3]

 

204

I/O

P0[3]:GPIO口

I

RXD0:UART0接收输入端

 

P0[4]

 

168

I/O

P0[4]:GPIO口

I/O

I2SRX_CLK:I2S总线接收时钟

I

RD2:CAN2接收输入端

I

CAP2[0]:Timer2的捕获输入通道0

 

P0[5]

 

166

I/O

P0[5]:GPIO口

I/O

I2SRX_WS:I2S总线接收字选择

I

TD2:CAN2发送输出端

I

CAP2[1]:Timer2的捕获输入通道1

 

P0[6]

 

164

I/O

P0[6]:GPIO口

I/O

I2SRX_SDA:I2S总线数据接收

I/O

SSEL1:SSP1从机选择

O

MAT2[0]:Timer2的匹配输出通道0

 

P0[7]

 

162

I/O

P0[7]:GPIO口

I/O

I2STX_CLK:I2S总线发送时钟

I/O

SCK1:SSP1串行时钟

O

MAT2[1]:Timer2的匹配输出通道1

 

P0[8]

 

160

I/O

P0[8]:GPIO口

I/O

I2STX_WS:I2S总线发送字选择

I/O

MISO1:SSP1主机输入从机输出

O

MAT2[2]:Timer2的匹配输出通道2

 

P0[9]

 

158

I/O

P0[9]:GPIO口

I/O

I2STX_SDA:I2S总线数据发送

I/O

MOSI1:SSP1主机输出从机输入

O

MAT2[3]:Timer2的匹配输出通道3

 

P0[10]

 

98

I/O

P0[10]:GPIO口

O

TXD2:UART2发送输出端

I/O

SDA2:I2C2数据输入/输出

O

MAT3[0]:Timer3的匹配输出通道0

 

P0[11]

 

100

I/O

P0[11]:GPIO口

I

RXD2:UART2接收输入端

I/O

SCL2:I2C2时钟输入/输出

O

MAT3[1]:Timer3的匹配输出通道1

 

P0[12]

 

41

I/O

P0[12]:GPIO口

O

USB_PPWR2:USB端口2端口电源使能

I/O

MISO1:SSP1主机输入从机输出

I

AD0[6]:A/D转换器0输入6

 

P0[13]

 

45

I/O

P0[13]:GPIO口

O

USB_UP_LED2:USB端口2LED

I/O

MOSI1:SSP1主机输出从机输入

I

AD0[7]:A/D转换器0输入7

 

P0[14]

 

69

I/O

P0[14]:GPIO口

O

USB_HSTEN2:USB端口2主机使能

O

USB_CONNECT2:USB端口2软件链接控制

I/O

SSEL1:SSP1从机选择

 

P0[15]

 

128

I/O

P0[15]:GPIO口

O

TXD1:UART1发送输出端

I/O

SCK0:SSP0串行时钟

I/O

SCK:SPI串行时钟

 

P0[16]

 

130

I/O

P0[16]:GPIO口

I

RXD1:UART1接收输入端

I/O

SSEL0:SSP0从机选择

I/O

SSEL:SPI从机选择

 

P0[17]

 

126

I/O

P0[17]:GPIO口

I

CTS1:UART1清除发送输入端

I/O

MISO0:SSP0主机输入从机输出

I/O

MISO:SPI主机输入从机输出

 

P0[18]

 

124

I/O

P0[18]:GPIO口

I

DCD1:UART1数据载波检测输入端

I/O

MOSI0:SSP0主机输出从机输入

I/O

MOSI:SPI主机输出从机输入

 

P0[19]

 

122

I/O

P0[19]:GPIO口

I

DSR1:UART1数据设置就绪端

O

MCICLK:SD/MMC接口时钟输出线

I/O

SDA1:I2C1数据输入/输出

 

P0[20]

 

120

I/O

P0[20]:GPIO口

O

DTR1:UART1数据终止就绪端

I/O

MCICMD:SD/MMC接口命令线

I/O

SCL1:I2C1时钟输入/输出

 

P0[21]

 

118

I/O

P0[21]:GPIO口

I

RI1:UART1铃响指示输入端

O

MCIPWR:SD/MMC电源供应使能

I

RD1:CAN1接收输入端

 

P0[22]

 

116

I/O

P0[22]:GPIO口

O

RTS1:UART1请求发送输出端

I/O

MCIDAT0:SD/MMC接口数据线0

O

TD1:CAN1发送输出端

 

P0[23]

 

18

I/O

P0[23]:GPIO口

I

AD0[0]:A/D转换器0输入0

I/O

I2SRX_CLK:I2S总线接收时钟

I

CAP3[0]:Timer3的捕获输入通道0

 

P0[24]

 

16

I/O

P0[24]:GPIO口

I

AD0[1]:A/D转换器0输入1

I/O

I2SRX_WS:I2S总线字选择

I

CAP3[1]:Timer3的捕获输入通道1

 

P0[25]

 

14

I/O

P0[25]:GPIO口

I

AD0[2]:A/D转换器0输入2

I/O

I2SRX_SDA:I2S总线数据接收

O

TXD3:UART3发送输出端

 

P0[26]

 

12

I/O

P0[26]:GPIO口

I

AD0[3]:A/D转换器0输入3

O

AOUT:D/A转换器输出

I

RXD3:UART3接收输入端

 

P0[27]

 

50

I/O

P0[27]:GPIO口

I/O

SDA0:I2C0数据输入/输出

 

P0[28]

 

48

I/O

P0[28]:GPIO口

I/O

SCL0:I2C0时钟输入/输出

 

P0[29]

 

61

I/O

P0[29]:GPIO口

I/O

USB_D+1:USB端口1双向D+线

 

P0[30]

 

62

I/O

P0[30]:GPIO口

I/O

USB_D-1:USB端口1双向D-线

 

P0[31]

 

51

I/O

P0[31]:GPIO口

I/O

USB_D+2:USB端口2双向D+线

2. P1口:  P1口也是一个32位的双向多功能I/O口,每位的方向可单独控制,且每位的功能取决于管脚链接模块的管脚功能选择。LPC2400的P1口管脚描述如表4.2所示。

4.2 LPC2400的P1口管脚描述

管脚名称

引脚号

类型

描  述

 

P1[0]

 

196

I/O

P1[0]:GPIO口

O

ENET_TXD0:以太网发送数据0(RMII/MII接口)

 

P1[1]

 

194

I/O

P1[1]:GPIO口

O

ENET_TXD1:以太网发送数据1(RMII/MII接口)

 

P1[2]

 

185

I/O

P1[2]:GPIO口

O

ENET_TXD2:以太网发送数据2(RMII/MII接口)

O

MCICLK:SD/MMC接口时钟输出线

O

PWM0[1]:脉宽调制器0输出1

 

P1[3]

 

177

I/O

P1[3]:GPIO口

O

ENET_TXD3:以太网发送数据3(RMII/MII接口)

O

MCICMD:SD/MMC接口命令线

O

PWM0[2]:脉宽调制器0输出2

 

P1[4]

 

192

I/O

P1[4]:GPIO口

O

ENET_TX_EN:以太网发送数据使能(RMII/MII接口)

 

P1[5]

 

156

I/O

P1[5]:GPIO口

O

ENET_TX_ER:以太网发送数据出错(MII接口)

O

MCIPWR:SD/MMC电源供应使能

O

PWM0[3]:脉宽调制器0输出3

 

P1[6]

 

171

I/O

P1[6]:GPIO口

I

ENET_TX_CLK:以太网发送时钟(MII接口)

I/O

MCIDAT0:SD/MMC接口数据线0

O

PWM0[4]:脉宽调制器0输出4

 

P1[7]

 

153

I/O

P1[7]:GPIO口

I

ENET_COL:以太网冲突检测(MII接口)

I/O

MCIDAT1:SD/MMC接口数据线1

O

PWM0[5]:脉宽调制器0输出5

 

P1[8]

 

190

I/O

P1[8]:GPIO口

I

ENET_CRS_DV/ENET_CRS:以太网载波检测/数据有效(RMII接口)/以太网载波检测(MII接口)

 

P1[9]

 

188

I/O

P1[9]:GPIO口

I

ENET_RXD0:以太网接收数据0(RMII/MII接口)

 

P1[10]

 

186

I/O

P1[10]:GPIO口

I

ENET_RXD1:以太网接收数据1(RMII/MII接口)

 

P1[11]

 

163

I/O

P1[11]:GPIO口

I

ENET_RXD2:以太网接收数据2(RMII/MII接口)

I/O

MCIDAT2:SD/MMC接口数据线2

O

PWM0[6]:脉宽调制器0输出6

 

P1[12]

 

157

I/O

P1[12]:GPIO口

I

ENET_RXD3:以太网接收数据3(RMII/MII接口)

I/O

MCIDAT3:SD/MMC接口数据线3

I

PCAP0[0]:脉宽调制器0捕获输入通道0

 

P1[13]

 

147

I/O

P1[13]:GPIO口

I

ENET_RX_DV:以太网接收数据有效(MII接口)

 

P1[14]

 

184

I/O

P1[14]:GPIO口

I

ENET_RX_ER:以太网接收错误(MII接口)

 

P1[15]

 

182

I/O

P1[15]:GPIO口

I

ENET_REF_CLK/ENET_RX_CLK:以太网参考时钟(RMII接口)/以太网接收时钟(MII接口)

 

P1[16]

 

180

I/O

P1[16]:GPIO口

I

ENET_MDC:以太网MIIM时钟

 

P1[17]

 

178

I/O

P1[17]:GPIO口

I/O

ENET_MDIO:以太网MI数据输入输出

 

P1[18]

 

66

I/O

P1[18]:GPIO口

O

USB_UP_LED1:USB端口1LED

O

PWM1[1]:脉宽调制器1输出1

I

CAP1[0]:Timer1捕获输入通道0

 

P1[19]

 

68

I/O

P1[19]:GPIO口

O

USB_TX_E1:USB端口1发送使能信号(OTG收发器)

O

USB_PPWR1:USB端口1端口电源使能信号

I

CAP1[1]:Timer1捕获输入通道1

 

P1[20]

 

70

I/O

P1[20]:GPIO口

O

USB_TX_DP1:USB端口1D+数据发送(OTG收发器)

O

PWM1[2]:脉宽调制器1输出2

I/O

SCK0:SSP0串行时钟

 

P1[21]

 

72

I/O

P1[21]:GPIO口

O

USB_TX_DM1:USB端口1D-数据发送(OTG收发器)

O

PWM1[3]:脉宽调制器1输出3

I/O

SSEL0:SSP0从机选择

 

P1[22]

 

74

I/O

P1[22]:GPIO口

I

USB_RCV1:USB端口1差分数据接收(OTG收发器)

I

USB_PWRD1:USB端口1电源状态(主机电源开关)

O

MAT1[0]:Timer1匹配输出通道0

 

P1[23]

 

76

I/O

P1[23]:GPIO口

I

USB_RX_DP1:USB端口1D+数据接收(OTG收发器)

O

PWM1[4]:脉宽调制器1输出4

I/O

MISO0:SSP0主机输入从机输出

 

P1[24]

 

78

I/O

P1[24]:GPIO口

I

USB_RX_DM1:USB端口1D-数据接收(OTG收发器)

O

PWM1[5]:脉宽调制器1输出5

I/O

MOSI0:SSP0主机输出从机输入

 

P1[25]

 

80

I/O

P1[25]:GPIO口

O

USB_LS1:USB端口1低速状态(OTG收发器)

O

USB_HSTEN1:USB端口1主机使能状态

O

MAT1[1]:Timer1匹配输出通道1

 

P1[26]

 

82

I/O

P1[26]:GPIO口

O

USB_SSPND1:USB端口1总线悬挂状态(OTG收发器)

O

PWM1[6]:脉宽调制器1输出6

I

CAP0[0]:Timer0捕获输入通道0

 

P1[27]

 

88

I/O

P1[27]:GPIO口

I

USB_INT1:USB端口1OTG ATX中断(OTG收发器)

I

USB_OVRCR1:USB端口1过流状态

I

CAP0[1]:Timer0捕获输入通道1

 

P1[28]

 

90

I/O

P1[28]:GPIO口

I/O

USB_SCL1:USB端口1I2C串行时钟(OTG收发器)

I

PCAP1[0]:脉宽调制器1捕获输入通道0

O

MAT0[0]:Timer0匹配输出通道0

 

P1[29]

 

92

I/O

P1[29]:GPIO口

I/O

USB_SDA1:USB端口1I2C串行数据(OTG收发器)

I

PCAP1[1]:脉宽调制器1捕获输入通道1

O

MAT0[1]:Timer0匹配输出通道1

 

P1[30]

 

42

I/O

P1[30]:GPIO口

I

USB_PWRD2:USB端口2电源状态

I

VBUS:指示USB总线当前电源。注意:当USB复位时这个信号必须为高电平

I

AD0[4]:A/D转换器0输入4

 

P1[31]

 

40

I/O

P1[31]:GPIO口

I

USB_OVRCR2:USB端口2过流状态

I/O

SCK1:SSP1串行时钟

I

AD0[5]:A/D转换器0输入5

3. P2口:  P2口也是一个32位的双向多功能I/O口,每位的方向可单独控制,且每位的功能取决于管脚链接模块的管脚功能选择。LPC2400的P2口管脚描述如表4.3所示。

4.3 LPC2400的P2口管脚描述

管脚名称

引脚号

类型

描  述

 

P2[0]

 

154

I/O

P2[0]:GPIO口

O

PWM1[1]:脉宽调制器1输出1

O

TXD1:UART1发送输出端

O

TRACECLK/LCDPWR:跟踪时钟/LCD面板电源使能

 

P2[1]

 

152

I/O

P2[1]:GPIO口

O

PWM1[2]:脉宽调制器1输出2

I

RXD1:UART1接收输入端

O

PIPESTAT0/LCDLE:流水线状态位0/LCD行结束信号

 

P2[2]

 

150

I/O

P2[2]:GPIO口

O

PWM1[3]:脉宽调制器1输出3

I

CTS1:UART1清除发送输入端

O

PIPESTAT1/LCDCP:流水线状态位1/LCD面板时钟

 

P2[3]

 

144

I/O

P2[3]:GPIO口

O

PWM1[4]:脉宽调制器1输出4

I

DCD1:UART1数据载波检测输入端

O

PIPESTAT2/LCDFP:流水线状态位2/LCD帧脉冲(STN)垂直同步脉冲(TFT)

 

P2[4]

 

142

I/O

P2[4]:GPIO口

O

PWM1[5]:脉宽调制器1输出5

I

DSR1:UART1数据设置就绪端

O

TRACESYNC/LCDAC:跟踪同步/LCD交流斜线驱动(STN)数据使能输出(TFT)

 

P2[5]

 

140

I/O

P2[5]:GPIO口

O

PWM1[6]:脉宽调制器1输出6

O

DTR1:UART1数据终止就绪端

O

TRACEPKT0/LCDAC:跟踪分组位0/LCD行同步脉冲(STN)水平同步脉冲(TFT)

 

P2[6]

 

138

I/O

P2[6]:GPIO口

I

PCAP1[0]:脉宽调制器1捕获输入通道0

I

RI1:UART1响铃指示输入端

O

TRACEPKT1/LCD[0]/LCD[4]:跟踪分组位1/LCD数据

 

P2[7]

 

136

I/O

P2[7]:GPIO口

I

RD2:CAN2接收输入

O

RTS1:UART1请求发送输出端

O

TRACEPKT2/LCD[1]/LCD[5]:跟踪分组位1/LCD数据

 

P2[8]

 

134

I/O

P2[8]:GPIO口

O

TD2:CAN2发送输出

O

TXD2:UART2接收输入端

O

TRACEPKT3/LCD[2]/LCD[6]:跟踪分组位3/LCD数据

 

P2[9]

 

132

I/O

P2[9]:GPIO口

O

USB_CONNECT1:USB1软链接控制

I

RXD2:UART2接收输入

I

EXTINT0/LCD[3]/LCD[7]:外部触发中断输入/LCD数据

 

P2[10]

 

110

I/O

P2[10]:GPIO口

I

EINT0:外部中断0输入

 

P2[11]

 

108

I/O

P2[11]:GPIO口

I/O

EINT1:外部中断1输入/LCDCLKIN:LCD时钟

I/O

MCIDAT1:SD/MMC接口数据线1

I/O

I2STX_CLK:I2S传输时钟。

 

P2[12]

 

106

I/O

P2[12]:GPIO口

I/O

EINT2:外部中断2输入/输出:LCD[4]/LCD[3]/LCD[8]/LCD[18]

I/O

MCIDAT2:SD/MMC接口数据线2

I/O

I2STX_WS:I2S传输字选择。

 

P2[13]

 

102

I/O

P2[13]:GPIO口

I/O

EINT3:外部中断3输入/输出:LCD[5]/LCD[9]/LCD[19]

I/O

MCIDAT3:SD/MMC接口数据线3

I/O

I2STX_SDA:I2S传输数据。

 

P2[14]

 

91

I/O

P2[14]:GPIO口

O

CS2:低电平有效片选信号2

I

CAP2[0]:Tmer2捕获输入通道0

I/O

SDA1:I2C1数据输入/输出

 

P2[15]

 

99

I/O

P2[15]:GPIO口

O

CS3:低电平有效片选信号3

I

CAP2[1]:Tmer2捕获输入通道1

I/O

SCL1:I2C1时钟输入/输出

 

P2[16]

 

87

I/O

P2[16]:GPIO口

O

CAS:低电平有效SDRAM列地址选择

 

P2[17]

 

95

I/O

P2[17]:GPIO口

O

RAS:低电平有效SDRAM行地址选择

 

P2[18]

 

59

I/O

P2[18]:GPIO口

O

CLKOUT0:SDRAM时钟0

 

P2[19]

 

67

I/O

P2[19]:GPIO口

O

CLKOUT1:SDRAM时钟1

 

P2[20]

 

73

I/O

P2[20]:GPIO口

O

DYCS0:SDRAM片选信号0

 

P2[21]

 

81

I/O

P2[21]:GPIO口

O

DYCS1:SDRAM片选信号1

 

P2[22]

 

85

I/O

P2[22]:GPIO口

O

DYCS2:SDRAM片选信号2

I

CAP3[0]:Timer3捕获输入通道0

I/O

SCK0:SSP0串行时钟

 

P2[23]

 

64

I/O

P2[23]:GPIO口

O

DYCS3:SDRAM片选信号3

I

CAP3[1]:Timer3捕获输入通道1

I/O

SSEL0:SSP0从机选择

 

P2[24]

 

53

I/O

P2[24]:GPIO口

O

CKEOUT0:SDRAM时钟使能信号0

 

P2[25]

 

54

I/O

P2[25]:GPIO口

O

CKEOUT1:SDRAM时钟使能信号1

 

P2[26]

 

57

I/O

P2[26]:GPIO口

O

CKEOUT2:SDRAM时钟使能信号2

O

MAT3[0]:Tmer3匹配输出通道0

I/O

MISO0:SSP0主机输入从机输出

 

P2[27]

 

47

I/O

P2[27]:GPIO口

O

CKEOUT3:SDRAM时钟使能信号3

O

MAT3[1]:Tmer3匹配输出通道1

I/O

MOSI0:SSP0主机输出从机输入

 

P2[28]

 

49

I/O

P2[28]:GPIO口

O

DQMOUT0:用于SDRAM和静态设备的数据掩码0

 

P2[29]

 

43

I/O

P2[29]:GPIO口

O

DQMOUT1:用于SDRAM和静态设备的数据掩码1

 

P2[30]

 

31

I/O

P2[30]:GPIO口

O

DQMOUT2:用于SDRAM和静态设备的数据掩码2

O

MAT3[2]:Tmer3匹配输出通道2

I/O

SDA2:I2C2数据输入/输出

 

P2[31]

 

39

I/O

P2[31]:GPIO口

O

DQMOUT3:用于SDRAM和静态设备的数据掩码3

O

MAT3[3]:Tmer3匹配输出通道3

I/O

SCL2:I2C2时钟输入/输出

4. P3口:  P3口也是一个32位的双向多功能I/O口,每位的方向可单独控制,且每位的功能取决于管脚链接模块的管脚功能选择。LPC2400的P3口管脚描述如表4.4所示。

4.4 LPC2400的P3口管脚描述

管脚名称

引脚号

类型

描  述

 

P3[0]

 

197

I/O

P3[0]:GPIO口

I/O

D0:外部存储器数据线0

 

P3[1]

 

201

I/O

P3[1]:GPIO口

I/O

D1:外部存储器数据线1

 

P3[2]

 

207

I/O

P3[2]:GPIO口

I/O

D2:外部存储器数据线2

 

P3[3]

 

3

I/O

P3[3]:GPIO口

I/O

D3:外部存储器数据线3

 

P3[4]

 

13

I/O

P3[4]:GPIO口

I/O

D4:外部存储器数据线4

 

P3[5]

 

17

I/O

P3[5]:GPIO口

I/O

D5:外部存储器数据线5

 

P3[6]

 

23

I/O

P3[6]:GPIO口

I/O

D6:外部存储器数据线6

 

P3[7]

 

27

I/O

P3[7]:GPIO口

I/O

D7:外部存储器数据线7

 

P3[8]

 

191

I/O

P3[8]:GPIO口

I/O

D8:外部存储器数据线8

 

P3[9]

 

199

I/O

P3[9]:GPIO口

I/O

D9:外部存储器数据线9

 

P3[10]

 

205

I/O

P3[10]:GPIO口

I/O

D10:外部存储器数据线10

 

P3[11]

 

208

I/O

P3[11]:GPIO口

I/O

D11:外部存储器数据线11

 

P3[12]

 

1

I/O

P3[12]:GPIO口

I/O

D12:外部存储器数据线12

 

P3[13]

 

7

I/O

P3[13]:GPIO口

I/O

D13:外部存储器数据线13

 

P3[14]

 

21

I/O

P3[14]:GPIO口

I/O

D14:外部存储器数据线14

 

P3[15]

 

28

I/O

P3[15]:GPIO口

I/O

D15:外部存储器数据线15

 

P3[16]

 

137

I/O

P3[16]:GPIO口

I/O

D16:外部存储器数据线16

O

PWM0[1]:脉宽调制器0输出1

O

TXD1:UART1发送输出端

 

P3[17]

 

143

I/O

P3[17]:GPIO口

I/O

D17:外部存储器数据线17

O

PWM0[2]:脉宽调制器0输出2

I

RXD1:UART1接收输入端

 

P3[18]

 

151

I/O

P3[18]:GPIO口

I/O

D18:外部存储器数据线18

O

PWM0[3]:脉宽调制器0输出3

I

CTS1:UART1清除发送输入端

 

P3[19]

 

161

I/O

P3[19]:GPIO口

I/O

D19:外部存储器数据线19

O

PWM0[4]:脉宽调制器0输出4

I

DCD1:UART1数据载波检测输入端

 

P3[20]

 

167

I/O

P3[20]:GPIO口

I/O

D20:外部存储器数据线20

O

PWM0[5]:脉宽调制器0输出5

I

DSR1:UART1数据设置就绪端

 

P3[21]

 

175

I/O

P3[21]:GPIO口

I/O

D21:外部存储器数据线21

O

PWM0[6]:脉宽调制器0输出6

O

DTR1:UART1数据终端准备就绪输出端

 

P3[22]

 

195

I/O

P3[22]:GPIO口

I/O

D22:外部存储器数据线22

I

PCAP0[0]:脉宽调制器0捕获输入通道0

I

RI1:UART1响铃指示输入端

 

P3[23]

 

65

I/O

P3[23]:GPIO口

I/O

D23:外部存储器数据线23

I

CAP0[0]:Timer0捕获输入通道0

I

PCAP1[0]:脉宽调制器1捕获输入通道0

 

P3[24]

 

58

I/O

P3[24]:GPIO口

I/O

D24:外部存储器数据线24

I

CAP0[1]:Timer0捕获输入通道1

O

PWM1[1]:脉宽调制器1输出1

 

P3[25]

 

56

I/O

P3[25]:GPIO口

I/O

D25:外部存储器数据线25

O

MAT0[0]:Tmer0匹配输出通道0

O

PWM1[2]:脉宽调制器1输出2

 

P3[26]

 

55

I/O

P3[26]:GPIO口

I/O

D26:外部存储器数据线26

O

MAT0[1]:Tmer0匹配输出通道1

O

PWM1[3]:脉宽调制器1输出3

 

P3[27]

 

203

I/O

P3[27]:GPIO口

I/O

D27:外部存储器数据线27

I

CAP1[0]:Timer1捕获输入通道0

O

PWM1[4]:脉宽调制器1输出4

 

P3[28]

 

5

I/O

P3[28]:GPIO口

I/O

D28:外部存储器数据线28

I

CAP1[1]:Timer1捕获输入通道1

O

PWM1[5]:脉宽调制器1输出5

 

P3[29]

 

11

I/O

P3[29]:GPIO口

I/O

D29:外部存储器数据线29

O

MAT1[0]:Tmer1匹配输出通道0

O

PWM1[6]:脉宽调制器1输出6

 

P3[30]

 

19

I/O

P3[30]:GPIO口

I/O

D30:外部存储器数据线30

O

MAT1[1]:Tmer1匹配输出通道1

O

RTS1:UART1请求发送输出端

 

P3[31]

 

25

I/O

P3[31]:GPIO口

I/O

D31:外部存储器数据线31

O

MAT1[2]:Tmer1匹配输出通道2

5. P4口:  P4口也是一个32位的双向多功能I/O口,每位的方向可单独控制,且每位的功能取决于管脚链接模块的管脚功能选择。LPC2400的P4口管脚描述如表4.5所示。

4.5 LPC2400的P4口管脚描述

管脚名称

引脚号

类型

描  述

 

P4[0]

 

75

I/O

P4[0]:GPIO口

I/O

A0:外部存储器地址线0

 

P4[1]

 

79

I/O

P4[1]:GPIO口

I/O

A1:外部存储器地址线1

 

P4[2]

 

83

I/O

P4[2]:GPIO口

I/O

A2:外部存储器地址线2

 

P4[3]

 

97

I/O

P4[3]:GPIO口

I/O

A3:外部存储器地址线3

 

P4[4]

 

103

I/O

P4[4]:GPIO口

I/O

A4:外部存储器地址线4

 

P4[5]

 

107

I/O

P4[5]:GPIO口

I/O

A5:外部存储器地址线5

 

P4[6]

 

113

I/O

P4[6]:GPIO口

I/O

A6:外部存储器地址线6

 

P4[7]

 

121

I/O

P4[7]:GPIO口

I/O

A7:外部存储器地址线7

 

P4[8]

 

1271

I/O

P4[8]:GPIO口

I/O

A8:外部存储器地址线8

 

P4[9]

 

131

I/O

P4[9]:GPIO口

I/O

A9:外部存储器地址线9

 

P4[10]

 

135

I/O

P4[10]:GPIO口

I/O

A10:外部存储器地址线10

 

P4[11]

 

145

I/O

P4[11]:GPIO口

I/O

A11:外部存储器地址线11

 

P4[12]

 

149

I/O

P4[12]:GPIO口

I/O

A12:外部存储器地址线12

 

P4[13]

 

155

I/O

P4[13]:GPIO口

I/O

A13:外部存储器地址线13

 

P4[14]

 

159

I/O

P4[14]:GPIO口

I/O

A14:外部存储器地址线14

 

P4[15]

 

173

I/O

P4[15]:GPIO口

I/O

A15:外部存储器地址线15

 

P4[16]

 

101

I/O

P4[16]:GPIO口

I/O

A16:外部存储器地址线16

 

P4[17]

 

104

I/O

P4[17]:GPIO口

I/O

A17:外部存储器地址线17

 

P4[18]

 

105

I/O

P4[18]:GPIO口

I/O

A18:外部存储器地址线18

 

P4[19]

 

111

I/O

P4[19]:GPIO口

I/O

A19:外部存储器地址线19

 

P4[20]

 

109

I/O

P4[20]:GPIO口

I/O

A20:外部存储器地址线20

I/O

SDA2:I2C2数据输入/输出

I/O

SCK1:SSP1串行时钟

 

P4[21]

 

115

I/O

P4[21]:GPIO口

I/O

A21:外部存储器地址线21

I/O

SCL2:I2C2时钟输入/输出

I/O

SSEL1:SSP1从机选择

 

P4[22]

 

123

I/O

P4[22]:GPIO口

I/O

A22:外部存储器地址线22

O

TXD2:UART2发送输出端

I/O

MISO1:SSP1主机输入从机输出

 

P4[23]

 

129

I/O

P4[23]:GPIO口

I/O

A23:外部存储器地址线23

I

RXD2:UART2接收输入端

I/O

MOSI1:SSP1主机输出从机输入

 

P4[24]

 

183

I/O

P4[24]:GPIO口

O

OE:低电平有效输出使能信号

 

P4[25]

 

179

I/O

P4[25]:GPIO口

O

WE:低电平有效写使能信号

 

P4[26]

 

119

I/O

P4[26]:GPIO口

O

BLS0:低电平有效字节定位选择信号0

 

P4[27]

 

139

I/O

P4[27]:GPIO口

O

BLS1:低电平有效字节定位选择信号1

 

P4[28]

 

170

I/O

P4[28]:GPIO口

O

BLS2:低电平有效字节定位选择信号2

O

MAT2[0]/LCD[6]/LCD[10]/LCD[2]:Timer2匹配输出通道0/LCD数据

O

TXD3:UART3发送输出端

 

P4[29]

 

176

I/O

P4[29]:GPIO口

O

BLS3:低电平有效字节定位选择信号3

O

MAT2[1]/LCD[7]/LCD[11]/LCD[3]:Timer2匹配输出通道1/LCD数据

I

RXD3:UART3接收输入端

 

P4[30]

 

187

I/O

P4[30]:GPIO口

O

CS0:低电平有效片选信号0

 

P4[31]

 

193

I/O

P4[31]:GPIO口

O

CS1:低电平有效片选信号1

6. 电源、复位、晶振及其它管脚的描述如表4.6所示。

4.6 LPC2400的其它管脚描述

管脚名称

引脚号

类型

描  述

ALARM

37

O

RTC实时时钟控制输出。这是一个1.8V引脚,当RTC产生报警信号时此引脚变为高电平。

USB_D-2

52

I/O

USB端口2双向D-线

DBGEN

9

I

JTAG接口控制信号,也用于边界扫描

TDO

2

O

JTAG接口测试数据输出

TDI

4

I

JTAG接口测试数据输入

TMS

6

I

JTAG接口测试模式选择

TRST

8

I

JTAG接口测试复位,低电平有效

TCK

10

I

JTAG接口测试时钟

RTCK

206

I/O

JTAG接口控制信号,当此引脚低电平时使能ETM引脚(P2[9:0]),用于复位后操做跟踪端口

RSTOUT

29

O

这是个1.8V引脚,当此引脚低电平时表示LPC2478处于复位状态

RESET

35

I

外部复位输入,低电平有效。该引脚具备迟滞做用的TTL电平,能承受5V电压,当此引脚低电平时器件复位,I/O口和外围功能进入默认状态,处理器从地址0开始执行程序

XTAL1

44

I

振荡器电路和内部时钟发生电路输入

XTAL2

46

O

振荡放大器输出

RTCX1

34

I

RTC振荡器电路输入

RTCX2

36

O

RTC振荡器电路输出

VSSIO

33,63,77,93,114,133,148,169,189,200

I

地:数字IO脚的0V电压参考点

VSSCORE

32,84,172

I

地:处理器内核的0V电压参考点

VSSA

22

I

模拟地:0V电压参考点,与VSS电压相同,为了下降噪声和出错概率,二者应当隔离

VDD(3V3)

15,60,71,89,112,125,146,165,181,198

I

3.3V供应电压:I/O口电源供应电压

NC

30,117,141

I

未链接引脚

VDD(DCDC)(3V3)

26,86,174

I

3.3V直流到直流转换供应电压:为片内DC-to-DC转换器提供电源

VDDA

20

I

模拟3.3V供应电压:为DAC和ADC供电,与VDD(3V3)电压相同,为了下降噪声和出错概率,二者应当隔离

VREF

24

I

ADC参考电压:与VDD(3V3)电压相同,为了下降噪声和出错概率,二者应当隔离,为ADC和DAC提供参考电压

VBAT

38

I

RTC电源供应:3.3V,为RTC提供电源

注:1. 本引脚定义表以LPC2478为准,LPC2470与此相同,LPC2468没有引脚定义的LCD部分。

2. 类型表示引脚信号方向:I/O为输入/输出,I为输入,O为输出。

4.2.2  引脚链接模块

从表4.1~表4.6能够看到,LPC2400系列芯片的绝大部分引脚是复用的,每根引脚都有可能用于不一样的外设功能。引脚具体用于什么外设功能是由引脚链接模块进行配置来实现的。当引脚选择了一个功能时,则其它功能无效。

在使用外设时,应当在激活外设以及使能任何相关的中断以前,将外设链接到相应的引脚上。不然,即便使用引脚链接模块激活外设,此激活也是无效的。

引脚链接模块共有21个寄存器,包括11个引脚功能选择寄存器和10个引脚模式寄存器。

1. 引脚功能选择寄存器(PINSEL0~PINSEL10)

引脚功能选择寄存器用于控制每一个引脚的功能,每一个寄存器32位,每2个bit用于控制1个引脚功能选择。以PINSEL0寄存器为例,寄存器的[1:0]位用于控制P0[0]引脚,[3:2]位用于控制P0[1]引脚,[31:30]位用于控制P0[15]引脚。而PINSEL1寄存器的[1:0]位用于控制P0[16]引脚,[3:2]位用于控制P0[17]引脚,[31:30]位用于控制P0[31]引脚。其他依次类推。

PINSEL0~PINSEL9寄存器,每两个寄存器用于一个端口组:PINSEL0寄存器用于P0口的[15:0]引脚,PINSEL1寄存器用于P0口的[31:30]引脚;PINSEL2寄存器用于P1口的[15:0]引脚,PINSEL3寄存器用于P1口的[31:30]引脚;PINSEL4寄存器用于P2口的[15:0]引脚,PINSEL5寄存器用于P2口的[31:30]引脚;PINSEL6寄存器用于P3口的[15:0]引脚,PINSEL7寄存器用于P3口的[31:30]引脚;PINSEL8寄存器用于P4口的[15:0]引脚,PINSEL9寄存器用于P4口的[31:30]引脚。

每一对比特设置引脚功能的定义如表4.7所示。

4.7 引脚功能选择寄存器位

PINSEL0~PINSEL9值

功能

复位值

00

主功能(缺省),通常为GPIO口

00

01

第一备用功能

10

第二备用功能

11

第三备用功能

每一个引脚默认为GPIO口,经过设置PINSEL的值来定义其引脚功能。以P0[0]脚为例,当PINSEL0寄存器的[1:0]位为00时,引脚功能为GPIO口;为01时,引脚功能为CAN1接收器输入;为10时,引脚功能为UART3发送输出端;为11时,引脚功能为I2C1数据输入/输出。

每一个引脚的具体定义方法参见表4.1~表4.6。表格中的引脚功能按PINSEL值排列。某些引脚只有两种功能,此时只使用PINSEL值00和01,值10和11保留。

PINSEL10寄存器用于控制ETM接口引脚。该寄存器只使用了位3,其他位均保留。当第3位为0时,关闭ETM接口功能;为1时启用ETM跟踪接口功能,此时不管PINSEL4怎么定义,P2[0]~P2[8]脚均用于ETM跟踪功能。

引脚功能被选择为GPIO时,引脚的方向控制由GPIO方向寄存器IODIR控制。对于其它功能,引脚的方向是由引脚功能控制的。

2. 引脚模式寄存器(PINMODE0~PINMODE9)

引脚模式寄存器PINMODE为全部的GPIO端口控制片内上拉/下拉电阻特性。当使用片内上拉或下接电阻时,若引脚信号不肯定,使用上拉时为高电平;而下拉时拉为低电平。

PNSEL寄存器同样,PINMODE寄存器每2个bit控制1个引脚。每两个寄存器控制一个端口组。

PINMOD寄存器取值如表4.8所示。

4.8 引脚模式寄存器位

PINMODE0~PINMODE9值

功能

复位值

00

使能引脚片内上拉电阻

00

01

保留

10

既不使用上拉也不使用下拉

11

使能引脚片内下拉电阻

引脚链接模块的寄存器总表如表4.9所示。

4.9 引脚控制模块寄存器列表

寄存器名

描述

访问

复位值

地址

PINSEL0

引脚功能选择寄存器0

读/写

0x0000 0000

0xE002 C000

PINSEL1

引脚功能选择寄存器1

读/写

0x0000 0000

0xE002 C004

PINSEL2

引脚功能选择寄存器2

读/写

0x0000 0000

0xE002 C008

PINSEL3

引脚功能选择寄存器3

读/写

0x0000 0000

0xE002 C00C

PINSEL4

引脚功能选择寄存器4

读/写

0x0000 0000

0xE002 C010

PINSEL5

引脚功能选择寄存器5

读/写

0x0000 0000

0xE002 C014

PINSEL6

引脚功能选择寄存器6

读/写

0x0000 0000

0xE002 C018

PINSEL7

引脚功能选择寄存器7

读/写

0x0000 0000

0xE002 C01C

PINSEL8

引脚功能选择寄存器8

读/写

0x0000 0000

0xE002 C020

PINSEL9

引脚功能选择寄存器9

读/写

0x0000 0000

0xE002 C024

PINSEL10

引脚功能选择寄存器10

读/写

0x0000 0000

0xE002 C028

PINMODE0

引脚模式寄存器0

读/写

0x0000 0000

0xE002 C040

PINMODE1

引脚模式寄存器1

读/写

0x0000 0000

0xE002 C044

PINMODE2

引脚模式寄存器2

读/写

0x0000 0000

0xE002 C048

PINMODE3

引脚模式寄存器3

读/写

0x0000 0000

0xE002 C04C

PINMODE4

引脚模式寄存器4

读/写

0x0000 0000

0xE002 C050

PINMODE5

引脚模式寄存器5

读/写

0x0000 0000

0xE002 C054

PINMODE6

引脚模式寄存器6

读/写

0x0000 0000

0xE002 C058

PINMODE7

引脚模式寄存器7

读/写

0x0000 0000

0xE002 C05C

PINMODE8

引脚模式寄存器8

读/写

0x0000 0000

0xE002 C060

PINMODE9

引脚模式寄存器9

读/写

0x0000 0000

0xE002 C064

4.2.3  引脚链接模块的使用举例

LPC2400系列芯片外设功能在使用前必须先设置其引脚功能。引脚功能是经过对引脚链接模块编程来实现的。

4.1:使用串口UART0

串口UART0只使用TXD0和RXD0两根引脚来进行数据的串行发送和接收,使用时需将对应的两根引脚P0[2]和P0[3]设置成TXD0和RXD0功能。查表4.1可知,两根引脚的对应PINSEL值均为01,所以写入PINSEL0寄存器的值为0x00000050。

相应程序行为:

PINSEL0 = 0x00000050;

PINSEL0 = 0x05<<4;

注意,因为PINSEL是可读写的寄存器,上述写法会使其它引脚的功能回到初始化默认配置。为了避免影响其它引脚的功能配置,实用中更好的办法是:先读取寄存器值,而后进行逻辑与和逻辑或操做,再回写到寄存器。

PINSEL0 = (PINSEL0 &0xFFFFFF0F) | (0x05<<4);

其他的引脚外设功能都可以采用相似方法进行操做。

4.2:启动代码中的相关部分

启动代码负责对芯片复位后的硬件功能进行初始化。芯片复位时,各PINSEL寄存器会自动设置为默认值,因此复位后芯片引脚的功能是肯定的。

若是启动之后,硬件系统各外设功能使用状况比较固定,能够将对应的引脚功能设置写入启动代码以加快启动速度。不然,能够在启动时将全部引脚都配置成GPIO端口,具体使用某部分外设时再对相关引脚进行初始化。

……

    PINSEL0 = 0x00000000;

    PINSEL1 = 0x00000000;

    PINSEL2 = 0x00000000;

    PINSEL3 = 0x00000000;

    PINSEL4 = 0x00000000;

    PINSEL5 = 0x00000000;

    PINSEL6 = 0x00000000;

    PINSEL7 = 0x00000000;

    PINSEL8 = 0x00000000;

    PINSEL9 = 0x00000000;

    PINSEL10 = 0x00000000;

……

4.3 存储器管理

LPC2400系列芯片集成了512KB的片内Flash存储器和64KB的静态SRAMLPC2470没有片内Flash),其中Flash存储器能够用作代码和数据的固态存储。对Flash存储器的编程能够经过几种方法来实现:经过串口UART0进行的在系统编程(ISP),经过调用嵌入片内的固化代码进行的在应用编程(IAP)以及经过内置的JTAG接口编程。

SRAM支持8位、16位和32位访问。须要注意的是,SRAM控制器包含一个回写缓冲区,它用于防止CPU在连续的写操做时中止运行。回写缓冲区老是保存着软件发送到SRAM的最后1字节。数据只有在软件执行另一次写操做时被写入SRAM。若是发生芯片复位,实际的SRAM内容将不会反映最近一次的写请求。任何在复位后检查SRAM内容的程序都必须注意这一点。

LPC2400系列芯片具有外部存储器接口,经过外部存储器控制器(EMC)能够扩展两组共8Bank的存储器组(Static memory bank0 bank3Dynamic memory bank0 bank3)。对于外扩的RAM存储器,使用ARMLDR/STR指令便可进行数据的读写操做;而对于外扩的FlashNOR)型,能够使用LDR指令读取数据,可是不能使用STR指令直接写数据,而是根据Flash芯片写操做时序进行控制,实现Flash的擦除编程。若是须要将程序代码烧写到扩展的Flash,则须要运行一个装载程序(Loader程序,通常由用户自行编写),而后由Loader程序对Flash存储器进行擦除和烧写。

4.3.1  存储器映射

ARM处理器共有4GB的寻址空间,LPC2400系列处理器将这个空间划分红了几个不一样的存储器组。图4.3所示为复位后从用户角度所看到的系统存储器地址空间映射。

 

4.3 LPC2400系统存储器映射

4.10 LPC2400存储器使用和细节

地址范围

通用用途

地址范围细节

功能描述

0x0000 0000

0x3FFF FFFF

片内非易失存储器和快速I/O

0x0000 0000 – 0x0007 FFFF

Flash 存储器(512KB

0x3FFF C000 – 0x3FFF FFFF

快速GPIO寄存器

0x4000 0000

0x7FFF FFFF

片内存储器

0x4000 0000 – 0x4000 FFFF

RAM64KB

0x7FE0 0000 – 0x7FE0 3FFF

以太网RAM16KB

0x7FD0 0000 – 0x7FD0 3FFF

USB RAM16KB

0x8000 0000

0xDFFF FFFF

 

片外存储器

四个静态存储器bank,每一个16MB

0x8000 0000 – 0x80FF FFFF

静态存储器bank0

0x8100 0000 – 0x81FF FFFF

静态存储器bank1

0x8200 0000 – 0x82FF FFFF

静态存储器bank2

0x8300 0000 – 0x83FF FFFF

静态存储器bank3

四个动态存储器bank,每一个256MB

0xA000 0000 – 0xAFFF FFFF

动态存储器bank0

0xB000 0000 – 0x3FFF FFFF

动态存储器bank1

0xC000 0000 – 0xCFFF FFFF

动态存储器bank2

0xD000 0000 – 0xDFFF FFFF

动态存储器bank3

0xE000 0000

0xEFFF FFFF

APB 外设

36个外设模块,每一个16KB

0xF000 0000

0xFFFF FFFF

AHB 外设

 

1. 外设存储器映射

LPC2400系列处理器的外设根据内部总线分为AHBAPB外设两类。AHB外设和APB外设在存储空间里都占2MB的区域,可各自分配最多128个外设。每一个外设空间的规格都为16KB。全部外设寄存器无论规格大小,都按照字地址进行分配(32位边界),且无论字仍是半字寄存器都是一次性访问。例如,不可能对一个字寄存器的最高字节执行单独的读或写操做。

4.4表示了AHBAPB外设占用存储空间示意图。

 

4.4 外设存储器映射(AHB外设和APB外设)

 

4.5所示为AHB外设占用存储空间示意图。其中04号外设分别分配给以太网控制器、GPDMA控制器、EMC控制器、USB控制器和LCD控制器,其它外设编号未使用。

 

4.5 AHB外设存储器映射

4.11所示为APB外设占用的存储空间示意图。

4.11 APB外设存储器映射

APB 外设

基地址

外设名

0

0xE000 0000

看门狗

1

0xE000 4000

定时器0

2

0xE000 8000

定时器1

3

0xE000 C000

UART0

4

0xE001 0000

UART1

5

0xE001 4000

PWM0

6

0xE001 8000

PWM1

7

0xE001 C000

I2C0

8

0xE002 0000

SPI

9

0xE002 4000

实时时钟RTC

10

0xE002 8000

GPIO

11

0xE002 C000

引脚链接模块

12

0xE003 0000

SSP1

13

0xE003 4000

ADC

14

0xE003 8000

CAN接收滤波器RAM

15

0xE003 C000

CAN接收滤波器寄存器

16

0xE004 0000

CAN通用寄存器

17

0xE004 4000

CAN控制器1

18

0xE004 8000

CAN控制器2

19 22

0xE004 C000 0xE005 8000

未使用

23

0xE005 C000

I2C1

24

0xE006 0000

未使用

25

0xE006 4000

未使用

26

0xE006 8000

SSP0

27

0xE006 C000

DAC

28

0xE007 0000

定时器2

29

0xE007 4000

定时器3

30

0xE007 8000

UART2

31

0xE007 C000

UART3

32

0xE008 0000

I2C3

33

0xE008 4000

电池RAM

34

0xE008 8000

I2S

35

0xE008 C000

SD/MMC卡接口

36 126

0xE009 0000 0xE01F BFFF

未使用

127

0xE01F C000

系统控制模块

在对LPC2400系列芯片编程时,要注意不要对一个保留地址或未使用区域的地址进行寻址,不然LPC2400将产生一个数据停止异常。另外,对AHBAPB外设地址执行任何指令取指都会致使产生预取指停止异常。

2. 存储器重映射和boot ROM

存储器映射的一个基本概念是:每一个存储器组在存储器映射中都有一个“物理上的”位置。它是一个地址范围,该范围内可写入程序代码,每个存储器空间的容量都永久固定在同一个位置,这样就不须要将代码设计成在不一样地址范围内运行。

由于ARM7处理器上的中断向量所处具体位置(地址0x0000 0000~0x0000 001C,见表4.12)的要求,Boot ROMSRAM空间的一小部分空间须要从新映射,来实如今不一样操做模式下对中断的不一样使用。

表4.12 ARM 异常向量位置

地址

异常

0x0000 0000

复位

0x0000 0004

未定义指令

0x0000 0008

软件中断

0x0000 000C

预取指停止(指令读取存储器出错)

0x0000 0010

数据停止(数据访问存储器出错)

0x0000 0014

保留

0x0000 0018

IRQ

0x0000 001C

FIQ

为了与未来器件兼容,整个Boot ROM都被映射到片内存储器空间的顶端。在这种方式下,使用较大或较小的Flash模块都不须要改变Boot ROM(须要改变Boot装载程序自身的代码)的位置或改变Boot ROM中断向量的映射。除了中断向量以外的存储器空间都保持固定的位置。

存储器从新映射的部分容许在不一样模式下处理中断。LPC2400共支持3种存储器映射模式,见表4.13。当处理器工做在用户Flash模式下时,不须要进行中断向量的从新映射,而在其它模式下则须要从新映射。它包括中断向量区(32 字节)和额外的32 字节,一共是64 字节。从新映射的代码位置与地址0x0000 0000~0x0000 003F 重叠,包含在SRAMFlash Boot Block 中的向量必须包含跳转到实际中断处理程序的分支或者其它执行跳转到中断处理程序的转移指令。一个位于Flash 存储器中的典型用户程序能够将整个FIQ 处理程序放置在地址0x0000 001C 而不须要考虑存储器的边界。

4.13  LPC2400存储器映射模式

模式

激活

用途

Boot装载程序模式

由任何复位硬件激活

在任何复位后都会执行Boot 装载程序。Boot ROM中断向量映射到存储器的底部以容许处理异常并在Boot 装载过程当中使用中断。

用户Flash   模式

Boot 代码软件激活

当在存储器中识别了一个有效的用户程序标识而且Boot 装载操做未被执行时,由Boot 装载程序激活。中断向量不做从新映射,它位于Flash 存储器的底部。

用户RAM  模式

由用户程序软件激活

由用户程序激活。中断向量从新映射到静态RAM 的底部。

选择这种配置有三个缘由:

1) 使Flash 存储器中的FIQ处理程序没必要考虑由于从新映射所致使的存储器边界问题;

2) 用来处理代码空间中段边界仲裁的SRAM Boot ROM向量的使用大大减小;

3) 为超过单字转移指令范围的跳转提供空间来保存常量。

从新映射的存储器组,包括Boot ROM和中断向量,除了从新映射的地址外,仍然继续出如今它们最初的位置。存储器重映射之后的存储器空间见图4.6所示。

 

4.6已从新映射和可从新映射区域的低存储器空间

3. 存储器映射控制寄存器MEMMAPMemory Mapping Control Register

存储器映射控制寄存器用于改变从地址0x00000000开始的中断向量的映射。这容许运行在不一样存储器空间中的代码对中断进行控制。MEMMAP是一个可读写寄存器,地址为0xE01FC040,功能为选择从Flash Boot Block、用户Flash RAM中读取ARM 中断向量。

4.14 存储器映射控制寄存器MEMMAP

符号

功能描述

复位值

1:0

MAP

00Boot 装载程序模式。中断向量从Boot Block 从新映射

01:用户Flash 模式。中断向量不从新映射,它位于Flash

10:用户RAM 模式。中断向量从静态RAM 从新映射

11:保留,不使用该选项

警告:不正确的设定会致使器件的错误操做

00

7:2

保留

 

NA

LPC2400MAP位的硬件复位值为00Boot装载程序会将用户看到的复位值更改,该程序老是在复位后当即运行。

存储器映射控制寄存器MEMMAP只从处理ARM异常(中断)必需的3 个数据源(FLASH中断向量、SRAM中断向量和Boot ROM中断向量,每一个64 字节)中选择一个使用。

每当产生一个软件中断请求,ARM内核就从0x0000 0008 处取出32 位数据(见表4.12,“ARM异常向量位置”)。这就意味着当MEMMAP[1:0]10(用户RAM模式)时,从0x0000 0008的读数/取指是对0x4000 0008单元进行操做。当MEMMAP[1:0]=00Boot装载程序模式)时,从0x0000 0008的读数/取指是对0x7FFF E008 单元的数据进行操做(Boot ROM从片内Flash存储器从新映射)。

4.3.2  存储器加速模块

LPC2400 在运行Flash存储器内的代码时,器件内部的存储器加速模块(MAM,Memory Accelerator Module)最大限度地提升了ARM处理器的性能,而此只须要使用一个简单的Flash组就可实现了。

1.操做

存储器加速模块(MAM)能够将须要的下一个ARM 指令锁存,以防止CPU 取指暂停。与之前的其它器件使用2个Flash组相比,LPC2400只使用一组Flash 存储器。这个Flash组包含3 个128位的缓冲区:预取指缓冲区、分支跟踪缓冲区和数据缓冲区。

当预取指缓冲区和分支跟踪缓冲区不能知足一次指令取指的须要,而且预取指尚未启动时,ARM在启动128位行的取指时暂停。若是预取指已经启动但还未完成,则ARM暂停的时间会更短一些。预取指在Flash结束前面的访问后当即启动,除非被数据访问停止。

预取指行被Flash 模块锁存,但MAM 不能在预取指缓冲区中捕获该行,直到ARM 内核给出预取指开始的地址。若是内核给出的地址与预取指地址不一样,则预取指行丢弃。

每一个预取指缓冲区和分支跟踪缓冲区包含4个32位ARM指令或8个16位Thumb指令。在连续执行代码时,一般预取指缓冲区包含当前指令和含有该指令的整个Flash 行。

分支和其它程序流的变化致使前面所讲述的连续指令取指出现中断。分支跟踪缓冲区捕获发生非连续中断的行。若是相同的分支再次出现,则从分支跟踪缓冲区内取出下条指令。当分支超出了预取指和分支跟踪缓冲区内容时,须要停止几个时钟来装载分支跟踪缓冲区。这样,不会再出现指令取指延时,直到一个新的和不一样的分支出现。

2.MAM 结构

存储器加速器分红如下几个功能模块:1个Flash地址锁存和1个增量器功能用于预取指地址、1个128位的预取指缓冲区及其相关的地址锁存和比较器、1个128位的分支跟踪缓冲区及其相关的地址锁存和比较器。

 

4.7 存储器加速器模块框图

3MAM 的操做模式

MAM 定义了3种操做模式,用户能够在性能和可预测性之间进行选择:

1MAM关闭。全部存储器请求都会致使Flash的读操做,无指令预取指。

2MAM部分使能。若是数据可用,则从保持锁存区执行连续的指令访问。指令预取指使能。非连续的指令访问启动Flash读操做。这意味着全部的转移指令都会致使对存储器的取指。因为缓冲的数据访问时序很难预测而且很是依赖于所处的情况,所以全部数据操做都会致使Flash读操做。

3MAM 彻底使能。任何存储器请求(代码或数据),若是其值已经包含在其中一个保持锁存当中,那么从缓冲区执行该代码或数据的访问。指令预取指使能。Flash读操做用于指令的预取指和当前缓冲区所没有的代码或数据的访问。

在复位后,MAM 默认为禁止状态,软件能够随时将存储器访问加速打开或关闭。这样就可以使大多数应用程序以最高速度运行,而某些要求更精肯定时的功能能够较慢但更可预测的速度运行。

在启用MAM之后,Flash编程功能不受MAM的控制,而是做为一个独立的功能进行处理。Boot ROM扇区包含可做为应用程序的一部分调用的Flash 编程算法(即IAP 代码)和一个可对Flash 存储器进行串行编程的装载程序(即ISP 代码)。

4.寄存器描述

1MAM控制寄存器-MAM Control RegisterMAMCR - 0xE01FC000。决定MAM的操做模式。两个配置位选择MAM3种操做模式。在复位后,MAM功能被禁止。改变MAM操做模式会致使MAM全部的保持锁存内容无效,所以须要执行新的Flash读操做。

4.15 存储器加速器模块控制寄存器(MAMCR

MAMCR

功能

描述

复位值

1:0

MAM 模式控制

00MAM 功能被禁止

01MAM 功能部分使能

10MAM 功能彻底使能

11-保留

0

7:2

保留

保留

NA

2MAM定时寄存器-MAM Timing RegisterMAMTIM - 0xE01FC004。决定Flash存储器取指所使用的时钟个数(17个处理器时钟),使用多少个cclk周期访问Flash存储器。这样可调整MAM时序使其匹配处理器操做频率。Flash访问时间能够从17个时钟,单个时钟的Flash访问实际上关闭了MAM,这种状况下能够选择MAM模式对功耗进行优化。

4.16 存储器加速定时寄存器(MAMTIM

MAMTIM

功能

描述

复位值

 

 

 

2:0

 

 

 

MAM取指周期

0000,保留

0011MAM 取指周期为1 个处理器时钟(cclk

0102MAM 取指周期为2 个处理器时钟(cclk

0113MAM 取指周期为3 个处理器时钟(cclk

1004MAM 取指周期为4 个处理器时钟(cclk

1015MAM 取指周期为5 个处理器时钟(cclk

1106MAM 取指周期为6 个处理器时钟(cclk

1117MAM 取指周期为7 个处理器时钟(cclk

警告:不正确的设定会致使器件的错误操做!

 

 

 

0x07

7:3

保留

保留

NA

5MAM 使用注意事项

1MAM 定时值问题

当改变MAM定时值时,必须先经过向MAMCR写入0来关闭MAM,而后将新值写入MAMTIM,最后,将须要的操做模式的对应值写入MAMCR,再次打开MAM

对于低于20MHz的系统时钟,MAMTIM设定为1;对于20MHz40MHz之间的系统时钟,建议将MAMTIM设定为2;而在高于40MHz的系统时钟下,建议使用3

2Flash 编程问题

在编程和擦除操做过程当中不容许访问Flash存储器。若是在Flash模块忙时存储器请求访问Flash地址,MAM就必须强制CPU等待(这经过声明ARM7TDMI-S局部总线信号CLKEN来实现)。在某些状况下,代码执行的延迟会致使看门狗超时。用户必须注意到这种可能性,并采起措施来确保不会在编程或擦除Flash 存储器时出现非预期的看门狗复位,从而致使系统故障。

6MAM使用举例

MAM功能在LPC2400的启动代码中实现,能够根据Fcclk的大小来自动设置MAM(target.c文件中)。首先要将MAM功能禁止,而后根据Fcclk的大小来设置MAM定时寄存器(经过条件编译实现,Fcclk的定义在target.h文件中),最后再使能MAM

代码清单4.1

void TargetResetInit(void)

{ …

MAMCR = 0; // 禁止MAM 功能

#if Fcclk < 20000000

MAMTIM = 1; // 系统时钟低于20M,建议设置为1

#else

#if Fcclk < 40000000

MAMTIM = 2; // 系统时钟再20M40M 之间,建议设置为2

#else

MAMTIM = 3; // 系统时钟高于40M,建议设置为3

#endif

MAMCR = 2; // 使能MAM

…}

4.3.3  外部存储器控制器

LPC2400的外部存储器控制器(EMC)是一个AMBA总线AHB从机模块,它支持多种不一样结构的存储器,包括经常使用的异步静态存储器,如RAM、ROM和Flash等,也支持动态存储器,如单数据率SDRAM等。EMC模块能够同时支持多达8个单独配置的存储器组,其中静态存储器和动态存储器各4Bank。静态存储器组由片选引脚CS0CS3选中,每一个组存储容量16MB,支持RAMROMFlash和其它一些外部I/O部件,支持8位、16位和32位数据宽度。动态存储器组由片选引脚DYCS0DYCS3选中,每一个组存储容量256MB,支持单数据率SDRAM,支持16位和32位数据宽度,刷新模式可由软件控制。

1.EMC功能框图和引脚信号

 

4.8 EMC功能框图

4.17 外部存储器控制器引脚描述

引脚名称

类 型

复位值

描 述

A[23:0]

输出

0x0000 0000

外部存储器地址线。SDRAM存储器只使用其中的位[14:0]

D[31:0]

输入/输出

0x0000 0000

外部存储器数据线

OE

输出

1

静态存储器输出使能信号,低电平有效

BLS[3:0]

输出

0x0F

静态存储器字节定位选择信号,低电平有效

WE

输出

1

写使能信号,低电平有效

CS[3:0]

输出

0x0F

静态存储器片选信号,低电平有效

DYCS[3:0]

输出

0x0F

动态存储器片选信号,低电平有效

CAS

输出

1

动态存储器列地址选通讯号,低电平有效

RAS

输出

1

动态存储器行地址选通讯号,低电平有效

CLKOUT[1:0]

输出

来自CCLK

SDRAM时钟

CKEOUT[3:0]

输出

0x0F

SDRAM时钟使能

DQMOUT[3:0]

输出

0x0F

SDRAM输出掩码。也可用于静态存储器

2.外部存储器接口

外部存储器接口取决于存储器组的数据宽度(32位、16位或8位,由EMCStaticConfig寄存器的MW位选择)。若是一个存储器组被配置为32位宽度,地址线A0A1能够用作非地址线;若是存储器组配置为16为宽度,则不须要A08位宽的存储器组则须要使用A0。经过引脚链接模块寄存器能够实现A0A1的地址或非地址功能。

4.9和图4.10所示为典型的32位总线宽度的存储器组的外部存储器接口硬件链接方式,其中符号“a_b”表示数据总线的最高位地址线,符号“a_m”表示使用外部存储器接口的存储器芯片的最高位地址线。

4.9中,一个32位宽度的存储器组由48位存储器芯片扩展而成,所以这4个芯片用同一个片选信号CS选中有效,同时使用同一个写使能信号OE。第一个存储器芯片构成存储器组32位中的高8位,所以其写使能信号WE链接到字节选择信号的最高位BLS[3]8位数据线链接到数据总线的最高8D[31:24]。其他三个芯片分别构成32位存储器组中的第234个字节。因为存储器组的数据宽度为32位,地址总线中的A0A1不使用,只使用最高位a_bbit2链接到存储芯片的地址线上。

4.10中的16位芯片引脚UBLB分别表示芯片中16位数据的高字节和低字节。32位芯片中的引脚B3B0表示芯片中32位数据的四个字节。其芯片引脚与总线的链接方式与图4.9是相似的。

按照图4.9和图4.10的方法,读者不可贵出16位和8位总线宽度的存储器组的外部存储器接口扩展方法。

 

4.9  48位静态存储器芯片构成32位宽存储器组

 

4.10  216位存储器芯片和132位存储器芯片构成32位宽存储器组

4.11所示为使用SDRAM芯片构成32位动态存储器组的外部存储器接口链接方法。图中使用的SDRAM芯片为K4S561632H,这款芯片的存储容量为256Mb32位宽度,存储空间分为4个组,使用时由组选择信号BA0BA1选择。在连线时,除了要注意使用与静态存储器不一样的动态存储器引脚如DYCSCLKOUTCKEOUTDQMOUT以外,要格外注意地址线的连法。LPC2400SDRAM地址线只使用地址线中的[14:0]15根线,最高位两根A14A13固定链接到芯片的组选择信号BA1BA0,其他地址线从A0开始一一链接。这种链接方式是LPC2400EMC特有的,与其它的ARM芯片,如三星的S3C系列芯片有很大区别,开发者在本身扩展SDRAM存储器时必定要特别注意。

 

4.11 外部扩展存储器接口SDRAM

3EMC相关寄存器

4.18所示为EMC的相关寄存器。

4.18 EMC寄存器汇总

寄存器名

类型

复位值

功能描述

地址

EMCControl

/

0x3

EMC控制操做

0xFFE0 8000

EMCStatus

只读

0x5

提供EMC控制信息

0xFFE0 8004

EMCConfig

/

0x0

EMC配置操做

0xFFE0 8008

EMCDynamic Control

/

0x6

控制动态存储器操做

0xFFE0 8020

EMCDynamic Refresh

/

0x0

配置动态存储器刷新操做

0xFFE0 8024

EMCDynamicReadConfig

/

0x0

配置动态存储器读策略

0xFFE0 8028

EMCDynamicRP

/

0x0F

选择预充电命令周期

0xFFE0 8030

EMCDynamicRAS

/

0x0F

选择激活预充电命令周期

0xFFE0 8034

EMCDynamicSREX

/

0x0F

选择刷新退出时间

0xFFE0 8038

EMCDynamicAPR

/

0x0F

选择最后数据输出激活命令时间

0xFFE0 803C

EMCDynamicDAL

/

0x0F

选择数据输入激活命令时间

0xFFE0 8040

EMCDynamicWR

/

0x0F

选择写修复时间

0xFFE0 8044

EMCDynamicRC

/

0x1F

选择激活有效命令周期

0xFFE0 8048

EMCDynamicRFC

/

0x1F

选择自动刷新周期

0xFFE0 804C

EMCDynamicXSR

/

0x1F

选择退出刷新有效命令时间

0xFFE0 8050

EMCDynamicRRD

/

0x0F

选择激活组A到组B延迟

0xFFE0 8054

EMCDynamicMRD

/

0x0F

选择有效命令时间的加载模式寄存器

0xFFE0 8058

EMCDynamicConfig0

/

0x0

选择动态存储器芯片0配置信息

0xFFE0 8100

EMCDynamicRasCas0

/

0x303

选择动态存储器芯片0RASCAS延迟

0xFFE0 8104

EMCDynamicConfig1

/

0x0

选择动态存储器芯片0配置信息

0xFFE0 8120

EMCDynamicRasCas1

/

0x303

选择动态存储器芯片0RASCAS延迟

0xFFE0 8124

EMCDynamicConfig2

/

0x0

选择动态存储器芯片0配置信息

0xFFE0 8140

EMCDynamicRasCas2

/

0x303

选择动态存储器芯片0RASCAS延迟

0xFFE0 8144

EMCDynamicConfig3

/

0x0

选择动态存储器芯片0配置信息

0xFFE0 8160

EMCDynamicRasCas3

/

0x303

选择动态存储器芯片0RASCAS延迟

0xFFE0 8164

EMCStaticConfig0

/

0x0

选择静态存储器芯片0配置

0xFFE0 8200

EMCStaticWaitWen0

/

0x0

选择写使能芯片0延迟

0xFFE0 8204

EMCStaticWaitOen0

/

0x0

选择输出使能芯片0延迟

0xFFE0 8208

EMCStaticWaitRd0

/

0x0

选择读访问芯片0延迟

0xFFE0 820C

EMCStaticWaitPage0

/

0x1F

选择芯片0异步页模式顺序访问延迟

0xFFE0 8210

EMCStaticWaitWr0

/

0x1F

选择写访问芯片0延迟

0xFFE0 8214

EMCStaticWaitTurn0

/

0x0F

选择芯片0总线翻转周期

0xFFE0 8218

EMCStaticConfig1

/

0x0

选择静态存储器芯片1配置

0xFFE0 8220

EMCStaticWaitWen1

/

0x0

选择写使能芯片1延迟

0xFFE0 8224

EMCStaticWaitOen1

/

0x0

选择输出使能芯片1延迟

0xFFE0 8228

EMCStaticWaitRd1

/

0x0

选择读访问芯片1延迟

0xFFE0 822C

EMCStaticWaitPage1

/

0x1F

选择芯片1异步页模式顺序访问延迟

0xFFE0 8230

EMCStaticWaitWr1

/

0x1F

选择写访问芯片1延迟

0xFFE0 8234

EMCStaticWaitTurn1

/

0x0F

选择芯片1总线翻转周期

0xFFE0 8238

EMCStaticConfig2

/

0x0

选择静态存储器芯片2配置

0xFFE0 8240

EMCStaticWaitWen2

/

0x0

选择写使能芯片2延迟

0xFFE0 8244

EMCStaticWaitOen2

/

0x0

选择输出使能芯片2延迟

0xFFE0 8248

EMCStaticWaitRd2

/

0x0

选择读访问芯片2延迟

0xFFE0 824C

EMCStaticWaitPage2

/

0x1F

选择芯片2异步页模式顺序访问延迟

0xFFE0 8250

EMCStaticWaitWr2

/

0x1F

选择写访问芯片2延迟

0xFFE0 8254

EMCStaticWaitTurn2

/

0x0F

选择芯片2总线翻转周期

0xFFE0 8258

EMCStaticConfig3

/

0x0

选择静态存储器芯片3配置

0xFFE0 8260

EMCStaticWaitWen3

/

0x0

选择写使能芯片3延迟

0xFFE0 8264

EMCStaticWaitOen3

/

0x0

选择输出使能芯片3延迟

0xFFE0 8268

EMCStaticWaitRd3

/

0x0

选择读访问芯片3延迟

0xFFE0 826C

EMCStaticWaitPage3

/

0x1F

选择芯片3异步页模式顺序访问延迟

0xFFE0 8270

EMCStaticWaitWr3

/

0x1F

选择写访问芯片3延迟

0xFFE0 8274

EMCStaticWaitTurn3

/

0x0F

选择芯片3总线翻转周期

0xFFE0 8278

EMCStaticExtendedWait

/

0x0

静态存储器读写传输时间

0xFFE0 8880

各寄存器的详细配置方法,因为篇幅所限,再也不赘述。在对系统进行外扩存储器开发时,须要仔细阅读外扩存储器芯片的相关文档,得到其准确的配置参数,再在初始化函数中对相关寄存器进行配置操做,才能正常使用外扩存储器。

4.4 系统控制模块

系统控制模块包括几个系统特性和控制寄存器,这些寄存器具备许多与特定外设器件无关的功能,每种类型的功能都有其自身的寄存器。

4.4.1  系统控制和状态寄存器

4.19所示位系统控制和状态寄存器(System Controls and Status register)。

4.19 系统控制和状态寄存器(SCS – 0xE01F C1A0

标识

功能描述

类型

复位值

0

GPIOM

 

GPIO访问模式选择

/

0

0

GPIO0和组1配置为与之前的LPC2000系列兼容的端口

1

GPIO0和组1配置为高速端口,使用片内存储器

标识

功能描述

类型

复位值

1

EMC Reset Disable

 

外部存储器控制器复位无效

/

0

0

复位时,EMC的全部寄存器和功能从新初始化

1

只有上电和掉电时EMC从新初始化

2

 

 

保留

 

 

3

MCIPWR Active Level

 

MCIPWR有效电平

/

0

0

MCIPWR引脚低电平

1

MCIPWR引脚高电平

4

OSCRANGE

 

主晶振范围选择

/

0

0

主晶振频率范围从1MHz20MHz

1

主晶振频率范围从15MHz24MHz

5

OSCEN

 

主晶振使能

/

0

0

主晶振无效

1

主晶振有效

6

OSCSTAT

 

主晶振状态

只读

0

0

主晶振未准备好

1

主晶振已准备好。能够经过OSCEN位设置做为一个时钟源使用

317

 

 

保留

 

NA

SCS寄存器主要用于设置晶振使用方法和GPIO属性,在后续相关章节里会几回使用到该寄存器。

4.4.2  外部中断

1. 逻辑结构

LPC2400含有4个外部中断输入(做为可选的管脚功能),四个引脚分别为EINT0EINT1EINT2EINT3。外部中断输入可用于将处理器从掉电模式唤醒。

可将多个管脚同时链接同一路外部中断,此时,外部中断逻辑根据方式位和极性位的不一样,分别进行以下处理:

1) 低有效电平激活方式,选用EINT功能的所有管脚的状态都链接到一个正逻辑与门。

2) 高有效电平激活方式,选用EINT功能的所有管脚的状态都链接到一个正逻辑或门。

3) 边沿激活方式,使用GPIO 端口号最低的管脚,与管脚的极性无关。(边沿激活方式中选择使用多个EINT管脚被看做编程出错。)

外部中断逻辑逻辑原理图见图4.12

 

4.12 外部中断逻辑原理图

当多个EINT 管脚逻辑或时,可在中断服务程序中经过IO0PINIO1PIN寄存器从GPIO端口读出管脚状态来判断产生中断的管脚。

2. 寄存器描述

外部中断具备4 个相关的寄存器,如表4.20所示。EXTINT寄存器包含中断标志,INTWAKE寄存器包含使能唤醒位,可以使能独立的外部中断输入将处理器从掉电模式唤醒,EXTMODEEXTPOLAR寄存器用来指定管脚使用电平或边沿激活方式。

4.20 外部中断寄存器

地址

寄存器名

功能描述

类型

0xE01FC140

EXTINT

外部中断标志寄存器,包含ENIT0EINT1 EINT2EINT3的中断标志

/

0xE01FC144

INTWAKE

中断唤醒寄存器,指示哪些中断能够唤醒掉电的CPU,以及控制是否使能唤醒

/

0xE01FC148

EXTMODE

外部中断方式寄存器,控制每一个管脚的边沿或电平激活

/

0xE01FC14C

EXTPOLAR

外部中断极性寄存器,控制由每一个管脚的哪一种电平或边沿来产生中断

/

 

1) 外部中断标志寄存器-External Interrupt Flag RegisterEXTINT - 0xE01FC140

当一个管脚选择使用外部中断功能时,对应在EXTPOLAR EXTMODE 寄存器中的位选择的电平或边沿将置位EXTINT寄存器中的中断标志,向VIC 提出中断请求,若是管脚中断使能,将会产生中断。

EXTINT 寄存器的位EINT0~位EINT3写入1可清除相应的外部中断标志。在电平激活方式下,只有在该管脚处于无效状态时才能清除相应的中断标志。

一旦EINT0EINT3中的一位被置位并开始执行相应的代码(处理唤醒和/或外部中断),必须将该位清零,不然之后该EINT 管脚所触发的事件将不能再被识别。

例如,若是外部中断0 管脚的低电平将系统从掉电模式唤醒,为了未来还能进入掉电模式,唤醒后的程序必须将EINT0位复位。若是EINT0位仍保持置位状态,后来的唤醒掉电模式的任何操做都将失败,外部中断也不例外。

4.21 外部中断标志寄存器

EXTINT

功能

功能描述

复位值

0

EINT0

电平激活方式下,若是管脚的EINT0 功能被选用且管脚处于有效状态时,该位置位;边沿激活方式下,若是管脚的EINT0 功能被选用且管脚上出现所选极性,该位置位。

该位经过写入1 清除,但电平激活方式下管脚处于有效状态的状况除外。

0

1

EINT1

电平激活方式下,若是管脚的EINT1 功能被选用且管脚处于有效状态时,该位置位;边沿激活方式下,若是管脚的EINT1 功能被选用且管脚上出现所选极性,该位置位。

该位经过写入1 清除,但电平激活方式下管脚处于有效状态的状况除外。

0

2

EINT2

电平激活方式下,若是管脚的EINT2 功能被选用且管脚处于有效状态时,该位置位;边沿激活方式下,若是管脚的EINT2 功能被选用且管脚上出现所选极性,该位置位。

该位经过写入1 清除,但电平激活方式下管脚处于有效状态的状况除外。

0

3

EINT3

电平激活方式下,若是管脚的EINT3 功能被选用且管脚处于有效状态时,该位置位;边沿激活方式下,若是管脚的EINT3 功能被选用且管脚上出现所选极性,该位置位。

该位经过写入1 清除,但电平激活方式下管脚处于有效状态的状况除外。

0

7:4

 

保留

NA

2) 中断唤醒寄存器-Interrupt Wakeup RegisterINTWAKE - 0xE01FC144

INTWAKE寄存器(有时亦称为EXTWAKE,外部中断唤醒寄存器)中的使能位容许外部中断、以太网、USBCANGPIOBOD或者RTC中断将处理器从掉电模式唤醒。相关的EINTn功能必须映射到管脚才能实现掉电唤醒,但中断并没必要要为了实现唤醒操做而在向量中断控制器中被使能。这样作的好处是容许外部中断输入将处理器从掉电模式唤醒,但不产生中断(只是简单地恢复操做),或者在掉电模式下使能中断而不将处理器唤醒(这样,当应用中并不须要唤醒特性时,也没必要关闭中断)。

4.22 外部中断唤醒寄存器

INTWAKE

功能

功能描述

复位值

0

EXTWAKE0

该位为1 时,使能EINT0将处理器从掉电模式唤醒

0

1

EXTWAKE1

该位为1 时,使能EINT1将处理器从掉电模式唤醒

0

2

EXTWAKE2

该位为1 时,使能EINT2将处理器从掉电模式唤醒

0

3

EXTWAKE3

该位为3 时,使能EINT3将处理器从掉电模式唤醒

0

4

ETHWAKE

该位为1 时,使能以太网中断将处理器从掉电模式唤醒

0

5

USBWAKE

该位为1 时,使能USB中断将处理器从掉电模式唤醒

0

6

CANWAKE

该位为1 时,使能CAN总线中断将处理器从掉电模式唤醒

0

7

GPIOWAKE

该位为1 时,使能特殊GPIO引脚中断将处理器从掉电模式唤醒

0

138

 

保留

NA

14

BODWAKE

该位为1 时,使能BOD中断将处理器从掉电模式唤醒

0

15

RTCWAKE

该位为1 时,使能实时时钟RTC中断将处理器从掉电模式唤醒

0

要使器件进入掉电模式并容许总线或管脚上的一个或多个事件能使其恢复正常操做,软件应该对管脚的外部中断功能从新编程,选择中断合适的方式和极性以及掉电模式。唤醒时软件应恢复管脚复用的外围功能。

上述的全部总线或管脚都是低电平有效。若是软件要使器件退出掉电模式来响应多个管脚共用的同一个EINTi 通道的事件,中断通道必须编程设定为低电平激活方式,由于只有在电平方式中通道才能使信号逻辑或来唤醒器件。

3)外部中断方式寄存器-External Interrupt Mode RegisterEXTMODE 0xE01F C148

EXTMODE寄存器中的位用来选择每一个EINT脚是电平触发仍是边沿触发。只有选择用做EINT功能(经过管脚链接模块)并已经过VICIntEnable(向量中断使能寄存器)使能的管脚才能产生外部中断(固然,若是管脚选择用做其它功能,则可能产生其它功能的中断)。

当某个中断在VICIntEnable 中被禁止时,软件应该只改变EXTMODE 寄存器中相应位的值。中断从新使能前,软件向EXTINT 写入1 来清除EXTINT 位,EXTINT 位可经过改变激活方式来置位。

4.23 外部中断方式寄存器

EXTMODE

功能

描述

复位值

0

EXTMODE0

0

EINT0 使用电平激活

0

1

EINT0 使用边沿激活

1

EXTMODE0

0

EINT0 使用电平激活

0

1

EINT0 使用边沿激活

2

EXTMODE0

0

EINT0 使用电平激活

0

1

EINT0 使用边沿激活

3

EXTMODE0

0

EINT0 使用电平激活

0

1

EINT0 使用边沿激活

74

 

 

保留

NA

4) 外部中断极性寄存器-External Interrupt Polarity RegisterEXTPOLAR 0xE01F C14C

在电平激活方式中,EXTPOLAR寄存器用来选择相应管脚是高电平仍是低电平有效;

在边沿激活方式中,EXTPOLAR寄存器用来选择管脚上升沿仍是降低沿有效。只有选择用做EINT功能(经过管脚链接模块)并已经过VICIntEnable(向量中断使能寄存器)使能的管脚才能产生外部中断(固然,若是管脚选择用做其它功能,则可能产生其它功能的中断)。

当某个中断在VICIntEnable 中被禁止时,软件应该只改变EXTPOLAR 寄存器中相应位的值。中断从新使能前,软件向EXTINT 写入1 来清除EXTINT 位,EXTINT 位可经过改变中断极性来置位。

4.24 外部中断极性寄存器

EXTPOLAR

功能

描述

复位值

0

EXTPOLAR0

0

EINT0低电平或降低沿有效(EXTMODE0决定)

0

1

EINT0 高电平或上升沿有效(EXTMODE0决定)

1

EXTPOLAR1

0

EINT1低电平或降低沿有效(EXTMODE1决定)

0

1

EINT1高电平或上升沿有效(EXTMODE1决定)

2

EXTPOLAR2

0

EINT2低电平或降低沿有效(EXTMODE2决定)

0

1

EINT2高电平或上升沿有效(EXTMODE2决定)

3

EXTPOLAR3

0

EINT3低电平或降低沿有效(EXTMODE3决定)

0

1

EINT3高电平或上升沿有效(EXTMODE3决定)

74

 

 

保留

NA

有关中断向量、中断设置与中断服务子程序的内容详见4.6节。

4.5 时钟和功率控制

4.5.1  晶体振荡器

LPC2400含有3个独立的晶体振荡器:主晶振、内部RC晶振和RTC晶振。每一个晶振针对不一样应用需求有多种使用方法。复位后,LPC2400系列处理器使用内部RC晶振提供时钟进行操做,直到使用软件进行切换为止。这使得系统能够不依赖于外部时钟进行操做,并且使引导加载程序能够在一个肯定的频率下进行操做。当Boot ROM转向用户程序以前,能够激活主晶振从而进入用户代码。

1.内部晶体振荡器(IRCInternal RC Oscillator

IRC能够用作看门狗定时器的时钟源,也能够做为时钟,驱动PLL锁相环提供给CPUIRC的精度不够,所以不能用于USB接口。一般的IRC频率是4MHz。在开机或芯片复位时,LPC2400使用IRC做为时钟源,以后能够使用软件转为使用其它时钟源。

2主晶振Main Oscillator

主晶振可用于为CPU提供时钟,其频率范围为1MHz24MHz。这个频率能够经过PLL倍频为更高的频率成为CPU的主频。一般把主晶振输出的时钟称为OSCCLKPLL输入引脚上的时钟称为PLLCLKINARM处理器内核时钟频率称为CCLK。当使用主晶振提供时钟而不激活PLL时,这三个值是相等的。

因为芯片复位时使用IRC晶振,主晶振由软件启动(使用SCS寄存器中的OSCEN位),而且在某些应用中始终不会用到。经过SCS寄存器中的OSCSTAT状态位能够使软件判断主晶振是否运行和稳定,也能够经过SCS寄存器中的OSCRANGE位设置其频率范围。

LPC2400的振荡器可工做在两种模式下:从属模式和振荡模式。从属模式下,输入时钟信号XTAL1与一个100pF相连,其幅值很多于200mVXTAL2管脚不链接。振荡模式下,因为片内集成了反馈电阻,只需在外部链接一个晶体和电容Cx1Cx2 就可造成基本模式的振荡。

两种振荡器模式的示意见图4.13

 

4.13 振荡器模式

3RTC晶振(RTC Oscillator

RTC晶振的频率为32.768KHz,通常用于给RTC实时时钟提供时钟源。RTC晶振也能够用于看门狗定时器,经过驱动PLL也能够用于提供CPU主频。

4.时钟源选择

几个时钟源均可以用来驱动PLL从而给CPU和片内外设提供时钟。当PLL未链接时,系统能够经过CLKSRCSEL寄存器安全的改变时钟源。

4.25 时钟源选择寄存器(CLKSRCSEL – 0xE01F C10C

CLKSRCSEL

功能

描述

复位值

10

CLKSRC

00

选择IRC晶振为PLL时钟源

00

01

选择主晶振为PLL时钟源

10

选择RTC晶振为PLL时钟源

11

保留

74

 

0

未使用,始终为0

0

4.5.2  PLL锁相环

PLL接受输入的时钟频率范围为32kHz50MHz。输入频率经过一个预分频器分频成为PLL内部频率,预分频器的值用变量“N”表示。而后再经过一个电流控制振荡器(CCO)倍增到范围275MHz~550MHz,倍频器的值用变量“M”表示。CCO频率再经过CPU频率设置寄存器分频成为提供给CPUCCLK时钟。

PLL 的激活由PLLCON寄存器控制,PLL倍频器和分频器的值由PLLCFG寄存器控制。为了防止PLL参数发生意外改变或PLL失效,对这两个寄存器进行了保护。当PLL提供芯片时钟时,因为芯片的全部操做,包括看门狗定时器在内都依赖于它,所以PLL设置的意外改变将致使CPU 执行不指望的动做。

1PLL控制寄存器-PLL Control RegisterPLLCON 0xE01FC080

PLLCON寄存器可用于使能和链接PLL,它是最新的PLL控制位的保持寄存器,写入该寄存器的值在有效的PLL 馈送序列执行以前不起做用。使能PLL将使PLL锁定到当前倍频器和分频器值的设定频率上。链接PLL将使处理器和全部片内功能都根据PLL输出时钟来运行。对PLLCON的更改只有在对PLLFEED寄存器执行了正确的PLL馈送序列后才生效。

4.26 PLL 控制寄存器

PLLCON

功能

描述

复位值

0

PLLE

PLL使能。当该位为1 而且在有效的PLL馈送以后,该位将激活PLL并容许其锁定到指定的频率。

0

1

PLLC

PLL链接。当PLLCPLLE都为1 而且在有效的PLL馈送后,将PLL做为时钟源链接到LPC2400。不然,LPC2400直接使用振荡器时钟。

0

7:2

保留

保留

NA

PLL在做为时钟源以前必须进行设置、使能并锁定。将振荡器时钟切换到PLL输出或反过来操做时,内部电路对操做进行同步以确保不会产生干扰。硬件不能确保PLL在链接以前锁定或在PLL在失去锁定时自动断开链接。在PLL失去锁定的状况下,振荡器极可能已经变得不稳定,这样即便断开PLL也挽救不了这种情况。

2PLL配置寄存器-PLL Configuration RegisterPLLCFG 0xE01FC084

PLLCFG寄存器是最新的PLL配置值的保持寄存器,包含PLL倍频器和分频器值。在执行正确的PLL馈送序列以前改变PLLCFG寄存器的值不会生效。

4.27 PLL配置寄存器

PLLCFG

功能

描述

复位值

14:0

MSEL

PLL倍频器值,在PLL频率计算中其值为M-1

0

15

保留

保留

NA

23:16

NSEL

PLL预分配器值,在PLL频率计算中其值为N

NA

31:24

保留

保留

NA

3PLL状态寄存器-PLL Status RegisterPLLSTAT 0xE01FC088

PLLSTAT为只读寄存器,它是PLL控制和配置信息的读回寄存器,反映了正在使用的真实PLL参数和状态。PLLSTAT可能与PLLCONPLLCFG中的值不一样,这是由于没有执行正确的PLL馈送序列,这两个寄存器中的值并未生效。

4.28 PLL状态寄存器

PLLSTAT

功能

描述

复位值

14:0

MSEL

读出的PLL倍频器值,这是PLL当前使用的值

0

15

保留

保留

NA

23:16

NSEL

读出的PLL预分频器值,这是PLL当前使用的值

NA

24

PLLE

读出的PLL使能位,该位为1时,PLL处于激活状态;为0时,PLL关闭;进入掉电模式时,该位自动清零

0

25

PLLC

读出的PLL链接位,当PLLCPLLE都为1 时,PLL做为时钟源链接到LPC2400;当PLLCPLLE位为0 时,PLL被旁路,LPC2400直接使用振荡器时钟;进入掉电模式时,该位自动清零

0

26

PLOCK

反映PLL的锁定状态,为0时,PLL未锁定;为1时,PLL锁定到指定的频率

 

31:27

保留

保留

NA

PLLSTAT 寄存器中的PLOCK位链接到中断控制器。这样可以使用软件打开PLL并链接到其它功能,不须要等待PLL锁定。当发生中断时(PLOCK=1),能够链接PLL并禁止中断。只能经过禁止PLL中断的方式返回。

PLL3种可能的工做模式,由PLLEPLLC组合获得。

4.29 PLL的工做模式

PLLC

PLLE

PLL 功能

0

0

PLL 被关闭并断开链接,系统使用未更改的时钟输入

0

1

PLL 被激活可是还没有链接,PLL 可在PLOCK 置位后链接

1

0

00 组合相同,这样消除了PLL 已链接但没有使能的可能性

1

1

PLL 已使能并链接处处理器做为系统时钟源

4PLL馈送寄存器-PLL Feed RegisterPLLFEED 0xE01FC08C

必须将正确的馈送序列写入PLLFEED寄存器才能使PLLCONPLLCFG寄存器的更改生效。馈送序列以下:

1) 将值0xAA 写入PLLFEED

2) 将值0x55 写入PLLFEED

这两个写操做的顺序必须正确,并且必须是连续的APB总线周期,这意味着在执行PLL馈送操做时必须禁止中断。无论是写入的值不正确仍是没有知足前两个条件,对PLLCONPLLCFG寄存器的更改都不会生效。

4.30 PLL 馈送寄存器

PLLFEED

功能

描述

复位值

7:0

PLLFEED

PLL馈送序列必须写入该寄存器才能使PLL配置和控制寄存器的更改生效

0x00

5PLL和掉电模式

掉电模式会自动关闭并断开PLL。从掉电模式唤醒不会自动恢复PLL的设定,PLL的恢复必须由软件来完成。一般,一个将PLL激活并等待锁定,而后将PLL链接的子程序能够在任何中断服务程序的开始调用。有一点很是重要,那就是不要试图在掉电唤醒以后简单地执行馈送序列来从新启动PLL,这会出如今PLL锁定创建以前同时使能并链接PLL的危险。

6PLL频率计算举例:

当一个LPC2400 ARM系统须要使用PLL,应当按照如下原则进行:

1) 肯定处理器的时钟频率CCLK。这能够根据系统对处理器的总体要求来决定,外围器件的时钟频率能够低于处理器频率。

2) 肯定PLL内部的时钟频率FCCOFCCO的值应当在275MHz550MHz之间,并且应当是CCLK的整数倍。

3) 肯定晶体振荡器频率FINFIN的值应当在32kHz50MHz之间。

PLL的输出频率公式为:FCCO = (2×M×FIN) / N

选择两个整数MN即可获得合适的FCCO值。M的取值范围为6512N的取值范围为132

例如:系统要求使用USB接口,CPU主频约为60MHz。外部晶振频率为4MHz

由要求可知:USB总线要求精确的48MHz时钟,所以能够选择FCCO480MHz。当N值为1时,M = 480 / (2×4) = 60。所以PLLCFG值为0x3BN-1 = 0M-1 = 0x3B)。

4.5.3  时钟分频

PLL的输出必须向下分频为更低频率的信号才能用于CPUUSB模块。提供给USB模块的分频器是独立的,由于USB的时钟要求必须是准确的48MHz并且有50%的占空比。分频给CPU的信号成为CCLK时钟,而且再分频成为各个片内外设的驱动时钟。

1CPU时钟配置寄存器-CPU Clock Configuration RegisterCCLKCFG 0xE01F C104

CCLKCFG寄存器控制PLL的分频输出提供给CPU。若是不使用PLL,分频值为1

4.31 CPU时钟配置寄存器

CCLKCFG

功能

描述

复位值

7:0

CCLKSEL

分频器值,用于生成CPU时钟(CCLK)。本值只能为0或奇数值(1,3,5,…,255

0x00

CCLK值为PLL的输出频率除以CCLKSEL+1。当CCLKSEL值为1时,CCLK值为PLL输出频率的一半。

2USB时钟配置寄存器-USB Clock Configuration RegisterUSBCLKCFG 0xE01F C108

USBCLKCFG寄存器控制PLL的分频输出提供给USB模块。若是不使用PLL,分频值为1。输出的频率应该为48MHz而且有50%的占空比。

4.32 USB时钟配置寄存器

USBCLKCFG

功能

描述

复位值

3:0

USBSEL

分频器值,用于生成USB时钟(CCLK

0x00

7:4

保留

NA

USB模块的时钟值为PLL的输出频率除以USBSEL+1。当USBSEL值为1时,USB时钟值为PLL输出频率的一半。

3IRC整理寄存器-IRC Trim RegisterIRCTRIM 0xE01F C1A4

这个寄存器用于整理片内4MHz的晶振。

4.33 IRC整理寄存器

IRCtrim

功能

描述

复位值

7:0

IRCtrim

IRC整理值,用于控制片内4MHzIRC晶振频率

0xA0

15:8

保留

NA

4.外设时钟选择寄存器01Peripheral Clock Selection registers 0 and 1PCLKSEL0 0xE01F C1A8 and PCLKSEL1 – 0xE01F C1AC

这一对寄存器中的每两位控制一个外设的时钟,其取值意义参见表4.36

4.34 外设时钟选择寄存器0

PCLKSEL0

功能

描述

复位值

1:0

PCLK_WDT

看门狗外设时钟选择

00

3:2

PCLK_TIMER0

定时器0外设时钟选择

00

5:4

PCLK_TIMER1

定时器1外设时钟选择

00

7:6

PCLK_UART0

串口0外设时钟选择

00

9:8

PCLK_UART1

串口1外设时钟选择

00

11:10

PCLK_PWM0

脉宽调制器0外设时钟选择

00

13:12

PCLK_PWM1

脉宽调制器1外设时钟选择

00

15:14

PCLK_I2C0

I2C0外设时钟选择

00

17:16

PCLK_SPI

SPI外设时钟选择

00

19:18

PCLK_RTC

实时时钟外设时钟选择

00

21:20

PCLK_SSP1

SSP1外设时钟选择

00

23:22

PCLK_DAC

DAC外设时钟选择

00

25:24

PCLK_ADC

ADC外设时钟选择

00

27:26

PCLK_CAN1

CAN1外设时钟选择

00

29:28

PCLK_CAN2

CAN2外设时钟选择

00

31:30

PCLK_ACF

CAN滤波器外设时钟选择

00

注:PCLK_RTC字段中,值“01”是无效的,试图写入“01”不会改变预设值。

4.35 外设时钟选择寄存器1

PCLKSEL1

功能

描述

复位值

1:0

PCLK_BAT_RAM

电池支持RAM外设时钟选择

00

3:2

PCLK_GPIO

GPIO外设时钟选择

00

5:4

PCLK_PCB

引脚链接模块外设时钟选择

00

7:6

PCLK_I2C1

I2C1外设时钟选择

00

9:8

保留,始终为0

00

11:10

PCLK_SSP0

SSP0外设时钟选择

00

13:12

PCLK_TIMER2

定时器2外设时钟选择

00

15:14

PCLK_TIMER3

定时器3外设时钟选择

00

17:16

PCLK_UART2

串口2外设时钟选择

00

19:18

PCLK_UART3

串口3外设时钟选择

00

21:20

PCLK_I2C2

I2C2外设时钟选择

00

23:22

PCLK_I2S

I2S总线外设时钟选择

00

25:24

PCLK_MCI

MCI外设时钟选择

00

27:26

保留,始终为0

00

PCLKSEL1

功能

描述

复位值

29:28

PCLK_SYSCON

系统控制模块外设时钟选择

00

31:30

保留,始终为0

00

4.36 外设时钟选择寄存器位值

功能描述

复位值

00

PCLK_xxx = CCLK / 4

00

01

PCLK_xxx = CCLK

00

10

PCLK_xxx = CCLK / 2

00

11

CAN1CAN2CAN滤波器部件中PCLK_xxx = HCLK / 6,其他部件中PCLK_xxx = HCLK / 8

00

4.5.4  功率控制

1. 节电模式

嵌入式系统通常使用电池供电,所以系统的耗电和待机时间是个重要指标。节电的方法主要是下降系统时钟频率:改变时钟源、重配置PLL值或者改变CPU时钟分频值。另外,也能够经过中止片内外设时钟的方法来关闭不使用的片内外设,进一步减小功耗。

LPC2400支持三种节电模式:空闲模式、睡眠模式和掉电模式。LPC2400有一个独立的功率控制单元用来给RTC和一个小的静态RAM供电,这个特性使得LPC2400能够将片内的其它大部分设备所有关闭。

1)空闲模式(Idel mode:指令的执行被挂起直到发生复位或中断为止。外设功能在空闲模式下继续保持并可产生中断使处理器恢复运行。空闲模式使处理器、存储器系统和相关控制器以及内部总线再也不消耗功率。任何中断均可以将CPU从空闲模式下唤醒。

2)睡眠模式(Sleep mode:主晶振关闭,全部时钟中止。IRC的输出无效,但IRC并未关闭而且能够快速唤醒。32kHzRTC晶振也未中止,由于RTC中断能够用来作唤醒的中断源。睡眠模式保持处理器状态和寄存器、外设寄存器和内部SRAM的值。芯片管脚的逻辑电平保持静态。复位或特定的不须要时钟仍能工做的中断可停止睡眠模式并使芯片恢复正常运行。因为睡眠模式使芯片全部的动态操做都挂起,所以芯片的功耗下降到几乎为零。芯片复位和特定的中断能够将CPU从睡眠模式下唤醒。

3)掉电模式(Power-down mode:掉电模式与睡眠模式相似,但不一样的是掉电模式会将Flash存储器也关闭。在掉电模式下,主晶振和IRC以及全部内部时钟都中止,只有32kHzRTC晶振继续工做。

2. 寄存器描述

外设的功率控制特性容许独立关闭应用中不须要的外设,这样能够进一步下降功耗。功率控制功能包含两个寄存器,分别是PCONPCONP

1) 功率控制寄存器-Power Control RegisterPCON 0xE01F C0C0

4.37 功率控制寄存器

PCON

功能

描述

复位值

0

PM0(IDL)

功耗模式控制位0

0

1

PM1(PD)

功耗模式控制位1

0

2

BODPDM

低电压掉电模式。当该位为0时,进入掉电模式时仍然保持低电压检测功能;当该位为1时,低电压检测功能也被关闭,这样能够进一步减小功耗,但存在着电压太低而没法从掉电模式中唤醒的可能

0

3

BOGD

低电压全局无效。当该位为1时,低电压检测功能无效;该位为0时,低电压检测功能使能

0

4

BORD

低电压复位无效。当该位为1时,低电压检测(2.6V)不会致使芯片复位;当该位为0时,低电压检测(2.9V)使芯片复位

0

6:3

-

保留

NA

7

PM2

功耗模式控制位2

0

利用PCON寄存器设置节电模式的方法详见表4.38PCON寄存器中的三个比特PM2PM1PM0联合控制进入LPC2400节电模式的方式。

4.38 节电模式控制位

PM2PM1PM0

功能描述

000

正常模式

001

空闲模式

101

睡眠模式

010

掉电模式

其它

保留

2)外设功率控制寄存器-Power Control for Peripherals RegisterPCONP 0xE01F C0C4

PCONP寄存器容许将所选的外设功能关闭以实现节电的目的,经过关断特定外围模块的时钟源来实现。有少数外设功能不能被关闭(例如看门狗定时器、GPIO、引脚链接模块和系统控制模块)。

某些外设,特别是包含模拟功能的外设,它们的操做无需时钟,但会消耗功率。这些外设包含独立的禁能控制位,能够经过它们来关闭电路以下降功耗。

PCONP中的每一个位都控制一个外设,每一个位所对应的外设编号见LPC2400存储器寻址部分的APB外设映射一节。当位值为1时该外设启用,当位值为0时该外设时钟关闭。外设在外设功率控制寄存器的对应位见表4.11

4.39外设功率控制寄存器

PCONP

功能

描述

复位值

0

-

未使用,始终为0

0

1

PCTIM0

定时器0功率时钟控制位

1

2

PCTIM1

定时器1功率时钟控制位

1

3

PCUART0

串口0功率时钟控制位

1

4

PCUART1

串口1功率时钟控制位

1

5

PCPWM0

脉宽调制器0功率时钟控制位

1

6

PCPWM1

脉宽调制器1功率时钟控制位

1

7

PCI2C0

I2C0功率时钟控制位

1

8

PCSPI

SPI功率时钟控制位

1

9

PCRTC

实时时钟功率时钟控制位

1

10

PCSSP1

SSP1接口功率时钟控制位

1

11

PCEMC

外扩存储器控制器

1

12

PCAD

A/D转换器功率时钟控制位。清零该位前先清零AD0CR 寄存器的PDN位,该位应当在置位PDN前被置位

0

13

PCCAN1

CAN1功率时钟控制位

0

14

PCCAN2

CAN2功率时钟控制位

0

18:15

保留

NA

19

PCI2C1

I2C1功率时钟控制位

1

20

PCLCD

液晶控制器功率时钟控制位

0

21

PCSSP0

SSP0功率时钟控制位

1

22

PCTIM2

定时器2功率时钟控制位

0

23

PCTIM3

定时器3功率时钟控制位

0

24

PCUART2

串口2功率时钟控制位

0

25

PCUART3

串口3功率时钟控制位

0

26

PCI2C2

I2C2功率时钟控制位

1

27

PCI2S

I2S接口功率时钟控制位

0

28

PCSDC

SD卡接口功率时钟控制位

0

29

PCGPDMA

通用DMA功能功率时钟控制位

0

30

PCENET

以太网模块功率时钟控制位

0

31

PCUSB

USB接口功率时钟控制位

0

复位之后,PCONP寄存器按照默认值使能选中的接口和外设控制器。用户程序应当在启动代码中对PCONP寄存器编程用来启动所须要的外设功能,并关闭不须要的接口和外设,以达到下降功耗的要求。系统启动之后,除了对外设功能相关的寄存器进行配置外,用户应用程序应当不要再访问PCONP 寄存器从而启动使用片内的任何外围功能。

4.5.5  时钟和功率控制举例

1. 系统时钟设置

LPC2400的启动代码中,系统时钟的设置是经过一个ConfigurePLL ( )函数来实现的。该函数首先关闭PLL,而后经过CLKSRCSEL寄存器选择主晶振为时钟源,再经过PLLCFG寄存器利用M值和N值设置CCO频率,用CCLKCFG寄存器分频为CPU时钟CCLK,最后使能PLL使设置生效。注意对PLLCON寄存器的每次操做都要用正确的馈送序列来实现。函数中的有关参数是在target.h头文件中定义的,其相关程序行以下:

代码清单4.2

……

#define Fosc 12000000

#define Fcclk 57600000

#define Fcco 288000000

#define Fpclk (Fcclk / 4)

#define PLL_MValue 11

#define PLL_NValue 0

#define CCLKDivValue 4

#define USBCLKDivValue 5

……

主晶振采用12MHz晶体振荡器,其宏定义Fosc值要跟实际的物理参数相同。因为M值为12N值为1(注意实际参数要在设置值上加1),CCO频率Fcco = 2×M×Fosc / N = 288MHz。CPU时钟CCLK = Fcco / (CCLKDivValue+1) = 57.6MHz。而USB时钟USBCLK = Fcco / (USBCLKDivValue+1) = 48MHz,正好知足使用要求。

代码清单4.3

void ConfigurePLL ( void )

{

if ( PLLSTAT & (1 << 25) ) // PLL是否链接

    { PLLCON = 1; // 使能PLL并断开链接

PLLFEED = 0xaa; // PLL馈送

PLLFEED = 0x55;    }

    PLLCON = 0; // 关闭PLL并断开链接

    PLLFEED = 0xaa;

    PLLFEED = 0x55;

    SCS |= 0x20; // 使能主晶振

    while( !(SCS & 0x40) );          // 读主晶振状态直到主晶振可用

    CLKSRCSEL = 0x1;         // 选择12MHz主晶振做为PLL时钟源

    PLLCFG = PLL_MValue | (PLL_NValue << 16); // 执行配置

    PLLFEED = 0xaa;

    PLLFEED = 0x55;

    PLLCON = 1; // 使能PLL

    PLLFEED = 0xaa;

    PLLFEED = 0x55;

    CCLKCFG = CCLKDivValue; // 设置时钟分频,设定CPU频率CCLK

#if USE_USB

    USBCLKCFG = USBCLKDivValue; // usbclk = 288 MHz/6 = 48 MHz

#endif

    while ( ((PLLSTAT & (1 << 26)) == 0) ); // 检查锁定位状态

    PLLCON = 3; // 使能并链接PLL

    PLLFEED = 0xaa;

    PLLFEED = 0x55;

while ( ((PLLSTAT & (1 << 25)) == 0) ); // 检查链接状态位

return;

}

2. 外设分频

外设启动和分频应在启动代码中实现。LPC2400的启动代码使用一个TargetResetInit( )函数实现,其中相关代码以下:

代码清单4.4

……

#if USE_USB

PCONP |= 0x80000000; // 若是使用USB则打开USB PCLK

#endif

ConfigurePLL();

#if (Fpclk / (Fcclk / 4)) == 1

    PCLKSEL0 = 0x00000000; // PCLK = 1/4 CCLK

    PCLKSEL1 = 0x00000000;

#endif

#if (Fpclk / (Fcclk / 4)) == 2

    PCLKSEL0 = 0xAAAAAAAA; // PCLK = 1/2 CCLK

    PCLKSEL1 = 0xAAAAAAAA;

#endif

#if (Fpclk / (Fcclk / 4)) == 4

    PCLKSEL0 = 0x55555555; // PCLK = CCLK

    PCLKSEL1 = 0x55555555;

#endif

……

为了下降外设功耗,通常都将APB外设时钟设为CCLK时钟的1/4

3. 进入Idle模式

代码清单4.5

……

PCON = 0x01;                   // 进入Idle状态,CPU中止

……

进入Sleep模式和Power Down模式采用不一样设置值进行设置便可。

4.6 向量中断控制器

4.6.1 LPC2400中断特性

LPC2400使用了ARM PrimeCellTM技术的向量中断控制器,利用映射到AHB总线的地址空间实现快速访问。支持最大32个向量IRQ中断,拥有16个可编程中断优先级,而且每一个可编程优先级对应固定硬件优先级,具备硬件优先级屏蔽逻辑。全部中断均可设置为FIQ中断,还能够产生软件中断。

4.6.2 功能概述

ARM处理器内核有两类中断:中断请求(IRQ)和快速中断请求(FIQ)。管理中断类型识别及优先级判断,并向ARM内核提供中断向量和中断信号的模块称为向量中断控制器(VIC)。VIC支持的32个中断能够编程设置为IRQFIQ中断类型。这样用户能够按照处理器外围模块的优先级别灵活设置中断的优先级别。

快速中断请求(FIQ)是优先级最高的中断。若是有一个以上中断被设置为FIQ,则VIC对中断输入进行“或”操做,最终向ARM内核产生一个FIQ信号。为了确保FIQ响应的最短延时,在实际应用中通常只设置一个中断源为FIQ类型。这样FIQ中断服务程序就能够直接处理对应模块。若是有多个中断源设置为FIQ,则在FIQ中断服务程序中要先读出VICFIQ中断状态字,从而判断真正发生的中断源才能处理对应的中断。

除了设置为FIQ的中断外,其他中断类型为向量IRQ。向量IRQ中断优先级能够编程设置。若是有一个以上IRQ中断分配相同优先级且同时产生中断请求,则链接到VIC的通道靠前的中断源先被应答服务。VIC通道数值分配见中断源小节表。

另外,VIC对全部向量IRQ进行“或”操做,最终向ARM内核产生一个IRQ信号。IRQ中断服务程序先读取VICIRQ中断状态字,肯定中断源后执行相应中断服务。

4.6.3 中断控制器结构

向量中断控制器VIC的结构如图4.14所示。

 

4.14 VIC的结构框图

4.6.4 寄存器描述

VIC内全部寄存器都为32位宽,具体名称及地址见表4.40

4.40 VIC寄存器映射表

名称

功能描述

访问方式

复位值[1]

地址

VICIRQStatus

IRQ中断状态寄存器。该寄存器保存各个IRQ中断请求是否有效。

只读

0

0xFFFFF000

VICFIQStatus

FIQ中断状态寄存器。该寄存器保存各个FIQ中断请求是否有效。

只读

0

0xFFFFF004

VICRawIntr

原始中断状态寄存器。该寄存器保存32个中断请求和软件中断是否有效,无论它们是否被使能。

只读

-

0xFFFFF008

VICIntSelect

中断类型选择寄存器。该寄存器用于把中断请求设置为FIQ或者IRQ

/

0

0xFFFFF00C

VICIntEnable

中断使能寄存器。该寄存器使能32个中断请求和软件中断产生IRQFIQ中断。

/

0

0xFFFFF010

VICIntEnClr

中断使能清除寄存器。该寄存器可清除中断使能寄存器已使能的各中断位。

只写

-

0xFFFFF014

VICSoftInt

软件中断寄存器。该寄存器内容与32个中断请求做相“或”操做。

/

0

0xFFFFF018

名称

功能描述

访问方式

复位值[1]

地址

VICSoftIntClear

软件中断清除寄存器。

只写

-

0xFFFFF01C

VICProtection

VIC保护使能寄存器。该寄存器限制软件在特权模式下运行时访问VIC各个寄存器。

/

0

0xFFFFF020

VICSWPriorityMask

软件优先级屏蔽寄存器。

/

0xFFFF

0xFFFFF024

VICVectAddr0

向量地址0寄存器。该寄存器保存IRQ0的中断服务程序入口地址。IRQ0优先级最高,IRQ32最低。

/

0

0xFFFFF100

VICVectAddr1

向量地址1寄存器。

/

0

0xFFFFF104

VICVectAddr2

向量地址2寄存器。

/

0

0xFFFFF108

VICVectAddr3

向量地址3寄存器。

/

0

0xFFFFF10C

VICVectAddr4

向量地址4寄存器。

/

0

0xFFFFF110

VICVectAddr5

向量地址5寄存器。

/

0

0xFFFFF114

VICVectAddr6

向量地址6寄存器。

/

0

0xFFFFF118

VICVectAddr7

向量地址7寄存器。

/

0

0xFFFFF11C

VICVectAddr8

向量地址8寄存器。

/

0

0xFFFFF120

VICVectAddr9

向量地址9寄存器。

/

0

0xFFFFF124

VICVectAddr10

向量地址10寄存器。

/

0

0xFFFFF128

VICVectAddr11

向量地址11寄存器。

/

0

0xFFFFF12C

VICVectAddr12

向量地址12寄存器。

/

0

0xFFFFF130

VICVectAddr13

向量地址13寄存器。

/

0

0xFFFFF134

VICVectAddr14

向量地址14寄存器。

/

0

0xFFFFF138

VICVectAddr15

向量地址15寄存器。

/

0

0xFFFFF13C

VICVectAddr16

向量地址16寄存器。

/

0

0xFFFFF140

VICVectAddr17

向量地址17寄存器。

/

0

0xFFFFF144

VICVectAddr18

向量地址18寄存器。

/

0

0xFFFFF148

VICVectAddr19

向量地址19寄存器。

/

0

0xFFFFF14C

VICVectAddr20

向量地址20寄存器。

/

0

0xFFFFF150

VICVectAddr21

向量地址21寄存器。

/

0

0xFFFFF154

VICVectAddr22

向量地址22寄存器。

/

0

0xFFFFF158

VICVectAddr23

向量地址23寄存器。

/

0

0xFFFFF15C

VICVectAddr24

向量地址24寄存器。

/

0

0xFFFFF160

VICVectAddr25

向量地址25寄存器。

/

0

0xFFFFF164

VICVectAddr26

向量地址26寄存器。

/

0

0xFFFFF168

VICVectAddr27

向量地址27寄存器。

/

0

0xFFFFF16C

VICVectAddr28

向量地址28寄存器。

/

0

0xFFFFF170

VICVectAddr29

向量地址29寄存器。

/

0

0xFFFFF174

VICVectAddr30

向量地址30寄存器。

/

0

0xFFFFF178

VICVectAddr31

向量地址31寄存器。

/

0

0xFFFFF17C

VICVectPriority0

向量优先级0寄存器。该寄存器设置IRQ0的优先级。

/

0xF

0xFFFFF200

VICVectPriority1

向量优先级1寄存器。

/

0xF

0xFFFFF204

VICVectPriority2

向量优先级2寄存器。

/

0xF

0xFFFFF208

VICVectPriority3

向量优先级3寄存器。

/

0xF

0xFFFFF20C

VICVectPriority4

向量优先级4寄存器。

/

0xF

0xFFFFF210

VICVectPriority5

向量优先级5寄存器。

/

0xF

0xFFFFF214

VICVectPriority6

向量优先级6寄存器。

/

0xF

0xFFFFF218

VICVectPriority7

向量优先级7寄存器。

/

0xF

0xFFFFF21C

VICVectPriority8

向量优先级8寄存器。

/

0xF

0xFFFFF220

VICVectPriority9

向量优先级9寄存器。

/

0xF

0xFFFFF224

VICVectPriority10

向量优先级10寄存器。

/

0xF

0xFFFFF228

VICVectPriority11

向量优先级11寄存器。

/

0xF

0xFFFFF22C

VICVectPriority12

向量优先级12寄存器。

/

0xF

0xFFFFF230

VICVectPriority13

向量优先级13寄存器。

/

0xF

0xFFFFF234

VICVectPriority14

向量优先级14寄存器。

/

0xF

0xFFFFF238

VICVectPriority15

向量优先级15寄存器。

/

0xF

0xFFFFF23C

VICVectPriority16

向量优先级16寄存器。

/

0xF

0xFFFFF240

VICVectPriority17

向量优先级17寄存器。

/

0xF

0xFFFFF244

VICVectPriority18

向量优先级18寄存器。

/

0xF

0xFFFFF248

VICVectPriority19

向量优先级19寄存器。

/

0xF

0xFFFFF24C

VICVectPriority20

向量优先级20寄存器。

/

0xF

0xFFFFF250

VICVectPriority21

向量优先级21寄存器。

/

0xF

0xFFFFF254

VICVectPriority22

向量优先级22寄存器。

/

0xF

0xFFFFF258

VICVectPriority23

向量优先级23寄存器。

/

0xF

0xFFFFF25C

VICVectPriority24

向量优先级24寄存器。

/

0xF

0xFFFFF260

VICVectPriority25

向量优先级25寄存器。

/

0xF

0xFFFFF264

VICVectPriority26

向量优先级26寄存器。

/

0xF

0xFFFFF268

VICVectPriority27

向量优先级27寄存器。

/

0xF

0xFFFFF26C

VICVectPriority28

向量优先级28寄存器。

/

0xF

0xFFFFF270

VICVectPriority29

向量优先级29寄存器。

/

0xF

0xFFFFF274

VICVectPriority30

向量优先级30寄存器。

/

0xF

0xFFFFF278

VICVectPriority31

向量优先级31寄存器。

/

0xF

0xFFFFF27C

VICAddress

向量地址寄存器。当发生IRQ中断时,该寄存器保存当前有效中断。

/

0

0xFFFFFF00

[1] 复位值只反映了使用位的数值,不包括保留位的内容。

下面将按照VIC逻辑中的使用顺序对VIC寄存器进行描述,该顺序为从与中断请求输入最密切的寄存器开始,到由软件所使用的最抽象的寄存器结束。对大多数人来讲,这也是在学习VIC时读取寄存器的最佳顺序。

1、 软件中断寄存器VICSoftInt0xFFFFF018

软件中断寄存器用于产生软件中断。在执行任何逻辑操做以前,该寄存器的内容将与32个不一样外设的中断请求相“或”。

4.41 软件中断寄存器位描述

功能描述

复位值

310

0

不产生中断请求。写0至该位无效。

0

1

强制产生与该位相关的中断请求。

2、软件中断清零寄存器VICSoftIntClear0xFFFFF01C

软件中断清零寄存器为只写寄存器。对该寄存器一个或多个位写1能够清除软件中断寄存器中的置1位。

4.42 软件中断清零寄存器

功能描述

复位值

310

0

0无效果。

0

1

1则软件中断寄存器中对应位被清除。

3、原始中断状态寄存器VICRawIntr0xFFFFF008

该只读寄存器读取全部32个中断请求和软件中断的状态,无论中断是否使能或分类。

4.43 原始中断状态寄存器

功能描述

复位值

310

0

对应位的中断请求或软件中断未声明。

-

1

对应位的中断请求或软件中断声明。

4、中断使能寄存器VICIntEnable0xFFFFF010

中断使能寄存器为读写寄存器。该寄存器使能分配位FIQIRQ的中断请求或软件中断。

4.44 中断使能寄存器

功能描述

复位值

310

当读取该寄存器时,读1表示中断请求使能为FIQIRQ,写入1,使能中断请求或软件中断分配为FIQIRQ;写入0无效。

0

5、中断使能清零寄存器VICIntEnClr0xFFFFF014

该寄存器为只写寄存器。用于清除中断使能寄存器中一个或多个中断使能位。

4.45中断使能清零寄存器

功能描述

复位值

310

0

0无效果。

-

1

1则中断使能寄存器中对应位被清除。

6、中断选择寄存器VICIntSelect0xFFFFF00C

该寄存器将32个中断请求分别分配为FIQIRQ.

4.46中断选择寄存器

功能描述

复位值

310

0

表示对应位的中断请求类型为IRQ

0

1

表示对应位的中断请求类型为FIQ

7IRQ状态寄存器VICIRQStatus0xFFFFF000

IRQ状态寄存器为只读寄存器。该寄存器读取使能并分配为IRQ的中断请求状态。

4.47 IRQ状态寄存器

功能描述

复位值

310

某位读取出1表明该位中断请求使能且被分配为IRQ

0

8FIQ状态寄存器VICFIQStatus0xFFFFF004

FIQ状态寄存器为只读寄存器。该寄存器读取使能并分配为FIQ的中断请求状态。若是有超过一个请求分配为FIQFIQ服务程序可读取该寄存器来肯定是哪个(几个)请求被激活。

4.48 FIQ状态寄存器

功能描述

复位值

310

某位读取出1表明该位中断请求使能且被分配为FIQ

0

9、向量地址寄存器VICVectAddr0~310xFFFFF100~17C

向量地址寄存器一共有32个,每一个寄存器可读可写。这些寄存器对应保存32个向量IRQ中断的中断服务程序的入口地址。

4.49 向量地址寄存器

功能描述

复位值

310

每一个寄存器对应一个中断源,该寄存器保存该中断源服务程序入口地址,中断源见表4.54

0x00000000

10、向量优先级寄存器VICVectPriority0~310xFFFFF200~27C

向量优先级寄存器用于设置32个向量中断各自优先级。优先级从0~150为最高优先级,15最低。全部向量优先级寄存器复位值为最低优先级15,且寄存器容许写操做逐一更改32个向量中断优先级。当优先级相同的中断同时发生,向量地址寄存器VICVectAddr0~31数值小的优先被相应。

4.50向量优先级寄存器

功能描述

复位值

30

设置相应向量中断优先级0~15

0xF

314

保留位,用户软件不该对保留进行写操做,读出的保留位值未定义。

NA

11、向量地址寄存器VICAddress0xFFFFFF00

当处理器响应一个IRQ中断后,该中断的中断服务程序(ISR)地址能够从向量地址寄存器VICAddress读出。而这个地址是由VIC32向量地址寄存器VICVectPriority0~31其中一个读出装入进来的。

4.51向量地址寄存器

功能描述

复位值

310

包含当前有效中断的ISR入口地址。该寄存器在ISR结束前必须被写入一个数值(任何值),以此更新VIC优先级硬件逻辑,其余时间对该寄存器写可能引发错误产生。

0

12、软件优先级屏蔽寄存器VICSWPrioriyMask0xFFFFF024

软件优先级屏蔽寄存器包含了16个中断优先级的屏蔽码。

4.52软件优先级屏蔽寄存器

功能描述

复位值

150

0

中断优先级被屏蔽。

0xFFFF

1

中断优先级未被屏蔽。

3116

-

保留位,用户软件不该对保留进行写操做,读出的保留位值未定义。

NA

13、保护使能寄存器VICProtection0xFFFFF020

保护使能寄存器为可读写寄存器。该寄存器控制VIC寄存器是否能被用户软件在用户态下访问。且该寄存器自己只能在管态下访问。

4.53保护使能寄存器

功能描述

复位值

0

0

VIC寄存器能够在用户态或管态下访问。

0

1

VIC寄存器只能在管态下访问。

311

-

保留位,用户软件不该对保留进行写操做,读出的保留位值未定义

NA

4.6.5 中断源

4.54列出了每一个外围模块的全部中断源。每一个外围设备都有一条或多条中断线链接到向量中断控制器,并且每根中断线可能表明不止一种中断源。除了肯定标准的ARM内核,中断线自己没有标志或优先级。

4.54 链接VIC通道的中断源

功能模块

标志

VIC通道

屏蔽码

WDT

看门狗中断(WDINT

0

0x0000 0001

-

软件中断保留

1

0x0000 0002

ARM内核

调试器接收命令中断

2

0x0000 0004

ARM内核

调试器发送命令中断

3

0x0000 0008

定时器0

匹配0~1MR0MR1),捕获0~1CR0CR1

4

0x0000 0010

功能模块

标志

VIC通道

屏蔽码

定时器1

匹配0~2MR0MR1MR2),捕获0~1CR0CR1

5

0x0000 0020

UART0

Rx线状态(RLS),发送保持寄存器空(THRE),Rx数据可用(RDA),字符超时指示(CTI

6

0x0000 0040

UART1

Rx线状态(RLS),发送保持寄存器空(THRE),Rx数据可用(RDA),字符超时指示(CTI),Modem控制更改

7

0x0000 0080

PWM0

PWM1

PWM0匹配0~6PWM0捕获0PWM1匹配0~6PWM1捕获0~1

8

0x0000 0100

I2C0

SI(状态改变)

9

0x0000 0200

SPISSP0

SPI中断标志(SPIF),模式错误(MODF),SSP0Tx FIFO半空(TXRIS),SSP0Rx FIFO 半满(RXRIS),SSP0接收超时(RTRIS),SSP0接收溢出(RORRIS

10

0x0000 0400

SSP1

SSP1Tx FIFO半空(TXRIS),SSP1Rx FIFO 半满(RXRIS),SSP1接收超时(RTRIS),SSP1接收溢出(RORRIS

11

0x0000 0800

PLL

PLL锁定

12

0x0000 1000

RTC

计数器增长(RTCCIF),报警(RTCALF),Sub-second中断(RTCSSF

13

0x0000 2000

系统控制

(外部中断)

外部中断0EINT0

14

0x0000 4000

外部中断1EINT1

15

0x0000 8000

外部中断2EINT2

16

0x0001 0000

外部中断3EINT3

注:EINT3GPIO中断共享

17

0x0002 0000

ADC0

A/D转换器0

18

0x0004 0000

I2C1

SI(状态改变)

19

0x0008 0000

BOD

掉电检测

20

0x0010 0000

以太网

Wakeup,软件中断,传输成功,传输结束,传输错误,传输XX,接收成功,接收结束,接受错误,接受溢出

21

0x0020 0000

USB

USB_INT_REQ_LPUSB_INT_REQ_HPUSB_INT_REQ_DMA

22

0x0040 0000

CAN

CAN命令,CAN0传输,CAN0接收,CAN1传输,CAN1接收

23

0x0080 0000

SD/MMC接口

RxDataAvlbl TxDataAvlblRxFifoEmptyTxFifoEmptyRxFifoFullTxFifoFullRxFifoHalFullTxFifoHalEmptyRxActiveTxActiveCmdActiveDataBlockEndStartBitErrDataEndCmdSentCmdRespEnd,RxOverrunTxUnderrun,DataTimeOutCmdTimeOutDataCrcFailCmdCrcFail

24

0x0100 0000

GP DMA

DMA通道0状态,DMA通道1状态

25

0x0200 0000

定时器2

匹配0~3,捕获0~1

26

0x0400 0000

定时器3

匹配0~3,捕获0~1

27

0x0800 0000

UART2

Rx线状态(RLS),发送保持寄存器空(THRE),Rx数据可用(RDA),字符超时指示(CTI

28

0x1000 0000

UART3

Rx线状态(RLS),发送保持寄存器空(THRE),Rx数据可用(RDA),字符超时指示(CTI

29

0x2000 0000

I2C2

SI(状态改变)

30

0x4000 0000

I2S

Irq_rxIrq_tx

31

0x8000 0000

4.6.6 VIC使用注意事项

1VIC中断与片内RAM调试。若是在片内RAM中调试程序(JTAG调试)时须要使用中断,那么必须将中断向量从新映射到地址0x00000000,这样作是由于全部的异常向量都位于地址0x00000000及以上。经过将寄存器MEMMAP(位于系统控制模块当中)配置为用户RAM模式来实现这一点。另外,用户代码编译连接时应该使中断向量表装载到地址0x40000000

2.多个FIQ中断。虽然能够选择多个中断源(经过设置VICIntSelect)为FIQ中断,可是只有一个专门的中断服务程序来响应全部出现的FIQ请求。所以,若是分配为FIQ的中断多于一个,FIQ中断服务程序就必须先读取VICFIQStatus的内容来识别具体有效的FIQ中断源,而后在进行相应中断处理。不过仍是建议用户只设置一个FIQ中断,以确保FIQ中断延迟最小。

3IRQ中断服务程序与VIC寄存器。在中断服务程序执行完毕后,对外设中断标准的清零将会对VIC寄存器(VICRawIntrVICFIQStatusVICIRQStatus)当中的对应位产生影响。另外,为了可以服务下次中断,必须在中断返回以前对VICVectAddr寄存器执行一次写操做(通常可写入0),该写操做将清零内部中断优先级硬件当中对应的标志。

4VIC中断禁能操做。若要禁止VIC中断,则必须清零VICIntEnable寄存器中的对应位,这能够经过写VICIntEnClr寄存器实现。这一样应用于VICSoftIntVICSoftIntClear

4.6.7 应用举例

本节以实现按键的外部中断为例介绍向量中断控制器的使用,以及在IAR Embedded Workbench集成开发环境中编写中断服务程序的方法。

1、基本操做流程

设置IRQ/FIQ中断,如果IRQ中断,则能够设置为向量中断并分配中断优先级,而后设置中断使能,以及向量中断对应地址。当产生中断后,如果IRQ中断,则能够读取向量地址寄存器,而后跳转到相应服务代码。当退出中断时,对向量地址寄存器写0,通知VIC中断结束。

对于中断源(VIC通道)的IRQ/FIQ选择,由VICIntSelect寄存器控制,每一个中断源于VICIntSelect的各位一一对应,好比VIC通道14(外部中断0)与VICIntSelectBit14位对应,设置该位为1,则分配为FIQ中断,不然为IRQ中断。

2、设置异常向量表

LPC2400的启动代码中(在cstartup.s79文件中)首先设置异常向量表并设置各个模式下的堆栈指针,最后跳转到用户程序运行。异常向量表是一个包含8种异常状况的向量表,具体分配如表4.55所示。

4.55 ARM异常向量表

地址

异常类型

0x0000 0000

复位

0x0000 0004

未定义指令

0x0000 0008

软件中断

0x0000 000C

预取指令错误

0x0000 0010

取数据错误

0x0000 0014

保留

0x0000 0018

IRQ中断

0x0000 001C

FIQ中断

系统一旦产生IRQ中断,LPC2400处理器会切换到IRQ模式,而且跳转到向量表0x00000018地址执行程序。如程序清单4.6②所示,在IRQ向量处使用的指令与其余向量不一样,当CPU执行这条指令但尚未跳转时, [PC, # -0x0120]表示当前PC值减去0x0120 ,当前PC的值为0x00000020,减去0x01200xFFFFFF00。这是VIC特殊寄存器VICVectAddr的物理地址,该寄存器保存当前将要服务的IRQ中断服务程序的入口,因此用这条LDR指令就能够直接跳转到须要的中断服务程序中。

一旦产生FIQ中断,处理器会切换到FIQ模式,而且跳转到向量表0x0000001C地址执行程序。如程序清单4.6③所示,程序将跳到FIQ_Handler标号处,处理FIQ中断服务程序。

代码清单4.6 异常向量表设置

__program_start

        LDR     PC, =Reset_Handler                                    ①

        LDR     PC, =Undef_Handler

        LDR     PC, =SWI_Handler

        LDR     PC, =PAbt_Handler

        LDR     PC, =DAbt_Handler

        B       .

        LDR     PC, [PC, # -0x0120]                                    ②

        LDR     PC, =FIQ_Handler                                     ③

3VIC初始化

接下来,在LPC2400的启动代码中包含有VIC初始化程序,如代码清单4.7所列。程序首先禁止全部中断(代码清单4.7 ①),设置VICVectAddr寄存器的值为0,将全部中断设置为IRQ中断(代码清单4.7 ③)。最后在for循环中把全部向量地址寄存器内容设置为0(代码清单4.7 ④ ),向量优先级寄存器设置为0xF,最低中断优先级(代码清单4.7 ⑤)。

禁止全部中断是避免调试时一个中断没有响应就再次装入程序运行,而VIC状态错误不能正确识别中断。

代码清单4.7 init_VIC()——VIC初始化

VICIntEnClr = 0xffffffff;                                                

VICVectAddr = 0;                                                     

VICIntSelect = 0;                                                      

/* set all the vector and vector control register to 0 */

for ( i = 0; i < VIC_SIZE; i++ )    // 32个中断服务向量复位

{

vect_addr = (DWORD *)(VIC_BASE_ADDR + VECT_ADDR_INDEX + i*4);  

vect_cntl = (DWORD *)(VIC_BASE_ADDR + VECT_CNTL_INDEX + i*4);   

*vect_addr = 0x0; //中断服务函数都指向开头                         ④

*vect_cntl = 0xF;       //优先级最低                                  ⑤

}

4、编写中断服务程序

IAR Embedded Workbench C/C++编译器支持ARM核的IRQ中断、FIQ快速中断和SWI软件中断,能够直接采用C语言编写中断函数。中断函数必须采用ARM模式编译,若是用户正在使用的是Thumb模式,应采用扩展关键字__arm或“#pragma type_attribute=__arm”指令将其转换到ARM模式。IRQ中断函数采用扩展字__irq#pragma type_attribute=__irq”指令声明,如程序清单4.8 所示。FIQ中断函数采用扩展字__fiq#pragma type_attribute=__fiq”指令声明。须要特别注意的是,IRQFIQ函数的返回值类型必须为void,而且不能带有参数。

在中断服务程序开始先清除外部中断标志寄存器EXTINTEINT0位,以后进行中断服务处理,最后写VICVectAddr寄存器,更新VIC优先级逻辑,以相应下次外部中断。

代码清单4.8 EINT0_Handler()——外部中断服务函数

__irq __arm void EINT0_Handler (void)                                     ①

{

    EXTINT = EINT0; /* 清除EXTINT寄存器中EINT0 */            ②

    ……/*中断服务*/

    VICVectAddr = 0; /* VICVectAddr寄存器,更新VIC优先级逻辑 */ ③

}

5、安装外部中断服务程序

安装外部中断服务程序主要是初始化VIC的几个特别寄存器。Install_irq一共有3个参数:IntNumber为链接VIC的中断通道数,HandlerAddr为中断函数地址,Priority为该中断通道的优先级。

如代码清单4.9所示,函数首先设置中断使能清除寄存器VICIntEnClr的对应位,无效该中断。接着经过中断通道数IntNumber获得对应向量地址寄存器VICVectAddrX和向量优先级寄存器VICVectPriorityX地址。而后使用其他两个参数初始化这两个寄存器。最后置位中断使能寄存器VICIntEnable的对应,位使能该中断。

代码清单4.9 install_irq()——中断安装函数

DWORD install_irq( DWORD IntNumber, void *HandlerAddr, DWORD Priority )

{

    DWORD *vect_addr;

    DWORD *vect_cntl;

    VICIntEnClr = 1 << IntNumber; /* Disable Interrupt */

    vect_addr=(DWORD *)(VIC_BASE_ADDR+VECT_ADDR_INDEX+IntNumber*4);

vect_cntl=(DWORD *)(VIC_BASE_ADDR+VECT_CNTL_INDEX+IntNumber*4);

*vect_addr=(DWORD)HandlerAddr; /* set interrupt vector */

*vect_cntl=Priority;

VICIntEnable = 1 << IntNumber;         /* Enable Interrupt */

}

代码清单4.10为调用install_irq函数安装EINT0_Handler中断服务函数的方法。

代码清单4.10安装EINT0_Handler函数

if ( install_irq( EINT0_INT, (void *)EINT0_Handler, HIGHEST_PRIORITY ) = = FALSE )

    {

return (FALSE);

    }

4.6 LPC2400最小系统

在嵌入式系统硬件开发过程当中,直接设计和开发目标板硬件会有至关大的难度和风险,能够先经过设计最小系统,将所需IO引脚都引出到一个插针或者板板链接器(FPC)上。实际应用电路板(本文简称底板)另行设计,最小系统板能够同直插封装的器件同样与应用电路板想链接。下文将介绍LPC2400的最小系统。

现在如同LPC2400这样的MCU芯片将FLASHSRAM以及一些总线等集成在一片芯片中,可是仍离不开一些外围电路的设计。这部分外围电路主要为MCU提供电源、时钟震荡、电压转换、I/O口保护和驱动等功能。LPC2400的最小系统如图4.15所示,这个最小系统此文暂称为核心板。

4.15. LPC2400核心板

本核心板分为供电电路、时钟电路、复位电路以及外部存储器电路。现作简单介绍:

1.供电电路。核心板电源主要靠实际应用电路+3.3V提供,经过左右两排插针中的相关引脚提供。LPC2400芯片采用单电源(+3.3V)供电,这样能够简化电路设计,下降产品成本。电源纹波直接影响着整个电路的工做,为了获得稳定的电压,须要外接一些电容。这些电容分为两类,一类为储能电容,这些电容的电容值比较大,如1uF10uF等。另外一类为去耦电容,其电容值较小,如0.1uF0.01uF等,它们能够达到抑制高频噪声的功用。

2.时钟电路。这部分电路主要有晶体振荡器、电容以及电阻组成。目前有些MCU已经将该部分集成到芯片内部,可是可能是以RC振荡电路形式提供所需时钟,其稳定性得不到较高的保证。使用外部晶振能够使MCU获得稳定的时钟频率。

3.复位电路。虽然目前大部分的MCU都集成有上电复位电路,在系统上电时MCU会自动产生复位信号。但在设计初期能够加入手动复位电路以方便调试。外部复位电路能够采用阻容振荡电路,也可采用诸如MAX811或者SGM811之类的专用复位芯片。

4.外部存储器电路。目前中高档的MCU尤为是ARM内核的MCU都引出有外部总线。因为大中型软件系统对FLASH以及RAM的容量的需求以及内部集成FLASH形成成本偏高的现实,使得采用外部FLASH做为存储器件最为合适。

因为LPC2478LPC2470LPC2468以及LPC2460等恩智浦LPC2400系列ARM7单片机在引脚上是兼容的,因此LPC2400最小系统一样也适用于上述芯片。

如图4.15所示,左右两排插针引出了实际应用电路板上所需的功能引脚,上下两排焊盘引出了LPC2478所能提供的外部总线。

LPC2400最小系统包括一下几个部分:电源电路、时钟电路、复位电路、JTAG调试电路以及功能接口电路等。其中各个部分功能以下:

一、 时钟电路给MCU提供一个外部12MHz的以及一个32.768MHz的石英振荡器。

二、 复位电路是经过引脚的方式与底板上的手动复位相连。经过底板复位电路提供手动复位信号。

三、 JTAG电路可让用户方便的经过仿真器调试或者下载程序。

四、 外部存储电路,即有板载外部存储器(Nor FlashNand FlashSDRAM),又将外部总线引出方便用户经过外部总线扩展其余器件。

根据电路板的工做环境,可能会对电路板提出不一样的要求。诸如噪声以及干扰较强的场合,以及对系统稳定性、可靠性要求较高时,印刷电路板会采用多层板设计。通常地,6层板噪声比4层板低10dB4层板比双面板的噪声低20dB。但板层越多,相应的成本也就越高。如图4.15所示的核心板采用6层板设计,为测试提供了稳定可靠的电路。

 

习题:

4.1  简单说明LPC2400系列芯片复位时的处理流程。

4.2  LPC2400系列芯片的存储器空间是如何分布的?

4.3  LPC2400芯片的引脚一般都是复用的,当要使用引脚的某个功能时,应如何进行设置?

4.4  简述使能PLL的工做过程。

4.5  若是LPC2400使用的外部晶振频率为12MHz,计算最大的系统时钟频率CCLK为多少,此时M值和N值各为多少,并编写设置PLL的程序段。

4.6  LPC2400有哪些下降功耗的措施?

4.7  若是要使用外部中断0来唤醒掉电的LPC2400,应设置哪些寄存器,各寄存器的值应为多少?写出其程序段。

 

 

3.1  ARM 处理器的指令格式

3.1.1  ARM指令集的特色

ARM内核属于RISC结构,因此其指令集有着一些独特的特色:指令长度固定,指令格式的种类少,寻址方式简单。因为ARM处理器采用固定长度的32位指令,所以处理器内部硬件设计可以被简化。ARM处理器内部的指令译码采用硬布线逻辑,不使用微程序控制,以减小指令的译码时间,大部分指令能够在一个时钟周期内完成。

ARM处理器的指令按功能可分为七大类:加载/存储指令、数据处理指令、乘法指令、跳转指令、程序状态寄存器处理指令、协处理器指令和异常中断指令。

须要特别指出的是,ARM处理器的指令集是加载/存储型的,也即指令集仅能处理寄存器中的数据,并且处理结果都要放回寄存器中,而对系统存储器的访问则须要经过专门的加载/存储指令来完成。

按照操做数的特色分,ARM指令能够分为无操做数指令、单操做数指令、双操做数指令和三操做数指令。每条指令都由操做码域、条件码域、条件码设置域、目标操做数、第一操做数寄存器和第二操做数组成。

3.1.2  ARM指令的格式

每条ARM指令都是32位的,其格式以下:

31   28  27     25 24      21 20  19         16 15        12  11          0

条件码

类别码

操做码

S

目的寄存器

第一操做数

第二操做数

ARM指令助记符表示为:

<opcode> {<cond>} {S} <Rd>, <Rn>, <shift_op2>

每一个域的含义以下:

1) <opcode>:操做码域,指令编码的助记符;

2) {<cond>}:条件码域,指令容许执行的条件编码。花括号表示此项可缺省。

ARM指令的一个重要特色是能够条件执行,每条ARM指令的条件码域包含4位条件码,共16种。几乎全部指令均根据CPSR中条件码的状态和指令条件码域的设置有条件的执行。当指令执行条件知足时,指令被执行,不然被忽略。指令条件码及其助记符后缀表示参见表3.1。

每种条件码可用两个字符表示,这两个字符能够做为后缀添加在指令助记符的后面和指令同时使用。例如,跳转指令B能够加上后缀EQ变为BEQ,表示“相等则跳转”,即当CPSR中的Z标志置位时发生跳转。

3.1 指令的条件码

条件码

助记符后缀

标 志

含 义

0000

EQ

Z置位

相等

0001

NE

Z清零

不相等

0010

CS

C置位

无符号数大于或等于

0011

CC

C清零

无符号数小于

0100

MI

N置位

负数

0101

PL

N清零

正数或零

0110

VS

V置位

溢出

0111

VC

V清零

未溢出

1000

HI

C置位Z清零

无符号数大于

1001

LS

C清零Z置位

无符号数小于或等于

1010

GE

N等于V

带符号数大于或等于

1011

LT

N不等于V

带符号数小于

1100

GT

Z清零且(N等于V

带符号数大于

1101

LE

Z置位或(N不等于V

带符号数小于或等于

1110

AL

忽略

无条件执行

3) {S}:条件码设置域。这是一个可选项,当在指令中设置{S}域时,指令执行的结果将会影响程序状态寄存器CPSR中相应的状态标志。

例如:

ADD R0R1R2 R1R2的和存放到R0寄存器中,不影响状态寄存器

ADDS R0R1R2 执行加法的同时影响状态寄存器

指令中比较特殊的是CMP指令,它不须要加S后缀就默认地根据计算结构更改程序状态寄存器。

4) <Rd>:目的操做数。ARM指令中的目的操做数老是一个寄存器。若是<Rd>与第一操做数寄存器<Rn>相同,也必需要指明,不能缺省。

5) <Rn>:第一操做数。ARM指令中的第一操做数也必须是个寄存器。

6) <shift_op2>:第二操做数。在第二操做数中能够是寄存器、内存存储单元或者当即数。

因为第二操做数只有12bit,用第二操做数表示当即数时,其取值范围为0~212-1,要表示超出这个范围的当即数,一般要依靠伪指令实现。

3.2  ARM指令的寻址方式

所谓寻址方式就是处理器根据指令中给出的地址信息来寻找物理地址的方式。目前ARM指令系统支持以下几种常见的寻址方式。

3.2.1  当即寻址

当即寻址也叫当即数寻址,这是一种特殊的寻址方式,操做数自己就在指令中给出,只要取出指令也就取到了操做数。这个操做数被称为当即数,对应的寻址方式也就叫作当即寻址。例如如下指令:

ADD R0R0,#1 R0R01

ADD R0R0,#0x3f R0R00x3f

在以上两条指令中,第二操做数即为当即数,要求以“#”为前缀,对于以十六进制表示的当即数,还要求在“#”后加上“0x”,以二进制表示的当即数,要求在“#”后加上“%”。

当当即数大于第二操做数的表示范围时,一般用如下伪指令实现:

LDR R0,=#0xffff0000

3.2.2  寄存器寻址

寄存器寻址就是利用寄存器中的数值做为操做数,这种寻址方式是各种微处理器常常采用的一种方式,也是一种执行效率较高的寻址方式。如下指令:

ADD R0R1R2 R0R1R2

该指令的执行效果是将寄存器R1R2的内容相加,其结果存放在寄存器R0中。

3.2.3  寄存器间接寻址

寄存器间接寻址就是以寄存器中的值做为操做数的地址,而操做数自己存放在存储器中。例如如下指令:

ADD R0R1[R2] R0R1[R2]

LDR R0[R1] R0[R1]

STR R0[R1] [R1]R0

在第一条指令中,以寄存器R2的值做为操做数的地址,在存储器中取得一个操做数后与R1相加,结果存入寄存器R0中。

第二条指令将以R1的值为地址的存储器中的数据传送到R0中。

第三条指令将R0的值传送到以R1的值为地址的存储器中。

3.2.4  基址变址寻址

基址变址寻址就是将寄存器(该寄存器通常称做基址寄存器)的内容与指令中给出的地址偏移量相加,从而获得一个操做数的有效地址。变址寻址方式经常使用于访问某基地址附近的地址单元。采用变址寻址方式的指令常见有如下几种形式,以下所示:

LDR R0[R1,#4] R0[R14]

LDR R0[R1,#4] R0[R14]R1R14

LDR R0[R1] ,#4 R0[R1]R1R14

LDR R0[R1R2] R0[R1R2]

在第一条指令中,将寄存器R1的内容加上4造成操做数的有效地址,从而取得操做数存入寄存器R0中。

在第二条指令中,将寄存器R1的内容加上4造成操做数的有效地址,从而取得操做数存入寄存器R0中,而后,R1的内容自增4个字节。

在第三条指令中,以寄存器R1的内容做为操做数的有效地址,从而取得操做数存入寄存器R0中,而后,R1的内容自增4个字节。

在第四条指令中,将寄存器R1的内容加上寄存器R2的内容造成操做数的有效地址,从而取得操做数存入寄存器R0中。

3.2.5  多寄存器寻址

多寄存器寻址是ARM处理器特有的一种寻址方式。因为ARM内核有较多的通用寄存器,采用多寄存器寻址方式,一条指令能够一次完成多个寄存器值的传送。这种寻址方式能够用一条指令完成传送最多16个通用寄存器的值。例如如下指令:

LDMIA R0{R1R2R3R4} R1[R0]

R2[R04]

R3[R08]

R4[R012]

该指令的后缀IA表示在每次执行完加载/存储操做后,R0按字长度增长,所以,指令可将连续存储单元的值传送到R1R4

多个连续的寄存器能够用-”符号链接;不连续的寄存器用“,”分隔书写,如上例可写成:

LDMIA R0{R1-R4}

LDMIA R0{R1-R3R4}

3.2.6  寄存器移位寻址

寄存器移位寻址是ARM指令集特有的寻址方式。ARM处理器内嵌桶型移位器(Barrel Shifter),支持数据的各类移位操做。当第二操做数为寄存器时,能够加入移位操做选项对它进行各类移位操做。

移位操做包括以下6种类型:

一、LSL(或ASL)逻辑(算术)左移

寻址格式:

通用寄存器,LSL(或ASL) 操做数      

完成对通用寄存器中的内容进行逻辑(或算术)的左移操做,按操做数所指定的数量向移位低位用零来填充。其中,操做数能够是通用寄存器,也能够是当即数(031)。

如:

   MOV    R0, R1, LSL#2 ;将R1中的内容左移两位后传送到R0中。

二、LSR逻辑右移

寻址格式:

通用寄存器,LSR 操做数      

完成对通用寄存器中的内容进行右移的操做,按操做数所指定的数量向移位,左端用零来填充。其中,操做数能够是通用寄存器,也能够是当即数(031)。

如:

   MOV    R0, R1, LSR#2 ;将R1中的内容右移两位后传送到R0中,左端用零来填充

三、ASR算术右移

寻址格式:

通用寄存器,ASR 操做数      

完成对通用寄存器中的内容进行右移的操做,按操做数所指定的数量向移位,左端31位的值来填充。其中,操做数能够是通用寄存器,也能够是当即数(031)。

如:

   MOV    R0, R1, ASR#2 ;将R1中的内容右移两位后传送到R0中,左端31位的值来填充

四、ROR循环右移

寻址格式:

通用寄存器,ROR 操做数      

完成对通用寄存器中的内容进行循环右移的操做,按操做数所指定的数量向右循环移位,左端右端移出的位来填充。其中,操做数能够是通用寄存器,也能够是当即数(031)。显然,当进行32位的循环右移操做时,通用寄存器中的值不改变。

如:

   MOV    R0, R1, ROR#2 ;将R1中的内容循环右移两位后传送到R0中。

五、RRX带扩展的循环右移

寻址格式:

通用寄存器,RRX 操做数      

完成对通用寄存器中的内容进行带扩展的循环右移的操做,按操做数所指定的数量向右循环移位,左端进位标志位C来填充。其中,操做数能够是通用寄存器,也能够是当即数(031)。

如:

   MOV    R0, R1, RRX#2 ;将R1中的内容进行带扩展的循环右移两位后传送到R0中。

3.2.7  相对寻址

与基址变址寻址方式相相似,相对寻址以程序计数器PC的当前值为基地址,指令中的地址标号做为偏移量,将二者相加以后获得操做数的有效地址。如下程序段完成子程序的调用和返回,跳转指令BL采用了相对寻址方式:

BL NEXT ;跳转到子程序NEXT处执行

……

NEXT

……

MOV PCLR ;从子程序返回

3.2.8  堆栈寻址

堆栈是一种数据结构,按先进后出(First In Last OutFILO)的方式工做,使用一个称做堆栈指针的专用寄存器指示当前的操做位置,堆栈指针老是指向栈顶。

当堆栈指针指向最后压入堆栈的数据时,称为满堆栈(Full Stack),而当堆栈指针指向下一个将要放入数据的空位置时,称为空堆栈(Empty Stack)。

同时,根据堆栈的生成方式,又能够分为递增堆栈(Ascending  Stack)和递减堆栈(Decending Stack)。当堆栈由低地址向高地址生成时,称为递增堆栈,当堆栈由高地址向低地址生成时,称为递减堆栈。这样就有四种类型的堆栈工做方式,ARM微处理器支持这四种类型的堆栈工做方式,即:

1. 满递增堆栈(FA):堆栈指针指向最后压入的数据,且由低地址向高地址生成。

2. 满递减堆栈(FD):堆栈指针指向最后压入的数据,且由高地址向低地址生成。

3. 空递增堆栈(EA):堆栈指针指向下一个将要放入数据的空位置,且由低地址向高地址生成。

4. 空递减堆栈(ED):堆栈指针指向下一个将要放入数据的空位置,且由高地址向低地址生成。

3.3  ARM指令集

本节对ARM指令集的七大类指令进行详细的描述。

3.3.1  加载/存储指令

ARM处理器支持加载/存储指令用于在寄存器和存储器之间传送数据,加载指令用于将存储器中的数据传送到寄存器,存储指令则完成相反的操做。经常使用的加载存储指令以下:

一、LDR指令

LDR指令的格式为:

LDR{条件} 目的寄存器,<存储器地址>

LDR指令用于从存储器中将一个32位的字数据传送到目的寄存器中。该指令一般用于从存储器中读取32位的字数据到通用寄存器,而后对数据进行处理。当程序计数器PC做为目的寄存器时,指令从存储器中读取的字数据被看成目的地址,从而能够实现程序流程的跳转。该指令在程序设计中比较经常使用,且寻址方式灵活多样,请读者认真掌握。

如:

LDR  R0[R1]            ;将存储器地址为R1的字数据读入寄存器R0

LDR  R0[R1R2]       ;将存储器地址为R1+R2的字数据读入寄存器R0

LDR  R0[R1,#8]       ;将存储器地址为R1+8的字数据读入寄存器R0

LDR  R0[R1R2]       ;将存储器地址为R1+R2的字数据读入寄存器R0,并将

;新地址R1R2写入R1

LDR  R0[R1,#8]       ;将存储器地址为R1+8的字数据读入寄存器R0,并将新

;地址R18写入R1

LDR  R0[R1]R2       ;将存储器地址为R1的字数据读入寄存器R0,并将新地

;址R1R2写入R1

LDR  R0[R1R2LSL2] ;将存储器地址为R1R2×4的字数据读入寄存器R0

;并将新地址R1R2×4写入R1

LDR  R0[R1]R2LSL2 ;将存储器地址为R1的字数据读入寄存器R0,并将新地

;址R1R2×4写入R1

二、STR指令

STR指令的格式为:

STR{条件} 源寄存器,<存储器地址>

STR指令用于从源寄存器中将一个32位的字数据传送到存储器中。该指令在程序设计中比较经常使用,且寻址方式灵活多样,使用方式可参考指令LDR

如:

STR R0[R1],#8 ;将R0中的字数据写入以R1为地址的存储器中,并将新地址R18写入R1

STR R0[R1,#8] ;将R0中的字数据写入以R18为地址的存储器中。

LDR/STR指令均可以加BHSBSH的后缀,分别表示加载/存储字节、半字、带符号的字节、带符号的半字。如LDRB指令表示从存储器加载一个字节进寄存器。当使用这些后缀时,要注意所使用的存储器要支持访问的数据宽度。

三、LDM(或STM)批量数据加载/存储指令

LDM(或STM)指令的格式为:

LDM(或STM){条件}{类型} 基址寄存器{!},寄存器列表{}

LDM(或STM)指令用于从由基址寄存器所指示的一片连续存储器到寄存器列表所指示的多个寄存器之间传送数据,该指令的常见用途是将多个寄存器的内容入栈或出栈。其中,{类型}为如下几种状况:

IA 每次传送后地址加1

IB 每次传送前地址加1

DA 每次传送后地址减1

DB 每次传送前地址减1

FD 满递减堆栈;

ED 空递减堆栈;

FA 满递增堆栈;

EA 空递增堆栈;

{}为可选后缀,若选用该后缀,则当数据传送完毕以后,将最后的地址写入基址寄存器,不然基址寄存器的内容不改变。

基址寄存器不容许为R15,寄存器列表能够为R0R15的任意组合。

{}为可选后缀,当指令为LDM且寄存器列表中包含R15,选用该后缀时表示:除了正常的数据传送以外,还将SPSR复制到CPSR。同时,该后缀还表示传入或传出的是用户模式下的寄存器,而不是当前模式下的寄存器。

如:

STMFD  R13!,{R0R4-R12LR} ;将寄存器列表中的寄存器(R0R4R12LR)存入堆栈。

LDMFD  R13!,{R0R4-R12PC} ;将堆栈内容恢复到寄存器(R0R4R12LR)。

四、SWP数据交换指令

SWP指令的格式为:

SWP{条件} 目的寄存器,源寄存器1,[源寄存器2]

SWP指令用于将源寄存器2所指向的存储器中的字数据传送到目的寄存器中,同时将源寄存器1中的字数据传送到源寄存器2所指向的存储器中。显然,当源寄存器1和目的寄存器为同一个寄存器时,指令交换该寄存器和存储器的内容。

如:

SWP  R0,R1[R2]      ;将R2所指向的存储器中的字数据传送到R0,同时将R1中的字数据传送到R2所指向的存储单元。

SWP  R0,R0[R1]      ;该指令完成将R1所指向的存储器中的字数据与R0中的字数据交换。

3.3.2  数据处理指令

数据处理指令可分为数据传送指令、算术逻辑运算指令和比较指令等。

数据传送指令用于在寄存器和存储器之间进行数据的双向传输。

算术逻辑运算指令完成经常使用的算术与逻辑的运算,该类指令不但将运算结果保存在目的寄存器中,同时更新CPSR中的相应条件标志位。

比较指令不保存运算结果,只更新CPSR中相应的条件标志位。

一、 MOV指令

MOV指令的格式为:

MOV{条件}{S} 目的寄存器,源操做数

MOV指令可完成从另外一个寄存器、被移位的寄存器或将一个当即数加载到目的寄存器。其中S选项决定指令的操做是否影响CPSR中条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值。

如:

MOV R1R0 ;将寄存器R0的值传送到寄存器R1

MOV PCR14 ;将寄存器R14的值传送到PC,经常使用于子程序返回

MOV R1R0LSL3 ;将寄存器R0的值左移3位后传送到R1

二、 MVN指令

MVN指令的格式为:

MVN{条件}{S} 目的寄存器,源操做数

MVN指令可完成从另外一个寄存器、被移位的寄存器、或一个当即数加载到目的寄存器。与MOV指令不一样之处是在传送以前位被反了,把一个被取反的值传送到目的寄存器中。其中S决定指令的操做是否影响CPSR中条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值。

如:

MVN R0,#0 ;将当即数0取反传送到寄存器R0中,完成后R0=-1

三、 CMP指令

CMP指令的格式为:

CMP{条件} 操做数1,操做数2

CMP指令用于把一个寄存器的内容和另外一个寄存器的内容或当即数进行比较,同时更新CPSR中条件标志位的值。该指令进行一次减法运算,但不存储结果,只更改条件标志位。标志位表示的是操做数1与操做2的关系(大、小、相等),例如,当操做数1大于操做操做数2,则此后的有GT 后缀的指令将能够执行。

如:

CMP R1R0 ;将寄存器R1的值与寄存器R0的值相减,并根据结果设置CPSR的标志位

CMP R1,#100 ;将寄存器R1的值与当即数100相减,并根据结果设置CPSR的标志位

 

四、 CMN指令

CMN指令的格式为:

CMN{条件} 操做数1,操做数2

CMN指令用于把一个寄存器的内容另外一个寄存器的内容或当即数取反后进行比较,同时更新CPSR中条件标志位的值该指令实际完成操做数1和操做数2相加并根据结果更改条件标志位。

如:

CMN R1R0 ;将寄存器R1的值与寄存器R0的值相加,并根据结果设置CPSR的标志位

CMN R1,#100 ;将寄存器R1的值与当即数100相加,并根据结果设置CPSR的标志位

五、 TST指令

TST指令的格式为:

TST{条件} 操做数1,操做数2

TST指令用于把一个寄存器的内容和另外一个寄存器的内容或当即数进行按位的与运算,并根据运算结果更新CPSR中条件标志位的值。操做数1是要测试的数据,而操做数2是一个位掩码,该指令通常用来检测是否设置了特定的位。

如:

TST R1,#%1 ;用于测试在寄存器R1中是否设置了最低位(%表示二进制数)

TST R1,#0xffe ;将寄存器R1的值与当即数0xffe按位与,并根据结果设置CPSR的标志位

六、 TEQ指令

TEQ指令的格式为:

TEQ{条件} 操做数1,操做数2

TEQ指令用于把一个寄存器的内容和另外一个寄存器的内容或当即数进行按位的异或运算,并根据运算结果更新CPSR中条件标志位的值。该指令一般用于比较操做数1和操做数2是否相等。

如:

TEQ R1R2 ;将寄存器R1的值与寄存器R2的值按位异或,并根据结果设置CPSR的标志位

七、 ADD指令

ADD指令的格式为:

ADD{条件}{S} 目的寄存器,操做数1,操做数2

ADD指令用于把两个操做数加,并将结果存放到目的寄存器中操做数1应是一个寄存器,操做数2能够是一个寄存器,被移位的寄存器,或一个当即数。

如:

ADD R0,R1,R2          ; R0 = R1 + R2

ADD R0,R1,#256            ; R0 = R1 + 256

ADD R0,R2,R3,LSL#1      ; R0 = R2 + (R3 << 1)

八、 ADC指令

ADC指令的格式为:

ADC{条件}{S} 目的寄存器,操做数1,操做数2

ADC指令用于把两个操做数相加,再加上CPSR中的C条件标志位的值,并将结果存放到目的寄存器中。它使用一个进位标志位,这样就能够作比32位大的数的加法,注意不要忘记设置S后缀来更改进位标志。操做数1应是一个寄存器,操做数2能够是一个寄存器,被移位的寄存器,或一个当即数。

如下指令序列完成两个128位数的加法,第一个数由高到低存放在寄存器R7~R4,第二个数由高到低存放在寄存器R11~R8,运算结果由高到低存放在寄存器R3~R0:

ADDS  R0,R4R8          ; 加低端的字

ADCS  R1R5R9            ; 加第二个字,带进位

ADCS  R2R6R10      加第三个字,带进位

ADC  R3R7R11      加第四个字,带进位

九、 SUB指令

SUB指令的格式为:

SUB{条件}{S} 目的寄存器,操做数1,操做数2

SUB指令用于把操做数1减去操做数2并将结果存放到目的寄存器中操做数1应是一个寄存器,操做数2能够是一个寄存器,被移位的寄存器,或一个当即数。该指令可用于有符号数或无符号数的减法运算。

如:

SUB  R0,R1,R2          ; R0 = R1 - R2

SUB  R0,R1,#256            ; R0 = R1 - 256

SUB  R0,R2,R3,LSL#1      ; R0 = R2 - (R3 << 1)

十、SBC指令

SBC指令的格式为:

SBC{条件}{S} 目的寄存器,操做数1,操做数2

SBC指令用于把操做数1减去操做数2再减去CPSR中的C条件标志位的反码,并将结果存放到目的寄存器中操做数1应是一个寄存器,操做数2能够是一个寄存器,被移位的寄存器,或一个当即数。该指令使用进位标志来表示借位,这样就能够作大于32位的减法,注意不要忘记设置S后缀来更改进位标志。该指令可用于有符号数或无符号数的减法运算。

如:

SUBS  R0,R1,R2          ; R0 = R1 - R2 - C,并根据结果设置CPSR的进位标志位

11RSB指令

RSB指令的格式为:

RSB{条件}{S} 目的寄存器,操做数1,操做数2

RSB指令称为逆向减法指令,用于把操做数2减去操做数1并将结果存放到目的寄存器中操做数1应是一个寄存器,操做数2能够是一个寄存器,被移位的寄存器,或一个当即数。该指令可用于有符号数或无符号数的减法运算。

如:

RSB  R0,R1,R2          ; R0 = R2 – R1

RSB  R0,R1,#256            ; R0 = 256 – R1

RSB  R0,R2,R3,LSL#1      ; R0 = (R3 << 1) - R2

十二、RSC指令

RSC指令的格式为:

RSC{条件}{S} 目的寄存器,操做数1,操做数2

RSC指令用于把操做数2减去操做数1再减去CPSR中的C条件标志位的反码,并将结果存放到目的寄存器中操做数1应是一个寄存器,操做数2能够是一个寄存器,被移位的寄存器,或一个当即数。该指令使用进位标志来表示借位,这样就能够作大于32位的减法,注意不要忘记设置S后缀来更改进位标志。该指令可用于有符号数或无符号数的减法运算。

如:

RSC  R0,R1,R2          ; R0 = R2 – R1 - C

1三、AND指令

AND指令的格式为:

AND{条件}{S} 目的寄存器,操做数1,操做数2

AND指令用于在两个操做数上进行逻辑与运算把结果放置到目的寄存器中操做数1应是一个寄存器,操做数2能够是一个寄存器,被移位的寄存器,或一个当即数。该指令经常使用于屏蔽操做数1的某些位

如:

AND  R0,R0,#3          ; 该指令保持R001位,其他位清零。

1四、ORR指令

ORR指令的格式为:

ORR{条件}{S} 目的寄存器,操做数1,操做数2

ORR指令用于在两个操做数上进行逻辑或运算把结果放置到目的寄存器中操做数1应是一个寄存器,操做数2能够是一个寄存器,被移位的寄存器,或一个当即数。该指令经常使用于设置操做数1的某些位

如:

ORR  R0,R0,#3          ; 该指令设置R001位,其他位保持不变。

1五、EOR指令

EOR指令的格式为:

EOR{条件}{S} 目的寄存器,操做数1,操做数2

EOR指令用于在两个操做数上进行逻辑异或运算把结果放置到目的寄存器中操做数1应是一个寄存器,操做数2能够是一个寄存器,被移位的寄存器,或一个当即数。该指令经常使用于反转操做数1的某些位

如:

EOR  R0,R0,#3          ; 该指令反转R001位,其他位保持不变。

1六、BIC指令

BIC指令的格式为:

BIC{条件}{S} 目的寄存器,操做数1,操做数2

BIC指令用于清除操做数1的某些位把结果放置到目的寄存器中操做数1应是一个寄存器,操做数2能够是一个寄存器,被移位的寄存器,或一个当即数。操做数232位的掩码,若是在掩码中设置了某一位,则清除这一位。未设置的掩码位保持不变。

如:

BIC  R0,R0,#%1011         ; 该指令清除 R0 中的位 01、和 3,其他的位保持不变。

3.3.3  乘法指令与乘加指令

ARM微处理器支持的乘法指令与乘加指令共有6条,可分为运算结果为32位和运算结果为64位两类。与前面的数据处理指令不一样,指令中的所有操做数、目的寄存器必须为通用寄存器不能对操做数使用当即或被移位的寄存器,同时,目的寄存器和操做数1必须是不一样的寄存器。 

一、 MUL指令

MUL指令的格式为:

MUL{条件}{S} 目的寄存器,操做数1,操做数2

MUL指令完成将操做数1与操做数2的乘法运算,并把结果放置到目的寄存器中,同时能够根据运算结果设置CPSR中相应的条件标志位。其中,操做数1和操做数2均为32位的有符号数或无符号数。

如:

MUL R0R1R2 R0 = R1 × R2

MULS R0R1R2 R0 = R1 × R2,同时设置CPSR中的相关条件标志位

二、 MLA指令

MLA指令的格式为:

MLA{条件}{S} 目的寄存器,操做数1,操做数2,操做数3

MLA指令完成将操做数1与操做数2的乘法运算,再将乘积加上操做数3,并把结果放置到目的寄存器中,同时能够根据运算结果设置CPSR中相应的条件标志位。其中,操做数1和操做数2均为32位的有符号数或无符号数。

如:

MLA R0R1R2R3 R0 = R1 × R2 + R3

MLAS R0R1R2R3 R0 = R1 × R2 + R3,同时设置CPSR中的相关条件标志位

三、 SMULL指令

SMULL指令的格式为:

SMULL{条件}{S} 目的寄存器Low,目的寄存器低High,操做数1,操做数2

SMULL指令完成将操做数1与操做数2的乘法运算,并把结果的低32放置到目的寄存器Low结果的高32放置到目的寄存器High,同时能够根据运算结果设置CPSR中相应的条件标志位。其中,操做数1和操做数2均为32位的有符号数。

如:

SMULL R0R1R2R3 R0 = R2 × R3)的低32

R1 = R2 × R3)的高32

四、 SMLAL指令

SMLAL指令的格式为:

SMLAL{条件}{S} 目的寄存器Low,目的寄存器低High,操做数1,操做数2

SMLAL指令完成将操做数1与操做数2的乘法运算,并把结果的低32位同目的寄存器Low中的值相加后又放置到目的寄存器Low结果的高32位同目的寄存器High中的值相加后又放置到目的寄存器High,同时能够根据运算结果设置CPSR中相应的条件标志位。其中,操做数1和操做数2均为32位的有符号数。

对于目的寄存器Low,在指令执行前存放64位加数的低32位,指令执行后存放结果的低32位。

对于目的寄存器High,在指令执行前存放64位加数的高32位,指令执行后存放结果的高32位。

如:

SMLAL R0R1R2R3 R0 = R2 × R3)的低32位 + R0

R1 = R2 × R3)的高32位 + R1

五、 UMULL指令

UMULL指令的格式为:

UMULL{条件}{S} 目的寄存器Low,目的寄存器低High,操做数1,操做数2

UMULL指令完成将操做数1与操做数2的乘法运算,并把结果的低32放置到目的寄存器Low结果的高32放置到目的寄存器High,同时能够根据运算结果设置CPSR中相应的条件标志位。其中,操做数1和操做数2均为32位的无符号数。

如:

UMULL R0R1R2R3 R0 = R2 × R3)的低32

R1 = R2 × R3)的高32

六、 UMLAL指令

UMLAL指令的格式为:

UMLAL{条件}{S} 目的寄存器Low,目的寄存器低High,操做数1,操做数2

UMLAL指令完成将操做数1与操做数2的乘法运算,并把结果的低32位同目的寄存器Low中的值相加后又放置到目的寄存器Low结果的高32位同目的寄存器High中的值相加后又放置到目的寄存器High,同时能够根据运算结果设置CPSR中相应的条件标志位。其中,操做数1和操做数2均为32位的无符号数。

对于目的寄存器Low,在指令执行前存放64位加数的低32位,指令执行后存放结果的低32位。

对于目的寄存器High,在指令执行前存放64位加数的高32位,指令执行后存放结果的高32位。

如:

UMLAL R0R1R2R3 R0 = R2 × R3)的低32位 + R0

R1 = R2 × R3)的高32位 + R1

3.3.4  跳转指令

跳转指令用于实现程序流程的跳转,在ARM程序中有两种方法能够实现程序流程的跳转:使用专门的跳转指令、直接向程序计数器PC写入跳转地址值。

直接向PC写入跳转地址值,能够实如今4GB的地址空间中任意跳转,在跳转以前结合使用MOV LRPC等相似指令,能够保存未来的返回地址值,从而实如今4GB连续的线性地址空间的子程序调用。

使用跳转指令能够完成从当前指令向前或向后的32MB的地址空间的跳转。

一、 B指令

B指令的格式为:

B{条件} 目标地址

B指令是最简单的跳转指令。一旦遇到一个指令,ARM 处理器将当即跳转到给定的目标地址,从那里继续执行。注意存储在跳转指令中的实际值是相对当前PC值的一个偏移量,而不是一个绝对地址,它的值由汇编器来计算(参考寻址方式中的相对寻址)。它是 24 位有符号数,左移两位后有符号扩展为 32 位,表示的有效偏移为 26 位(先后32MB的地址空间)。

如:

B Label ;程序无条件跳转到标号Label处执行

CMP R1,#0 ;当CPSR寄存器中的Z条件码置位时,程序跳转到标号Label处执行

BEQ Label

二、 BL指令

BL指令的格式为:

BL{条件}  目标地址

BL 是另外一个跳转指令,但跳转以前,会在寄存器R14中保存PC的当前内容,所以,能够经过将R14 的内容从新加载到PC中,来返回到跳转指令以后的那个指令处执行。该指令是实现子程序调用的一个基本但经常使用的手段。

如:

BL Label ;当程序无条件跳转到标号Label处执行时,同时将当前的PC值保存到R14

Label标号处能够是一个子程序,在子程序的最后能够使用MOV PC,LR指令跳回BL Label指令处的下一条指令继续执行。

三、 BLX指令

BLX指令的格式为:

BLX  目标地址

BLX指令从ARM指令集跳转到指令中所指定的目标地址,并将处理器的工做状态由ARM状态切换到Thumb状态,该指令同时将PC的当前内容保存到寄存器R14中。所以,当子程序使用Thumb指令集,而调用者使用ARM指令集时,能够经过BLX指令实现子程序的调用和处理器工做状态的切换。同时,子程序的返回能够经过将寄存器R14值复制到PC中来完成。

四、 BX指令

BX指令的格式为:

BX{条件}  目标地址

BX指令跳转到指令中所指定的目标地址,目标地址处的指令既能够是ARM指令,也能够是Thumb指令。

3.3.5  程序状态寄存器访问指令

ARM指令不容许直接操做程序状态寄存器CPSRSPSR。能够经过程序状态寄存器访问指令,在程序状态寄存器和通用寄存器之间传送数据,而后在通用寄存器中进行处理。

一、 MRS指令

MRS指令的格式为:

MRS{条件} 通用寄存器,程序状态寄存器(CPSR或SPSR)

MRS指令用于将程序状态寄存器的内容传送到通用寄存器中。该指令通常用在如下几种状况:

1) 当须要改变程序状态寄存器的内容时,可用MRS将程序状态寄存器的内容读入通用寄存器,修改后再写回程序状态寄存器。

2) 当在异常处理或进程切换时,须要保存程序状态寄存器的值,可先用该指令读出程序状态寄存器的值,而后保存。

如:

MRS R0CPSR ;传送CPSR的内容到R0

MRS R0SPSR ;传送SPSR的内容到R0

二、 MSR指令

MSR指令的格式为:

MSR{条件} 程序状态寄存器(CPSR或SPSR)_<域>,操做数

MSR指令用于将操做数的内容传送到程序状态寄存器的特定域中。其中,操做数能够为通用寄存器或当即数。<域>用于设置程序状态寄存器中须要操做的位,32位的程序状态寄存器可分为4个域:

[31:24]为条件标志位域,用f表示;

[23:16]为状态位域,用s表示;

[15:8]为扩展位域,用x表示;

[7:0]为控制位域,用c表示;

该指令一般用于恢复或改变程序状态寄存器的内容,在使用时,通常要在MSR指令中指明将要操做的域。

如:

MSR CPSRR0 ;传送R0的内容到CPSR

MSR SPSRR0 ;传送R0的内容到SPSR

MSR CPSR_cR0 ;传送R0的内容到SPSR,但仅仅修改CPSR中的控制位域

3.3.6  协处理器指令

ARM微处理器可支持多达16个协处理器,用于各类协处理操做,在程序执行的过程当中,每一个协处理器只执行针对自身的协处理指令,忽略ARM处理器和其余协处理器的指令。

ARM的协处理器指令主要用于ARM处理器初始化ARM协处理器的数据处理操做,以及在ARM处理器的寄存器和协处理器的寄存器之间传送数据,和在ARM协处理器的寄存器和存储器之间传送数据。

一、CDP指令

CDP指令的格式为:

CDP{条件} 协处理器编码,协处理器操做码1,目的寄存器,源寄存器1,源寄存器2,协处理器操做码2。

CDP指令用于ARM处理器通知ARM协处理器执行特定的操做,若协处理器不能成功完成特定的操做,则产生未定义指令异常。其中协处理器操做码1和协处理器操做码2为协处理器将要执行的操做,目的寄存器和源寄存器均为协处理器的寄存器,指令不涉及ARM处理器的寄存器和存储器。

如:

CDP  P32C12C10C34      ;该指令完成协处理器P3的初始化

二、LDC指令

LDC指令的格式为:

LDC{条件}{L} 协处理器编码,目的寄存器,[源寄存器]

LDC指令用于将源寄存器所指向的存储器中的字数据传送到目的寄存器中,若协处理器不能成功完成传送操做,则产生未定义指令异常。其中,{L}选项表示指令为长读取操做,如用于双精度数据的传输。

如:

LDC  P3C4[R0]      ;将ARM处理器的寄存器R0所指向的存储器中的字数据传送到协处理器P3的寄存器C4中。

三、STC指令

STC指令的格式为:

STC{条件}{L} 协处理器编码,源寄存器,[目的寄存器]

STC指令用于将源寄存器中的字数据传送到目的寄存器所指向的存储器中,若协处理器不能成功完成传送操做,则产生未定义指令异常。其中,{L}选项表示指令为长读取操做,如用于双精度数据的传输。

如:

STC  P3C4[R0]      ;将协处理器P3的寄存器C4中的字数据传送到ARM处理器的寄存器R0所指向的存储器中。

四、MCR指令

MCR指令的格式为:

MCR{条件} 协处理器编码,协处理器操做码1,源寄存器,目的寄存器1,目的寄存器2,协处理器操做码2。

MCR指令用于将ARM处理器寄存器中的数据传送到协处理器寄存器中,若协处理器不能成功完成操做,则产生未定义指令异常。其中协处理器操做码1和协处理器操做码2为协处理器将要执行的操做,源寄存器为ARM处理器的寄存器,目的寄存器1和目的寄存器2均为协处理器的寄存器。

如:

MCR  P33R0C4C56    ;该指令将ARM处理器寄存器R0中的数据传送到协处理器P3的寄存器C4C5中。

五、MRC指令

MRC指令的格式为:

MRC{条件} 协处理器编码,协处理器操做码1,目的寄存器,源寄存器1,源寄存器2,协处理器操做码2。

MRC指令用于将协处理器寄存器中的数据传送到ARM处理器寄存器中,若协处理器不能成功完成操做,则产生未定义指令异常。其中协处理器操做码1和协处理器操做码2为协处理器将要执行的操做,目的寄存器为ARM处理器的寄存器,源寄存器1和源寄存器2均为协处理器的寄存器。

如:

MRC  P33R0C4C56    ;该指令将协处理器P3的寄存器中的数据传送到ARM处理器寄存器中。

3.3.7  异常中断指令

一、SWI指令

SWI指令的格式为:

SWI{条件} 24位的当即数

SWI指令用于产生软件中断,以便用户程序能调用操做系统的系统例程。操做系统在SWI的异常处理程序中提供相应的系统服务,指令中24位的当即数指定用户程序调用系统例程的类型,相关参数经过通用寄存器传递,当指令中24位的当即数被忽略时,用户程序调用系统例程的类型由通用寄存器R0的内容决定,同时,参数经过其余通用寄存器传递。 

如:

SWI  0x02     ;该指令调用操做系统编号位02的系统例程。

二、BKPT指令

BKPT指令的格式为:

BKPT   16位的当即数

BKPT指令产生软件断点中断,可用于程序的调试

3.4  Thumb指令集

为兼容数据总线宽度为16位的应用系统,ARM体系结构除了支持执行效率很高的32ARM指令集之外,同时支持16位的Thumb指令集。Thumb指令集是ARM指令集的一个子集,容许指令编码为16位的长度。与等价的32位代码相比较,Thumb指令集在保留32位代码优点的同时,大大的节省了系统的存储空间。

全部的Thumb指令都有对应的ARM指令,并且Thumb的编程模型也对应于ARM的编程模型,在应用程序的编写过程当中,只要遵循必定调用的规则,Thumb子程序和ARM子程序就能够互相调用。当处理器在执行ARM程序段时,称ARM处理器处于ARM工做状态,当处理器在执行Thumb程序段时,称ARM处理器处于Thumb工做状态。

ARM指令集相比较,Thumb指令集中的数据处理指令的操做数仍然是32位,指令地址也为32位,但Thumb指令集为实现16位的指令长度,舍弃了ARM指令集的一些特性,如大多数的Thumb指令是无条件执行的,而几乎全部的ARM指令都是有条件执行的;大多数的Thumb数据处理指令的目的寄存器与其中一个源寄存器相同。

因为Thumb指令的长度为16位,即只用ARM指令一半的位数来实现一样的功能,因此,要实现特定的程序功能,所需的Thumb指令的条数较ARM指令多。在通常的状况下,Thumb指令与ARM指令的时间效率和空间效率关系为:

— Thumb代码所需的存储空间约为ARM代码的60%~70%

— Thumb代码使用的指令数比ARM代码多约30%~40%

— 若使用32位的存储器,ARM代码比Thumb代码快约40%

— 若使用16位的存储器,Thumb代码比ARM代码快约40%~50%

— ARM代码相比较,使用Thumb代码,存储器的功耗会下降约30%

显然,ARM指令集和Thumb指令集各有其优势,若对系统的性能有较高要求,应使用32位的存储系统和ARM指令集,若对系统的成本及功耗有较高要求,则应使用16位的存储系统和Thumb指令集。固然,若二者结合使用,充分发挥其各自的优势,会取得更好的效果。

3.5  伪指令

ARM编译器通常都支持汇编语言的程序设计和C/C++语言的程序设计,以及二者的混合编程。在ARM汇编语言程序,有一些特殊指令助记符,这些助记符与指令系统的助记不一样,没有相对应的操做码,一般称这些特殊指令助记符为伪指令,他们所完成的操做称为伪操做。伪指令在源程序中的做用是为完成汇编程序做各类准备工做的,这些伪指令仅在汇编过程当中起做用,一旦汇编结束,伪指令的使命就完成。

ARM的汇编程序中,有以下几种伪指令:ARM伪指令、符号定义伪指令数据定义伪指令、段定义伪指令、模块控制伪指令、汇编控制伪指令处理伪指令等等

须要特别指出的是,除了几条ARM伪指令之外,其它的伪指令依赖于编译器。也就是说,不一样的ARM编译器的伪指令集是不相同的。例如,ADS编译器的段定义伪指令为AREA,而IAR编译器的段定义伪指令为RSEGASEG。这种状况使得不一样编译器下编出的ARM汇编程序是不一样的。读者在阅读不一样学习材料时应注意分辨在不一样编译器下ARM汇编程序的区别。

本书介绍的是IAR EWARM编译器支持的ARM汇编伪指令。

3.5.1  ARM伪指令

ARM伪指令不是ARM指令集中的指令。它能够象其它ARM指令同样使用,但在编译时这些指令将被等效的ARM指令所取代。

一、LDR-大范围地址读取

LDR伪指令的格式为:

LDR{条件} reg,=expr/label_expr

reg为加载的目的寄存器;expr32位当即数;label_expr为地址表达式或外部表达式。

LDR伪指令将32位常量或一个32位地址加载到指定寄存器。

如:

LDR  R0=#0x12345         ;加载32位当即数0x12345到寄存器R0

LDR  R0=DATA_BUF+60     ;加载DATA_BUF地址+60

二、ADR-小范围地址读取

ADR伪指令的格式为:

ADR{条件} reg,expr

reg为加载的目的寄存器;expr为相对偏移表达式,非字对齐时取值范围为-255~255字节,字对齐时取值范围为-1020~1020字节。

ADR伪指令将基于当前PC相对偏移的地址值读取到寄存器中。

如:

Start: MOV R0#10

ADR R4start ;至关于SUB R4PC#0x0c

三、ADRL-中范围地址读取

ADRL伪指令与ADR相似,不一样在expr的取值范围,非字对齐时取值范围为64KB,字对齐时取值范围为256KB

四、NOP-空操做

3.5.2  数据定义伪指令

一、DCB和DC8

该伪指令的格式为:

标号 DCB或DC8 表达式

DCBDC8伪指令用于分配一片连续的8位字节存储单元,并用伪指令中指定的表达式初始化。其中表达式能够为0255的数字或字符串。

如:

Str DCB “This is a test!” ;分配一个字符串,每一个字符8位字节

二、DCW和DC1六、DCD和DC32

DCBDC8用法相同,不一样的是分别分配16位半字节单元和32位字单元。

三、DF32和DF64

分别表示32位的单精度浮点数和64位的双精度浮点数。

四、DS八、DS1六、DS24和DS32

分别用于保留8位字节、16位半字、24位字和32位字的存储器空间。

如:

Dataspace DS8 100 ;保留1008位字节的存储器空间

3.5.3  符号定义伪指令

一、=、ALIAS和EQU

该伪指令的格式为:

标号 = 表达式

标号 ALIAS 表达式

标号 EQU 表达式

伪指令EQU和=可用于为程序模块中的常量、标号等赋值,定义的局部符号仅在其所在的模块内有效。伪指令ALIAS为符号起个别名。定义的符号采用PUBLIC伪指令声明其属性可以使之被其它模块引用,引用其它模块内符号时必须采用EXTERN伪指令声明其属性。

如:

Test EQU 50 ;定义符号Test的值为50

二、ASSIGN、SET、SETA和VAR

用法与EQU等相似,可用于定义一个变量符号。采用VAR定义的变量符号不能用PUBLIC声明其属性。

三、DEFINE

用于定义在整个程序文件内都有效的全局符号。该符号能够被文件内的全部程序模块引用,但不能在同一文件内从新定义。

四、LIMIT

该伪指令的格式为:

LIMIT 表达式, 最小值, 最大值, 提示信息

用于检查表达式的值是否位于给定范围以内。若是表达式值的范围超限,则输出提示信息。

如:

Speed VAR 23 ;定义符号speed的值为23

LIMIT speed1030…speed out of range… ;检查speed的值是否超限

五、EXTERN(或IMPORT)

该伪指令的格式为:

EXTERN 符号,[符号]……

EXTERN伪指令用于通知汇编器,要使用的符号在其它源文件中定义,但要在当前源文件中引用。

如:

Name Start ;程序模块Start

EXTERN Main ;告诉汇编器Main符号在其它源文件中定义

……

BL Main ;在本模块中引用Main符号

END

六、PUBLIC(或EXPORT)

该伪指令的格式为:

PUBLIC 符号,[符号]……

PUBLIC伪指令用于在程序中声明一个全局符号,该符号可在其它文件中引用。

七、REQUIRE

PUBLIC伪指令用于将一个符号标记为已经被引用。

3.5.4  段定义伪指令

一、ASEG和ASEGN

该伪指令的格式为:

ASEG [起始地址[(对齐)]]

ASEGN 段名[:存储器类型],地址

ASEG伪指令用于定义一个绝对段,并设置段的起始地址。不指定地址值时第一个段默认起始地址为0,后续段地址依次递增。ASEGN伪指令用于设置指定段的绝对起始地址,并容许规定段类型。存储器类型能够为CODE(代码段)、DATA(数据段)、STACK(堆栈段)。

如:

ASEG 0 ;定义一个绝对段,起始地址0

ASEGN CODECODE0 ;定义一个名为CODE的代码段,起始地址0

二、RSEG

该伪指令的格式为:

RSEG 段名[:存储器类型][:(NO)ROOT|(NO)REORDER|SORT][(对齐)]

RSEG伪指令用于定义一个可重定位段,段的起始地址由汇编器临时分配。单个模块中最多可定义65536个可重定位段。

如:

RSEG CODECODEROOT(2) ;定义一个名为CODE的可重定位代码段,用户权限为ROOT(可读写),段内存储器对齐方式为4字节对齐

三、DATA

该伪指令的格式为:

DATA 段名[:存储器类型][(对齐)]

DATA伪指令能够在代码段内定义一个数据区。

如:

RSEG CODECODEROOT(2)

DATA

f1:    DC32 subrtn

四、STACK

该伪指令的格式为:

COMMON 段名[:存储器类型][(对齐)]

STACK伪指令用于定义一个堆栈段,用做堆栈的存储器地址从高向低变化,而用做可重定位段的存储器地址是从低向高变化。

五、COMMON

该伪指令的格式为:

COMMON 段名[:存储器类型][(对齐)]

COMMON伪指令用于定义公共段,各源文件中同名的COMMON段共享同一段内存。它的典型应用是多个不一样子程序共享一段数据存储区。中断向量表也可安排在COMMON段,以便容许从多个服务子程序访问。

六、CODE16和CODE32

CODE16伪指令用于告诉汇编器,其后的指令序列为16位的Thumb指令;CODE32伪指令用于告诉汇编器,其后的指令序列为32位的ARM指令。所以,在使用ARM指令和Thumb指令混合编程的代码中,可用这两条伪指令进行切换。但须要注意的是,它们只通知汇编器其后指令的类型,并不能对处理器进行状态切换。

七、ORG

该伪指令的格式为:

ORG 地址表达式

ORG伪指令用于设置段的起始地址。地址表达式的计算结果应与当前段的类型保持一致,如在RSEG(可重定位段)中,不要使用“ORG 10”,由于10是一个绝对地址,而应当使用“ORG +10”,表示当前段偏移量为10的地址。另外,地址表达式中不能包括任何前向和外部引用。

八、ALIGNRAM和ALIGNROM

该伪指令的格式为:

ALIGNRAM 对齐

ALIGNROM 对齐[,填充值]

用于设置存储器地址边界的对齐方式,“对齐”是一个值为230的常数,并按2230设定对齐地址。ALIGNRAM以数据增量方式对齐,ALIGNROM以填充0字节方式对齐。

九、EVEN和ODD

该伪指令的格式为:

EVEN [填充值]

ODD [填充值]

EVEN伪指令用于将程序计数器PC以偶数地址对齐(等价于ALIGNROM 1),ODD伪指令用于将程序计数器PC以奇数地址对齐。

3.5.5  模块控制伪指令

一、NAME和PROGRAM

该伪指令的格式为:

NAME 模块名

PROGRAM 模块名

NAMEPROGRAM伪指令用于定义一个程序模块。程序模块相似于C语言中的函数,是程序中相对独立的一个部分。程序模块即便没有被调用也会被无条件连接。

如:

NAME Main ;定义一个名为Main的程序模块

二、END和ENDMOD

END伪指令用于结束整个汇编语言程序,ENDMOD用于结束当前程序模块。每一个汇编语言程序最后必须使用END伪指令通知汇编器已经到了源程序结尾,以结束汇编。

三、LIBRARY和MODULE

伪指令用于定义多模块文件中的小模块,其中每一个小模块表明一段子程序,从而能够方便地建立库模块文件。与NAMEPROGRAM不一样的是,用LIBRARYMODULE定义的模块只有在被调用时才会复制到连接代码中。

四、RTMODEL

该伪指令的格式为:

RTMODEL 关键字字符串,值字符串

该伪指令用于声明模块的运行模式属性,以强制模块之间的一致性。全部能被连接在一块儿的模块必须具备相同的关键字;值字符串要么具备相同的值,要么其值为星号*”。

3.5.6  汇编控制伪指令

一、$和INCLUDE

该伪指令的格式为:

$ 文件名

INCLUDE 文件名

该伪指令用于给当前源文件加载头文件。

二、CASEOFF和CASEON

该伪指令用于源程序文件中禁止和容许大小写字符敏感。

三、LTORG

在使用ARM伪指令LDR加载地址数据时,要在适当的位置加入LTORG声明一个数据区,把要加载的数据保存在数据区内,再用LDR读出数据。LTORG伪指令一般放在无条件分支或子程序返回指令后面,这样处理器就不会错误的将数据区中的数据看成指令执行。

四、RADIX

该伪指令用于声明当前使用的数制形式。如:

RADIX 16D ;声明当前使用十六进制数

MOV R0#12 ;此处#120x12

五、IF、ELSE和ENDIF

该伪指令的格式为:

IF 逻辑表达式

指令序列1

ELSE

指令序列2

ENDIF

条件汇编伪指令能根据设定条件的成立与否决定是否对指令序列进行汇编生成目标代码。若逻辑表达式为真,则对指令序列1汇编生成目标代码;不然对指令序列2汇编。其中还能够用ELSEIF伪指令设定新条件。

如:

DEFINE Test ;定义一个全局变量Test

……

IF Test TRUE

指令序列1

ELSE

指令序列2

ENDIF

3.5.7  宏处理伪指令

一、MACRO和ENDM

该伪指令的格式为:

宏名 MACRO [,参数][ ,参数]……

指令序列

ENDM

MACRO伪指令用于定义一个宏,引用宏时必须使用定义的宏名,并可向宏中传递参数。ENDM伪指令用于结束宏定义。

如:

errmac MACRO  text

BL abort

DATA

DC8 text,0

ENDM

包含在MACROENDM之间的指令序列称为宏定义体。在宏定义体的第一行应声明宏的原型(包括宏名和所需的参数),而后就能够在汇编程序中经过宏名来调用该指令序列。在源程序被编译时,汇编器将宏调用展开,用宏定义中的指令序列代替程序中的宏调用,并将实际参数值传递给宏定义中的形式参数。

二、REPT和ENDR

该伪指令的格式为:

REPT 表达式

指令序列

ENDR

伪指令用于指示汇编器将指定的指令序列进行重复汇编,重复次数由表达式的值肯定。若是表达式的值为0,则不进行任何操做。

三、REPTC和ENDR

该伪指令的格式为:

REPTC 符号,替换字符串

指令序列

ENDR

该伪指令用于在宏展开时用替换字符串中的单个字符逐次替换符号。

四、REPTI和ENDR

该伪指令的格式为:

REPTI 符号,替换字符串[,替换字符串]……

指令序列

ENDR

该伪指令用于在宏展开时用整个替换字符串替换符号。

3.6  ARM汇编语言的语句格式

3.6.1  ARM汇编语言的语句格式

ARMThumb)汇编语言的语句格式为:

[标号[:]] 指令或伪指令 操做数 [;注释]

其中,方括号内的内容为可选项。

标号顶格书写时后面可不用冒号,非顶格书写时后面必须用冒号。

标号前加一个问号?”前缀,表示该标号为外部标号,且仅能经过汇编语言访问;标号前加两个下划线“__”前缀,表示该标号为外部标号,能经过C语言和汇编语言访问;没有前缀的标号为局部标号,仅能在本模块内访问。

IAR汇编器对大小写字符敏感,通常指令和伪指令助记符使用大写,标号使用大小写混杂的方式以示区分。

同时,若是一条语句太长,可将该长语句分为若干行来书写,在行的末尾用\”表示下一行与本行为同一条语句。

IAR汇编器规定汇编语言程序文件的默认扩展名为“.s79”,也能够用“.s”或“.asm”做为扩展名。

3.6.2  符号

在汇编语言程序设计中,常用各类符号代替地址、变量和常量等,以增长程序的可读性。尽管符号的命名由编程者决定,但并非任意的,必须遵循如下的约定:

1.符号由大小写字母、数字及下划线组成,符号不能用数字开头。

2.符号区分大小写,同名的大、小写符号会被编译器认为是两个不一样的符号。

3.符号在其做用范围内必须惟一。

4.自定义的符号名不能与系统的保留字相同。

5.符号名不该与指令或伪指令同名。

6IAR汇编器内部预约义符号以双下划线开头和结尾。如:__IAR_SYSTEMS_ASM__

3.6.3  常量和变量

一、 常量

程序中的常量是指其值在程序的运行过程当中不能被改变的量。ARMThumb)汇编程序所支持的常量有数字常量、逻辑常量和字符串常量。

数字常量通常为32位的整数,看成为无符号数时,其取值范围为0232-1,看成为有符号数时,其取值范围为-231231-1。数字常量有4种表示形式:十进制数如123、-456等;十六进制数如0x1230FFFFH等;八进制数如1234q等;二进制数如1010b等。

逻辑常量只有两种取值状况:TRUEFALSE

字符串常量为一个固定的字符串,通常用于程序运行时的信息提示。用法与标准C语言相同。

二、 变量

程序中的变量是指其值在程序的运行过程当中能够改变的量。ARMThumb)汇编程序所支持的变量有数字变量、逻辑变量和字符串变量。

数字变量用于在程序的运行中保存数字值,但注意数字值的大小不该超出数字变量所能表示的范围。

逻辑变量用于在程序的运行中保存逻辑值,逻辑值只有两种取值状况:真或假。

字符串变量用于在程序的运行中保存一个字符串,但注意字符串的长度不该超出字符串变量所能表示的范围。

3.7  ARM汇编语言的程序结构

3.7.1  汇编语言的程序结构

ARMThumb)汇编语言程序中,以程序段为单位组织代码。段是相对独立的指令或数据序列,具备特定的名称。段能够分为代码段和数据段,代码段的内容为执行代码,数据段存放代码运行时须要用到的数据。一个汇编程序至少应该有一个代码段,当程序较长时,能够分割为多个代码段和数据段,多个段在程序编译连接时最终造成一个可执行的映象文件。

可执行映象文件一般由如下几部分构成:

11个或多个代码段,代码段的属性为只读。

20个或多个包含初始化数据的数据段,数据段的属性为可读写。

30个或多个不包含初始化数据的数据段,数据段的属性为可读写。

连接器根据系统默认或用户设定的规则,将各个段安排在存储器中的相应位置。所以源程序中段之间的相对位置与可执行的映象文件中段的相对位置通常不会相同。

3.7.2  一个简单的ARM汇编语言程序

如下是一个汇编语言源程序的基本结构:

代码清单3.1

NAME ASM_EXAMPL ;定义一个名为ARM_EXAMPL的程序模块

RSEG CODE:CODE:ROOT(2) ;定义一个可重定位的代码段

CODE32 ;执行32ARM指令

ORG 0x1000 ;定义程序起始地址为0x1000

Start: LDR R0,=0x3FF5000 Start处的地址即为0x1000

LDR R1,=0xff

STR R1,[R0]

MOV R0,#0x10

MOV R1,#0x20

ADD R0,R0,R1

Stop: B Stop ;跳转到指令自己,程序中止运行

ENDMOD ;本程序模块结束

END ;本程序结束

程序很简单,它完成的功能并不重要,但它已经表示出了一个ARM汇编语言程序的基本结构。

3.8  ARM程序设计举例

3.8.1  分支程序

程序设计中的三种基本结构是:顺序结构、分支结构和循环结构。在C语言中能够使用if-else语句实现单分支和双分支结构,也能够经过switch-case语句实现多分支结构。可是在汇编语言中,分支结构通常是经过跳转指令结合标号来实现的。

ARM汇编语言程序中,因为ARM指令支持条件执行,从而大大减小了分支程序的复杂程度。

例如:用两个整数展转相减的方法求它们的最大公约数。注意体会B指令加条件码的执行方式。程序中使用的main标号是由于IAR汇编器通常默认从main标号处开始执行。

代码清单3.2

NAME GCD

PUBLIC  main                         ;声明外部引用标号main

B      main ;main标号处开始执行

RSEG CODE:CODE                           

CODE32                              

main: MOV R0,#120

MOV R1,#96

Gcd: CMP R0,R1 ;比较两数的大小

BEQ Stop ;若是两数相等则跳到结束处

BLT Less ;若是R0<R1则跳到Less标号处

SUB R0,R0,R1 ;不然R0=R0-R1

B Gcd

Less: SUB R1,R1,R0 R1=R1-R0

 B Gcd

Stop: B Stop ;跳转到指令自己,程序中止运行

ENDMOD ;本程序模块结束

END ;本程序结束

3.8.2  循环程序

经过跳转指令还能够实现程序的循环结构。

例如:求n=1+2+…+10累加的和。

代码清单3.3

NAME SUM

PUBLIC  main                        

B       main

RSEG CODE                           

CODE32                              

main: MOV R0,#10

MOV R1,R0 ;利用R1寄存器作循环计数器

Loop: SUBS R1,R1,1 ;循环次数减1

ADD   R0,R0,R1

BNE Loop ;循环次数为0则结束循环

Stop: B Stop

ENDMOD

END

3.8.3  子程序调用

经过BL指令能够实现子程序调用,语法:BL子程序名。

在子程序的结束处,能够经过MOV  PCLR返回到主程序中。一般能够使用寄存器R0R3完成传递参数到子程序和从子程序返回运算的结果。

如下是使用BL指令调用子程序的汇编语言源程序的例子,该程序编写了一个在内存里拷贝字符串的子程序,而后在主程序里调用它。

代码清单3.4

       NAME  STRCPY                         

        PUBLIC  main                        

        B       main

        RSEG CODE                           

        CODE32                              

main LDR R1,=srcstr       ;R1指向源字符串

       LDR R0,=dststr  ;R0指向目标字符串

  BL strcopy  ;调用strcopy子程序

stop:   B stop  ;程序中止

strcopy:  ;子程序定义

        LDRB R2,[R1],#1   ;读一个字符到R2,并更新源字符地址

        STRB R2,[R0],#1   ;写一个字符,并更新目的字符地址

        CMP R2,#0  ;是否结束。以数字0为标志

        BNE strcopy   ;循环执行

 

        DATA  ;数据区

srcstr DCB "First string - source ",0

dststr DCB "Second string - destination ",0

        ENDMOD                               

        END        

3.8.4  查表法

查表法是编程中经常使用的一种技巧。当程序涉及到较多的数据、数据串或数据表格时,能够经过地址来对它们进行访问。一般有两种方法装载地址:(1)经过ADRADRL伪指令直接装载地址;(2)经过伪指令LDR Rd,=Label从数据表格中装载地址。

下面的程序设置了3个参数,arithfunc根据3个参数返回一个R0值。当R0=0时,R0=R1+R2;当R0=1时,R0=R1-R2;当R0>1时,R0=R1+R2。:

代码清单3.5

      NAME  JUMP                         

        PUBLIC  main                        

        B       main

   Num  EQU 2 ;跳转表格的入口数

        RSEG CODE                           

        CODE32                              

main  MOV  R0,#0        ;如下设置3个参数

        MOV R1,#3  

   MOV R2,#2

   BL arithfunc   ;调用子程序

stop:    B stop ;程序中止

arithfunc:  

        CMP R0,#Num   ;比较参数

        BHS Doadd  ;R0>=2,则执行加法

        ADR R3,jumptable   ;装载跳转表格标号地址

        LDR PC,[R3,R0,LSL #2]   ;跳到相应子程序入口地址处

Jumptable:

        DCD Doadd   ;Doadd子程序的入口地址

        DCD Dosub   ;Dosub子程序的入口地址

Doadd:  ADD R0,R1,R2   ;=0>1时执行的操做

   MOV PC,LR

Dosub:  SUB R0,R1,R2   ;=1时执行的操做

   MOV PC,LR

        ENDMOD                               

        END        

3.8.5  汇编语言与C/C++的混合编程

在应用系统的程序设计中,若全部的编程任务均用汇编语言来完成,其工做量是可想而知的,同时,不利于系统升级或应用软件移植,事实上,ARM体系结构支持C/C+以及与汇编语言的混合编程,在一个完整的程序设计的中,除了初始化部分用汇编语言完成之外,其主要的编程任务通常都用C/C++ 完成。

汇编语言与C/C++的混合编程一般有如下几种方式:

1. 在C/C++代码中嵌入汇编指令。

ARM C中,能够使用关键字__arm来标识一段汇编指令程序。格式以下:

 __asm

{

  汇编指令序列

}

便可在C语言源程序中直接执行ARM汇编指令。

2. 在汇编程序和C/C++的程序之间进行变量的互访。

3. 汇编程序、C/C++程序间的相互调用。

能够把汇编程序和C/C++程序中须要共享的变量或函数用PUBLICextern关键字分别声明为全局变量或全局函数,而后在其它程序文件中便可进行访问和调用。可是从好的编程风格来讲,最好尽可能减小全局变量和全局函数的使用。

混合编程中,必须遵照必定的调用规则,如物理寄存器的使用、参数的传递等。ARM专门为此制定了一个标准ATPCS(ARM-Thumb Procedure Call StandardARM-Thumb过程调用标准)。对于初学者来讲,这是很是烦琐的,在实际工做中也没有太多必要。

在实际的编程应用中,使用较多的方式是:系统程序的初始化部分用汇编语言完成,而后用C/C++完成主要的编程任务,程序在执行时首先完成初始化过程,而后跳转到C/C++程序代码中。汇编程序和C/C++程序之间通常没有参数的传递,也没有频繁的相互调用,所以,整个程序的结构显得相对简单,容易理解。

如下是一个这种结构程序的基本示例。该程序很是简单,创建一个工程asm_c.eww,工程中包括一个汇编语言程序文件init.s79和一个C语言程序文件hello.c

代码清单3.6——init.s79文件

        NAME INIT

        PUBLIC  main                                          

        EXTERN  Main                           ;声明引入C程序的Main()函数

   B main

        RSEG CODE                                     

        CODE32                                         

main:

        NOP               ;此处能够插入用户本身编写的系统初始化代码

 

        B Main                                 ;转向C语言程序

        ENDMOD                                                  

        END     

代码清单3.7——hello.c文件:

#include <stdio.h>

/*注意此处C语言程序的入口函数是大小写敏感的Main()函数,而不是经常使用的main()函数。这是为了跟汇编程序中的main入口区别开,以避免形成工程有两个程序入口。*/

int Main(void)

{

   printf("Hello, world!\n");

}

3.9  ARM汇编语言编写系统启动程序

基于ARM内核的芯片多数为复杂的片上系统,这种复杂系统里的多数硬件模块都是能够配置的,须要由软件来设置其须要的工做状态。因为C语言具备模块性和可移植性的特色,大部分基于ARM的应用系统程序都采用C语言编写。可是当系统复位启动时,在进入C语言的main函数以前,须要有一段启动程序来完成对存储器配置、地址重映射和ARM芯片内部集成外围功能初始化等工做。这类工做直接面对处理器内核和硬件控制器进行编程,用C语言较难实现,所以通常采用汇编语言编写。

3.9.1  编写启动程序的通常规则

ARM内核的处理器在复位后,从0x00000000地址处开始读取指令。实现启动最简单的方法是将应用程序放在映射空间地址为0ROM中。这样当执行第1条指令时,应用程序就从0x00000000处开始执行。但这种方法有不少缺点:ROM的存储宽度较小且速度较慢,会下降系统启动和处理器对异常处理的速度;异常向量表放在ROM中,程序将没法修改向量表,所以常将地址为0的空间映射成RAM,但RAM中的程序掉电没法保存,所以必须将ROM映射为0地址,以保证有效的复位向量,而后再使用重映射命令将RAM映射为0地址,ROM映射到其余地址空间,并将异常向量从ROM复制到RAM中。

编写启动程序应遵循如下通常规则:

1. 设置入口指针

启动程序首先必须定义入口指针,并且整个应用程序只有一个入口指针,一般应用程序的入口地址为0

2. 设置异常向量

基于ARM7TDMI内核的处理器共支持7种异常,异常处理地址存放在地址0处的异常向量表中,共8×4字节的空间。异常向量表的内容参见2.4.2节。

异常向量表一般放在存储器底部,每一个异常分配4个字节的空间。每一个向量入口包含一条跳转指令或加载PC的指令,以执行适当的转移到具体的异常处理程序。若是ROM定位于0地址,则向量表由一系列固定的用以指向每一个异常的指令组成;不然向量必须被动态初始化。能够在启动程序中添加一段代码,使其在运行时将向量表拷贝到0地址开始的存储器空间。对于没有使用的异常,使其指向一个只含返回指令的哑函数,以防止错误异常引发系统混乱。

3. 初始化片内集成外围功能

因为ARM公司仅设计内核并出售给其它半导体厂商,不一样的厂商购买内核受权后加入本身的外围功能,从而致使ARM核处理器芯片丰富多样,但也使得不一样芯片的启动代码在这一部分差异很大。编写这一部分时应根据芯片和应用系统要求对它们进行合适的初始化。比较重要的操做通常有:外部总线接口的初始化、配置时钟锁相环、配置中断控制器、禁用看门狗电路等。

4. 初始化存储系统

有些ARM核芯片可经过对寄存器编程来初始化系统存储器,而对于较复杂系统一般由存储管理单元MMU来管理内存空间。为正确运行应用程序,在初始化期间应将系统须要读写的数据和变量从ROM拷贝到RAM中;一些要求快速响应的程序,例如中断处理程序,也须要在RAM中运行;若是使用Flash,对Flash的擦除和写入操做也必定要在RAM中运行。

5. 初始化堆栈寄存器

系统堆栈初始化取决于用户使用了哪些中断,以及系统须要处理哪些错误类型。通常来讲管理模式堆栈必须初始化。若是使用IRQ中断,则IRQ堆栈必须初始化,而且必须在容许中断以前进行。若是使用FIQ中断,则FIQ堆栈也必须初始化,而且必须在容许中断以前进行。通常在简单的嵌入式系统中不使用停止状态堆栈和未定义指令堆栈,但为了调试方便仍是将其初始化。若是系统使用DRAM或其它外设,还须要设置相关寄存器,以肯定其刷新频率、数据总线宽度等信息。

6. 改变处理器模式和状态

此时能够经过清除CPSR寄存器中的中断控制位来容许中断,这里是安全开启中断的最先地方。这个阶段处理器仍处于管理模式下。若是程序须要在用户模式下运行,能够在此处切换到用户模式并初始化用户模式堆栈指针。

7. 跳转到C语言主程序

在从启动程序跳转到C语言程序的main函数以前,还须要初始化数据存储空间。一般是加入一段循环代码对数据存储空间清0。这样作的主要缘由是C语言中没有初值的变量默认值均为0。已经初始化变量的初值必须从ROM中复制到RAM中,其它变量的初值必须为0

3.9.2  IAR EWARM软件包给出的通常启动程序

下面给出了IAR EWARM软件包提供的通常启动程序代码,实际应用中能够根据具体芯片及应用系统要求进行适当修改,以适应不一样场合的须要。

代码清单3.8——IAR EWARM启动代码

;-----------------------------------------------------------------------------

; 文件中标号的命名规则:

;  ?xxx   - 仅能由汇编语言访问的外部标号

;  __xxx  - 可由C语言访问或定义的外部标号

;  xxx   - 单个模块中的局部标号(注意,本文件包含多个模块)

;  main   - 用户程序的起点

;---------------------------------------------------------------

; 适用于整个文件的宏和模式定义

;---------------------------------------------------------------

; 模式,对应于CPSR寄存器的05

MODE_BITS DEFINE 0x1F ; 用于CPSR模式的位屏蔽

USR_MODE DEFINE 0x10 ; 用户模式

FIQ_MODE DEFINE 0x11 ; FIQ模式

IRQ_MODE DEFINE 0x12 ; IRQ模式

SVC_MODE DEFINE 0x13 ; 管理模式

ABT_MODE DEFINE 0x17 ; 停止模式

UND_MODE DEFINE 0x1B ; 未定义指令模式

SYS_MODE DEFINE 0x1F ; 系统模式

;---------------------------------------------------------------

; ?RESET

; 复位向量。一般INTVEC段被连接到地址0。为程序调试方便,也能够放在其它地址

;---------------------------------------------------------------

MODULE ?RESET

COMMON INTVEC:CODE:NOROOT(2)

PUBLIC  __program_start

EXTERN ?cstartup

EXTERN undef_handler, swi_handler, prefetch_handler

EXTERN data_handler, irq_handler, fiq_handler

        CODE32 ; 复位后始终为ARM模式

org 0x00

__program_start

ldr pc,[pc,#24] ; 绝对跳转地址范围为4GB

; ldr b,?cstartup ; 相对跳转容许重映射,限于32MB

; 能够去掉如下指令前的注释分号来容许异常向量

; 也能够在C语言中采用预编译命令“#pragma vector”

org 0x04

; ldr pc,[pc,#24] ; 跳转到undef_handler

org 0x08

; ldr pc,[pc,#24] ; 跳转到swi_handler

org 0x0c

; ldr pc,[pc,#24] ; 跳转到prefetch_handler

org 0x10

; ldr pc,[pc,#24] ; 跳转到data_handler

org 0x18

; ldr pc,[pc,#24] ; 跳转到irq_handler

org 0x1c

; ldr pc,[pc,#24] ; 跳转到fiq_handler

; 用于ldr pc”指令的常数表入口定位于0x20

; 异常向量能够用C语言的预编译命令“#pragma vector”指定,也能够

; 在如下dc32指令后面填入向量地址。向量地址为ARM向量号+20

org 0x20

         dc32 ?cstartup

org 0x24

;         dc32 undef_handler

org 0x28

;         dc32 swi_handler

org 0x2c

;         dc32 prefetch_handler

org 0x30

;         dc32 data_handler

org 0x38

;         dc32 irq_handler

org 0x3c

;         dc32 fiq_handler

LTORG

; ENDMOD __program_start

        ENDMOD

;---------------------------------------------------------------

; ?CSTARTUP

;---------------------------------------------------------------

MODULE ?CSTARTUP

RSEG IRQ_STACK:DATA(2)

RSEG ABT_STACK:DATA:NOROOT(2)

RSEG UND_STACK:DATA:NOROOT(2)

RSEG FIR_STACK:DATA:NOROOT(2)

RSEG SVC_STACK:DATA:NOROOT(2)

RSEG CSTACK:DATA(2)

RSEG ICODE:CODE:NOROOT(2)

PUBLIC ?cstartup

EXTERN ?main

; 从这里开始执行

; 复位后为ARM管理模式,禁止中断

CODE32

?cstartup

; 须要时在这里加入创建堆栈指针以前的初始化指令

; 初始化堆栈指针

; 如下方式可用于任何异常堆栈:FIQ, IRQ, SVC, ABT, UND, SYS.

; 用户模式使用与SYS模式相同的堆栈

; 堆栈段必须在连接器命令文件中定义,而且已经在上面声明

        mrs r0,cpsr             ; 原PSR值

        bic r0,r0,#MODE_BITS  ; 清除模式位

        orr   r0,r0,#IRQ_MODE   ; 置IRQ模式位

        msr   cpsr_c,r0           ; 改变模式

        ldr sp,=SFE(IRQ_STACK)&0xFFFFFFF8 ; IRQ_STACK结束

        bic   r0,r0,#MODE_BITS  ; 清除模式位

        orr   r0,r0,#ABT_MODE  ; 置Abort模式位

        msr   cpsr_c,r0          ; 改变模式

        ldr sp,=SFE(ABT_STACK)&0xFFFFFFF8  ; ABT_STACK结束

        bic   r0,r0,#MODE_BITS  ; 清除模式位

        orr   r0,r0,#SVC_MODE   ; 置Supervisor模式位

        msr   cpsr_c,r0           ; 改变模式

        ldr sp,=SFE(SVC_STACK) & 0xFFFFFFF8  ; SVC_STACK结束

        bic   r0,r0,#MODE_BITS   ; 清除模式位

        orr   r0,r0,#UND_MODE   ; 置Undefined模式位

        msr   cpsr_c,r0            ; 改变模式

        ldr sp,=SFE(UND_STACK) & 0xFFFFFFF8   ; FIR_STACK结束

        bic   r0,r0,#MODE_BITS    ; 清除模式位

        orr   r0,r0,#FIQ_MODE      ; 置FIR模式位

        msr   cpsr_c,r0              ; 改变模式

        ldr sp,=SFE(FIR_STACK) & 0xFFFFFFF8     ; FIR_STACK结束

        bic   r0,r0,#MODE_BITS     ; 清除模式位

        orr   r0,r0,#SYS_MODE     ; 置System模式位

        msr   cpsr_c,r0              ; 改变模式

        ldr sp,=SFE(CSTACK) & 0xFFFFFFF8      ; CSTACK结束

#ifdef __ARMVFP__

; 容许VFP协处理器

        mov   r0, #0x40000000     ; VFPEN位

        fmxr   fpexc, r0             ; FPEXC, 清除其它

; 将缓冲区清0以禁止下溢出。为知足IEEE 754标准,应删除该指令并安装合适的异常句柄

        mov   r0, #0x01000000  ; VFPFZ位

        fmxr   fpscr, r0               ; FPSCR, 清除其它

#endif

; 在这里能够添加更多的用户自定义初始化指令

; 跳转到?main标号的地方,继续IAR系统的启动程序

         ldr    r0,=?main

         bx    r0

         LTORG

         ENDMOD

         END

习题

3.1  ARM7TDMI有几种寻址方式?LDR R1,[R0,#0x04]属于哪一种寻址方式?

3.2  ARM指令的条件码有多少个?默认条件码是什么?

3.3  ARM指令中第二个操做数有哪几种形式?

3.4  请指出MOV指令与LDR加载指令的区别及用途.

3.5  CMP指令的功能是什么?写一个程序,判断R1的值是否大于0x30,是则将R1减去0x30

3.6  调用子程序是用B仍是用BL指令?请写出返回子程序的指令。

3.7  ARM状态与Thumb状态的切换指令是什么?请举例说明。

3.8  Thumb状态与ARM状态的寄存器有区别吗?Thumb指令对哪些寄存器的访问受到必定限制?

3.9  Thumb指令集的堆栈入栈、出栈指令是哪两条?

3.10 把下面的C代码转换成汇编代码。数组ab分别存放在以0x40000x5000为起始地址的存储区内,类型为long型(32位)。

fori=0;i<8;i++

{

  a[i] = b[7-i];

}

3.11 编写程序,将R1的高8位传送到R2的低8

3.12 编写一段64位加法运算的程序,要求知足:[R1:R0]+[R3:R2],结果存入[R1:R0]

3.13 编写程序将地址0x0000 10000x0000 1030的数据所有搬迁到0x0000 20000x0000 2030的区域中,并将源数据区清零。


4LPC2400系列处理器原理

处理器的“体系结构”指从程序员角度观察到的处理器的组织方式,因此又称为处理器的编程模型。其主要内容为处理器内的寄存器组织、对存储器的寻址方式、指令系统等。本章将介绍ARM7TDMI程序员模型、工做状态与工做模式、ARM和Thumb状态的寄存器组织、存储器组织结构、异常及协处理器接口等一些基本概念。本章还要讲述ARM的编程基础,如ARM微处理器的基本工做原理、与程序设计相关的基本技术细节等。

4.1  LPC2400系列处理器简介

4.1.1  LPC2400系列处理器特性

LPC2400系列处理器包括LPC2468/LPC2470/LPC2478等多款芯片,是基于支持实时仿真和跟踪的16/32位ARM7TDMI-S内核的微控制器,它与全部NXP LPC 2000处理器具备相同的存储器映射、中断向量控制、Flash编程和更新机制,以及调试和仿真功能。LPC2468/LPC2478的512KB大容量嵌入式高速Flash存储器具备128位宽度的存储器接口和独特的加速结构,使得32位代码可以在最高时钟频率72MHz下运行。16位Thumb模式能够将代码规模下降30%以上,而性能损失却很小。LPC2470/LPC2478芯片内部还集成了LCD接口支持(最高1024×768像素、15阶灰度单色和每像素24位真彩色TFT面板),使得这两款芯片能够普遍应用于各类手持式设备中

LPC2400系列处理器拥有丰富的片上资源和外设接口。这一系列芯片的共同特性有:

-ARM7TDMI-S内核,最高72MHz主频;

-98KB的片内静态存储器,其中64KB的片内SRAM,16KB SRAM用于以太网,16KB SRAM用于DMA控制器(也可用于USB控制器),2KB SRAM用于RTC实时时钟;

-512KB片内Flash程序存储器,片内Boot实现IAP和ISP片内Flash编程;

-可配置的外部存储器接口,最多支持8个Bank,支持外部RAM、ROM和Flash存储器扩展,每一个Bank最大可支持到256MB,可支持8/16/32位字宽;

-高级向量中断控制器,支持32个向量中断,可配置优先级和向量地址;

-通用AHB DMA控制器(GPDMA)能够用于支持SSP、I2S和SD/MMC接口;

-10/100M以太网MAC接口;

-多个串行接口,包括4路UART、3路I2C串行总线接口和1个SPI接口;

-10位A/D和D/A转换器,转换时间低至2.44微秒;

-USB device/host/OTG接口;

-2个CAN总线接口;

-4个32位的定时器、2个PWM脉冲调制单元(每一个6路输出)、实时时钟和看门狗;

-160个高速GPIO端口(可承受5V电压),4个独立外部中断引脚;

-标准ARM调试接口,兼容各类现有的调试工具;

-片内晶振频率范围1~24MHz;

-4个低功耗模式:空闲、睡眠、掉电和深度掉电模式;

-供电电压3.3V(3.0V~3.6V)。

LPC2400系列芯片中,LPC2468是LPC2478的无LCD控制器版本,LPC2470是LPC2478的无片内Flash版本,芯片的大多数特性是彻底相同的。因此在后面的章节中,本书一概采用LPC2478芯片为例进行讲解,请读者在实际工做中注意具体芯片的差异。

4.1.2 LPC2400系列处理器结构

LPC2400系列处理器包含一个支持仿真的ARM7TDMI-S CPU、与片内存储器控制器接口的ARM7局部总线、与中断控制器接口的AMBA高性能总线(AHB总线)和链接片内外设功能的AMBA外设总线(APB总线)。存储模式为小端模式。

AHB总线和APB总线都是ARM公司推出的AMBA片上总线规范的一部分。AHB(Advanced High performance Bus)系统总线主要用于高性能模块(如CPU、DMA和DSP等)之间的链接,通常用于片内高性能高速度的外设,如:外部存储器、USB接口、DMA控制器、以太网控制器、LCD液晶屏控制器以及高速GPIO控制器等。LPC2400中的AHB外设一共分配了2MB的地址范围,它位于4GB ARM存储器空间的最顶端。每一个AHB外设都分配了16KB的地址空间。

LPC2400的外设功能模块都链接到APB总线。APB(Advanced Peripheral Bus)外围总线主要用于低带宽的周边外设之间的链接,如:UART、I2C、SPI、I2S、A/D、D/A、CAN等等。APB总线与AHB总线之间经过AHB到APB的桥相连。APB外设也分配了2MB的地址范围,每一个APB外设在APB地址空间内都分配了16KB的地址空间。

片内外设与器件引脚的链接由引脚链接模块控制。软件能够经过控制该模块让引脚与特定的片内外设相链接。

LPC2400的结构框图如图4.1所示。


4.1 LPC2400结构框图

4.2  处理器引脚配置

4.2.1引脚配置

LPC2400系列处理器共有208个引脚,通常提供两种封装形式:LQFP208和TFBGA208。其管脚封装如图4.2所示。

 

LQFP208 FBGA208

4.2 LPC2400系列处理器管脚封装图

LQFP指封装本体厚度为1.4mm的薄型QFP(四侧引脚扁平封装quad flat package),它是一种表面贴装型封装,引脚从四个侧面引出呈L型,每一个侧面52个引脚,引脚号分别为1~5二、53~10四、105~15六、157~208。FBGA是塑料封装的BGA(Ball Grid Array Package),即球栅阵列封装,其引脚都在芯片底部,用英文字母行和数字列标识。因为LPC2400系列处理器在实际使用中更多使用QFP封装,本节引脚介绍以QFP封装为准。

从功能上,LPC2400的208个引脚分为P0口、P1口、P2口、P3口、P4口,以及电源、复位、晶振和其它管脚几部分。下面对这几个部分分别进行介绍。

1. P0口:  P0口是一个32位的双向多功能I/O口,每位的方向可单独控制,且每位的功能取决于管脚链接模块的管脚功能选择。LPC2400的P0口管脚描述如表4.1所示。

4.1 LPC2400的P0口管脚描述

管脚名称

引脚号

类型

描  述

 

P0[0]

 

94

I/O

P0[0]:GPIO口

I

RD1:CAN1接收器输入

O

TXD3:UART3发送输出端

I/O

SDA1:I2C1数据输入/输出

 

P0[1]

 

96

I/O

P0[1]:GPIO口

O

TD1:CAN1发送器输出

I

RXD3:UART3接收输入端

I/O

SCL1:I2C1时钟输入/输出

 

P0[2]

 

202

I/O

P0[2]:GPIO口

O

TXD0:UART0发送输出端

 

P0[3]

 

204

I/O

P0[3]:GPIO口

I

RXD0:UART0接收输入端

 

P0[4]

 

168

I/O

P0[4]:GPIO口

I/O

I2SRX_CLK:I2S总线接收时钟

I

RD2:CAN2接收输入端

I

CAP2[0]:Timer2的捕获输入通道0

 

P0[5]

 

166

I/O

P0[5]:GPIO口

I/O

I2SRX_WS:I2S总线接收字选择

I

TD2:CAN2发送输出端

I

CAP2[1]:Timer2的捕获输入通道1

 

P0[6]

 

164

I/O

P0[6]:GPIO口

I/O

I2SRX_SDA:I2S总线数据接收

I/O

SSEL1:SSP1从机选择

O

MAT2[0]:Timer2的匹配输出通道0

 

P0[7]

 

162

I/O

P0[7]:GPIO口

I/O

I2STX_CLK:I2S总线发送时钟

I/O

SCK1:SSP1串行时钟

O

MAT2[1]:Timer2的匹配输出通道1

 

P0[8]

 

160

I/O

P0[8]:GPIO口

I/O

I2STX_WS:I2S总线发送字选择

I/O

MISO1:SSP1主机输入从机输出

O

MAT2[2]:Timer2的匹配输出通道2

 

P0[9]

 

158

I/O

P0[9]:GPIO口

I/O

I2STX_SDA:I2S总线数据发送

I/O

MOSI1:SSP1主机输出从机输入

O

MAT2[3]:Timer2的匹配输出通道3

 

P0[10]

 

98

I/O

P0[10]:GPIO口

O

TXD2:UART2发送输出端

I/O

SDA2:I2C2数据输入/输出

O

MAT3[0]:Timer3的匹配输出通道0

 

P0[11]

 

100

I/O

P0[11]:GPIO口

I

RXD2:UART2接收输入端

I/O

SCL2:I2C2时钟输入/输出

O

MAT3[1]:Timer3的匹配输出通道1

 

P0[12]

 

41

I/O

P0[12]:GPIO口

O

USB_PPWR2:USB端口2端口电源使能

I/O

MISO1:SSP1主机输入从机输出

I

AD0[6]:A/D转换器0输入6

 

P0[13]

 

45

I/O

P0[13]:GPIO口

O

USB_UP_LED2:USB端口2LED

I/O

MOSI1:SSP1主机输出从机输入

I

AD0[7]:A/D转换器0输入7

 

P0[14]

 

69

I/O

P0[14]:GPIO口

O

USB_HSTEN2:USB端口2主机使能

O

USB_CONNECT2:USB端口2软件链接控制

I/O

SSEL1:SSP1从机选择

 

P0[15]

 

128

I/O

P0[15]:GPIO口

O

TXD1:UART1发送输出端

I/O

SCK0:SSP0串行时钟

I/O

SCK:SPI串行时钟

 

P0[16]

 

130

I/O

P0[16]:GPIO口

I

RXD1:UART1接收输入端

I/O

SSEL0:SSP0从机选择

I/O

SSEL:SPI从机选择

 

P0[17]

 

126

I/O

P0[17]:GPIO口

I

CTS1:UART1清除发送输入端

I/O

MISO0:SSP0主机输入从机输出

I/O

MISO:SPI主机输入从机输出

 

P0[18]

 

124

I/O

P0[18]:GPIO口

I

DCD1:UART1数据载波检测输入端

I/O

MOSI0:SSP0主机输出从机输入

I/O

MOSI:SPI主机输出从机输入

 

P0[19]

 

122

I/O

P0[19]:GPIO口

I

DSR1:UART1数据设置就绪端

O

MCICLK:SD/MMC接口时钟输出线

I/O

SDA1:I2C1数据输入/输出

 

P0[20]

 

120

I/O

P0[20]:GPIO口

O

DTR1:UART1数据终止就绪端

I/O

MCICMD:SD/MMC接口命令线

I/O

SCL1:I2C1时钟输入/输出

 

P0[21]

 

118

I/O

P0[21]:GPIO口

I

RI1:UART1铃响指示输入端

O

MCIPWR:SD/MMC电源供应使能

I

RD1:CAN1接收输入端

 

P0[22]

 

116

I/O

P0[22]:GPIO口

O

RTS1:UART1请求发送输出端

I/O

MCIDAT0:SD/MMC接口数据线0

O

TD1:CAN1发送输出端

 

P0[23]

 

18

I/O

P0[23]:GPIO口

I

AD0[0]:A/D转换器0输入0

I/O

I2SRX_CLK:I2S总线接收时钟

I

CAP3[0]:Timer3的捕获输入通道0

 

P0[24]

 

16

I/O

P0[24]:GPIO口

I

AD0[1]:A/D转换器0输入1

I/O

I2SRX_WS:I2S总线字选择

I

CAP3[1]:Timer3的捕获输入通道1

 

P0[25]

 

14

I/O

P0[25]:GPIO口

I

AD0[2]:A/D转换器0输入2

I/O

I2SRX_SDA:I2S总线数据接收

O

TXD3:UART3发送输出端

 

P0[26]

 

12

I/O

P0[26]:GPIO口

I

AD0[3]:A/D转换器0输入3

O

AOUT:D/A转换器输出

I

RXD3:UART3接收输入端

 

P0[27]

 

50

I/O

P0[27]:GPIO口

I/O

SDA0:I2C0数据输入/输出

 

P0[28]

 

48

I/O

P0[28]:GPIO口

I/O

SCL0:I2C0时钟输入/输出

 

P0[29]

 

61

I/O

P0[29]:GPIO口

I/O

USB_D+1:USB端口1双向D+线

 

P0[30]

 

62

I/O

P0[30]:GPIO口

I/O

USB_D-1:USB端口1双向D-线

 

P0[31]

 

51

I/O

P0[31]:GPIO口

I/O

USB_D+2:USB端口2双向D+线

2. P1口:  P1口也是一个32位的双向多功能I/O口,每位的方向可单独控制,且每位的功能取决于管脚链接模块的管脚功能选择。LPC2400的P1口管脚描述如表4.2所示。

4.2 LPC2400的P1口管脚描述

管脚名称

引脚号

类型

描  述

 

P1[0]

 

196

I/O

P1[0]:GPIO口

O

ENET_TXD0:以太网发送数据0(RMII/MII接口)

 

P1[1]

 

194

I/O

P1[1]:GPIO口

O

ENET_TXD1:以太网发送数据1(RMII/MII接口)

 

P1[2]

 

185

I/O

P1[2]:GPIO口

O

ENET_TXD2:以太网发送数据2(RMII/MII接口)

O

MCICLK:SD/MMC接口时钟输出线

O

PWM0[1]:脉宽调制器0输出1

 

P1[3]

 

177

I/O

P1[3]:GPIO口

O

ENET_TXD3:以太网发送数据3(RMII/MII接口)

O

MCICMD:SD/MMC接口命令线

O

PWM0[2]:脉宽调制器0输出2

 

P1[4]

 

192

I/O

P1[4]:GPIO口

O

ENET_TX_EN:以太网发送数据使能(RMII/MII接口)

 

P1[5]

 

156

I/O

P1[5]:GPIO口

O

ENET_TX_ER:以太网发送数据出错(MII接口)

O

MCIPWR:SD/MMC电源供应使能

O

PWM0[3]:脉宽调制器0输出3

 

P1[6]

 

171

I/O

P1[6]:GPIO口

I

ENET_TX_CLK:以太网发送时钟(MII接口)

I/O

MCIDAT0:SD/MMC接口数据线0

O

PWM0[4]:脉宽调制器0输出4

 

P1[7]

 

153

I/O

P1[7]:GPIO口

I

ENET_COL:以太网冲突检测(MII接口)

I/O

MCIDAT1:SD/MMC接口数据线1

O

PWM0[5]:脉宽调制器0输出5

 

P1[8]

 

190

I/O

P1[8]:GPIO口

I

ENET_CRS_DV/ENET_CRS:以太网载波检测/数据有效(RMII接口)/以太网载波检测(MII接口)

 

P1[9]

 

188

I/O

P1[9]:GPIO口

I

ENET_RXD0:以太网接收数据0(RMII/MII接口)

 

P1[10]

 

186

I/O

P1[10]:GPIO口

I

ENET_RXD1:以太网接收数据1(RMII/MII接口)

 

P1[11]

 

163

I/O

P1[11]:GPIO口

I

ENET_RXD2:以太网接收数据2(RMII/MII接口)

I/O

MCIDAT2:SD/MMC接口数据线2

O

PWM0[6]:脉宽调制器0输出6

 

P1[12]

 

157

I/O

P1[12]:GPIO口

I

ENET_RXD3:以太网接收数据3(RMII/MII接口)

I/O

MCIDAT3:SD/MMC接口数据线3

I

PCAP0[0]:脉宽调制器0捕获输入通道0

 

P1[13]

 

147

I/O

P1[13]:GPIO口

I

ENET_RX_DV:以太网接收数据有效(MII接口)

 

P1[14]

 

184

I/O

P1[14]:GPIO口

I

ENET_RX_ER:以太网接收错误(MII接口)

 

P1[15]

 

182

I/O

P1[15]:GPIO口

I

ENET_REF_CLK/ENET_RX_CLK:以太网参考时钟(RMII接口)/以太网接收时钟(MII接口)

 

P1[16]

 

180

I/O

P1[16]:GPIO口

I

ENET_MDC:以太网MIIM时钟

 

P1[17]

 

178

I/O

P1[17]:GPIO口

I/O

ENET_MDIO:以太网MI数据输入输出

 

P1[18]

 

66

I/O

P1[18]:GPIO口

O

USB_UP_LED1:USB端口1LED

O

PWM1[1]:脉宽调制器1输出1

I

CAP1[0]:Timer1捕获输入通道0

 

P1[19]

 

68

I/O

P1[19]:GPIO口

O

USB_TX_E1:USB端口1发送使能信号(OTG收发器)

O

USB_PPWR1:USB端口1端口电源使能信号

I

CAP1[1]:Timer1捕获输入通道1

 

P1[20]

 

70

I/O

P1[20]:GPIO口

O

USB_TX_DP1:USB端口1D+数据发送(OTG收发器)

O

PWM1[2]:脉宽调制器1输出2

I/O

SCK0:SSP0串行时钟

 

P1[21]

 

72

I/O

P1[21]:GPIO口

O

USB_TX_DM1:USB端口1D-数据发送(OTG收发器)

O

PWM1[3]:脉宽调制器1输出3

I/O

SSEL0:SSP0从机选择

 

P1[22]

 

74

I/O

P1[22]:GPIO口

I

USB_RCV1:USB端口1差分数据接收(OTG收发器)

I

USB_PWRD1:USB端口1电源状态(主机电源开关)

O

MAT1[0]:Timer1匹配输出通道0

 

P1[23]

 

76

I/O

P1[23]:GPIO口

I

USB_RX_DP1:USB端口1D+数据接收(OTG收发器)

O

PWM1[4]:脉宽调制器1输出4

I/O

MISO0:SSP0主机输入从机输出

 

P1[24]

 

78

I/O

P1[24]:GPIO口

I

USB_RX_DM1:USB端口1D-数据接收(OTG收发器)

O

PWM1[5]:脉宽调制器1输出5

I/O

MOSI0:SSP0主机输出从机输入

 

P1[25]

 

80

I/O

P1[25]:GPIO口

O

USB_LS1:USB端口1低速状态(OTG收发器)

O

USB_HSTEN1:USB端口1主机使能状态

O

MAT1[1]:Timer1匹配输出通道1

 

P1[26]

 

82

I/O

P1[26]:GPIO口

O

USB_SSPND1:USB端口1总线悬挂状态(OTG收发器)

O

PWM1[6]:脉宽调制器1输出6

I

CAP0[0]:Timer0捕获输入通道0

 

P1[27]

 

88

I/O

P1[27]:GPIO口

I

USB_INT1:USB端口1OTG ATX中断(OTG收发器)

I

USB_OVRCR1:USB端口1过流状态

I

CAP0[1]:Timer0捕获输入通道1

 

P1[28]

 

90

I/O

P1[28]:GPIO口

I/O

USB_SCL1:USB端口1I2C串行时钟(OTG收发器)

I

PCAP1[0]:脉宽调制器1捕获输入通道0

O

MAT0[0]:Timer0匹配输出通道0

 

P1[29]

 

92

I/O

P1[29]:GPIO口

I/O

USB_SDA1:USB端口1I2C串行数据(OTG收发器)

I

PCAP1[1]:脉宽调制器1捕获输入通道1

O

MAT0[1]:Timer0匹配输出通道1

 

P1[30]

 

42

I/O

P1[30]:GPIO口

I

USB_PWRD2:USB端口2电源状态

I

VBUS:指示USB总线当前电源。注意:当USB复位时这个信号必须为高电平

I

AD0[4]:A/D转换器0输入4

 

P1[31]

 

40

I/O

P1[31]:GPIO口

I

USB_OVRCR2:USB端口2过流状态

I/O

SCK1:SSP1串行时钟

I

AD0[5]:A/D转换器0输入5

3. P2口:  P2口也是一个32位的双向多功能I/O口,每位的方向可单独控制,且每位的功能取决于管脚链接模块的管脚功能选择。LPC2400的P2口管脚描述如表4.3所示。

4.3 LPC2400的P2口管脚描述

管脚名称

引脚号

类型

描  述

 

P2[0]

 

154

I/O

P2[0]:GPIO口

O

PWM1[1]:脉宽调制器1输出1

O

TXD1:UART1发送输出端

O

TRACECLK/LCDPWR:跟踪时钟/LCD面板电源使能

 

P2[1]

 

152

I/O

P2[1]:GPIO口

O

PWM1[2]:脉宽调制器1输出2

I

RXD1:UART1接收输入端

O

PIPESTAT0/LCDLE:流水线状态位0/LCD行结束信号

 

P2[2]

 

150

I/O

P2[2]:GPIO口

O

PWM1[3]:脉宽调制器1输出3

I

CTS1:UART1清除发送输入端

O

PIPESTAT1/LCDCP:流水线状态位1/LCD面板时钟

 

P2[3]

 

144

I/O

P2[3]:GPIO口

O

PWM1[4]:脉宽调制器1输出4

I

DCD1:UART1数据载波检测输入端

O

PIPESTAT2/LCDFP:流水线状态位2/LCD帧脉冲(STN)垂直同步脉冲(TFT)

 

P2[4]

 

142

I/O

P2[4]:GPIO口

O

PWM1[5]:脉宽调制器1输出5

I

DSR1:UART1数据设置就绪端

O

TRACESYNC/LCDAC:跟踪同步/LCD交流斜线驱动(STN)数据使能输出(TFT)

 

P2[5]

 

140

I/O

P2[5]:GPIO口

O

PWM1[6]:脉宽调制器1输出6

O

DTR1:UART1数据终止就绪端

O

TRACEPKT0/LCDAC:跟踪分组位0/LCD行同步脉冲(STN)水平同步脉冲(TFT)

 

P2[6]

 

138

I/O

P2[6]:GPIO口

I

PCAP1[0]:脉宽调制器1捕获输入通道0

I

RI1:UART1响铃指示输入端

O

TRACEPKT1/LCD[0]/LCD[4]:跟踪分组位1/LCD数据

 

P2[7]

 

136

I/O

P2[7]:GPIO口

I

RD2:CAN2接收输入

O

RTS1:UART1请求发送输出端

O

TRACEPKT2/LCD[1]/LCD[5]:跟踪分组位1/LCD数据

 

P2[8]

 

134

I/O

P2[8]:GPIO口

O

TD2:CAN2发送输出

O

TXD2:UART2接收输入端

O

TRACEPKT3/LCD[2]/LCD[6]:跟踪分组位3/LCD数据

 

P2[9]

 

132

I/O

P2[9]:GPIO口

O

USB_CONNECT1:USB1软链接控制

I

RXD2:UART2接收输入

I

EXTINT0/LCD[3]/LCD[7]:外部触发中断输入/LCD数据

 

P2[10]

 

110

I/O

P2[10]:GPIO口

I

EINT0:外部中断0输入

 

P2[11]

 

108

I/O

P2[11]:GPIO口

I/O

EINT1:外部中断1输入/LCDCLKIN:LCD时钟

I/O

MCIDAT1:SD/MMC接口数据线1

I/O

I2STX_CLK:I2S传输时钟。

 

P2[12]

 

106

I/O

P2[12]:GPIO口

I/O

EINT2:外部中断2输入/输出:LCD[4]/LCD[3]/LCD[8]/LCD[18]

I/O

MCIDAT2:SD/MMC接口数据线2

I/O

I2STX_WS:I2S传输字选择。

 

P2[13]

 

102

I/O

P2[13]:GPIO口

I/O

EINT3:外部中断3输入/输出:LCD[5]/LCD[9]/LCD[19]

I/O

MCIDAT3:SD/MMC接口数据线3

I/O

I2STX_SDA:I2S传输数据。

 

P2[14]

 

91

I/O

P2[14]:GPIO口

O

CS2:低电平有效片选信号2

I

CAP2[0]:Tmer2捕获输入通道0

I/O

SDA1:I2C1数据输入/输出

 

P2[15]

 

99

I/O

P2[15]:GPIO口

O

CS3:低电平有效片选信号3

I

CAP2[1]:Tmer2捕获输入通道1

I/O

SCL1:I2C1时钟输入/输出

 

P2[16]

 

87

I/O

P2[16]:GPIO口

O

CAS:低电平有效SDRAM列地址选择

 

P2[17]

 

95

I/O

P2[17]:GPIO口

O

RAS:低电平有效SDRAM行地址选择

 

P2[18]

 

59

I/O

P2[18]:GPIO口

O

CLKOUT0:SDRAM时钟0

 

P2[19]

 

67

I/O

P2[19]:GPIO口

O

CLKOUT1:SDRAM时钟1

 

P2[20]

 

73

I/O

P2[20]:GPIO口

O

DYCS0:SDRAM片选信号0

 

P2[21]

 

81

I/O

P2[21]:GPIO口

O

DYCS1:SDRAM片选信号1

 

P2[22]

 

85

I/O

P2[22]:GPIO口

O

DYCS2:SDRAM片选信号2

I

CAP3[0]:Timer3捕获输入通道0

I/O

SCK0:SSP0串行时钟

 

P2[23]

 

64

I/O

P2[23]:GPIO口

O

DYCS3:SDRAM片选信号3

I

CAP3[1]:Timer3捕获输入通道1

I/O

SSEL0:SSP0从机选择

 

P2[24]

 

53

I/O

P2[24]:GPIO口

O

CKEOUT0:SDRAM时钟使能信号0

 

P2[25]

 

54

I/O

P2[25]:GPIO口

O

CKEOUT1:SDRAM时钟使能信号1

 

P2[26]

 

57

I/O

P2[26]:GPIO口

O

CKEOUT2:SDRAM时钟使能信号2

O

MAT3[0]:Tmer3匹配输出通道0

I/O

MISO0:SSP0主机输入从机输出

 

P2[27]

 

47

I/O

P2[27]:GPIO口

O

CKEOUT3:SDRAM时钟使能信号3

O

MAT3[1]:Tmer3匹配输出通道1

I/O

MOSI0:SSP0主机输出从机输入

 

P2[28]

 

49

I/O

P2[28]:GPIO口

O

DQMOUT0:用于SDRAM和静态设备的数据掩码0

 

P2[29]

 

43

I/O

P2[29]:GPIO口

O

DQMOUT1:用于SDRAM和静态设备的数据掩码1

 

P2[30]

 

31

I/O

P2[30]:GPIO口

O

DQMOUT2:用于SDRAM和静态设备的数据掩码2

O

MAT3[2]:Tmer3匹配输出通道2

I/O

SDA2:I2C2数据输入/输出

 

P2[31]

 

39

I/O

P2[31]:GPIO口

O

DQMOUT3:用于SDRAM和静态设备的数据掩码3

O

MAT3[3]:Tmer3匹配输出通道3

I/O

SCL2:I2C2时钟输入/输出

4. P3口:  P3口也是一个32位的双向多功能I/O口,每位的方向可单独控制,且每位的功能取决于管脚链接模块的管脚功能选择。LPC2400的P3口管脚描述如表4.4所示。

4.4 LPC2400的P3口管脚描述

管脚名称

引脚号

类型

描  述

 

P3[0]

 

197

I/O

P3[0]:GPIO口

I/O

D0:外部存储器数据线0

 

P3[1]

 

201

I/O

P3[1]:GPIO口

I/O

D1:外部存储器数据线1

 

P3[2]

 

207

I/O

P3[2]:GPIO口

I/O

D2:外部存储器数据线2

 

P3[3]

 

3

I/O

P3[3]:GPIO口

I/O

D3:外部存储器数据线3

 

P3[4]

 

13

I/O

P3[4]:GPIO口

I/O

D4:外部存储器数据线4

 

P3[5]

 

17

I/O

P3[5]:GPIO口

I/O

D5:外部存储器数据线5

 

P3[6]

 

23

I/O

P3[6]:GPIO口

I/O

D6:外部存储器数据线6

 

P3[7]

 

27

I/O

P3[7]:GPIO口

I/O

D7:外部存储器数据线7

 

P3[8]

 

191

I/O

P3[8]:GPIO口

I/O

D8:外部存储器数据线8

 

P3[9]

 

199

I/O

P3[9]:GPIO口

I/O

D9:外部存储器数据线9

 

P3[10]

 

205

I/O

P3[10]:GPIO口

I/O

D10:外部存储器数据线10

 

P3[11]

 

208

I/O

P3[11]:GPIO口

I/O

D11:外部存储器数据线11

 

P3[12]

 

1

I/O

P3[12]:GPIO口

I/O

D12:外部存储器数据线12

 

P3[13]

 

7

I/O

P3[13]:GPIO口

I/O

D13:外部存储器数据线13

 

P3[14]

 

21

I/O

P3[14]:GPIO口

I/O

D14:外部存储器数据线14

 

P3[15]

 

28

I/O

P3[15]:GPIO口

I/O

D15:外部存储器数据线15

 

P3[16]

 

137

I/O

P3[16]:GPIO口

I/O

D16:外部存储器数据线16

O

PWM0[1]:脉宽调制器0输出1

O

TXD1:UART1发送输出端

 

P3[17]

 

143

I/O

P3[17]:GPIO口

I/O

D17:外部存储器数据线17

O

PWM0[2]:脉宽调制器0输出2

I

RXD1:UART1接收输入端

 

P3[18]

 

151

I/O

P3[18]:GPIO口

I/O

D18:外部存储器数据线18

O

PWM0[3]:脉宽调制器0输出3

I

CTS1:UART1清除发送输入端

 

P3[19]

 

161

I/O

P3[19]:GPIO口

I/O

D19:外部存储器数据线19

O

PWM0[4]:脉宽调制器0输出4

I

DCD1:UART1数据载波检测输入端

 

P3[20]

 

167

I/O

P3[20]:GPIO口

I/O

D20:外部存储器数据线20

O

PWM0[5]:脉宽调制器0输出5

I

DSR1:UART1数据设置就绪端

 

P3[21]

 

175

I/O

P3[21]:GPIO口

I/O

D21:外部存储器数据线21

O

PWM0[6]:脉宽调制器0输出6

O

DTR1:UART1数据终端准备就绪输出端

 

P3[22]

 

195

I/O

P3[22]:GPIO口

I/O

D22:外部存储器数据线22

I

PCAP0[0]:脉宽调制器0捕获输入通道0

I

RI1:UART1响铃指示输入端

 

P3[23]

 

65

I/O

P3[23]:GPIO口

I/O

D23:外部存储器数据线23

I

CAP0[0]:Timer0捕获输入通道0

I

PCAP1[0]:脉宽调制器1捕获输入通道0

 

P3[24]

 

58

I/O

P3[24]:GPIO口

I/O

D24:外部存储器数据线24

I

CAP0[1]:Timer0捕获输入通道1

O

PWM1[1]:脉宽调制器1输出1

 

P3[25]

 

56

I/O

P3[25]:GPIO口

I/O

D25:外部存储器数据线25

O

MAT0[0]:Tmer0匹配输出通道0

O

PWM1[2]:脉宽调制器1输出2

 

P3[26]

 

55

I/O

P3[26]:GPIO口

I/O

D26:外部存储器数据线26

O

MAT0[1]:Tmer0匹配输出通道1

O

PWM1[3]:脉宽调制器1输出3

 

P3[27]

 

203

I/O

P3[27]:GPIO口

I/O

D27:外部存储器数据线27

I

CAP1[0]:Timer1捕获输入通道0

O

PWM1[4]:脉宽调制器1输出4

 

P3[28]

 

5

I/O

P3[28]:GPIO口

I/O

D28:外部存储器数据线28

I

CAP1[1]:Timer1捕获输入通道1

O

PWM1[5]:脉宽调制器1输出5

 

P3[29]

 

11

I/O

P3[29]:GPIO口

I/O

D29:外部存储器数据线29

O

MAT1[0]:Tmer1匹配输出通道0

O

PWM1[6]:脉宽调制器1输出6

 

P3[30]

 

19

I/O

P3[30]:GPIO口

I/O

D30:外部存储器数据线30

O

MAT1[1]:Tmer1匹配输出通道1

O

RTS1:UART1请求发送输出端

 

P3[31]

 

25

I/O

P3[31]:GPIO口

I/O

D31:外部存储器数据线31

O

MAT1[2]:Tmer1匹配输出通道2

5. P4口:  P4口也是一个32位的双向多功能I/O口,每位的方向可单独控制,且每位的功能取决于管脚链接模块的管脚功能选择。LPC2400的P4口管脚描述如表4.5所示。

4.5 LPC2400的P4口管脚描述

管脚名称

引脚号

类型

描  述

 

P4[0]

 

75

I/O

P4[0]:GPIO口

I/O

A0:外部存储器地址线0

 

P4[1]

 

79

I/O

P4[1]:GPIO口

I/O

A1:外部存储器地址线1

 

P4[2]

 

83

I/O

P4[2]:GPIO口

I/O

A2:外部存储器地址线2

 

P4[3]

 

97

I/O

P4[3]:GPIO口

I/O

A3:外部存储器地址线3

 

P4[4]

 

103

I/O

P4[4]:GPIO口

I/O

A4:外部存储器地址线4

 

P4[5]

 

107

I/O

P4[5]:GPIO口

I/O

A5:外部存储器地址线5

 

P4[6]

 

113

I/O

P4[6]:GPIO口

I/O

A6:外部存储器地址线6

 

P4[7]

 

121

I/O

P4[7]:GPIO口

I/O

A7:外部存储器地址线7

 

P4[8]

 

1271

I/O

P4[8]:GPIO口

I/O

A8:外部存储器地址线8

 

P4[9]

 

131

I/O

P4[9]:GPIO口

I/O

A9:外部存储器地址线9

 

P4[10]

 

135

I/O

P4[10]:GPIO口

I/O

A10:外部存储器地址线10

 

P4[11]

 

145

I/O

P4[11]:GPIO口

I/O

A11:外部存储器地址线11

 

P4[12]

 

149

I/O

P4[12]:GPIO口

I/O

A12:外部存储器地址线12

 

P4[13]

 

155

I/O

P4[13]:GPIO口

I/O

A13:外部存储器地址线13

 

P4[14]

 

159

I/O

P4[14]:GPIO口

I/O

A14:外部存储器地址线14

 

P4[15]

 

173

I/O

P4[15]:GPIO口

I/O

A15:外部存储器地址线15

 

P4[16]

 

101

I/O

P4[16]:GPIO口

I/O

A16:外部存储器地址线16

 

P4[17]

 

104

I/O

P4[17]:GPIO口

I/O

A17:外部存储器地址线17

 

P4[18]

 

105

I/O

P4[18]:GPIO口

I/O

A18:外部存储器地址线18

 

P4[19]

 

111

I/O

P4[19]:GPIO口

I/O

A19:外部存储器地址线19

 

P4[20]

 

109

I/O

P4[20]:GPIO口

I/O

A20:外部存储器地址线20

I/O

SDA2:I2C2数据输入/输出

I/O

SCK1:SSP1串行时钟

 

P4[21]

 

115

I/O

P4[21]:GPIO口

I/O

A21:外部存储器地址线21

I/O

SCL2:I2C2时钟输入/输出

I/O

SSEL1:SSP1从机选择

 

P4[22]

 

123

I/O

P4[22]:GPIO口

I/O

A22:外部存储器地址线22

O

TXD2:UART2发送输出端

I/O

MISO1:SSP1主机输入从机输出

 

P4[23]

 

129

I/O

P4[23]:GPIO口

I/O

A23:外部存储器地址线23

I

RXD2:UART2接收输入端

I/O

MOSI1:SSP1主机输出从机输入

 

P4[24]

 

183

I/O

P4[24]:GPIO口

O

OE:低电平有效输出使能信号

 

P4[25]

 

179

I/O

P4[25]:GPIO口

O

WE:低电平有效写使能信号

 

P4[26]

 

119

I/O

P4[26]:GPIO口

O

BLS0:低电平有效字节定位选择信号0

 

P4[27]

 

139

I/O

P4[27]:GPIO口

O

BLS1:低电平有效字节定位选择信号1

 

P4[28]

 

170

I/O

P4[28]:GPIO口

O

BLS2:低电平有效字节定位选择信号2

O

MAT2[0]/LCD[6]/LCD[10]/LCD[2]:Timer2匹配输出通道0/LCD数据

O

TXD3:UART3发送输出端

 

P4[29]

 

176

I/O

P4[29]:GPIO口

O

BLS3:低电平有效字节定位选择信号3

O

MAT2[1]/LCD[7]/LCD[11]/LCD[3]:Timer2匹配输出通道1/LCD数据

I

RXD3:UART3接收输入端

 

P4[30]

 

187

I/O

P4[30]:GPIO口

O

CS0:低电平有效片选信号0

 

P4[31]

 

193

I/O

P4[31]:GPIO口

O

CS1:低电平有效片选信号1

6. 电源、复位、晶振及其它管脚的描述如表4.6所示。

4.6 LPC2400的其它管脚描述

管脚名称

引脚号

类型

描  述

ALARM

37

O

RTC实时时钟控制输出。这是一个1.8V引脚,当RTC产生报警信号时此引脚变为高电平。

USB_D-2

52

I/O

USB端口2双向D-线

DBGEN

9

I

JTAG接口控制信号,也用于边界扫描

TDO

2

O

JTAG接口测试数据输出

TDI

4

I

JTAG接口测试数据输入

TMS

6

I

JTAG接口测试模式选择

TRST

8

I

JTAG接口测试复位,低电平有效

TCK

10

I

JTAG接口测试时钟

RTCK

206

I/O

JTAG接口控制信号,当此引脚低电平时使能ETM引脚(P2[9:0]),用于复位后操做跟踪端口

RSTOUT

29

O

这是个1.8V引脚,当此引脚低电平时表示LPC2478处于复位状态

RESET

35

I

外部复位输入,低电平有效。该引脚具备迟滞做用的TTL电平,能承受5V电压,当此引脚低电平时器件复位,I/O口和外围功能进入默认状态,处理器从地址0开始执行程序

XTAL1

44

I

振荡器电路和内部时钟发生电路输入

XTAL2

46

O

振荡放大器输出

RTCX1

34

I

RTC振荡器电路输入

RTCX2

36

O

RTC振荡器电路输出

VSSIO

33,63,77,93,114,133,148,169,189,200

I

地:数字IO脚的0V电压参考点

VSSCORE

32,84,172

I

地:处理器内核的0V电压参考点

VSSA

22

I

模拟地:0V电压参考点,与VSS电压相同,为了下降噪声和出错概率,二者应当隔离

VDD(3V3)

15,60,71,89,112,125,146,165,181,198

I

3.3V供应电压:I/O口电源供应电压

NC

30,117,141

I

未链接引脚

VDD(DCDC)(3V3)

26,86,174

I

3.3V直流到直流转换供应电压:为片内DC-to-DC转换器提供电源

VDDA

20

I

模拟3.3V供应电压:为DAC和ADC供电,与VDD(3V3)电压相同,为了下降噪声和出错概率,二者应当隔离

VREF

24

I

ADC参考电压:与VDD(3V3)电压相同,为了下降噪声和出错概率,二者应当隔离,为ADC和DAC提供参考电压

VBAT

38

I

RTC电源供应:3.3V,为RTC提供电源

注:1. 本引脚定义表以LPC2478为准,LPC2470与此相同,LPC2468没有引脚定义的LCD部分。

2. 类型表示引脚信号方向:I/O为输入/输出,I为输入,O为输出。

4.2.2  引脚链接模块

从表4.1~表4.6能够看到,LPC2400系列芯片的绝大部分引脚是复用的,每根引脚都有可能用于不一样的外设功能。引脚具体用于什么外设功能是由引脚链接模块进行配置来实现的。当引脚选择了一个功能时,则其它功能无效。

在使用外设时,应当在激活外设以及使能任何相关的中断以前,将外设链接到相应的引脚上。不然,即便使用引脚链接模块激活外设,此激活也是无效的。

引脚链接模块共有21个寄存器,包括11个引脚功能选择寄存器和10个引脚模式寄存器。

1. 引脚功能选择寄存器(PINSEL0~PINSEL10)

引脚功能选择寄存器用于控制每一个引脚的功能,每一个寄存器32位,每2个bit用于控制1个引脚功能选择。以PINSEL0寄存器为例,寄存器的[1:0]位用于控制P0[0]引脚,[3:2]位用于控制P0[1]引脚,[31:30]位用于控制P0[15]引脚。而PINSEL1寄存器的[1:0]位用于控制P0[16]引脚,[3:2]位用于控制P0[17]引脚,[31:30]位用于控制P0[31]引脚。其他依次类推。

PINSEL0~PINSEL9寄存器,每两个寄存器用于一个端口组:PINSEL0寄存器用于P0口的[15:0]引脚,PINSEL1寄存器用于P0口的[31:30]引脚;PINSEL2寄存器用于P1口的[15:0]引脚,PINSEL3寄存器用于P1口的[31:30]引脚;PINSEL4寄存器用于P2口的[15:0]引脚,PINSEL5寄存器用于P2口的[31:30]引脚;PINSEL6寄存器用于P3口的[15:0]引脚,PINSEL7寄存器用于P3口的[31:30]引脚;PINSEL8寄存器用于P4口的[15:0]引脚,PINSEL9寄存器用于P4口的[31:30]引脚。

每一对比特设置引脚功能的定义如表4.7所示。

4.7 引脚功能选择寄存器位

PINSEL0~PINSEL9值

功能

复位值

00

主功能(缺省),通常为GPIO口

00

01

第一备用功能

10

第二备用功能

11

第三备用功能

每一个引脚默认为GPIO口,经过设置PINSEL的值来定义其引脚功能。以P0[0]脚为例,当PINSEL0寄存器的[1:0]位为00时,引脚功能为GPIO口;为01时,引脚功能为CAN1接收器输入;为10时,引脚功能为UART3发送输出端;为11时,引脚功能为I2C1数据输入/输出。

每一个引脚的具体定义方法参见表4.1~表4.6。表格中的引脚功能按PINSEL值排列。某些引脚只有两种功能,此时只使用PINSEL值00和01,值10和11保留。

PINSEL10寄存器用于控制ETM接口引脚。该寄存器只使用了位3,其他位均保留。当第3位为0时,关闭ETM接口功能;为1时启用ETM跟踪接口功能,此时不管PINSEL4怎么定义,P2[0]~P2[8]脚均用于ETM跟踪功能。

引脚功能被选择为GPIO时,引脚的方向控制由GPIO方向寄存器IODIR控制。对于其它功能,引脚的方向是由引脚功能控制的。

2. 引脚模式寄存器(PINMODE0~PINMODE9)

引脚模式寄存器PINMODE为全部的GPIO端口控制片内上拉/下拉电阻特性。当使用片内上拉或下接电阻时,若引脚信号不肯定,使用上拉时为高电平;而下拉时拉为低电平。

PNSEL寄存器同样,PINMODE寄存器每2个bit控制1个引脚。每两个寄存器控制一个端口组。

PINMOD寄存器取值如表4.8所示。

4.8 引脚模式寄存器位

PINMODE0~PINMODE9值

功能

复位值

00

使能引脚片内上拉电阻

00

01

保留

10

既不使用上拉也不使用下拉

11

使能引脚片内下拉电阻

引脚链接模块的寄存器总表如表4.9所示。

4.9 引脚控制模块寄存器列表

寄存器名

描述

访问

复位值

地址

PINSEL0

引脚功能选择寄存器0

读/写

0x0000 0000

0xE002 C000

PINSEL1

引脚功能选择寄存器1

读/写

0x0000 0000

0xE002 C004

PINSEL2

引脚功能选择寄存器2

读/写

0x0000 0000

0xE002 C008

PINSEL3

引脚功能选择寄