STM32涉及到的汇编基础知识

本文为使用汇编开发STM32系列文章之----基础知识篇,全部文章目录点此跳转。


★说明★:本文暂不深究其中的原理,仅描述与汇编相关的简要知识点,相关细节将会在后续文章使用到时详细说明。

一、STM32F1内核基础知识

1.Cortex-M3 内核结构

  STM32F1使用的是属于ARMv7-M架构的ARM Cortex-M3 内核 ,是一个32位的处理器内核,其内部的数据路径是32位的、寄存器是32位的以及存储器接口也是32位的。并且使用了哈佛结构,拥有独立的指令总线和数据总线为数字信号的处理提供了较高的性能。下方是Cortex-M3 内核的简略图。
在这里插入图片描述

2.Cortex-M3 内核的指令

  Cortex-M3 内核只使用Thumb‐2 指令集,其中既包括16位的指令,又包括32位的指令,这使得在编程时不必再像从前一样去手动切换指令状态(32 位的ARM 状态和 16 位的 Thumb 状态,切换时会消耗额外的切换时间),即可达到性能和存储之间的平横。因为在32位指令下,性能极高;而在16位指令下,代码密度提高了一倍,可以在相同的内存和缓存中存放更多的指令。
  为了使芯片结构保持简单情况下进一步提升系统的运行效率,Cortex-M3 内核采用简单的3级流水线。每个指令的执行分为三个步骤:取指令、译码和执行。"取指令"时需要通过指令总线读取存储器中的对应指令,此操作会占用指令总线;"译码"时将指令转换为具体的控制信号,不占用任何总线;"执行"时进行读取寄存器堆栈、操作数在通信移位器中移位、ALU产生相应的运算结果并写到目的寄存器中并根据需求更改状态寄存器条件位,此时占用数据总线。
  因为Cortex-M3 内核使用的是哈弗结构,具有单独的数据总线和指令总线,所以在组成3级流水线时,这三个操作并不会相互影响,从而将单个指令的执行时间为3周期,但在单周期内可以有1个指令的吞吐率。单周期指令的3级流水线如下如图所示。
在这里插入图片描述

3.Cortex-M3 内核的寄存器组

  Cortex-M3内核拥有通用寄存器 R0‐R15 以及一些特殊功能寄存器,其中R0-R12属于通用寄存器,但是大多数的16位指令只能使用R0‐R7(低组寄存器),而 32 位的指令则可以访问所有通用寄存器。特殊功能寄存器有预定义的功能,而且必须通过专用的指令来访问。寄存器组如下图所示。
在这里插入图片描述

3.1 堆栈指针寄存器(MSP和PSP)

  R13是堆栈指针寄存器,且Cortex-M3 内核中共有两个堆栈指针,分别是主堆栈指针(MSP)和进程堆栈指针(PSP)。主堆栈指针(MSP)是缺省的堆栈指针,它由 OS 内核、异常服务例程以及所有需要特权访问的应用程序代码来使用。进程堆栈指针(PSP),用于常规的应用程序代码(不处于异常服用例程中时)。因为有两个堆栈指针,所以Cortex-M3 内核也就支持两个堆栈。当引用 R13(或写作SP)时,你引用到的是当前正在使用的那一个,另一个必须用特殊的指令来访问(MRS,MSR 指令)。而且堆栈指针的最低两位永远是 0,这意味着堆栈总是 4 字节对齐的。
注:在 ARM 编程领域中,凡是打断程序顺序执行的事件,都被称为异常(exception)。在不严格的上下文中,异常与中断也可以混用。

3.2 连接寄存器(LR)

  R14是连接寄存器(LR),用于在调用子程序时存储返回地址。

3.3 程序计数器(PC)

  R15是程序计数器(PC),用于指示下次欲执行的指令的地址,因为 CM3 内部使用了指令流水线,读 PC 时返回的值是当前指令的地址+4。

3.4 特殊功能寄存器

  特殊功能寄存器包含三种功能的寄存器:程序状态寄存器(xPSR或PSR)、中断屏蔽寄存器和控制寄存器(CONTROLl)。他们只能用MSR和MRS指令访问,而且他们也没有寄存器地址。

