概述

学习目标

预备知识

  • 单片机:单片微型计算机
  • CPU时序: 单片机内的取指、分析、执行等各种操作都是在一系列时钟脉冲控制下进行的,而各脉冲在时间上是有先后顺序的,这种顺序就称为时序。

1.1 ARM概述

1.1.1 ARM 简介

  • ARM两个显著特点:
    • ARM既是一个公司的名称,也是一类微处理器的通称。

      由苹果电脑,Acorn电脑,VLSI技术(公司)合资,1990年成立于英国剑桥,主要出售芯片设计技术的授权。
      
    • ARM既是一种技术的名称,也是一种商业思想/模式。

  • ARM Cortex-M3
    • ARMv7内核处理器
    • 简称CM3

1.1.2 ARM 的RISC体系结构

CISC与RISC

其中RISC与CISC各有优势

到目前为止,RISC 体系结构还没有严格的定义,一般认为,RISC 体系结构应具有如下特点:

  • 指令格式长度固定、归整、简单、基本寻址方式有 2~3 种。
  • 使用单周期指令,便于流水线操作执行。
  • 大量使用寄存器,数据处理指令只用寄存器,访问存储器用加载/存储指令

1.1.3 ARM 的各种构架版本

  • 学习的是ARMv7
    • 采用了Thunmb-2技术
    • 定义3种内核 :
      • A:面向应用的微处理器,针对复杂操作系统和应用程序设计;
      • R:针对实时系统的嵌入式处理器
      • M:针对成本敏感应用优化的深度嵌入式处理器

1.1.4 ARM 处理器的命名法则

1.1.5 ARM 的各系列CPU

除了ARM7还要学习Cortex系列


1.2 Cortex-M3概述

Cortex-M3 简称CM3,完整的CM3 MCU(微型控制单元)就是CM3内核+其他组件,如:

1.2.1 Cortex-M3处理器的结构

  • 32位处理器内核,哈弗体系结构

    • 位内部数据路径,32 位寄存器,32 位存储器接口
    • 拥有独立的指令总线数据总线(这个就是指哈弗结构),可并行取指与访问数据,数据访问不占用指令总线,提升了性能。
  • 大小端格式的数据存储

    • 小端格式:低字节字数据存放在低地址,高字节字数据存放在高地址存储器中.通常来说CM3采用小端格式
    • 大端格式:与小端相反

1.2.2 Cortex-M3处理器的特点

特点:

  • 分为内核和高级系统外设,称为分级处理器
  • CM3处理器
    • Cortex-M3 内核

      • 哈佛体系结构
      • 拥有分支预测功能的三级流水线
      • Thumb®-2 指令集和传统的 Thumb指令集
      • 带有 硬件除法和 单信号周期乘法的ALU
      • 支持两种状态:Thumb 和调试状态
    • 可配置的中断控制器

    • 总线矩阵

    • 先进的调试组件

    • 可选择的 MPU & ETM

1.2.3 Cortex-M3可配置的选项

  • 1 中断
    • 外部中断可配置1-240个
    • 中断优先级可配置3-8个
  • 2 存储器管理单元(MPU)
    • 1个
  • 3 嵌入式跟踪宏单元(ETM)
    • 1个

1.2.4 Cortex-M3指令集

1) ARM的指令集有三个

  • 32位ARM指令集
    • 对应处理器的ARM状态
  • 16位Thumb指令集
    • ARM指令集子集
    • 对应处理器的Thumb状态

这两种指令集对应两种处理器执行状态。处理器可以在两种执行状态之间动态切换。尽管切换开销很大,但能带来更高的代码密度,给目标代码减肥。

  • Thumb-2指令集体系结构(ISA)
    • Thumb指令集的一个超集

Thumb‐2首次实现16位与32位指令并存,结果在Thumb状态下,同样工作需要的指令周期数明显下降。

那么我们学习的Cortex-M3的指令集使用的就是Thumb‐2的一种子集.

2) Cortex-M3的指令集

  • Cortex‐M3不是向后兼容的,ARM7的ARM汇编程序不能直接移植上CM3。
  • Cortex‐M3支持绝大多数传统的Thumb指令。
  • Cortex‐M3支持16位和32位指令,可自如在Thumb和ARM之间切换状态。这种切换在ARM7和ARM9是司空见惯的,尤其是在使用大型条件嵌套,以及执行复杂运算的时候,那可是要下大功夫的。
  • Cortex‐M3破天荒地支持了“非对齐数据访问”。

3) Cortex-M3 与三种指令集的关系

