嵌入式微处理器知识点整理

第一章 嵌入式微处理器

1. 嵌入式微处理器定义

  • IEEE(国际电气和电子工程师协会)定义

    • devices used to control, monitor, or assist the operation of equipment, machinery or plants.
    • 嵌入式系统是“用于控制、监视或者辅助操作机器和设备的装置”。
    • 嵌入式系统是软件和硬件的综合体,还可以涵盖机械等附属装置。
  • 我国嵌入式系统的行业定义

    嵌入式系统是指以应用为中心,以计算机技术为基础,软件硬件可剪裁,适应应用系统对功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。

    • 具有很强的专用性
    • 交叉学科,知识集成系统
    • 较IEEE定义更侧重细节

2. 嵌入式微处理器组成

image-20200630222657767

3. 嵌入式系统硬件组成:

  • 嵌入式处理器(CPU)

    是嵌入式系统的核心部分 ARM、PowerPC、MC 68000、MIPS等

  • 外围设备

    • 存储设备(如RAM、SRAM、Flash等)
    • 通信设备(如RS-232接口、SPI接口、以太网接口等)
    • 显示设备(如显示屏等)

4. 硬件系统特点

  • 对实时多任务有很强的支持能力
  • 具有功能很强的存储区保护功能
  • 可扩展的处理器结构
  • 嵌入式微处理器必须功耗很低。

5. 硬件系统分类

image-20200630223132466

6. 嵌入式软件

image-20200630223132466
  • 嵌入式操作系统

    为了使嵌入式系统的开发更加方便和快捷,需要有专门负责管理存储器分配、中断处理及任务调度等功能的软件模块,这就是EOS。EOS是用来支持嵌入式应用的系统软件,是嵌入式系统极为重要的组成部分。

    通常包括与硬件相关的底层驱动软件、系统内核、设备驱动接口、通信协议、图形界面GUI、标准化浏览器等。嵌入式操作系统具有编码体积小,面向应用,可裁剪和移植,实时性强,可靠性高,专用性强等特点。

7. 嵌入式操作系统划分

  • 按其应用对象不同分类

    • 基于Windows兼容,可包括有WindowsCE、嵌入式Linux等;
    • 工业和通信类,包括有VxWorks、Psos、QNX等;
    • 单片机类,包括有uC/OS、CMX、iRMX;
    • 面向Intelnet类包括有Plam、Visor、Hopen、PPSM。
  • 依据嵌入式系统操作系统的类型划分

    • 实时操作系统

      系统内有多个程序运行,每个程序有不同的优先级,只有最高优先级的任务才能占有CPU的控制权。

    • 分时操作系统

      系统内同时可以有多个程序运行,把CPU的时间分按顺序分成若干片,每个时间片内执行不同的程序,如UNIX。

    • 顺序执行系统

      系统内只含有一个程序,独占CPU的运行时间,按语句顺序执行该程序,直至执行完毕,另一程序才能启动运行。如DOS操作系统。

  • 按实时性划分

    • 具有强(硬)实时特点的嵌入式操作系统

      系统在指定的时间内未能实现某个确定的任务,会导致系统的全面失败,则被称为硬(强)实时系统。硬实时系统,其系统响应时间在毫秒或微秒级(数控机床)。一个硬实时系统通常在硬件上需要添加专门用于时间和优先级管理的控制芯片, uc/os和VxWorks是典型的实时操作系统。

    • 具有弱(软)实特点的嵌入式操作系统

      在软实时系统中,虽然响应时间同样重要,但是超时却不会发生致命的错误。软实时系统则主要在软件方面通过编程实现现实的管理。比如Windows CE、uCLinu是一个多任务分时系统。系统响应时间在毫秒或几秒的数量级上。

  • 经济上分为商业版和开源版

    • 商业版的实时操作系统功能稳定、可靠,有完善的技术支持和售后服务,但价格昂贵。比如有VxWorks、Windows Embedded、Psos、Palm、OS-9、LynxOS和QNX等。
    • 开源版在价格方面具有优势,目前主要有Linux和uC/OS。但不可靠,无技术咨询。
  • 按软件结构分类

    • 循环轮询系统:(Polling Loop)

      最简单的软件结构是循环轮询,程序依次检查系统的每一个输入条件,一旦条件成立就进行相应的处理。

    • 事件驱动系统:

      事件驱动系统是能对外部事件直接响应的系统。它包括前后台、实时多任务、多处理器等,是嵌入式实时系统的主要形式。

      应用程序是一个无限的循环,循环中调用相应的函数完成相应的操作,这部分可以看成后台行为(background)。

      中断服务程序处理异步事件,这部分可以看成前台行为(foreground)。

后台也可以叫做任务级,前台也叫中断级。

平时微处理器处在待机状态,所有的事都靠中断服务来完成。

8. 交叉编译过程

image-20200630224515678

第二章 体系结构

1. ARM体系结构的基本版本命名规则

ARM {x} {y} {z} {T} {D} {M} {I} {E} {J} {F} {-S}

  • x —— 系列号,例如:ARM9中的“9”;
  • y —— 内部存储管理/保护单元,例如ARM92中的“2”、ARM94中的“4”;
  • z —— 内含有高速缓存Cache;
  • T —— 支持16位的Thumb指令集;
  • D ——支持JTAG片上调试;
  • M ——支持用于长乘法操作(64位结果)的ARM指令,包含快速乘法器;
  • I —— 带有嵌入式追踪宏单元ETM(Embedded Trace Macro),用来设置断点和观察点的调试硬件;
  • E —— 增强型DSP指令(基于TDMI);
  • J —— 含有Java加速器Jazelle,与Java虚拟机相比,Java加速器Jazelle使Java代码运行速度提高了8倍,功耗降低到原来的80%;
  • F——向量浮点单元;
  • S——可综合版本,意味着处理器内核是以源代码形式提供的。这种源代码形式又可以被编译成一种易于EDA工具使用的形式。

2. ARM9体系框图

image.png

