Cortex-M3/M4基础

2023-09-22 12:17:45

一、Cortex-M3/M4 通用寄存器

1、我们首先来了解一下M3/M4的寄存器,M4比M3多了一个浮点单元FPU。其他的部分基本和M3是一样的。

2、Cortex-M3/M4系列处理器拥有通用寄存器R0-R15以及一些特殊功能的寄存器。

3、R0‐ R12 是最“通用目的”的。

4、但是绝大多数的 16 位指令只能使用 R0‐ R7(低组寄存器),而 32 位的 Thumb‐ 2 指令则可以访问所有通用寄存器。这里提到Thumb-2指令,我简单地介绍一下。

Thumb-2是一种精简指令集(RISC)架构,最初由ARM公司开发,并广泛用于ARM处理器上。Thumb-2指令集是ARM指令集的一个扩展,旨在提高代码密度和执行效率

Thumb-2指令集提供了两种指令集状态:Thumb状态和Thumb-2状态。在Thumb状态下,指令长度为16位,相对于32位的ARM指令来说,代码密度更高。在Thumb-2状态下,指令长度可以是16位或32位,这样就可以运行更复杂的指令,提高程序的执行效率。

Thumb-2指令集具有以下特点:

  1. 兼容性:Thumb-2指令集能够与之前的Thumb指令集和ARM指令集兼容,既可以在Thumb状态下执行16位指令,也可以在Thumb-2状态下执行32位指令。
  2. 代码密度:Thumb-2指令集通过使用16位指令来减小代码大小,从而提高代码密度。这对于存储空间受限或带宽有限的嵌入式系统尤为重要。
  3. 执行效率:Thumb-2指令集在Thumb-2状态下可以执行更复杂的指令,包括对大多数ARM指令的支持,从而提高执行效率和系统性能。

总而言之,Thumb-2指令集是ARM处理器上一种具有代码密度和执行效率优势的指令集,适用于各种嵌入式系统和移动设备应用。

 5、特殊功能寄存器有预定义的功能,而且必须通过专用的指令来访问, Cortex-M3/M4 的通用寄存器如图所示。

基于上图,我将逐一讲解各种寄存器的作用。

1)通用目的寄存器 R0-R7

R0‐ R7 也被称为低组寄存器。所有指令都能访问它们。它们的字长全是 32 位,复位后的初始值是不可预料的。
2)通用目的寄存器 R8-R12

R8‐ R12 也被称为高组寄存器。这是因为只有很少的 16 位 Thumb 指令能访问它们,32位的指令则不受限制。它们也是 32 位字长,且复位后的初始值是不可预料的。

3)堆栈指针 R13

R13 是堆栈指针。在 CM3/CM4 处理器内核中共有两个堆栈指针,于是也就支持两个堆栈。当引用 R13(或写作 SP)时,你引用到的是当前正在使用的那一个,另一个必须用特殊的指令来访问( MRS,MSR 指令)。这两个堆栈指针分别是:


(1)、主堆栈指针(MSP),或写作 SP_main。这是缺省的堆栈指针,它由 OS 内核、异常服务例程以及所有需要特权访问的应用程序代码来使用。


(2)、进程堆栈指针(PSP),或写作 SP_process。用于常规的应用程序代码(不处于异常用例程中时)。要注意的是,并不是每个应用都必须用齐两个堆栈指针。简单的应用程序只使MSP 就够了。堆栈指针用于访问堆栈,并且 PUSH 指令和 POP 指令默认使用 SP


4)连接寄存器 R14
1、R 1 4 是连接寄存器( L R)。在一个汇编程序中,你可以把它写作 b o t h LR 和 R14。

2、LR 用于在调用子程序时存储返回地址。例如,当你在使用 BL(分支并连接, Branch and Link)指令时,就自动填充 LR 的值。尽管 PC 的 LSB 总是 0(因为代码至少是字对齐的), LR 的 LSB 却是可读可写的。这是历史遗留的产物。在以前,由位 0 来指示 ARM/Thumb 状态。因为其它有些 ARM 处理器支持 ARM 和 Thumb 状态并存,为了方便汇编程序移植, CM3/CM4 需要允许 LSB 可读可写。

5)程序计数器 R15
1、R15 是程序计数器,在汇编代码中你也可以使用名字“PC”来访问它。
2、因为 CM3/CM4内部使用了指令流水线,读 PC 时返回的值是当前指令的地址+4。

例如:

ox1000: MOV   R0,  PC   ;    R0 = 0x1004

3、如果向 PC 中写数据,就会引起一次程序的分支(但是不更新 LR 寄存器)。CM3/CM4中的指令至少是半字对齐的,所以 PC 的 LSB 总是读回 0。

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

6)特殊功能寄存器组

1、程序状态寄存器组( PSRs 或者 xPSR)