3.4.1 程序状态寄存器(xPSR或PSR)

程序状态寄存器内部各位定义如下:
在这里插入图片描述
✦N:正负标志,N=1表示运算结果为负数,N=0表示运算结果为正数或者0。
✦Z:零标志,Z=1表示运算结果为0,Z=0表示运算结果为非0。
✦C:加法运算时表示进位标志,C=1表示产生进位,C=0表示未产生进位;减法运算时表示借位标志,C=0表示产生借位,C=1表示未产生借位;
✦V:溢出标志,V=1表示有溢出,V=0表示无溢出。
✦Q:表示增强的DSP指令是否发生溢出,在ARMv7-M架构的ARM Cortex-M3 内核无定义。
✦ICI/IT[26:25]:暂未找到解释,后期再补上。
✦T:暂未找到解释,后期再补上。
✦ICI/IT[15:10]:暂未找到解释,后期再补上。
✦Exception Number[8:0]:中断号。

3.4.2 中断屏蔽寄存器

  中断屏蔽寄存器包含三个寄存器,用于控制异常的使能和除能。只有在特权级下,才允许访问这 3 个寄存器。
  ✦PRIMASK:此寄存器只有一个位,设置为1时,会关闭所有的可屏蔽异常(中断),只有NMI和硬件异常(fault)可以相应。默认值0。
  ✦FAULTMASK:此寄存器只有一个位,设置为1时,只有NMI会响应,其他的所有异常(中断)和硬件异常(fault)全部关闭响应。默认值0。
  ✦BASEPRI:这个寄存器最多有 9 位(由表达优先级的位数决定)。它定义了被屏蔽优先级的阈值。当它被设成某个值后,所有优先级号大于等于此值的中断都被关(优先级号越大,优先级越低)。但若被设成 0,则不关闭任何中断,0 也是默认值。

3.4.3 控制寄存器(CONTROL)

  控制寄存器用于定义特权级别,还用于选择当前使用哪个堆栈指针。

功能
CONTROL[1]堆栈指针的选择;
0 = 选择主堆栈指针 MSP(复位后缺省值)
1 = 选择进程堆栈指针 PSP
在线程或基础级(没有在响应异常——译注),可以使用 PSP。
在 handler 模式下,只允许使用 MSP,所以此时不得往该位写 1。
CONTROL[0]0 = 特权级的线程模式;
1 = 用户级的线程模式;
Handler模式永远都是特权级的。

4.Cortex‐M3 内核的操作模式

  Cortex‐M3 支持 2 个模式:处理者模式(handler模式)和线程模式(Thread模式),以及两个特权等级:特权级和用户级。当处理器处在线程状态下时,既可以使用特权级,也可以使用用户级;另一方面,处理者模式总是特权级的。在复位后,处理器进入线程模式+特权级。对应的模式和级别关系如下图所示。

.特权级用户级
异常时处理的代码处理者模式错误用法
主应用程序的代码线程模式线程模式

  在特权级下的代码可以通过置位 CONTROL[0]来进入用户级。而不管是任何原因产生了任何异常,处理器都将以特权级来运行其服务例程,异常返回后将回到产生异常之前的特权级。用户级下的代码不能再试图修改 CONTROL[0]来回到特权级。它必须通过一个异常 handler,由那个异常 handler 来修改 CONTROL[0],才能在返回到线程模式后拿到特权级。改变流程如下图所示。
在这里插入图片描述

5.Cortex‐M3 内核的异常

  Cortex‐M3 内核支持大量异常,包括 11 个系统异常和最多240个外部中断(IRQ),但是外部中断具体用多少个要看具体的MCU的设计。异常说明以及向量表偏移地址,如下表所示。其中异常标号用于分辨当先发生的异常类型,以及根据偏移地址计算中断回调函数的地址。异常编号可以在程序状态寄存器(xPSR或PSR)中获取到。