Cortex-M3 与三种指令集的关系

1.3 STM32概述

STM32是意法半导体的基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7、A7内核并具备丰富外设选择的32位微控制器及微处理器。

1.3.1 STM32的分类

1.3.2 STM32的命名规则

1.3.3 STM32F1的命名规则

1.3.4 STM32F1系列MCU分类与选型

1.3.5 芯片封装与管腿描述

1.3.6 STM32F1系列MCU的性能特点

1.3.7 STM32的固件库与开发工具

ARM CM3的指令系统

2.1概述

2.2工作模式和访问权限

一. 前提概念: 异常

在ARM 中,凡是打断程序顺序执行的事件,都被称为异常。

  • ARM异常包括:外部中断外,指令执行“非法操作”,访问被禁内存区间,各种错误产生的故障,不可屏蔽中断等。
  • 在不严格的上下文中,异常与中断也可以混用。
  • 程序代码也可以主动请求进入异常状态的(常用于系统调用)。

二.两种工作模式

  • 处理模式:用于执行异常处理例程的处理器工作模式

  • 线程模式:用于执行主应用程序的处理器工作模式

  • 目的:用于区别普通应用代码和异常例程代码

三.两种访问权限(特权级别)

  • 特权级: 可以访问任意资源、执行任何指令
  • 用户级: 不能访问有限制或被禁止的资源
  • 目的: 提供一种资源访问的保护机制,防止普通用户代码或意外、或恶意地执行要害操作.是构成一个硬件层上的基本安全模型

四. 工作模式与访问权限的关系

image-20221024212634504

2.3工作模式、访问权限的转换

访问权限转换途径

image-20221024214456922
  1. 复位后^1,CM3默认进入:线程模式 + 特权级

  2. 主应用程序运行线程模式下,可使用特权级用户级

  3. 异常处理例程运行在处理模式下,必须使用*特权级

  4. 特权级切换到用户级,修改CONTROL寄存器^2即可

  5. 用户级切换回特权级模式,必须执行一条系统调用指令SVC,触发SVC异常,在异常处理例程中修改CONTROL才能回到特权级
    image-20221024214243009

  6. 处理模式下,执行异常退出,则返回线程模式

  7. 线程模式下,触发异常转入处理模式

为什么

线程模式下为什么不能从 用户级权限 直接返回到 特权级权限

  • 原因
    • 用户级权限有限
      • 禁止访问系统控制空间(SCS)
        • 包含配置寄存器
        • 调试组件寄存器
      • 禁止MSR 访问特殊功能(寄存器–除有APSR 例外)
      • 访问了就是FAULT
  • 方法
    • 从特权级进入用户级只用置位CONTROL[0]即可,但是不能反过来,那么可以通过触发一个(软)中断,再由服务例程改写该位,才能在返回到线程模式后拿到特权级。(唯一途径)

2.4数据类型与存储器格式

一. 数据类型

image-20221024215218252

二. 储存器格式

1.概述

  • Cortex-M3 处理器存储器的地址是从0 开始向上编号的字节的线性集合。例如:

    • 字节 0-3 存放第一个字,字节 4-7 存放第二个字
  • Cortex-M3 处理器支持小端格式大端格式存储器数据字的访问。

  • ARM 处理器默认的小端存储器格式,访问代码始终使用小端格式。
  • Cortex-M3 处理器可以通过配置管脚 BIGEND,来选择小端格式BE-8 大端格式。该管脚在复位时被采样,结束复位后存储器格式不能修改。

  • 注:

    • 对系统控制空间(SCS)的访问始终采用小端格式。
    • 在非复位的状态下试图改变存储器格式的操作将被忽略。
    • 专用外设总线(PPB)空间只能为小端格式,BIGEND 的设置无效。

2.大、小端数据格式

  • 小端数据格式:数据高位存入高地址,数据低位存入低地址
  • 大端数据格式:数据低位存入高地址,数据高位存入低地址。image-20221025194409558

2.5寄存器

概述

  • 寄存器类型
    • 通用寄存器
      • R0-R12
      • R13、R14、R15
    • 特殊功能寄存器
      • 程序状态寄存器组
      • 中断屏蔽寄存器组
      • 控制寄存器

image-20221025195102180

一. 通用寄存器 R0-R15

从图上可以看出分为低组和高组,绝大多数16 位Thumb 指令只能访问低组寄存器–R0‐R7,高组寄存器R8-R12,只有少量16 位Thumb 指令能访问,而32 位Thumb‐2 指令可以访问所有寄存器。另外,R0-R12仅作通用寄存器使用,R13-R15不仅可作通用寄存器,还有特殊功能。还有,复位后,寄存器初始值不可确定,无论高低组。

