精华内容
下载资源
问答
  • 计算机指令系统

    千次阅读 多人点赞 2020-05-27 12:01:48
    计算机指令系统性的发展,指令系统的性能要求,指令格式,操作数类型,指令和数据的寻址方式。

    指令系统的发展和性能要求

    1.1指令系统的发展

    程序一一用于解决实际问题的一系列的指令;
    指令一一使计算机执行某种操作的命令
    从组成的层次结构来说,计算机的指令可分为如下3类:

    • 微指令:微程序级的命令,它属于硬件;
    • 机器指令(指令):可完成一个独立的算术或逻辑运算;
    • 宏指令:由若干条机器指令组成的软件指令,它属于软件

    指令系统: 一台计算机中所有机器指令的集合,指令系统的格式和功能直接影响机器的硬件结构、软件系统、以及机器的适用范围。

    计算机指令系统的发展过程:
    ● 50年代:只有定点加减、逻辑运算、数据传送、转移等十几至几十条指令。
    ● 60年代后期:增加了乘除运算、浮点运算、十进制运算、字符串处理等指令,指令数目多达一二百条,寻址方式也趋多样化,出现了系列计算机
    ● 70年代末期:复杂指令系统计算机(CISL)、精简指令系统计算机(RSC),早期的X86处理器(486之前)都是CISL指令系统,奔腾系列CPU使用了RSC和CC构架相结合的办法;

    系列计算机:
    基本指令系统、基本体系结构相同的一系列计算机,不过具体的器件、结构和性能都不会完全相同,一般新机种在各方面要优于旧机种。一个系列往往有多种型号,各型号计算机的指令系统是向下兼容的,新机种的指令系统包含旧机种的全部指令,如 Pentiu系列PC机。

    CISC (complex instruction set computer) 采用复杂的的指令系统,来达到增强计算机的功能、提高机器速度的目的
    CISC指令系统的特点:
    1.指令系统复杂庞大,指令数目多
    2.指令格式多,字长不固定,多种寻址方式;
    3.可访存指令不受限制;
    4.各种指令的执行时间相差很大;
    5.大都采用微程序控制器;

    RISC (Reduced instruction set computer) 从简化指令系统和优化硬件设计的角度来提高系统的性能与速度。
    RISC指令系统的主要特点:
    1.选取使用频率高的简单指令;
    2.指令长度固定,指令格式少,寻址方式种类少
    3.采用流水线技术
    4.使用较多的通用寄存器,减少访存;
    5.控制器以组合逻辑控制为主;
    6.采用优化编译技术;

    1.2 指令系统性能的要求
    指令系统的性能决定了计算机的基本功能,它的设计直接关系到计算机的硬件结构和用户的需要。
    一个完善的指令系统应满足如下四方面的要求:
    ①.完备性常用指令齐全,编程方便;
    ②.有效性程序占用内存少,运行速度快;
    ③.规整性指令和数据的使用规则统一,易学易记;
    ④.兼容性:同一系列的低档计算机的程序能够在新的高档计算机上运行;

    指令系统的规整性要求: 规整性包括对称性、匀齐性、指令格式和数据格式的一致性三方面的要求。
    1.对称性:所有的指令都可使用各种寻址方式
    2.匀齐性:一种操作性质的指令可以支持各种数据类型
    3.指令格式和数据格式的一致性:指令长度和数据长度有一定的关系,以方便处理和存取

    1.3 低级语言与硬件结构的关系
    ● 低级语言: 机器语言、汇编语言,是一种面向机器的语言,和具体机器的指令系统密切相关。
    ● 高级语言与低级语言的比较如表所示:

    比较内容 高级语言 低级语言
    1 对机器独立的程度 独立 不独立
    2 编制程序的难易程度
    3 编制程序所需的时间 较长
    4 程序执行时间 较长
    5 编译过程对计算机资源的要求
    对程序员的训练要求 高级语言 低级语言
    通用算法 需要 需要
    语言规则 了解 较多了解
    硬件知识 不需要 需要

    指令格式

    指令的一般格式:
    指令字(简称指令):表示一条指令的机器字。
    指令格式:指令字用二进制代码表示的结构形式,由操作码字段和地址码字段组成。
    在这里插入图片描述
    操作码字段: 表征指令的操作特性与功能
    地址码字段: 通常指定参与操作的操作数的地址。

    2.1 操作码
    操作码字段的位数取决于指令系统的规模;
    操作码的类型:

    • 固定长度的操作码:
      操作码字段为4位,则指令系统中的指令数目为24=16条。
      ◆特征:所有指令长度均相同。
      ◆优点:控制简单,速度快,适用于指令条数不多的场合
    • 可变长度的操作码
      ◆特征:利用操作码扩展技术将操作码扩展到地址码字段,使各类指令的操作码长度不相同;
      ◆优点:充分利用软硬件资源,适用于大规模的指令系统。

    2.2 地址码
    一条指令格式中有几个地址码字段,就称为是几地址指令;

    • 零地址指令:
      在这里插入图片描述
      ①无任何操作数运算。(如NOP、HALT等指令)。
      ②单操作数运算:隐含一个操作数,如Acc。(如CBW指令)
      OP (Acc) → Acc

    • 一地址指令
      在这里插入图片描述
      ①单操作数运算:OP (A1) → A1(如INC指令)
      ②双操作数运算:隐含一个操作数,如Acc
      A(cc) OP (A1)→Acc/A1 (如MUL指令)

    • 两地址指令
      在这里插入图片描述
      功能:(A1) OP (A2) → A1 (如ADD、XOR等指令)

    • 三地址指令
      在这里插入图片描述
      功能:(A1) OP (A2) → A3

    • 多地址指令(如四地址)
      这类指令功能强,一般用高档小型机或中大型机,用于实现成批数据处理,字符串处理、向量或矩阵运算指令等

    两地址指令的分类:
    在这里插入图片描述

    • 根据操作数的物理位置分:
      存储器-存储器(SS)型指令
      A1、A2均为存储单元;
      这类指令的操作时都涉及到内存单元,参与操作的数都放在内存内。
      寄存器-寄存器(RR)型指令
      A1、A2均为寄存器;
      这类指令执行过程中,需要多个通用寄存器或个别专用寄存器,从寄存器中取操作数,把操作数结果存放到另一个寄存器中,执行时不需要访问内存。
      寄存器-存储器(RS)型指令
      A1、A2中一个为寄存器,一个为存储单元;
      执行此类指令时,既要访问内存单元,又要访问寄存器。

    • 指令的操作码扩展技术
      一个指令系统中,若操作码长度固定,且指令格式不同
      指令格式如图:
      在这里插入图片描述
      操作码字段长度取决于指令系统中的指令总数目,地址码较少的指令,编码浪费。

      操作码扩展
      对于不需要某个地址码的指令,把它们的操作码扩充到该地址字段;既充分利用指令字的各字段,又在不增加指令长度的情况下扩展操作码的长度;
      举例:设某指令长16位,包括4位基本操作码字段和3个4位地址码字段。
      在这里插入图片描述
      ① 若全是三地址指令,则最多能有多少条指令?
      操作码为4位的,则指令条数为2<sup>4</sup>=16。

      ② 若三地址指令需15条,两地址指令需15条,单地址指令需15条零地址指令需16条应如何安排?
      可使用操作码扩展技术,缩短固定操作码长度
      在这里插入图片描述
      ① 为了缩短指令的平均长度,应用频率比较高的指令应该分配较短的操作码。
      ② 确保指令码的唯一性。

    在这里插入图片描述
    在这里插入图片描述

    2.3 指令字长度

    • 机器字长
      运算器一次能处理的二进制数的位数。机器指令的长度直接决定着CPU运算的精度直接寻址能力的大小
    • 指令字长
      一个指令字中包含二进制代码的位数;
      指令字长由操作码长度操作数长度个数共同决定。
      ● 指令有半字长单字长双字长多字长等不同的长度类型。
      ● 指令系统可分为等长指令字结构变长指令字结构两种。

    2.4 指令助记符

    • 指令助记符:使用3~4个英文缩写字母来表示的指令操作码
    • 在不同的计算机中,指令助记符的规定是不一样的,指令助记符只是指令操作码字段的一种表示方法;机器内部保存的还是二进制代码形式的机器指令;
      由汇编或编译程序,将助记符翻译成机器代码。
      在这里插入图片描述
      在这里插入图片描述
      指令举例:
      在这里插入图片描述

    操作数类型

    机器指令对数据进行操作,数据通常分为以下四类:

    • 地址数据无符号整数,通过某种运算确定操作数在主存中的有效地址;
    • 数值数据定点整数、小数;浮点数;压缩十进制数
    • 字符数据文本数据或字符串;
    • 逻辑数据由若干二进制位组成,每位的值可以是1或0。

    指令和数据的寻址方式

    4.1指令的寻址方式

    • 1.顺序寻址方式
      当程序执行的流向不发生变化时,指令的寻址方式;由程序计数器记录所要执行指令的地址;一般在每次取指之后,其值加本条指令所占存储单元数。

    • 2.跳跃寻址方式
      当程序转移执行时的指令寻址方式,程序计数器的内容由本条指令给出,而不是顺序改变。

      • 直接寻址方式:指令中给出要转向的有效地址
      • 相对寻址方式:指令中给出要转向单元与当前单元的偏移量
      • 间接寻址方式:指令中给出保存要转向地址的寄存器或存储单元
        在这里插入图片描述

    4.2 操作数的寻址方式
    一种单地址码指令的结构如下图:
    在这里插入图片描述

    • 将指令中的形式地址A变换成操作数有效地址的过程,称为寻址过程。
    • 典型而常用的寻址方式有:隐含寻址、立即寻址、直接寻址、间接寻址、寄存器寻址、寄存器间接寻址、偏移寻址、堆栈寻址。
    隐含寻址 立即寻址
    在这里插入图片描述 在这里插入图片描述
    直接寻址 间接寻址
    在这里插入图片描述 在这里插入图片描述
    寄存器寻址 寄存器间接寻址
    在这里插入图片描述 在这里插入图片描述
    偏移寻址 相对寻址
    在这里插入图片描述 在这里插入图片描述
    变址寻址 基址寻址
    在这里插入图片描述 在这里插入图片描述
    堆栈寻址
    在这里插入图片描述
    • 隐含寻址
      ● 操作数地址隐含在操作码中;
      ● 如8086的MUL指令,被乘数隐含在AX(16位)或AL(8位)中
      ●指令字中少了一个地址字段,可缩短指令字长;

    • 立即寻址
      ● 形式地址A就是操作数;
      ● 优点:指令执行阶段不需要访存,速度快
      ● 缺点:形式地址A字段的位数限制了立即数的范围

    • 直接寻址
      ● 有效地址由形式地址字段A直接给出;
      ● EA=A
      ● 特点:执行阶段访问一次存储器,A的位数决定了该指令操作数的寻址范围;操作数的地址不易修改(必须修改A)

    • 间接寻址
      ● 有效地址由形式地址字段A间接提供,
      ● EA=(A)
      ● 特点:可扩大寻址范围;A字段的长度受指令字长和指令格式的限制;寻址时,可根据需要进行多次间址;可用寻址特制字段区分直接寻址和间接寻址方式

    • 寄存器寻址
      ● 形式地址字段A为寄存器编号
      ● EA=Ri
      ● 特点:执行阶段不访存,只访问寄存器,执行速度快,寄存器个数有限,可缩短指令字长

    • 寄存器间接寻址
      ● 形式地址字段A用于指出存放有效地址的寄存器编号;
      ● OEA=(Ri)
      ● 特点:执行阶段访存;○便于编制循环程序

    • 偏移寻址
      ● 直接寻址和寄存器间接寻址方式的结合
      ● 有效地址EA=A+® A是显式的形式地址字段;OR可以是显式的,也可以隐含的,某个专用的寄存器;
      ● 常用的偏移寻址
      ○ 变址寻址:EA=(变址R)+A,变址R+1变址R
      ○ 基址寻址:EA=(基址R)+A,A+1→A
      ○ 相对寻址:EA=(专用R)+A

    • 变址寻址方式
      ● 形式地址A作为基准地址,
      ● 变址寄存器作为可修改量;变址寄存器可自动增减量
      ● 适用于数组、字符串等成批连续数据的处理;
      ● 变址寄存器:可用通用寄存器充当,一般包含多个,在指令中要用一个字段指明当前所用的变址寄存器;

    • 基址寻址方式
      ● 基址寄存器作为基准地址,形式地址A作为可修改量;
      ● 形式地址相当于位移量,可正可负;一般基址寄存器为专用寄存器
      ● 基址寻址原来用于大型机,用作将用户地址转换成物理地址;可以实现地址的重定位,和扩大直接寻址空间
      ● 用途:
      ○ 大型机中,一般用特权指令来管理;
      ○ 小、微型机中,一般与变址寻址联合使用

    • 相对寻址方式
      ● 寻址特征:是基址寻址的一种变通
      ○ 程序计数器PC提供基准地址;
      ○ 形式地址作为位移量D,专用R可正可负;OEA:(PC )+D:
      ●适用于:所要寻找的操作数与现行指令位置间隔固定的场合

    • 堆栈寻址方式
      ● 隐含寻址方式的一种变形,其隐含的操作数在堆栈段中,由栈顶指针指定
      ● 8086堆栈指令举例
      ○ 入栈指令 PUSH SRC
      SP-2→SP;SRC→[SP]
      ○ 出栈指令 POP DST
      [SP]→DST;SP+2→SP

    例题在这里插入图片描述

    例题:
    在这里插入图片描述

    例题:
    设某机字长16位,直接寻址空间为128字,变址时的位移量为-64~+63,16个通用寄存器都可以作为变址寄存器,请设计一套指令系统,满足下列寻址类型的要求:
    (1)直接寻址的二地址指令3条
    (2)变址寻址的一地址指令6条
    (3)寄存器寻址的二地址指令8条;
    (4)直接寻址的一地址指令12条;
    (5)零地址指令32条。
    ● 直接寻址的二地址指令3条
    在这里插入图片描述
    ○这3条指令的操作码为00、01、10;
    ● 变址寻址的一地址指令6条:
    在这里插入图片描述
    ○这6条指令的操作码为:11000~11101
    ● 寄存器寻址的二地址指令8条:
    在这里插入图片描述
    这8条指令的操作码为11110000~11110111直接寻址的一地址指令12条:

    这12条指令的操作码为:111110000~111111011
    ● 零地址指令32条:
    在这里插入图片描述
    这32条指令的操作码为:
    111111000000000~11111110000111

    例题:
    某计算机数据线和地址线均是8根,有一条相对寻址的无条件转移指令存于内存的20H单元中,指令给出的偏移量是15H,设该指令占用2个字节,请计算:
    (1)取该条指令时PC的内容。
    (2)该指令执行结束时Pc的内容。
    解答:
    (1)取指令时,PC的内容为20H
    (2)转移地址=PC+2+D=20H+2+15H=37H
    该条指令执行结束时PC的内容是37H。

    例题:
    某指令系统指令字长为20位,具有双操作数、单操作数和无操作数3种指令格式,每个操作数地址规定用6位表示,当双操作数指令条数取最大值,而且单操作数指令条数也取最大值时,这3种指令最多可能拥有的指令数各是多少?
    解:按操作码扩展技术来设计,双操作数指令最多28-1条,单操作数指令最多63条,因此无操作数指令条数的最大值为64条
    在这里插入图片描述

    例题
    某机器字长为16位,主存容量是64K字,有专用的变址寄存器,采用单字长单地址指令,共有54条指令。试采用直接、立即、变址、相对四种寻址方式设计指令格式。解答
    在这里插入图片描述
    ○54条指令,故操作码需要6位。因为四种寻址方式,所以寻址特征位取2位,余下的8位作为形式地址D。其指令格式为
    O寻址模式X定义如下:
    X=00直接寻址有效地址E=D(256个单元)
    X=01立即寻址D=操作数
    X=10变址寻址有效地址E=®+D(64K)
    X=11相对寻址有效地址E=(PC)+D(64K)其中R为变址寄存器(16位)、PC为程序计数器(16位)相对寻址和变址寻址中,D可正可负。

    展开全文
  • ARM指令系统

    万次阅读 2017-08-19 22:22:24
    ARM指令系统 3.1 ARM处理器的指令格式 3.1.1 ARM指令集的特点 第3章 ARM指令系统 第3章 ARM指令系统 3.1 ARM处理器的指令格式 3.1.1 ARM指令集的特点 ARM内核属于RISC结构,所以其指令集有着一些独特的...

    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

    条件码

    类别码

    操作码

    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种类型:

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

    寻址格式:

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

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

    如:

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

    2、LSR逻辑右移

    寻址格式:

    通用寄存器,LSR 操作数      

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

    如:

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

    3、ASR算术右移

    寻址格式:

    通用寄存器,ASR 操作数      

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

    如:

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

    4、ROR循环右移

    寻址格式:

    通用寄存器,ROR 操作数      

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

    如:

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

    5、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处理器支持加载/存储指令用于在寄存器和存储器之间传送数据,加载指令用于将存储器中的数据传送到寄存器,存储指令则完成相反的操作。常用的加载存储指令如下:

    1、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

    2、STR指令

    STR指令的格式为:

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

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

    如:

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

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

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

    3、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)。

    4、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中相应的条件标志位。

    1、 MOV指令

    MOV指令的格式为:

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

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

    如:

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

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

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

    2、 MVN指令

    MVN指令的格式为:

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

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

    如:

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

    3、 CMP指令

    CMP指令的格式为:

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

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

    如:

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

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

     

    4、 CMN指令

    CMN指令的格式为:

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

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

    如:

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

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

    5、 TST指令

    TST指令的格式为:

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

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

    如:

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

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

    6、 TEQ指令

    TEQ指令的格式为:

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

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

    如:

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

    7、 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)

    8、 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      加第四个字,带进位

    9、 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)

    10、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

    12、RSC指令

    RSC指令的格式为:

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

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

    如:

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

    13、AND指令

    AND指令的格式为:

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

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

    如:

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

    14、ORR指令

    ORR指令的格式为:

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

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

    如:

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

    15、EOR指令

    EOR指令的格式为:

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

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

    如:

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

    16、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必须是不同的寄存器。 

    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中的相关条件标志位

    2、 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中的相关条件标志位

    3、 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

    4、 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

    5、 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

    6、 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的地址空间的跳转。

    1、 B指令

    B指令的格式为:

    B{条件} 目标地址

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

    如:

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

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

    BEQ Label

    2、 BL指令

    BL指令的格式为:

    BL{条件}  目标地址

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

    如:

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

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

    3、 BLX指令

    BLX指令的格式为:

    BLX  目标地址

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

    4、 BX指令

    BX指令的格式为:

    BX{条件}  目标地址

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

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

    ARM指令不允许直接操作程序状态寄存器CPSRSPSR。可以通过程序状态寄存器访问指令,在程序状态寄存器和通用寄存器之间传送数据,然后在通用寄存器中进行处理。

    1、 MRS指令

    MRS指令的格式为:

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

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

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

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

    如:

    MRS R0CPSR ;传送CPSR的内容到R0

    MRS R0SPSR ;传送SPSR的内容到R0

    2、 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协处理器的寄存器和存储器之间传送数据。

    1、CDP指令

    CDP指令的格式为:

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

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

    如:

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

    2、LDC指令

    LDC指令的格式为:

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

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

    如:

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

    3、STC指令

    STC指令的格式为:

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

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

    如:

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

    4、MCR指令

    MCR指令的格式为:

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

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

    如:

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

    5、MRC指令

    MRC指令的格式为:

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

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

    如:

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

    3.3.7  异常中断指令

    1、SWI指令

    SWI指令的格式为:

    SWI{条件} 24位的立即数

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

    如:

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

    2、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指令所取代。

    1、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

    2、ADR-小范围地址读取

    ADR伪指令的格式为:

    ADR{条件} reg,expr

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

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

    如:

    Start: MOV R0#10

    ADR R4start ;相当于SUB R4PC#0x0c

    3、ADRL-中范围地址读取

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

    4、NOP-空操作

    3.5.2  数据定义伪指令

    1、DCB和DC8

    该伪指令的格式为:

    标号 DCB或DC8 表达式

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

    如:

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

    2、DCW和DC16、DCD和DC32

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

    3、DF32和DF64

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

    4、DS8、DS16、DS24和DS32

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

    如:

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

    3.5.3  符号定义伪指令

    1、=、ALIAS和EQU

    该伪指令的格式为:

    标号 = 表达式

    标号 ALIAS 表达式

    标号 EQU 表达式

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

    如:

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

    2、ASSIGN、SET、SETA和VAR

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

    3、DEFINE

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

    4、LIMIT

    该伪指令的格式为:

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

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

    如:

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

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

    5、EXTERN(或IMPORT)

    该伪指令的格式为:

    EXTERN 符号,[符号]……

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

    如:

    Name Start ;程序模块Start

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

    ……

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

    END

    6、PUBLIC(或EXPORT)

    该伪指令的格式为:

    PUBLIC 符号,[符号]……

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

    7、REQUIRE

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

    3.5.4  段定义伪指令

    1、ASEG和ASEGN

    该伪指令的格式为:

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

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

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

    如:

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

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

    2、RSEG

    该伪指令的格式为:

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

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

    如:

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

    3、DATA

    该伪指令的格式为:

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

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

    如:

    RSEG CODECODEROOT(2)

    DATA

    f1:    DC32 subrtn

    4、STACK

    该伪指令的格式为:

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

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

    5、COMMON

    该伪指令的格式为:

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

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

    6、CODE16和CODE32

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

    7、ORG

    该伪指令的格式为:

    ORG 地址表达式

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

    8、ALIGNRAM和ALIGNROM

    该伪指令的格式为:

    ALIGNRAM 对齐

    ALIGNROM 对齐[,填充值]

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

    9、EVEN和ODD

    该伪指令的格式为:

    EVEN [填充值]

    ODD [填充值]

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

    3.5.5  模块控制伪指令

    1、NAME和PROGRAM

    该伪指令的格式为:

    NAME 模块名

    PROGRAM 模块名

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

    如:

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

    2、END和ENDMOD

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

    3、LIBRARY和MODULE

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

    4、RTMODEL

    该伪指令的格式为:

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

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

    3.5.6  汇编控制伪指令

    1、$和INCLUDE

    该伪指令的格式为:

    $ 文件名

    INCLUDE 文件名

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

    2、CASEOFF和CASEON

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

    3、LTORG

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

    4、RADIX

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

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

    MOV R0#12 ;此处#120x12

    5、IF、ELSE和ENDIF

    该伪指令的格式为:

    IF 逻辑表达式

    指令序列1

    ELSE

    指令序列2

    ENDIF

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

    如:

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

    ……

    IF Test TRUE

    指令序列1

    ELSE

    指令序列2

    ENDIF

    3.5.7  宏处理伪指令

    1、MACRO和ENDM

    该伪指令的格式为:

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

    指令序列

    ENDM

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

    如:

    errmac MACRO  text

    BL abort

    DATA

    DC8 text,0

    ENDM

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

    2、REPT和ENDR

    该伪指令的格式为:

    REPT 表达式

    指令序列

    ENDR

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

    3、REPTC和ENDR

    该伪指令的格式为:

    REPTC 符号,替换字符串

    指令序列

    ENDR

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

    4、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  常量和变量

    1、 常量

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

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

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

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

    2、 变量

    程序中的变量是指其值在程序的运行过程中可以改变的量。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~52、53~104、105~156、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调试电路以及功能接口电路等。其中各个部分功能如下:

    1、 时钟电路给MCU提供一个外部12MHz的以及一个32.768MHz的石英振荡器。

    2、 复位电路是通过引脚的方式与底板上的手动复位相连。通过底板复位电路提供手动复位信号。

    3、 JTAG电路可以让用户方便的通过仿真器调试或者下载程序。

    4、 外部存储电路,即有板载外部存储器(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种类型:

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

    寻址格式:

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

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

    如:

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

    2、LSR逻辑右移

    寻址格式:

    通用寄存器,LSR 操作数      

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

    如:

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

    3、ASR算术右移

    寻址格式:

    通用寄存器,ASR 操作数      

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

    如:

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

    4、ROR循环右移

    寻址格式:

    通用寄存器,ROR 操作数      

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

    如:

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

    5、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处理器支持加载/存储指令用于在寄存器和存储器之间传送数据,加载指令用于将存储器中的数据传送到寄存器,存储指令则完成相反的操作。常用的加载存储指令如下:

    1、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

    2、STR指令

    STR指令的格式为:

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

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

    如:

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

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

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

    3、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)。

    4、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中相应的条件标志位。

    1、 MOV指令

    MOV指令的格式为:

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

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

    如:

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

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

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

    2、 MVN指令

    MVN指令的格式为:

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

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

    如:

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

    3、 CMP指令

    CMP指令的格式为:

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

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

    如:

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

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

     

    4、 CMN指令

    CMN指令的格式为:

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

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

    如:

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

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

    5、 TST指令

    TST指令的格式为:

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

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

    如:

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

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

    6、 TEQ指令

    TEQ指令的格式为:

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

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

    如:

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

    7、 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)

    8、 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      加第四个字,带进位

    9、 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)

    10、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

    12、RSC指令

    RSC指令的格式为:

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

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

    如:

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

    13、AND指令

    AND指令的格式为:

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

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

    如:

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

    14、ORR指令

    ORR指令的格式为:

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

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

    如:

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

    15、EOR指令

    EOR指令的格式为:

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

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

    如:

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

    16、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必须是不同的寄存器。 

    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中的相关条件标志位

    2、 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中的相关条件标志位

    3、 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

    4、 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

    5、 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

    6、 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的地址空间的跳转。

    1、 B指令

    B指令的格式为:

    B{条件} 目标地址

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

    如:

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

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

    BEQ Label

    2、 BL指令

    BL指令的格式为:

    BL{条件}  目标地址

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

    如:

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

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

    3、 BLX指令

    BLX指令的格式为:

    BLX  目标地址

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

    4、 BX指令

    BX指令的格式为:

    BX{条件}  目标地址

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

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

    ARM指令不允许直接操作程序状态寄存器CPSRSPSR。可以通过程序状态寄存器访问指令,在程序状态寄存器和通用寄存器之间传送数据,然后在通用寄存器中进行处理。

    1、 MRS指令

    MRS指令的格式为:

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

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

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

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

    如:

    MRS R0CPSR ;传送CPSR的内容到R0

    MRS R0SPSR ;传送SPSR的内容到R0

    2、 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协处理器的寄存器和存储器之间传送数据。

    1、CDP指令

    CDP指令的格式为:

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

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

    如:

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

    2、LDC指令

    LDC指令的格式为:

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

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

    如:

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

    3、STC指令

    STC指令的格式为:

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

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

    如:

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

    4、MCR指令

    MCR指令的格式为:

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

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

    如:

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

    5、MRC指令

    MRC指令的格式为:

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

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

    如:

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

    3.3.7  异常中断指令

    1、SWI指令

    SWI指令的格式为:

    SWI{条件} 24位的立即数

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

    如:

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

    2、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指令所取代。

    1、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

    2、ADR-小范围地址读取

    ADR伪指令的格式为:

    ADR{条件} reg,expr

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

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

    如:

    Start: MOV R0#10

    ADR R4start ;相当于SUB R4PC#0x0c

    3、ADRL-中范围地址读取

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

    4、NOP-空操作

    3.5.2  数据定义伪指令

    1、DCB和DC8

    该伪指令的格式为:

    标号 DCB或DC8 表达式

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

    如:

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

    2、DCW和DC16、DCD和DC32

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

    3、DF32和DF64

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

    4、DS8、DS16、DS24和DS32

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

    如:

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

    3.5.3  符号定义伪指令

    1、=、ALIAS和EQU

    该伪指令的格式为:

    标号 = 表达式

    标号 ALIAS 表达式

    标号 EQU 表达式

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

    如:

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

    2、ASSIGN、SET、SETA和VAR

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

    3、DEFINE

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

    4、LIMIT

    该伪指令的格式为:

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

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

    如:

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

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

    5、EXTERN(或IMPORT)

    该伪指令的格式为:

    EXTERN 符号,[符号]……

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

    如:

    Name Start ;程序模块Start

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

    ……

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

    END

    6、PUBLIC(或EXPORT)

    该伪指令的格式为:

    PUBLIC 符号,[符号]……

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

    7、REQUIRE

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

    3.5.4  段定义伪指令

    1、ASEG和ASEGN

    该伪指令的格式为:

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

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

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

    如:

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

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

    2、RSEG

    该伪指令的格式为:

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

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

    如:

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

    3、DATA

    该伪指令的格式为:

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

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

    如:

    RSEG CODECODEROOT(2)

    DATA

    f1:    DC32 subrtn

    4、STACK

    该伪指令的格式为:

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

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

    5、COMMON

    该伪指令的格式为:

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

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

    6、CODE16和CODE32

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

    7、ORG

    该伪指令的格式为:

    ORG 地址表达式

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

    8、ALIGNRAM和ALIGNROM

    该伪指令的格式为:

    ALIGNRAM 对齐

    ALIGNROM 对齐[,填充值]

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

    9、EVEN和ODD

    该伪指令的格式为:

    EVEN [填充值]

    ODD [填充值]

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

    3.5.5  模块控制伪指令

    1、NAME和PROGRAM

    该伪指令的格式为:

    NAME 模块名

    PROGRAM 模块名

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

    如:

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

    2、END和ENDMOD

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

    3、LIBRARY和MODULE

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

    4、RTMODEL

    该伪指令的格式为:

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

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

    3.5.6  汇编控制伪指令

    1、$和INCLUDE

    该伪指令的格式为:

    $ 文件名

    INCLUDE 文件名

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

    2、CASEOFF和CASEON

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

    3、LTORG

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

    4、RADIX

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

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

    MOV R0#12 ;此处#120x12

    5、IF、ELSE和ENDIF

    该伪指令的格式为:

    IF 逻辑表达式

    指令序列1

    ELSE

    指令序列2

    ENDIF

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

    如:

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

    ……

    IF Test TRUE

    指令序列1

    ELSE

    指令序列2

    ENDIF

    3.5.7  宏处理伪指令

    1、MACRO和ENDM

    该伪指令的格式为:

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

    指令序列

    ENDM

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

    如:

    errmac MACRO  text

    BL abort

    DATA

    DC8 text,0

    ENDM

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

    2、REPT和ENDR

    该伪指令的格式为:

    REPT 表达式

    指令序列

    ENDR

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

    3、REPTC和ENDR

    该伪指令的格式为:

    REPTC 符号,替换字符串

    指令序列

    ENDR

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

    4、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  常量和变量

    1、 常量

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

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

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

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

    2、 变量

    程序中的变量是指其值在程序的运行过程中可以改变的量。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~52、53~104、105~156、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