异常编号类型偏移地址优先级简介
0N/A0x00N/A异常编号为0表示此时无异常发生。
因为此时无异常,故向量表偏移地址0x00处无中断回调函数,所以此处用来存储MSP(主堆栈指针)的初始值。
1复位0x04-3(最高)复位中断,偏移地址0x04处存放复位中断回调函数地址。
特殊的,此处存储的地址在内核上电复位后自动赋值给PC(程序计数器指针),故程序会首先运行复位中断回调函数。
2NMI0x08-2不可屏蔽中断(来自外部 NMI 输入脚)。
3硬件异常
(hard fault)
0x0C-1当被失能的异常触发时将产生硬件异常(hard fault)。
4存储器管理异常
(Mem Manage fault)
0x10可编程存储器管理异常。
MPU 访问犯规以及访问非法位置均可引发。企图在“非执行区”取指也会引发此 fault。
5总线异常0x14可编程从总线系统收到了错误响应,原因可以是预取流产(Abort)或数据流产,或者企图访问协处理器
6用法异常0x18可编程由于程序错误导致的异常。通常是使用了一条无效指令,或者是非法的状态转换,例如尝试切换到 ARM 状态。
7-10保留0x1C-0x28N/AN/A
11SVCall0x2C可编程执行系统服务调用指令(SVC)引发的异常
12调试监视器异常0x30可编程调试监视器发起的请求产生的异常,包括设置的断点,数据观察点,或者是外部调试请求。(注意,异常并不一定是错误,所有打断正常循序执行的事件都称为异常)
13保留0x34N/AN/A
14PendSV0x38可编程为系统设备而设的“可悬挂请求”(pendable request)
15SysTick0x3C可编程系统滴答定时器(周期性溢出的一个内核级别的定时器)
16-255外部中断16-2550x40-0x3FF可编程外部中断16 到 外部中断255
“外部”指 Cortex‐M3 内核的外部,与stm32的外部中断注意区分。

  在发生异常时,Cortex‐M3 内核会自动将寄存器中的值保存至栈中(俗称现场保护),再跳转至中断回调函数进行处理,处理完毕后自动将栈中的寄存器值还原到之前的寄存器,然后继续执行原先正在执行的程序。

二、STM32F1基础外设知识

1.内存分布

  STM32F103x的内存分布如下图所示。左侧部分是 Cortex‐M3 内核给出的可寻址的内存全部地址,框内的说明是STM32F1使用的情况,右侧引出的部分是本系列教程会涉及到的关键内容及地址。在后期文章实际用到时会详细说明。
在这里插入图片描述

2.启动配置

  在上面的内存分布小节的图中可以看到地址0x0000 0000 - 0x0007 FFFF处的内存作用是不定的,可以是Flash也可以是系统内存,并且被BOOT引脚设置。接下来将介绍这么做的原因。
  因为Cortex-M3内核在启动时始终从代码区0x0000 0000开始,导致在启动时只能从Cortex-M3内核设置的flash启动。而STM32F1系列单片机将开始的0x0000 0000 - 0x0007 FFFF地址空出来,并且通过后期映射的方法实现了从FLASH启动、系统存储器启动以及SRAM启动的功能。

  在STM32F10xxx里,可以通过BOOT[1:0]引脚选择三种不同启动模式,如下表所示。

启动模式选择引脚启动模式说明
BOOT1BOOT0
X0FLASHFLASH被选为启动区域
01系统存储器系统存储器被选为启动区域
11SRAMSRAM被选为启动区域
  根据选定的启动模式,FLASH、系统存储器或SRAM可以按照以下方式访问:

  ● 从FLASH启动:FLASH被映射到启动空间(0x0000 0000),但仍然能够在它原有的地址(0x0800 0000)访问它,即FLASH的内容可以在两个地址区域访问,0x0000 0000或0x0800 0000。
  ● 从系统存储器启动:系统存储器被映射到启动空间(0x0000 0000),但仍然能够在它原有的地址0x1FFF F000访问它。
  ● 从内置SRAM启动:只能在0x2000 0000开始的地址区访问SRAM。

3.时钟树与系统结构

  对于时钟树的理解其实是很简单的,只要下载个官方配置软件:STM32CubeMX,进入时钟配置界面,可以一目了然的看到各个时钟的走向,各种倍频分频可设置部分非常详尽,每个外设所挂载的总线很容易获取。下图是我翻译后的版本,图很高清,请点击打开后观看。