1. 堆栈指针寄存器R13(SP)

关于栈和R13的推荐阅读[^3]

  • 分组的堆栈寄存器,含两个堆栈指针,任一时刻只能使用一个。
  • 当引用R13(或写作SP)时,引用到的是当前正在使用的那一个,另一个必须用特殊的指令来访问(MRSMSR 指令)。
  • Cortex-M3支持2个堆栈,都指向R13
    • 主堆栈MSP:别名为SP_main ,复位后缺省的堆栈指针,系统内核、异常、特权访问时使用。
    • 进程堆栈PSP:别名SP_process,由用户的应用程序代码使用。
    • 堆栈指针的最低两位永远是0,堆栈总是4 字节对齐的。
    • 不要求每个应用必须用齐两个堆栈指针。简单的应用程序只使用MSP就够了,PUSHPOP 指令默认使用SPimage-20221025202155767

2. 链接寄存器R14(LR)

  • R14 用于保存子程序调用和异常的返回地址
  • R14 保存的是当前正在执行的指令的_一下条指令的地址_,LR的值_自动填充_。
  • 因为代码至少是字对齐的,所以PC的LSB(有效最低位)始终为0。但LR的LSB可读/写,这是历史遗留产物。以前,因为有些ARM芯片同时支持ARM状态和Thumb状态,要由LR的第0位来指示ARM/Thumb状态。为方便程序移植,CM3允许LR的LSB位可读/可写。

3.程序计数器R15(PC)

  • 指向当前正在取指的指令地址。如果修改它的值,就能改变程序的执行流

  • CM3内部使用了三级指令流水线,读PC时返回值是当前指令地址+4

    例如:0x1000: MOV R0, PC ; R0 = 0x1004

  • CM3中的指令至少是半字对齐 的,所以PC的最低有效位总是读回0

  • 在分支时,无论是直接写PC 的值还是使用分支指令,都必须保证加载到PC 的数值是奇数(即LSB=1),用以表明这是在Thumb 状态下执行。倘若写了0,则视为企图转入ARM 模式,CM3 将产生一个fault 异常

二. 特殊功能寄存器

特殊功能的意思就是说在设计之初就是定死的,往往不能后续改变

概述

image-20221025205833150
  • 程序状态寄存器组 xPSR

    • 应用程序状态寄存器(APSR)
    • 中断号程序状态寄存器(IPSR)
    • 执行程序状态寄存器(EPSR)
  • 中断屏蔽寄存器组

    • 中断屏蔽寄存器PRIMASK
    • 异常关闭寄存器FAULTMASK
    • 中断优先级屏蔽寄存器BASEPRI
  • 控制寄存器CONTROL

  • 特殊功能寄存器有预定义的功能必须用专门指令来访问。

  • 特殊功能寄存器没有存储器地址,只能被专用的MSR MRS 指令访问,访问格式:

    1
    2
    MRS <gp_reg>, <special_reg> ;读特殊功能寄存器的值到通用寄存器
    MSR <special_reg>, <gp_reg> ;写通用寄存器的值到特殊功能寄存器

一. 程序状态寄存器(PSRs 或xPSR)

1. 应用程序状态寄存器APSR

2. 中断号程序状态寄存器IPSR

3. 执行程序状态寄存器EPSR

2.6异常与中断

2.7向量表

2.8堆栈操作

2.9复位序列

[^3]: (23条消息) ARM堆栈指针sp(r13)详解_Leo丶Fun的博客-CSDN博客_arm sp指针

第 3 章 ARM-Cortex-M3的指令系统

3.2 Cortex-M3的八种寻址方式

Cortex-M3的指令格式—ARM的三地址指令格式:

1
2
3
4
5
标号 <Opcode> {<Cond>}{S}{.N|.W} <Rd>,<Rn>[,<Operand2>];注释

标号 <操作码> {条件码} <第一操作数>,<第二操作数>[,<第三操作数>];注释

标号 <指令码> {条件码} <目标寄存器>,<源寄存器1> [,<源寄存器2>];注释(通常来说)

1、寄存器寻址

指令中的地址码字段(第一或第二操作数)给出的是寄存器编号,操作数的值在寄存器中,指令执行时直接取出寄存器值来操作。例:

1
2
3
MOV  R1,R2; 将R2的值存入R1 

SUB R0,R1,R2 ;将R1的值减去R2的值,结果存R0