2、中断屏蔽寄存器组( PRIMASK, FAULTMASK,以及 BASEPRI)

3、控制寄存器( CONTROL)

注意:它们只能被专用的 MSR 和 MRS 指令访问,而且它们也没有存储器地址

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

 7)程序状态寄存器(PSRs 或曰 PSR)

1、应用程序 PSR( APSR)

2、中断号 PSR( IPSR)

3、执行 PSR( EP SR)

说明:通过 M RS / M S R 指令,这 3 个 PSR s 既可以单独访问,也可以组合访问( 2 个组合, 3 个组合都可以)。当使用三合一的方式访问时,应使用名字“ xPSR”或者“ PSR”。三个寄存器的各个位的含义如下图。

PRIMASK,FAULTMASK 和 BASEPRI
这三个寄存器很重要,这三个寄存器用于控制异常的使能和除能,这三个寄存器的介绍如下图:


 

 说明:对于时间‐关键任务而言, PRIMASK 和 BASEPRI 对于暂时关闭中断是非常重要的。 而
FAULTMASK 则可以被 OS 用于暂时关闭 fault 处理机能,这种处理在某个任务崩溃时可能需要。因为在任务崩溃时,常常伴随着一大堆 faults。在系统料理“后事”时,通常不再需要响应这些 fault——人死帐清。总之 FAULTMASK 就是专门留给 OS 用的。

要访问 PRIMASK, FAULTMASK 以及 BASEPRI,同样要使用 MRS/MSR 指令,如:

MRS R0,
MRS R0,
MRS R0,
MSR BASEPRI,
MSR FAULTMASK,
MSR PRIMASK,
BASEPRI
FAULTMASK
PRIMASK
R0
R0
R0
; 读取 BASEPRI 到 R0 中
; 同上
; 同上
; 写入 R0 到 BASEPRI 中
; 同上
; 同上

只有在特权级下,才允许访问这 3 个寄存器, 为了快速地开关中断, CM3/CM4 还专门设置了一条 CPS 指令,有 4 种用法,这四种用法非常重要,我们在移植 UCOS 操作系统的时候就是用这下面的方法来开关中断的。

CPSIDI;PRIMASK=1,; 关中断
CPSIEI;PRIMASK=0,; 开中断
CPSIDF;FAULTMASK=1, ; 关异常
CPSIEF;FAULTMASK=0; 开异常

 8)控制寄存器(CONTROL)

CONTROL 寄存器用于定义特权级别和堆栈指针的使用, CONTROL 寄存器如下表 所示,注
意 CONTROL[2]只有 Cortex-M4 才有。

 CONTROL[2]
Cortex-M4 中有 FPU 单元如果我们使用了 FPU,那么在处理异常时就需要保存 FPU 环境, 此位用来指示是否需要保存浮点环境。

 CONTROL[1]
在 Cortex‐ M3 的 handler 模式中, CONTROL[1]总是 0。在线程模式中则可以为 0 或1。仅当处于特权级的线程模式下,此位才可写,其它场合下禁止写此位。改变处理器的模式也有其它的方式:在异常返回时,通过修改 LR 的位 2,也能实现模式切换。

CONTROL[0]
仅当在特权级下操作时才允许写该位。一旦进入了用户级,唯一返回特权级的途径,就是触发一个(软)中断,再由服务例程改写该位。 CONTROL 寄存器也是通过 MRS 和 MSR 指令来操作的:
 

MRSR0,CONTROL
MSRCONTROL,R0

 9)EXC_RETURN

在进入异常服务程序后, L R 的值被自动更新为特殊的 EXC_RETURN,对于 Cortex-M4
来说这是一个高 27 位全为 1 的值(M3 是高 28 位都为 1)。 M4 中[4:0]位有意义,在 M3 中[3:0]
有意义,并且和 M4 中的相同, EXC_RETURN 位段如表 2.1.4 所示。
注意! EXC_RETURN 的 bit4 非常重要,我们可以根据此位的值来获知硬件会对哪些寄存器进
行自动压入栈和出栈处理。

二、操作模式和特权级别

1、Cortex-M3/CM4 处理器支持两种处理器的操作模式,还支持两级特权操作。

2、两种操作模式分别为: 处理者模式 (handler mode)和线程模式(thread mode)。引入两个模式的本意,是用于区别普通应用程序的代码和异常服务例程的代码——包括中断服务例程的代码。

3、Cortex-M3/M4 的另一个侧面则是特权的分级——特权级和用户级。这可以提供一种存储器访问的保护机制,使得普通的用户程序代码不能意外地,甚至是恶意地执行涉及到要害的操作。处
理器支持两种特权级,如表 2.2.1 所示,这也是一个基本的安全模型。

 说明:在 CM3/CM4 运行主应用程序时(线程模式),既可以使用特权级,也可以使用用户级;但是异常服务例程必须在特权级下执行。复位后,处理器默认进入线程模式,特权级访问。在特权级下,程序可以访问所有范围的存储器(如果有 MPU,还要在 MPU 规定的禁地之外),并且可以执行所有指令。