请添加图片描述
  在下方的STM32F1系统结构图中可以很清楚的看到各种外设、总线之间的关系,可以获取APB1总线和APB2总线下到底连接着哪些外设。
在这里插入图片描述

4.GPIO

  GPIO全名叫做General-purpose input/output,即多功能(或通用)输入输出引脚,从名称即可知道GPIO口可以设置为多种模式。可设置的模式中共有三大种类:输出模式、输入模式和复用模式。而根据电路结构又可以分为上拉、下拉、浮空、推挽等模式。下表只描述常用功能,复用等其他特殊功能后期用到在详细说。

模式结构全称
输入上拉上拉输入
下拉下拉输入
浮空浮空输入
模拟模拟输入
输出推挽推挽输出
开漏开漏输出
  每个GPIO端口有7个32位的常用配置寄存器,例如GPIOA口的七个常用寄存器功能和地址如下表所示,其他端口除了地址不同外其他与此完全一致。
寄存器名称地址功能
GPIOA_CRL0x4001 0600端口配置低寄存器
设置GPIOA 0-7引脚的输入输出模式及IO翻转速度
GPIOA_CRH0x4001 0620端口配置高寄存器
设置GPIOA 8-15引脚的输入输出模式及IO翻转速度
GPIOA_IDR0x4001 0640端口输入数据寄存器
读取GPIOA 16个引脚的状态值
GPIOA_ODR0x4001 0660端口输出数据寄存器
控制GPIOA 16个引脚的输出高低电平,会一次性控制16个引脚状态
GPIOA_BSRR0x4001 0680端口位设置/清除寄存器
将GPIOA 16个引脚的某些引脚的输出设置为1清除为0,可单独操作某些引脚
GPIOA_BRR0x4001 06A0端口位清除寄存器
将GPIOA 16个引脚的某些引脚的输出清除为0,可单独操作某些引脚
GPIOA_LCKR0x4001 06C0端口配置锁定寄存器
该寄存器用来锁定端口位的配置,设置后在下次系统复位之前将不能再更改端口位的配置

三、ARM汇编指令

1.ARM汇编语言基础语法

  ARM汇编指令一般较为完整的书写格式如下所示:

{标号}
   操作码{执行条件}{S} 目的寄存器,操作数 1,操作数 2, …  {;注释}

注:{ }不包含在内,意思为{ }中的内容是可选的。

其中:
  ①标号是可选的,如果有,它必须顶格写。标号的作用是让汇编器来计算程序转移的地址,类似与C语言里的函数名。
  ②操作码是指令的助记符,也就是常写的汇编指令,它的前面必须有至少一个空白符,通常使用一个 “Tab” 键来产生。
  ③操作码紧跟的是执行条件后缀,要紧贴操作码写。可以空着不写,表示无条件执行本指令。执行条件往往配合比较指令来使用。执行条件如下表所示(稍微往后放一下,以防打乱阅读节奏)。
  ④执行条件后紧跟影响标志后缀:S,如果没有执行条件则紧贴操作码写。S可以空着不写,表示此指令执行的结果不影响程序状态寄存器(xPSR或PSR)的值。但是在使用比较指令时,无需加S即可改变程序状态寄存器(xPSR或PSR)的值。
  ⑤目的寄存器,指令执行后结果的存放寄存器。
  ⑥操作数往往会有若干个,不同指令需要不同数目的操作数,并且对操作数的语法要求也可以不同。

注:“x” 表示与之比较的值。