3. ARM9流水线

  • 取指:从指令Cache中读取指令。
  • 译码:对指令进行译码,识别出是对哪个寄存器进行操作并从通用寄存器中读取操作数。
  • 执行:进行ALU运算和移位操作,如果是对存储器操作的指令,则在ALU中计算出要访问的存储器地址。
  • 存储器访问:如果是对存储器访问的指令,用来实现数据缓冲功能(通过数据Cache)。
  • 寄存器回写:将指令运算或操作结果写回到目标寄存器中。

image-20200630230558570

4. ARM微处理器的工作模式

ARM微处理器支持 7 种工作模式:

  • User-用户模式(usr):
    • ARM处理器正常的程序执行状态
  • FIQ-快速中断模式(fiq):
    • 用于高速数据传输或通道处理
  • IRQ-外部中断模式(irq):
    • 用于通用的中断处理
  • Supervisor-管理模式(svc):
    • 操作系统使用的保护模式
    • 复位、软中断调用(SWI)
  • Abort-中止模式(abt):
    • 当数据访问或指令预取中止时进入该模式
    • 可用于虚拟存储及存储保护
  • Undefined-未定义指令异常模式(und):
    • 当未定义的指令执行时进入该模式
    • 可用于支持硬件协处理器的软件仿真
  • System-系统模式(sys):
    • 运行具有特权的操作系统任务
    • 使用和User模式相同寄存器组
  • 特权模式
    除用户模式以外,其余6种模式称之为特权模式(Privileged Modes)
    当处理器运行在用户模式下时,某些被保护的系统资源是不能被访问的
  • 异常模式:
    除去用户模式和系统模式以外的5种又称为异常模式(Exception Modes)
    常用于处理中断或异常,以及需要访问受保护的系统资源等情况

5. 工作模式的改变

  • 处理器模式可以通过软件控制进行切换,也可以通过外部中断或异常处理过程进行切换。
  • 在用户模式下,如果没异常发生,不允许应用程序自行改变处理器的工作模式,如果有异常发生,处理器会自动切换工作模式。
  • 在特权模式模式下,程序可以访问所有的系统资源,也可以任意地进行处理器模式的切换。

6. ARM微处理器的两种工作状态

  • ARM状态:

    • 处理器执行32位的ARM指令

    • ARM指令要求字对齐(相邻的4个字节且首字节地址能被4整除)

  • Thumb状态:

    • 处理器执行16位的Thumb指令
    • Thumb指令要求半字对齐(相邻的2个字节且首字节地址能被2整除)

7. 两种工作状态间的切换

在程序的执行过程中,处理器可以随时在两种工作状态之间切换
处理器工作状态的转变并不影响处理器的工作模式和相应寄存器中的内容
ARM微处理器复位后进入ARM状态

  • 进入Thumb状态:
    • 执行BX指令
      • BX:带状态切换的跳转指令

      • 当操作数寄存器的最低位[0]为1时,可以使微处理器从ARM状态切换到Thumb状态

        1
        BX  R0	;R0的最低位[0]为1
    • 处理器工作在Thumb状态,如果发生异常并进入异常处理子程序,则异常处理完毕返回时,自动从ARM状态切换到Thumb状态
  • 进入ARM状态:
    • 执行BX指令
      • BX:带状态切换的跳转指令

      • 当操作数寄存器的最低位[0]为0时,可以使微处理器从Thumb状态切换到ARM 状态

        1
        BX  R0	;R0的最低位[0]为0
    • 处理器工作在Thumb状态,如果发生异常并进入异常处理子程序,则进入时处理器自动从Thumb状态切换到ARM状态

8. ARM体系结构的寄存器组织

ARM 有37个32-Bits长的寄存器

  • 30 个通用寄存器
  • 1个用作CPSR(current program status register)
  • 5个用作SPSR(saved program status registers)
  • 1 个用作PC( program counter)

这些寄存器不能被同时访问
取决于处理器的工作状态工作模式

image-20200630232329875

9. 三个特殊的寄存器

  • R13寄存器:
    • 常用作堆栈指针SP(Stack Pointer),一种习惯用法
    • 也可使用其他的寄存器作为堆栈指针
    • 在Thumb指令集中,某些指令强制使用R13作为堆栈指针
    • 在应用程序初始化时,一般都要初始化每种模式下的R13,使其指向该工作模式的栈空间
  • R14寄存器:
    • 也称链接寄存器LR (Link Register)
      • 当执行BL子程序调用指令时,R14中得到R15(程序计数器PC)的备份

        1
        BL Label	;下一条指令地址→LR, Label→PC
    • 当发生中断或异常时,对应的分组寄存器R14_svc、R14_irq、R14_fiq、R14_abt和R14_und用来保存R15的返回值
    • 其他情况下,R14用作通用寄存器
  • R15寄存器:
    • R15寄存器用作程序计数器(PC)
    • ARM状态:位[1:0]为0,位[31:2]用于保存PC
    • Thumb状态:位[0]为0,位[31:1]用于保存PC
    • 由于ARM体系结构采用了多级流水结构,对于ARM指令集而言,PC总是指向当前执行指令的下两条指令的地址,即PC的值为当前执行指令的地址值加8个字节 (4字节*2 取指(PC)、译码)。

10. ARM异常

异常(Exception)通常定义为:处理器需要中止指令正常执行的任何情形并转向相应的处理,包括ARM内核产生复位,取指或存储器访问失败,遇到未定义指令,执行软件中断指令,或者出现外部中断等。

  • 在处理异常之前,当前处理器的状态必须保留,这样当异常处理完成之后,当前程序可以继续执行
  • 处理器允许多个异常同时发生,它们将会按固定的优先级进行处理