在特权级下的程序可以为所欲为,但也可能会把自己给玩进去——切换到用户级。一旦进入用户级,再想回来就得走“法律程序”了——用户级的程序不能简简单单地试图改写CONTROL 寄存器就回到特权级, 事实上,从用户级到特权级的唯一途径就是异常如果在程序执行过程中触发了一个异常,处理器总是先切换入特权级,并且在异常服务例程执行完毕退出时,返回先前的状态。
 

更多推荐

Controller统一异常处理和yaml配置

目录Controller统一异常处理url解析static下静态资源文件的访问配置类如何访问static下的资源文件yaml基础语法注解赋值批量注入单个注入Controller统一异常处理Controller统一异常处理@ControllerAdvice:统一为Controller进行"增强"@ExceptionHan

微信小程序的疫苗接种预约设计与实现vue+uniapp

对于本小程序的疫苗预约的设计来说,系统开发主要是采用java语言,在整个系统的设计中应用MySql数据库来完成数据存储,具体根据疫苗预约信息的现状来进行开发的,具体根据现实的需求来实现疫苗预约网络化的管理,各类信息有序地进行存储,进入微信小程序的疫苗预约页面之后,方可开始操作主控界面,主要功能包括用户、疫苗分类、疫苗信

html学习综合案例1

<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>个人简介</title></head><body><h1>尤

【c++&GDAL】IHS融合

【c++&GDAL】IHS融合基于IHS变换融合,实现多光谱和全色影像之间的融合。IHS分别指亮度(I)、色度(H)、饱和度(S)。IHS变换融合基于亮度I进行变换,色度和饱和度空间保持不变。IHS融合步骤:(1)将多光谱RGB影像变换到IHS空间;(2)基于一定融合规则使用亮度分量I与全色影像进行变换,得到新的全色I

WebGL 选中物体

目录前言如何实现选中物体示例程序(PickObject.js)代码详解gl.readPixels()函数规范示例效果前言有些三维应用程序需要允许用户能够交互地操纵三维物体,要这样做首先就得允许用户选中某个物体。对物体进行选中操作的用处很广泛。比如,让用户选中三维用户界面上的一个按钮,或者让用户选中三维场景中的多张照片中

提升前端开发效率:基于vue的van-radio-group组件封装指南

前言vant作为一款流行的ui框架,其中,van-radio-group组件是一个常用的单选框组件,但有时我们需要根据项目需求进行定制化封装。本文将介绍如何基于vue框架封装van-radio-group组件,让我们一起来探索吧!封装文件在这个组件中,使用了vant框架提供的van-radio-group和van-ra

Linux-网卡和网络配置

链接一篇大佬的博客:Linux之手把手教会修改网卡名称文章目录修改网卡名称步骤1:修改“/etc/default/grub”步骤2:修改“/etc/sysconfig/network-scripts”下的文件步骤3:修改“ifcfg-eth0”配置步骤4:判断操作系统的引导模式步骤5:根据不同的引导模式重新读取配置文件

el-table 列背景色渐变

最初的想法是,给每一行添加背景色,逐行递减透明度,发现结果比较突兀,效果如下:如果有需要这种样式的,代码如下:<template><div><el-table:data="tableData":header-cell-style="headerCellStyle":cell-style="cellStyle"style

Redis Part1

单体架构:一台Web服务器、一台数据库服务器。回顾,关系型数据库:基于二维表来存储数据的数据库就是关系型数据库。MySQL跟Redis的区别:MySQL是关系型数据库,它是基于表来存储数据的,MySQL数据是写在磁盘的,它是跟磁盘进行交互的;Redis是非关系型数据库,它是把数据存储在内存当中的,是跟内存进行交互的。M

Go基础语法:数组

6数组6.1数组的定义数组在定义时就需要声明其元素数量和类型://T即元素类型var数组变量名[元素数量]T如:vara[5]int.数组的长度必须是常量,并且长度是数组类型的一部分,一旦定义,长度不能变。所以,[5]int和[10]int是不同的类型。packagemainimport"fmt"funcmain(){

功能基础篇3——Python中的输入输出、文件读写、序列化

IO文件读写openopen()为内置函数,用于读写文件mode读写x,create,创建,文件存在报错,可写不可读r,read,读入,默认读写方式,文件不存在报错,可读不可写w,write,写入,文件不存在会创建文件,存在清空文件内容,可写不可读a,append,追加,文件不存在会创建文件,光标移至文件末尾,可写不可

热文推荐