条件码助记符含义使用 程序状态寄存器(xPSR或PSR) 的相关位
EQ= xZ = 1
NE≠ xZ = 0
CS无符号数 ≥ xC = 1
CC无符号数 < xC = 0
MIx 为负数N = 1
PLx 为正数或0N = 0
VS溢出V = 1
VC未溢出V = 0
HI无符号数 > xC = 1 且 Z = 0
LS无符号数 ≤ xC = 0 且 Z = 1
GE有符号数 ≥ xN = V
LT有符号数 < xN ≠ V
GT有符号数 > xZ = 0 且 N = V
LE有符号数 ≤ xZ = 1 或 N ≠ V
AL无条件执行忽略

  为了可以更好的理解,现举几个例子进行说明。其中MOV是数据传送指令,CMP是比较指令(比较指令无需加S后缀便可自动更新程序状态寄存器的标志位)。普通数值前加符号"#“表示为常数数值,在汇编语言中称为"立即数”。
注意:ARM汇编指令可以使用大写字母也可以小写字母,只要统一格式即可,只要有一处用大写字母就要全部用大写字母,反之全部用小写字母。
请添加图片描述

2.Thumb-2 常用指令

  下表仅列出Thumb-2 常用的一些指令,后期用到时再做详细使用说明。

指令助记符描述 指令助记符描述
ADC带进位加法LSR逻辑右移
ADD加法MOV数据传送
AND逻辑与MUL乘法
ASR算术右移MVN取反后的数据传送
B分支指令NEG取反
BIC逻辑位清除ORR逻辑或运算
POP出栈PUSH压栈
BL带链接的相对分支指令BLX带交换的分支指令
ROR循环右移CMN相反数比较
SBC带借位减法CMP比较指令
STM多寄存器存储EOR逻辑异或
STR单寄存器数据存储LDM多寄存器加载
SUB减法LDR单寄存器加载
LSL逻辑 左移SWI软中断
BKPT断点指令TST位测试

3.常用伪指令

3.1 Thumb的伪指令

  Thumb的伪指令不是Thumb指令集中的指令,只是为了编程方便而定义的伪指令,使用时可以像其他的Thumb指令一样使用,但在编译的时候编译器会将其替换为Thumb存在的等效指令。Thumb的伪指令共有三个:ADR、LDR和NOP。其中LDR伪指令与Thumb中的LDR指令的区别是,LDR伪指令的参数中有等号:“=”。其他两个都是新符号。

伪指令助记符格式功能说明
ADRADR 目标寄存器,地址表达式获取地址值,可以是获取某标号处的地址值
注意:要获取的地址值相对程序计数器(PC)的地址之间的偏移量要为正数并小于1KB。
NOPNOP空操作
会被替换为像如 "MOV R0,R0"这样的指令
LDRLDR 目标寄存器,=地址表达式用于加载一个32位立即数或一个地址值到目标寄存器。
注意:如果要加载的常数超过MOV或MVN的范围,则会创建文字池,那么文字池地址值相对程序计数器(PC)的地址之间的偏移量要小于1KB。

3.2 ARMCC编译器的伪指令

  RAMCC编译器是Keil5软件带有的ARM编译器,RAMCC编译器的伪指令是用于告诉RAMCC编译器如何进行汇编的指令。暂时整理以下常用伪指令,后期有需要在添加和详细说明。

伪指令助记符格式功能说明
AREAAREA 段名 属性1,属性2…定义一个代码段或者数据段
ENTRYENTRY汇编程序的入口点
ENDEND汇编程序的程序的结尾
EQU常量名 EQU 常量数值定义一个常量,相当于c语言中的 define
EXPORTEXPORT 标号声明一个全局的标号,可以在其他文件使用声明的标号
IMPORTIMPORT 标号通知编译器要使用一个在其他文件中定义的标号,相当于c语言中的 extern
DCDDCD 表达式用于分配一片连续的字存储单元并用伪指令中指定的表达式初始化,表达式可以是程序标号或数字表达式
PROCPROC表示一个汇编子程序的开始。相当于C语言中函数开始。
ENDPENDP表示一个汇编子程序的结束。相当于C语言中函数结束。

四、参考文献

[1]Cotex-M3权威指南(中文版),宋岩(译)
[2]汇编语言程序设计–基于ARM体系结构(第2版),北京航空航天大学出版社。
[3]STM32F103xCDE_DS_CH_V5.pdf

最后,由于本人水平有限,文中难免出现错误,敬请大家批评指正,感谢!🙏

  • 19
    点赞
  • 111
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

超级网吧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值