异常类型 具体含义
复位 当处理器的复位电平有效时,产生复位异常,程序跳转到复位异常处理程序处执行
未定义指令 当ARM处理器或协处理器遇到不能处理的指令时,产生未定义指令异常。可使用该异常机制进行软件仿真
软件中断 该异常由执行SWI指令产生,可用于用户模式下的程序调用特权操作指令。可使用该异常机制实现系统功能调用
指令预取中止 若处理器预取指令的地址不存在,或该地址不允许当前指令访问,存储器会向处理器发出中止信号,但当预取的指令被执行时,才会产生指令预取中止异常
数据访问中止 若处理器数据访问的地址不存在,或该地址不允许当前指令访问时,产生数据中止异常
IRQ(外部中断请求) 当处理器的外部中断请求引脚有效,且CPSR中的I位为0时,产生IRQ异常。系统的外设可通过该异常请求中断服务
FIQ(快速中断请求) 当处理器的快速中断请求引脚有效,且CPSR中的F位为0时,产生FIQ异常

11. 对异常的响应和从异常返回

  1. 将下一条指令的地址存入相应链接寄存器LR(R14)
    • LR中保存的是下一条指令的地址(当前执行指令地址+4或+8,与异常类型有关)
  2. 复制CPSR到相应的SPSR中
  3. 设置CPSR
    • 根据异常类型,强制设置CPSR的工作模式位
    • 设置中断禁止位,以禁止中断发生
    • 如果处理器处于Thumb状态,则切换到ARM状态
  4. 强制PC从相关的异常向量地址取下一条指令执行,从而跳转到相应的异常处理程序处
1
2
3
4
5
6
7
8
9
用伪码描述对异常的响应过程(CPU自动完成)
R14_<Exception_Mode> = Return Link
SPSR_<Exception_Mode> = CPSR
CPSR[4:0] = Exception Mode Number
CPSR[5] = 0 ;切换到ARM工作状态
If <Exception_Mode> == Reset or FIQ then
CPSR[6] = 1 ;禁止新的FIQ异常
CPSR[7] = 1 ;禁止新的IRQ异常
PC = Exception Vector Address
  • 异常处理完毕之后,ARM微处理器会执行以下几步操作从异常返回(编程完成)

    • 将SPSR复制回CPSR中

    • 将链接寄存器LR的值减去相应偏移量(偏移量计算不作要求)后送到PC中

      注意:复位异常处理程序不需要返回

12. 各类异常的具体描述

  1. 复位异常
    • 响应过程

      1
      2
      3
      4
      5
      6
      7
      R14_svc = Return Link(不可预知) 
      SPSR_svc = CPSR (不可预知)
      CPSR[4:0] = 0b10011
      CPSR[5] = 0 ;切换到ARM工作状态
      CPSR[6] = 1 ;禁止新的FIQ异常
      CPSR[7] = 1 ; 禁止新的IRQ异常
      PC = 0x00000000
  2. 未定义指令异常
    • 当ARM处理器遇到不能处理的指令时,会产生未定义指令异常

      • 采用这种机制,可以通过软件仿真扩展ARM或Thumb指令集
    • 异常返回

      1
      2
      MOVS  PC, R14_und
      ;恢复PC(从R14_und)和CPSR(从SPSR_und)的值,并返回到未定义指令后的下一条指令(注意:后缀“S”)
    • 未定义指令异常的响应过程

      1
      2
      3
      4
      5
      6
      7
      R14_und = Return Link 
      SPSR_und = CPSR
      CPSR[4:0] = 0b11011
      CPSR[5] = 0 ;切换到ARM工作状态
      // CPSR[6]保持不变
      CPSR[7] = 1 ; 禁止新的IRQ异常
      PC = 0x00000004
  3. 软中断SWI
    • 软件中断指令(SWI)用于进入管理模式,常用于请求执行特定的管理功能

      • 操作系统用 SWI 来为编程者提供各种例程
    • 异常返回

      1
      2
      MOVS  PC,  R14_svc
      ;恢复PC(从R14_svc)和CPSR(从SPSR_svc)的值,并返回到SWI的下一条指令
    • SWI的响应过程

      1
      2
      3
      4
      5
      6
      7
      R14_svc = Return Link
      SPSR_svc = CPSR
      CPSR[4:0] = 0b10011
      CPSR[5] = 0 ;切换到ARM工作状态
      // CPSR[6]保持不变
      CPSR[7] = 1 ;禁止新的IRQ异常
      PC = 0x00000008
  4. 中止异常
    • 产生中止异常意味着对存储器的访问失败

    • 中止异常包括两种类型:

      • 指令预取中止
      • 数据访问中止
    • 异常返回

      1
      2
      SUBS  PC, R14_abt, #4 ; 指令预取中止
      SUBS PC, R14_abt, #8 ; 数据访问中止
    • 中止异常的响应过程

      1
      2
      3
      4
      5
      6
      7
      R14_abt = Return Link 
      SPSR_abt = CPSR
      CPSR[4:0] = 0b10111
      CPSR[5] = 0 ;切换到ARM工作状态
      // CPSR[6]保持不变
      CPSR[7] = 1 ;禁止新的IRQ异常
      PC = 0x0000000c/ 0x00000010
  5. 外部中断IRQ
    • IRQ异常属于正常的中断请求

      • 若CPSR的I位置1,则禁止IRQ中断,若CPSR的I位清零,处理器会在指令执行完之前检查IRQ的输入
      • 只有在特权模式下才能改变I位的状态
    • 异常返回

      1
      2
      SUBS  PC , R14_irq , #4
      ;该指令将寄存器R14_irq的值减去4后,复制到程序计数器PC中,同时将SPSR_irq寄存器的内容复制到CPSR中,并返回到引起中断的下一条指令
    • IRQ的响应过程

      1
      2
      3
      4
      5
      6
      7
      R14_irq = Return Link
      SPSR_irq = CPSR
      CPSR[4:0] = 0b10010
      CPSR[5] = 0 ; 切换到ARM工作状态
      // CPSR[6]保持不变
      CPSR[7] = 1 ; 禁止新的IRQ异常
      PC = 0x00000018
  6. 快速中断FIQ
    • FIQ异常是为支持数据传输或者通道处理而设计的

      • 若将CPSR的F位置1,则禁止FIQ中断,若将CPSR的F位清零,处理器会在指令执行时检查FIQ的输入
      • 只有在特权模式下才能改变F位的状态
    • 异常返回

      1
      2
      SUBS   PC, R14_fiq , #4
      ;该指令将寄存器R14_fiq的值减去4后,复制到程序计数器PC中,同时将SPSR_fiq寄存器的内容复制到CPSR中,并返回到引起中断的下一条指令
    • FIQ的响应过程

      1
      2
      3
      4
      5
      6
      7
      R14_fiq = Return Link
      SPSR_fiq = CPSR
      CPSR[4:0] = 0b10001
      CPSR[5] = 0 ;切换到ARM工作状态
      CPSR[6] = 1 ;禁止新的FIQ异常
      CPSR[7] = 1 ;禁止新的IRQ异常
      PC = 0x0000001c