2、立即寻址

直接把整数作为地址给寄存器

地址码字段(第一或第二操作数)直接给出是一整数(称立即数),例

1
2
SUBS R0,R0,#1;  R0减1结果放入R0,影响标志位
MOV R0,#0xFF000; 将立即数0xFF000装入R0

3、寄存器移位寻址

地址码字段(第一或第二操作数)在操作之前,先进行移位操作。

1
2
3
MOV	R0,R2,LSL #3 ;R2的值左移3位,结果存R0,相当如R0=R2*8.

ANDS R1,R1,R2,LSL R3 ;R2的值左移R3位,再和R1相“与”操作,结果放入R1
  • 可采用的移位操作
    • LSL逻辑左移(Logical Shift Left):寄存器中数据位低端空出的位补0;
    • LSR逻辑右移(Logical Shift Right):寄存器中数据位高端空出的位补0;
    • ASR算术右移(Arithmetic Shift Right):移位过程中保持符号位不变,即若源操作数为正数,则数据位的高端空出的位补0,否则补1;
    • ROR循环右移(Rotate Right):由数据位的低端移出的位填入数据位的高端空出的位;
    • RRX带扩展的循环右移(Rotate Right eXtended by 1 place):操作数右移一位,高端空出的位用原C标志值填充。

4、寄存器间接寻址

地址码字段(第一或第二操作数)给出的是一个通用寄存器的编号,所需的操作数保存在寄存器指定地址的存储单元中,即寄存器为操作数的地址指针,例:

1
LDR R1,[R2] ; 将R2指向的存储单元的数据读出存R1.(这里的R2相当于指针)

5、基址寻址

就是将基址寄存器的内容与给出的偏移量相加,形成操作数的有效地址。用于查表、数组操作、功能部件寄存器访问等。例:

实际上也是间接寻址

