IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32涉及到的汇编基础知识 -> 正文阅读

[嵌入式]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

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

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-04-09 18:36:52  更:2022-04-09 18:38:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 4:47:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码