13. 存储器大/小端

ARM存储字数据采用两种方法:

  • 大端模式(Big endian):
    • 字数据的高字节存储在低地址中
    • 字数据的低字节存放在高地址中
  • 小端模式(Little endian):
    • 低地址中存放的是字数据的低字节
    • 高地址中存放的是字数据的高字节

第三章 ARM的指令系统

1. 堆栈操作寻址方式

根据不同的寻址方式,将堆栈分为4种:

  • Full栈:堆栈指针指向最后一个压入堆栈的数据(last used location)
  • Empty栈:堆栈指针指向下一个将要放入数据的空位置(the first unused location)
  • 递减栈:堆栈向内存地址减小的方向生长
  • 递增栈:堆栈向内存地址增加的方向生长

ARM支持四种类型的堆栈工作方式:

  • 满递减FD(Full Descending) —LDMFD, STMFD
  • 空递减ED(Empty Descending)—LDMED, STMED
  • 满递增FA(Full Ascending) —LDMFA, STMFA
  • 空递增EA(Empty Ascending) —LDMEA, STMEA
1
2
3
4
STMFD   SP!, {R0-R7, LR}
;LR最先进栈,R0最后
LDMFD SP!, {R0-R7, PC}
;R0最先出栈,PC最后

2. Load/Store指令

  • Load/Store在ARM寄存器和存储器之间传送数据。

  • 3种基本的数据传送指令:

    • 单寄存器Load/Store指令LDR/STR

      在ARM寄存器和存储器之间提供单数据项传送方式。支持的数据类型有字节/半字/字。

      image-20200630235333433

      • LDR指令:

        • 格式:LDR{<cond>} <Rd>,

        • 功能:用于从内存中将一个32位的字读取到目标寄存器

        • 举例:

          1
          2
          3
          4
          5
          LDR  R1,[R0]
          LDR R1,[R0,R2]
          LDR R1,[R0,R2,LSL #2]
          LDR Rd,label
          LDR Rd,[Rn],#0x04
      • STR指令:

        • 格式:STR{<cond>} <Rd>,

        • 功能:用于将一个32位的字数据写入到指令中指定的内存单元

        • 举例:

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          1.变量访问
          NumCount EQU 0x40003000
          LDR R0,=NumCount
          LDR R1,[R0]
          ADD R1,R1,#1
          STR R1,[R0]

          2.GPIO设置
          GPIO_BASE EQU 0xe0028000
          LDR R0,=GPIO_BASE
          LDR R1,=0x00ffff00
          STR R1,[R0,#0x0C]

          3.程序散转
          MOV R2,R2,LSL #2;功能号乘以4
          LDR PC,[PC,R2]
          NOP
          FUN_TAB DCD FUN_SUB0
          DCD FUN_SUB1
          DCD FUN_SUB2
      • LDRB指令:

        • 格式:LDR{<cond>}B <Rd>,
        • 功能:根据addr_mode所确定的地址模式从内存中取出指定的8位字节放入目标寄存器Rd 的低8位,并将 Rd的高24位清0。
      • STRB指令:

        • 格式:STR{<cond>}B <Rd>,
        • 功能:把寄存器Rd中的低8位字节数据保存到addr_mode所表示的内存地址中。
      • LDRH指令:

        • 格式:LDR{<cond>}H <Rd>,
        • 功能:用于从内存中将一个16位的半字读取到目标寄存器,并将Rd的高16位清0。
      • STRH指令:

        • 格式:STR{<cond>}H <Rd>,
        • 功能:把寄存器Rd中的低16位半字数据保存到addr_mode所表示的内存地址中,而且addr_mode所表示的地址必须是半字对齐的。
    • 多寄存器Load/Store指令

      • 多寄存器的Load/Store指令也叫批量加载/存储指令,它可以实现在一组寄存器和一块连续的内存单元之间传送数据。
      • 多寄存器的Load/Store指令主要用于现场保护、数据复制和参数传递等。

      image-20200701000329983

      • LDM指令:

        • 格式:LDM {<cond>} <Rn> {!}, <register>{^}
        • 功能:
          • 将数据从连续的内存单元中读取到指令中指定的寄存器列表中的各寄存器中。
          • 当PC包含在LDM指令的寄存器列表中时,实现指令的跳转。
          • 寄存器R0~R15分别对应于指令编码中bit[0]~bit[15]位。如果Ri存在于寄存器列表中,则相应的位等于1,否则为0。
      • STM指令:

        • 格式:STM {<cond>} <Rn> {!}, <register>{^}
        • 功能:将指令中寄存器列表中的各寄存器数值写入到连续的内存单元中。主要用于块数据的写入、数据栈操作及进入子程序时保存相关寄存器等操作。
      • addr_mode:

        LDM/STM的主要用途有现场保护、数据复制和参数传递等。addr_mode有8种,其中前面4种用于数据块的传输,后面4种是堆栈操作。

        image-20200701000706968

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      1. 数据复制。
      LDR R0,=SrcData ;设置源数据地址
      LDR R1,=DstData ;设置目标地址
      LDMIA R0,{R2-R9} ;加载数据到寄存器R2~R9
      STMIA R1,{R2-R9} ;存储R2~R9到目标地址
      2. 现场寄存器保护与恢复
      STMFD SP!,{R0-R7,LR} ;寄存器压栈保护

      BL DELAY ;调用DELAY子程序

      LDMFD SP!,{R0-R7,PC} ;恢复寄存器并返回
    • 单数据交换指令

      • SWP允许寄存器和存储器中的数值进行交换,在一条指令中有效地完成Load/Store操作。
      • 交换指令是Load/Store指令的一种特例。
      • 交换指令是一个原子操作(Atomic Operation),即在连续的总线操作中读/写一个存储单元,在操作期间阻止其他任何指令对该存储单元的读/写。

      image-20200701000950422

      • 字交换指令SWP:
        • 格式:SWP{<cond>} <Rd>,<Rm>,[<Rn>]
        • 功能:将<Rn>所指内存单元的字数据读取到目的寄存器Rd中,同时将另一个寄存器<Rm>的内容写入到该内存单元中。当<Rd>和<Rm>为同一个寄存器时,指令交换该寄存器和内存单元的内容。
        • 举例:SWP R1,R1,[R0]
      • 字节交换指令SWPB:
        • 格式:SWP{<cond>}B <Rd>,<Rm>,[<Rn>]
        • 功能:将<Rn>所指内存单元的字节数据读取到目的寄存器Rd中,寄存器Rd的高24位设为0,同时将另一个寄存器<Rm>的低8位内容写入到该内存字节单元中。当<Rd>和<Rm>为同一个寄存器时,指令交换该寄存器低8位内容和内存字节单元的内容。
        • 举例:SWPB R1,R2,[R0]

第四章 ARM汇编语言

1. 汇编语言伪指令

  • 伪指令是ARM处理器支持的汇编语言程序里的特殊助记符,它不在处理器运行期间由机器执行,只是在汇编时被翻译成ARM或者Thumb(或Thumb-2)指令(或指令序列),从而实现真正的指令操作。
  • ARM伪指令包含ADR、ADRL、LDR等。
    • 小范围地址读取伪指令ADR :
      • 格式:**ADR{cond}{.W} register,label **
      • 功能:
        • 将基于PC相对偏移地址或基于寄存器相对偏移地址值读取到寄存器中
          • 字节地址对齐时,取值范围为−255~255
          • 字地址对齐时,取值范围为−1020~1020
          • 16字节地址对齐时其取值范围更大
        • ADR伪指令被汇编器编译成一条指令。汇编器通常使用ADD指令或SUB指令来实现伪操作的地址装载功能。如果不能用一条指令来实现ADR伪指令的功能,汇编器将报告错误。
    • 中等范围地址读取伪指令ADRL:
      • 格式:ADRL{cond} register,label
      • 功能:
        • 将基于PC相对偏移的地址或基于寄存器相对偏移的地址值读取到寄存器中
          • 字节地址对齐时,取值范围为−64~64KB;
          • 字地址对齐时,取值范围为−256~256KB。
          • 16字节地址对齐时,其取值范围更大。
        • ADRL伪指令被编译器换成两条指令。即使一条指令可以完成该操作,编译器也将产生两条指令,其中一条为多余指令。如果汇编器不能在两条指令内完成操作,将报告错误,中止编译。
    • 大范围地址读取伪指令LDR:
      • 格式:LDR{cond}{.W} register,=[expr | label-expr]
      • 功能:
        • 将一个32位的常数或者一个地址值读取到寄存器中,可以看作是加载寄存器的内容。
        • 如果加载的常数符合MOV或MVN指令立即数的要求,则用MOV或MVN指令替代LDR伪指令。
        • 如果加载的常数不符合MOV或MVN指令立即数的要求,汇编器将常量放入数据缓存池,并使用一条程序相对偏移的LDR指令从数据缓存池读出常量。

2. 汇编语言伪操作

  • 伪操作(Directive)是ARM汇编语言程序里的一些特殊的指令助记符,其作用主要是为完成汇编程序做各种准备工作,对源程序运行汇编程序处理,而不是在计算机运行期间由处理器执行。
  • 伪操作只是汇编过程中起作用,一旦汇编结束,伪操作也就随之消失。
  • ARM公司推出的开发工具所支持的汇编伪操作
    • 符号定义伪操作

      • 全局变量定义GBLA、GBLL及GBLS

      • 局部变量定义LCLA、LCLL及LCLS

        • 格式:GCLA/ GCLL/ GCLS variable
        • 格式:LCLA/ GCLL/ GCLS variable
        • 说明
          • variable -全局/局部变量名称
          • A-算术变量(初始化为0)
          • L-逻辑变量(初始化为假F)
          • S-字符串变量(初始化为空)
      • 变量赋值伪操作SETA、SETL及SETS

        • 格式:Variable SETA/SETL/SETS expr

        • 说明:Expr-算术、逻辑或字符串表达式,也就是将要赋予变量的值

        • 示例

          1
          2
          3
          4
          5
          6
                      LCLA    Test4	
          Test3 SETA 0xaa
          ​ LCLL Test5
          Test4 SETL {TRUE}
          ​ LCLS Test6
          Test6 SETS "Testing"
      • 给通用寄存器列表定义名称RLIST

        • 格式:Name RLIST {list-of-registers}

        • 说明

          • Name-寄存器列表的名称
          • list-of-registers-通用寄存器列表
      • 示例

        1
        2
        3
        将寄存器列表名称定义为RegList,可在ARM指令LDM/STM中通过该名称访问寄存器列表。

        RegList RLIST {R0-R5,R8,R10}
    • 数据定义伪操作

      • 数据定义伪操作一般用于为特定的数据分配存储单元,同时可完成已分配存储单元的初始化。

      • DCB/DCW(DCWU)/DCD(DCDU)/DCQ(DCQU)

        • 格式

          • {label} DCD expr{, expr }…
          • {label} DCDU expr{, expr }…
        • 说明

          • Label-可选的程序标号;
          • Expr-表达式。
          • DCD可能在分配的内存单元前加1~3字节以保证内存字对齐。当程序对内存对齐方式要求不严格时可以是DCDU伪操作。
        • 示例

          1
          2
          3
          4
          5
          6
          7
          Str           DCB     "This is a test!"    
          C_string DCB "C_string",0
          DTest1 DCW 1,2,3
          Data DCW -255,2*number
          DCWU number+4
          DTest2 DCD 4,5,6
          DTest3 DCQ 100
      • DCFD(DCFDU)/DCFS(DCFSU)

      • LTORG

        • 在使用LDR伪指令时,要在适当的位置加入LTROG声明数据缓存池,这样就会把要加载的数据保存到缓存池中,再使用ARM加载指令读出,如果没有使用LTROG声明数据缓冲池,则汇编器会在程序末尾自动声明。
        • 格式: LTROG
      • SPACE

        • 格式:{label} SPACE expr

        • 说明

          • Label-可选的程序标号;
          • Expr-分配的字节数。
        • 示例

          分配连续100字节的存储单元并初始化为0。
          DataSpace SPACE 100

      • MAP/FIELD

        • 格式

          • MAP expr {,base_register}
          • {label} FIELD expr
        • 示例

          1
          2
          3
          4
          5
          6
          7
          8
                  MAP    0x100
          A FIELD 16
          B FIELD 32
          S FIELD 256
          ​ MAP 4,R9; 表的首地址设为R9+4的值
          ​ FIELD 4
          LAB FIELD 4
          ​ LDR r0,LAB;相当于LDR R0,[R9,#8]
    • 汇编控制伪操作

      • 汇编器在对程序代码进行编译时,会根据汇编控制伪操作的定义情况对程序进行编译。
      • 常用的汇编控制伪操作
        • 条件编译(IF、ELSE、ENDIF)
        • 重复汇编(WHILE、WEND)
        • 宏定义 (MACRO、MEND、MEXIT)
    • 杂项伪操作

      • AREA 段属性定义伪操作

        • 格式:AREA sectionname {,attr} {,attr}…
        • 说明
          • 定义一个代码段或数据段,AREA 伪操作指示汇编器汇编新的代码段或数据段。
          • 一个ARM源程序至少需要一个代码段,大的程序可以包含多个代码段和数据段。
          • Sectionname-指定所定义段的段名。段名若以数字开头,则该段名需用“|”括起来,如:|1_test|。
          • Attr-指定代码段或数据段的属性。在AREA伪操作中,各属性之间用逗号隔开。
      • ALIGN 对齐方式设置

        • 格式:ALIGN{expr{,offset{,pad}}}

        • 说明

          • 对齐方式设置ALIGN 伪操作通过用零或 NOP 指令进行填充来使当前位置与指定的边界对齐。
          • Expr-对齐表达式。表达式的值用于指定对齐方式,可能的取值为2的幂,如1、2、4、8、16等。若未指定表达式,则将当前位置对齐到下一个字的位置。
          • Offset-偏移量,若使用该字段,则当前位置的对齐方式为:n*expr+偏移量。
          • Pad-用作填充的字节。如果没有指定pad,用零填充
        • 示例:

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
            通过ALIGN伪操作使程序中的地址标号字对齐。
          AREA Example, CODE, READONLY
          START LDR R0,= Sdfjk

          MOV PC,LR
          Sdfjk DCB 0x58
          ALIGN ;声明字对齐
          SUBI MOV R1,R3 ;其他代码

          MOV PC,LR
      • ENTRY 声明程序的入口点

        • 格式:ENTRY

        • 说明

        • 一个完整的汇编程序中至少要有一个ENTRY,如果在程序连接时没有发现ENTRY伪操作,连接器将产生警告信息。

          • 在一个源文件里最多只能有一个ENTRY,如果多个ENTRY同时出现在源文件中,汇编时将产生错误信息。
        • 示例:

        1
        2
          AREA    Init, CODE, READONLY
        ENTRY ;指定应用程序的入口点
      • END 源程序结尾标识

        • 格式:END
      • 说明:

        • END伪操作用于通知汇编程序已经到了源程序的结尾。

        • 每一个汇编源文件必须以END结束。

    • 示例:

      1
      2
      3
      AREA    Init, CODE, READONLY

      END
      • EQU 定义常量或标号名称

        • 格式:name EQU expr{, type}
      • 说明:

        • 为程序中的常量、标号等定义一个等效的符号名称。
          • name -符号名称。
          • expr -32位表达式。其值为基于寄存器的地址值、程序中的标号、32位的地址常量或32位的常量。
        • Type-数据类型,为一个可选项。
      • 示例:

        1
        2
        Test  EQU 50	
        Addr EQU 0x55,CODE32
    • EXPORT(或GLOBAL)声明全局标号

      • 格式:EXPORT {symbol} {[WEAK,attr]}
        • 说明:
          • 用于在程序中声明一个全局的标号,该标号可在其他的文件中引用。EXPORT可用GLOBAL代替。
          • Symbol-声明的符号名称。名称区分大小写。如果symbol被忽略,所有符号被定义为可以被其他文件引用属性。
          • [WEAK]-声明其他的同名标号优先于该标号被引用。
        • [attr]-符号属性。默认情况下,被定义为全局的(global)的符号对其他文件是“可见的”,也就是说可以被其他文件引用。
    • EXPORTAS 将符号导出到目标文件

      • 格式:EXPORTAS symbol1,symbol2

      • 说明:

        • 用于修改已被编译的目标文件中的符号。
        • Symbol1-源文件中的符号名。symbol1必须在源文件中已被定义。它可以是段名、标号或常量。
        • symbol2,希望在目标文件中出现的符号名称,该符号名称区分大小写。
      • IMPORT/EXTERN 外部符号声明

      • 格式

        • IMPORT symbol {[attr}]}
        • IMPORT symbol [WEAK{,attr}]
          • EXTERN symbol {[attr}]}
          • EXTERN symbol [WEAK{,attr}]
        • 说明
          • IMPORT不管当前源文件中是否引用都导入到当前源文件的符号表中
          • EXTERN在当前源文件中引用时才导入到当前源文件的符号表中
      • GET(或INCLUDE)/INCBIN 文件包含伪操作

        • 格式
          • GET (或INCLUDE) filename
          • INCBIN filename
        • 说明
          • GET(或INCLUDE)将一个源文件包含到当前源文件中,并将被包含的文件在其当前位置进行汇编处理
          • INCBIN将一个源文件包含到当前源文件中,但被包含文件不进行汇编处理

3. ARM 汇编语言的语句格式

  1. ARM编译环境下汇编语句格式

    • {程序标号} {指令} {;注释}
    • {程序标号} {伪操作} {;注释}
    • {程序标号} {伪指令} {;注释}
  2. ARM编译环境下汇编语句中的符号规则

    1. 符号命名规则

      • 符号由大小写字母、数字、下划线组成,且符号是区分大小写的。
      • 符号在其作用范围内必须是唯一的。
      • 程序中的符号不要与指令助记符或者伪操作同名。
      • 局部标号可以用数字开头,其他的标号不能。
    2. 变量

      • 数字变量
      • 逻辑变量
      • 字符串变量
    3. 常量

      • 十进制数,如535、246。
      • 十六进制数,如0x64、0xff00。
      • n_XXX, n表示n进制数,从2~9,XXX是具体的数字。例如:8_3777
      • 字符常量用一对单引号括起来,包括一个单字符或者标准C中的转义字符。例如‘A’、‘\n’。
      • 字符串常量由一对双引号以及由它括住的一组字符串组成,包括标准C中的转义字符。
      • 如果需要使用双引号”或字符$,则必须用””和$$代替。
    4. 字符串表达式操作

    • 字符串表达式一般由字符串常量、字符串变量、运算符和括号构成。
      • 与字符串表达式相关的运算符:
        • LEN:计算字符串长度运算符。

        • CHR:ASCII码转换运算符。

        • STR:字符串转换运算符。

        • LEFT:字符串取左运算符。

        • RIGHT:字符串取右运算符。

        • CC:字符串连接运算符。

    • 例如:
      > abc SETS “one “” double quote”
      > improb SETS “literal”:CC:(abc:LEFT:4)
    1. 地址标号

      • 段内标号的地址在汇编时确定,而段外标号地址值在链接时确定。
      • PC相关标号
        位于目标指令前的标号或程序中的数据定义伪操作前的标号。在汇编时将被处理成PC值加上或减去一个数字常量。它常用于表示跳转指令的目标地址或代码段中所嵌入的少量数据。
      • 寄存器相关标号
        在汇编时将被处理成寄存器的值加上或减去一个数字常量。它常被用于访问数据段中的数据。通常用MAP和FIELD伪操作定义,也可以用EQU伪操作定义。
      • 绝对地址
        绝对地址是一个32位的数字量,使用它可以直接寻址整个内存空间。
    2. 局部标号

      • 局部标号是一个0~99之间的十进制数字,可重复定义。局部标号后面可以紧接一个通常表示该局部变量作用范围的符号。局部变量的作用范围为当前段,也可以用伪操作ROUT来定义局部标号的作用范围。
      • 局部变量命名语法:n{routname}
      • 局部变量引用的语法格式:
        • %{F|B}{A|T}n{routname}
        • 汇编器默认搜索:先向后搜索,再向前搜索。从当前层次到宏最高层次,比当前层次低的层次不再搜索。
        • n是局部标号的数字号。
        • routname是当前局部范围的名称。
        • %表示引用操作。
        • F指示汇编器只向前搜索。
        • B指示汇编器只向后搜索。
        • A指示汇编器搜索宏的所有嵌套层次。
        • T指示汇编器搜索宏的当前层次。
  3. GNU环境下ARM汇编语句格式

    • {程序标号:} {指令} {@注释}
    • {程序标号:} {伪操作} {@注释}
    • {程序标号:} {伪指令} {@注释}
  4. GNU环境下ARM汇编程序编译

    1. 预处理
      GNU汇编器as的内部预处理包括:移除多余的间隔符及代码中的所有注释,并将字符常量转换为数字值。它不作宏处理和文件包含处理,但这些事情可以交由gcc编译器去做,文件包含可以用.include伪指令来实现。
    2. 注释
      GNU ARM Assembly可识别的注释方式有:C风格多行注释符/* … */或GNU单行注释符“@”或“#”。
    3. 符号
      与C语言基本一致,符号名由字母、数字以及’_’和’.’组成,大小写敏感。
    4. 段与重定位
      链接器ld用于把多个目标文件合并为一个可执行文件。汇编器as生成的目标文件都假定从地址0开始,ld为其指定最终的地址。链接器ld把目标文件中的每个section都作为一个整体,为其分配运行的地址。

4. 汇编语言与C语言的混合编程

在嵌入式程序设计中,有些场合(如对具体的硬件资源进行访问)必须用汇编语言来实现。

  1. 过程调用标准AAPCS

    • 为了使不同编译器编译的程序之间能够相互调用,必须为子程序间的调用规定一定的规则。

    • AAPCS( Procedure Call Standard for the ARM Architecture),即ARM体系结构过程调用标准。它是ABI(Application Binary Interface (ABI) for the ARM Architecture (base standard) [BSABI])标准的一部分。

    • 可以使用“–apcs”选项告诉编译器将源代码编译成符合AAPCS调用标准的目标代码。

      1. 寄存器使用规则

        • 子程序间通过寄存器R0~R3传递参数,寄存器R0~R3可记作A1~A4。当参数个数超过4个时,超过部分使用数据栈进行参数传递。被调用的子程序在返回前无须恢复寄存器R0~R3的内容。
        • 在子程序中,ARM状态下使用寄存器R4~R11来保存局部变量,寄存器R4~R11可记作V1~V8;Thumb状态下只能使用R4~R7来保存局部变量。
        • 寄存器R12用作子程序间调用时临时保存栈指针,函数返回时使用该寄存器进行出栈,记作IP;在子程序间的链接代码中常有这种使用规则。
        • 通用寄存器R13用作数据栈指针,记作SP。
        • 通用寄存器R14用作链接寄存器 ;
        • 通用寄存器R15用作程序计数器,记作PC 。
      2. 数据栈使用规则

        • 过程调用标准规定数据栈为FD类型,并且对数据栈的操作时要求8字节对齐的。
      3. ARM寄存器在函数调用过程中的保护规则

        image-20200701005742142

  2. 在嵌入式C语言程序中嵌入汇编语言

  3. ARM汇编语言与嵌入式C程序相互调用

第五章 S3C2410硬件结构与关键技术

1. S3C2410简介

  • S3C2410是著名的半导体公司SAMSUNG推出的一款32位RISC处理器,它为手持设备和一般类型的应用提供了低价格、低功耗、高性能微控制器的解决方案。
  • S3C2410的内核基于ARM920T,带有MMU功能,采用0.18m工艺,主频可达203MHz,适合于对成本和功耗敏感的需求。
  • 采用了AMBA(Advanced Microcontroller Bus Architecture)的总线结构,实现了MMU、AMBA BUS、Harvard的高速缓冲体系结构,支持Thumb16位压缩指令集,从而能以较小的存储空间需求,获得32位的系统性能。

2. 三种总线标准

  1. AHB (Advanced High-performance Bus)
    用来研发宽带宽处理器芯核的片上总线。应用于高性能、高时钟频率的系统模块,它构成了高性能的系统骨干总线。
  2. ASB (Advanced System Bus )
    是第1代AMBA系统总线,数据宽度较AHB小,支持的典型数据宽度为8位、16位、32位。
  3. APB(Advanced Peripheral Bus)
    是本地二级总线(local secondary bus ),通过桥和AHB/ASB相连。满足不需要高性能流水线接口或不需要高带宽接口的设备的互连。它将来自AHB/ASB的信号转换为合适的形式以满足挂在APB上的设备的要求。

3. S3C2410的主要功能与特点

  1. 独立的16KB指令Cache和16KB数据Cache;
  2. LCD控制器(支持STN、TFT液晶显示屏,集成1个DMA控制器);
  3. 内置系统存储控制器(片选逻辑,支持ROM、SRAM、Flash、FP/EDO/SDRAM)。
  4. NAND Flash控制器。
  5. 4个通道的DMA,支持存储器与IO之间的数据直接传输。
  6. 3个带硬件握手的UART控制器。
  7. 1个支持多主设备的I2C控制器。
  8. 1个IIS总线控制器。
  9. 2个SPI接口
  10. 2个USB主机接口,1个USB设备接口。
  11. SD卡接口和MMC接口。
  12. 4个具有PWM功能的16位定时/计数器和1个16位内部定时器,支持外部的时钟源。
  13. 看门狗定时器Watch Dog。
  14. 117个通用可能编的I/O口和24个外部中断源。
  15. 具有8通道输入的10位ADC。
  16. 具有日历功能的实时时钟RTC。
  17. 功率控制模式:Nomal、Slow、Idle和Stop。
  18. 带锁相环PLL的片内时钟发生器。

image-20200701010340438

4. S3C2410地址空间

image-20200701010423617

5. S3C2410的Bank6/7地址分布

image-20200701010450490

6. NorFlashh和NandFlash

NorFlash

NOR Flash需要很长的时间进行抹写,但是它提供完整的寻址与数据总线,并允许随机存取存储器上的任何区域,这使的它非常适合取代老式的ROM芯片。当时ROM芯片主要用来存储几乎不需更新的代码,例如电脑的BIOS或机上盒(Set-top Box)的固件。NOR Flash可以忍受一万到一百万次抹写循环,它同时也是早期的可移除式快闪存储媒体的基础。CompactFlash本来便是以NOR Flash为基础的,虽然它之后跳槽到成本较低的 NAND Flash。

NandFlash

NAND Flash式东芝在1989年的国际固态电路研讨会(ISSCC)上发表的, 要在NandFlash上面读写数据,要外部加主控和电路设计。NAND Flash具有较快的抹写时间, 而且每个存储单元的面积也较小,这让NAND Flash相较于NOR Flash具有较高的存储密度与较低的每比特成本。同时它的可抹除次数也高出NOR Flash十倍。然而NAND Flash 的I/O接口并没有随机存取外部地址总线,它必须以区块性的方式进行读取,NAND Flash典型的区块大小是数百至数千比特。

因为多数微处理器与微控制器要求字节等级的随机存取,所以NAND Flash不适合取代那些用以装载程序的ROM。从这样的角度看来,NAND Flash比较像光盘、硬盘这类的次级存储设备。NAND Flash非常适合用于储存卡之类的大量存储设备。第一款创建在NAND Flash基础上的可移除式存储媒体是SmartMedia,此后许多存储媒体也跟着采用NAND Flash,包括MultiMediaCard、Secure Digital、Memory Stick与xD卡。

7. 最小的系统组成部分

嵌入式最小系统由硬件层中间层系统软件层这三个部分组成:

  • 硬件层
    硬件层中包含嵌入式微处理器、存储器(SDRAM、ROM、Flash等)、通用设备接口和I/O接口(A/D、D/A、I/O等)。在一片嵌入式处理器基础上添加电源电路、时钟电路和存储器电路,就构成了一个嵌入式核心控制模块。其中操作系统和应用程序都可以固化在ROM中。
  • 中间层
    硬件层与软件层之间为中间层,它将系统上层软件与底层硬件分离开来,使系统的底层驱动程序与硬件无关,上层软件开发人员无需关心底层硬件的具体情况,根据BSP层提供的接口即可进行开发。
    该层一般包含相关底层硬件的初始化、数据的输入/输出操作和硬件设备的配置功能。BSP具有以下两个特点。
  • 系统软件层
    系统软件层由实时多任务操作系统(Real-time Operation System,RTOS)、文件系统、图形用户接口(Graphic User Interface,GUI)、网络系统及通用组件模块组成。RTOS是嵌入式应用软件的基础和开发平台。