1
LDR R2,[R3,#0x0C]   ;读(R3)+0x0C地址上的存储单元的值存R2 

6、多寄存器寻址

多寄存器寻址一次可传送几个寄存器值,允许一条指令传送16个寄存器的任何子集或所有寄存器。

最多就16个寄存器

1
LDMIA R1!,{R2-R4,R6}; 将R1指向单元中的数据存到R2~R4、R6中(R1自动加4) 先存储在增加

7、堆栈寻址

  • 堆栈是一个按特定顺序进行存取的存储区,后进先出。
  • 堆栈寻址是隐含的,使用一个专门的寄存器–堆栈指针SP,指向堆栈的存储单元即栈顶
  • 按堆栈指针生长方式可分为:向上生长与向下生长的堆栈:
  • 注意增长方向与栈顶的位置
  • 压栈就是加入数据

  • 堆栈分类
    • 按堆栈指向的位置可分为:满堆栈和空堆栈
    • 满堆栈:堆栈指针指向最后压入的有效数据项
    • 空堆栈:堆栈指针指向下一个待压入数据的空位置
  • 堆栈方式
    • 向上生长的满栈

      Cortex-M3向下生长的满栈模型
      
    • 向上生长的空栈

    • 向下生长的满栈

    • 向下生长的空栈


例:

1
2
STMDB SP!, {R1-R7, LR} ; 将R1~R7、LR 入栈
LDMIA SP!, {R1-R7, PC} ; 出栈,到R1~R7、LR 寄存器

8、相对寻址

相对寻址是基址寻址的一种变通。由程序计数器PC提供基准地址,指令中的地址码字段作为偏移量,两者相加后得到的地址即为操作数的有效地址.

3.3 Thumb-2 汇编程序结构

由两个部分组成:代码段+数据段

3.4 Thumb-2指令基本格式

1.指令基本格式

3.5 Cortex-M3常用的Thumb-2指令

3.5.1 数据传送类指令

就是MOV

一、数据传送指令 – 6种

二、存储器访问指令

  • 功能:用于产生PC相关地址、处理器寄存器和存储器之间传送数据。
  • 分类
    • 加载指令:将存储器中的数据传送到寄存器中
    • 存储指令:将寄存器中的数据传送到存储器中
  • 特点:处理器对存储器的访问只能通过加载/存储指令实现。
  • 具体六种

1.数据运算指令

就是RDR

2.存储器访问指令

3.5.2 数据运算类指令

3.算术运算指令

加减乘除

4.逻辑运算指令

与或非异或

5.移位和循环指令

逻辑左移右移 循环移动

6.符号扩展指令(展开指令)

7.数据调序指令(字节交换指令)

比如一个字当中的4个字节变换位置(字节交换)

8.饱和运算指令

3.5.3 位域处理类指令

9.位处理指令

对某一个字节单独的位处理

3.5.4 控制转移类指令

10.子程序调用与无条件转移指令

11.条件转移指令

12.隔离指令

4.4 ARM汇编语言的程序结构

4.4.1 汇编语言的程序格式

4.4.2 汇编语言子程序调用

  • 调用方法:BL子程序名
  • 调用过程:返回地址存放在连接寄存器LR中,同时将程序计数器PC指向子程序的入口点。
  • 调用返回:当子程序返回时,将存放在LR中的返回地址重新拷贝给程序计数器PC。
  • 参数传递:R0-R3
    - 最多传递4个,多出的要用堆栈处理
  • 结果返回
    • R0,返回32位数
    • R0,R1返回64位数
    • ….以此类推

比如:

4.4.3 过程调用标准AAPCS

二、ARM寄存器使用规则

  • 子程序间通过寄存器R0、R1、R2、 R3来传递参数。如果参数多于4个,则多出的部分用堆栈传递。被调用的子程序在返回前无需恢复寄存器R0-R3的内容。
  • 在子程序中,使用寄存器R4-R11来保存局部变量.如果在子程序中使用到了寄存器R4-R11中的某些寄存器,子程序进入时必须保存这些寄存器的值,在返回前必须恢复这些寄存器的值;对于子程序中没有用到的寄存器则不必进行这些操作。在Thumb程序中,通常只能使用寄存器R4-R7来保存局部变量

4.4.4 scatter文件的使用

  • 告知编译器地址信息的方法有两种
    • 使用命令行(简单的情况)
    • 使用scatter文件

scatter file—-分散加载文件

分散加载区域分为两部分:加载区和执行区。每个加载区可以创建一个或多个执行区 。

程序设计

1
2
3
4
5
6
7
8
9
10
11
12
分支程序设计
已知32位有符号数X存放在存储器的地址0x90010中,要求实现:
Y=X (X〉=0)或 Y=-X (X<0

LDR R1,= 0x90010
LDR R2,[R1]
MOV R0#0
CMP R2R0 ;比较
SUBLT R2R0R2;小于0
STR R2,[R1]
END

4.6.6 汇编程序调用C程序

下面是C语言定义的子程序函数,为汇编调用

1
2
3
4
int g(int a, int b, int c, int d, int e) 
{
return a + b + c + d + e;
}

下面是汇编调用C语言子程序的程序段。假设程序进入f时,R0中的值为 i

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
; int f(int i) { return g(i, 2*i, 3*i, 4*i, 5*i); }
PRESERVE8 ; 预编译,8字节对齐,遵从AAPCS规则
EXPORT f ; 申明可以被其他文件调用的符号
AREA f, CODE, READONLY
IMPORT g ; 声明外部C程序g()
STR lr, [sp, #-4]! ; 保存返回地址 lr
ADD R1, R0, R0 ; 计算2*i(第2个参数),a = R0,b = R1
ADD R2, R1, R0 ; 计算3*i(第3个参数),c = R2
ADD R3, R1, R2 ; 计算5*I ,e = 堆栈传递
STR R3, [sp, #-4]! ; 第五个参数通过堆栈传递
ADD R3, R1, R1 ; 计算4*i(第4个参数),d = R3
BL g ; **调用C程序**
ADD sp, sp, #4 ; 从堆栈中删除第5个参数
LDR pc, [sp], #4 ; 返回
END

第五章 ARM Cortex-M3微处理器的体系构架 Contents Contents

5.1 Cortex-M3微处理器的内部功能组成

    这部分知道就好

一、框图中应用程序可访问的组件

NVIC - 嵌套向量控制器

二、框图中用于调试的组件

三、Cortex-M3 的总线接口

5.2 存储器系统

5.2.1 存储器系统的功能概览

  • ① Cortex-M3 只有一个单一固定的存储器映射。

  • ② Cortex-M3的存储器映射是预定义的,并且规定好了哪个位置使用哪条总线。

  • ③ Cortex-M3 的存储器系统支持所谓的位带——位寻址操作。通过它,可以实现对单一比特的原子操作。位带操作仅适用于一些特殊的存储器区域。

    不可分割、打断的操作
    
  • ④ Cortex-M3 的存储器系统支持非对齐访问和互斥访问。这两个特性是直到了v7M 时才出来的。

  • ⑤ Cortex-M3 的存储器系统支持小端配置和大端配置