深入理解 Cortex-M3 特殊寄存器
在上一篇文章中分享了 Cortex-M3 内核寄存器组的相关知识,实际上除了内核寄存器组外,CM3 处理器中还存在多个特殊寄存器,它们分别为 程序状态寄存器,中断/异常屏蔽寄存器 和 控制寄存器。
需要注意的是,特殊寄存器未经过存储器映射,即没有对应的存储器地址,也只能使用专门的 MSR 和 MRS 等特殊寄存器访问指令来进行访问:
MRS <reg> <special_reg> ;将特殊寄存器读入寄存器
MSR <special_reg> <reg> ;写入特殊寄存器
CMSIS-Core 也提供了几个用于访问特殊寄存器的 C 函数,其本质也是以上两个指令的封装。如在 gcc 环境下(cmsis_gcc.h),对 CONTROL 寄存器的操作如下:
__STATIC_FORCEINLINE uint32_t __get_CONTROL(void)
{uint32_t result;__ASM volatile ("MRS %0, control" : "=r" (result) );return(result);
}__STATIC_FORCEINLINE void __set_CONTROL(uint32_t control)
{__ASM volatile ("MSR control, %0" : : "r" (control) : "memory");
}
接下来我们看一下这些特殊寄存器的具体含义。
程序状态寄存器(PSRs 或 xPSR)
程序状态寄存器包含以下三个状态寄存器:
-
应用 PSR(APSR)
-
执行 PSR(EPSR)
-
中断 PSR(IPSR)
通过上面提到的 MRS 和 MSR 指令,这三个 PSRs 可以单独访问:
MRS r0, APSR ;将应用状态读入 R0
MRS r0, IPSR ;将中断/异常状态读入 R0
MSR APSR, R0 ;写应用状态
也可以组合访问(两个组合或三个组合都可以)。当使用三合一方式访问时,应使用 “xPSR” 或 “PSR” 这两个名字。
MRS r0, PSR ;读组合程序状态字
MSR PSR, r0 ;写组合程序状态字
需要注意的是,软件代码无法直接使用 MRS (读出为 0)或 MSR 直接访问 EPSR。同时 IPSR 为只读,可以从组合 PSR 中读出。
这三个寄存器的位域结构如下:
组合形式:
其中每个位域字段的含义如下:
-
N:负标志。
-
Z:零标志。
-
C:进位(或非借位)标志。
-
V:溢出标志。
-
Q:饱和标志(ARMv6-M 中不存在)。
-
ICI/IT:中断继续指令状态位(ICI),用于条件执行的 IF-THEN 指令状态位(ARMv6-M 中不存在)。
-
T:Thumb 状态,总是 1,尝试清除此位会引起错误异常。
-
Exception Number:表示处理器正在处理的异常对应的编号。
PRIMASK, FAULTMASK 和 BASEPRO
PRIMASK、FAULTMASK 和 BASEMASK 寄存器都用于异常或中断的屏蔽,每个异常(包括中断)都有一个优先等级,数值越小优先级越高,反之数值越大优先级越低。以上三个特殊寄存器可以基于优先级屏蔽异常,只有在特权访问等级才能对它们进行操作(非特权状态下的写操作会被忽略,而读取则会返回 0)。它们的默认值都为 0,即不屏蔽任何异常或中断。这些寄存器的编程模型如下图所示:
PRIMASK 寄存器是位宽为 1 的中断屏蔽寄存器。在置位时,它会阻止不可屏蔽中断(NMI)和 HardFault 异常之外的所有异常(包括中断)。实际上,它的原理是将当前异常优先级提升为 0,这也是可编程异常/中断的最高优先级。PRIMASK 最常见的用途是在一些时间要求很严格的进程中禁止所有中断,在该进程完成后,需要将 PRIMASK 清除以重新使能中断。
FAULTMASK 和 PRIMASK 非常相似,不过它还能屏蔽 HardFault 异常,它实际上是将异常优先级提升到了 -1。错误处理代码可以使用 FAULTMASK 以免在错误处理期间再次触发其他错误(只有几种)。例如, FAULTMASK 可用于旁路 MPU 或屏蔽总线错误(这些都是可配置的),这样,错误处理代码执行修复措施也就更容易了。与 PRIMASK 不同, FAULTMASK 在异常返回时会被自动清除。
BASEPRI 会根据优先级屏蔽异常或中断。BASEPRI 的宽度取决于设计中实际实现的优先级数量,这通常是由微控制器供应商决定的。大多数 Cortex-M3 或 Cortex-M4 微控制器都有 8 个或 16 个可编程的异常优先级,此时 BASEPRI 的宽度就相应地为 3 位或者 4 位。BASEPRI 为 0 时不会起作用,当被设置为非 0 数值时,他就会屏蔽具有相同或更低优先级的异常(包括中断),而更高优先级的则仍然会被处理器接受。
CMSIS-Core 提供了多个 C 函数用于访问 PRIMASK、FAULTMASK、及 BASEPRI 寄存器。(这些寄存器只能在特权等级下访问)
x = __get_BASEPRI(); // 读 BASEPRI 寄存器
x = __get_PRIMARK(); // 读 PRIMASK 寄存器
x = __get_FAULTMASK(); // 读 FAULTMASK 寄存器
__set_BASEPRI(x); // 设置 BASEPRI
__set_PRIMASK(x); // 设置 PRIMASK
__set_FAULTMASK(x); // 设置 FAULTMASK
__disable_irq(); // 设置 PRIMASK, 禁用 IRQ
__enable_irq(); // 清除 PRIMASK, 使能 IRQ
同时也可以使用汇编代码访问这些寄存器:
MRS r0, BASEPRI ; 将 BASEPRI 寄存器的值读入 R0
MRS r0, PRIMASK ; 将 PRIMASK 寄存器的值读入 R0
MRS r0, FAULTMASK ; 将 FAULTMASK 寄存器的值读入 R0
MSR BASEPRI, r0 ; 将 R0 寄存器的值写入 BASEPRI
MSR PRIMASK, r0 ; 将 R0 寄存器的值写入 PRIMASK
MSR FAULTMASK, r0 ; 将 R0 寄存器的值写入 FAULTMASK
此外,利用修改处理器状态(CPS)指令,可以非常方便地设置或清除 PRIMASK 和 FAULTMASK 的值:
CPSIE i ; 使能 interrupt (清除 PRIMASK)
CPSID i ; 禁用 interrupt (设置 PRIMASK)
CPSIE f ; 使能 interrupt (清除 FAULTMASK)
CPSID f ; 禁用 interrupt (设置 FAULTMASK)
CONTROL 寄存器
CONTROL 寄存器中包含了如下两个主要信息:
-
栈指针的选择(主栈指针 MSP 和 进程栈指针 PSP)。
-
线程模式的访问等级(特权级和非特权级)。
其编程模型如下:
具体的位域描述为:
位 | 描述 |
CONTROL[1] (SPSEL) | 定义栈指针的选择 0=选择主栈指针 MSP(复位后缺省值) 1=选择进程栈指针 PSP 在线程或基础级(没有在响应异常),可以使用 PSP。在 handler 模式下, 只允许使用 MSP,所以此时不得往该位写 1。 |
CONTROL[0] (nPRIV) | 定义线程模式中的特权等级 0=特权级的线程模式 1=用户级的线程模式 Handler 模式永远都是特权级的。 |
复位后,CONTROL 寄存器默认为 0,这意味着处理器此时处于线程模式,具有特权访问权限并且使用主栈指针。通过写 CONTROL 寄存器,特权线程模式的程序可以切换栈指针的选择或进入非特权访问等级,如下图所示:
不过,nPRIV(CONTROL[0])置位后,运行在线程模式的程序就不能访问 CONTROL 寄存器了。
运行在非特权等级的程序一般情况下无法再切换回特权访问等级,这样就提供了一个基本安全的模型。例如,嵌入式系统中可能会具有运行在非特权等级且不受信任的应用,这些应用的访问权限就需要受到限制,以免不可靠的程序引起系统的崩溃。
若需要在线程模式切换回特权访问等级,则需要借助于异常机制。在异常处理期间,处理程序可以清除 nPRIV 位。在返回到线程模式后,处理器就会进入特权访问等级。
若使用嵌入式 OS,每次上下文切换时都可以重新编程 CONTROL 寄存器,以满足应用间不同特权访问等级的需要。
nPRIV 和 SPSEL 的设置有 4 种组合方式,其中 3 种在实际应用中较为常见:
nPRIV | SPSEL | 应用场景 |
0 | 0 | 简单应用,整个应用运行在特权访问等级,主程序和中断处理只会使用一个栈,即主栈 MSP |
0 | 1 | 具有嵌入式 OS 的应用,当前执行的任务运行在特权级线程模式,当前任务选择使用进程栈指针 PSP,而 MSP 则用于 OS 内核以及异常处理 |
1 | 1 | 具有嵌入式 OS 的应用,当前执行的任务运行在非特权级线程模式,当前任务选择使用进程栈指针 PSP,而 MSP 则用于 OS 内核以及异常处理 |
1 | 0 | 线程模式运行在非特权访问等级,且使用 MSP,在 Handler 模式下可以观察到,而在用户任务中一般不会使用,这是因为在多数嵌入式 OS 中,应用任务的栈和 OS 内核以及异常处理使用的栈是相互独立的 |
对于未使用嵌入式 OS 的多数简单应用,无须修改 CONTROL 寄存器的数值,整个应用可以运行在特权访问等级并且只使用 MSP:
要利用 C 语言访问 CONTROL 寄存器,可以使用符合 CMSIS 的设备驱动库提供的以下函数:
x = __get_CONTROL(); // 读取当前 CONTROL 寄存器的值
__set_CONTROL(x); // 设置 CONTROL 寄存器的值为 x
如果使用汇编,则可以借助于 MRS 和 MSR 指令:
MRS r0, CONTROL ;将 CONTROL 寄存器的值读到 r0
MSR CONTROL, r0 ;将 r0 中的值写到 CONTROL 寄存器
最后,你可以通过检查 CONTROL 和 IPSR 的数值来确定当前是否为特权等级:
int in_privileged(void) {if (__get_IPSR() != 0)return 1; // Trueelse if ((__get_CONTROL() & 0x1) == 0)return 1; // Trueelsereturn 0; // False
}
相关文章:

深入理解 Cortex-M3 特殊寄存器
在上一篇文章中分享了 Cortex-M3 内核寄存器组的相关知识,实际上除了内核寄存器组外,CM3 处理器中还存在多个特殊寄存器,它们分别为 程序状态寄存器,中断/异常屏蔽寄存器 和 控制寄存器。 需要注意的是,特殊寄存器未经…...

[Java实战]Spring Boot 3 整合 Ehcache 3(十九)
[Java实战]Spring Boot 3 整合 Ehcache 3(十九) 引言 在微服务和高并发场景下,缓存是提升系统性能的关键技术之一。Ehcache 作为 Java 生态中成熟的内存缓存框架,其 3.x 版本在性能、功能和易用性上均有显著提升。本文将详细介绍…...

建筑物渗水漏水痕迹发霉潮湿分割数据集labelme格式1357张1类别
数据集中有增强图片详情看图片 数据集格式:labelme格式(不包含mask文件,仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数):1357 标注数量(json文件个数):1357 标注类别数:1 标注类别名称:["water&qu…...
Doris和Clickhouse对比
目录 一、Doris和Clickhouse对比1. 底层架构**DorisClickHouse** 2. 运行原理DorisClickHouse 3. 使用场景DorisClickHouse 4. 优缺点对比总结 二、MPP架构和Shared-Nothing 架构对比1. 什么是 MPP 架构?定义特点典型代表 2. 什么是 Shared-Nothing 架构?…...

第二十二天打卡
数据预处理 import pandas as pd from sklearn.model_selection import train_test_splitdef data_preprocessing(file_path):"""泰坦尼克号生存预测数据预处理函数参数:file_path: 原始数据文件路径返回:preprocessed_data: 预处理后的数据集""&quo…...
Android Activity之间跳转的原理
一、Activity跳转核心流程 Android Activity跳转的底层实现涉及 系统服务交互、进程间通信(IPC) 和 生命周期管理,主要流程如下: startActivity() 触发请求 应用调用 startActivity() 时,通过 Inst…...
MATLAB 矩阵与数组操作基础教程
文章目录 前言环境配置一、创建矩阵与数组(一)直接输入法(二)特殊矩阵生成函数(三)使用冒号表达式创建数组 二、矩阵与数组的基本操作(一)访问元素(二)修改元…...
【Linux】第十六章 分析和存储日志
1. RHEL 日志文件保存在哪个目录中? 一般存储在 /var/log 目录中。 2. 什么是syslog消息和非syslog消息? syslog消息是一种标准的日志记录协议和格式,用于系统和应用程序记录日志信息。它规定了日志消息的结构和内容,包括消息的…...

解锁性能密码:Linux 环境下 Oracle 大页配置全攻略
在 Oracle 数据库运行过程中,内存管理是影响其性能的关键因素之一。大页内存(Large Pages)作为一种优化内存使用的技术,能够显著提升 Oracle 数据库的运行效率。本文将深入介绍大页内存的相关概念,并详细阐述 Oracle 在…...

Spark,在shell中运行RDD程序
在hdfs中/wcinput中创建一个文件:word2.txt在里面写几个单词 启动hdfs集群 [roothadoop100 ~]# myhadoop start [roothadoop100 ~]# cd /opt/module/spark-yarn/bin [roothadoop100 ~]# ./spark-shell 写个11测试一下 按住ctrlD退出 进入环境:spa…...

SAP学习笔记 - 开发11 - RAP(RESTful Application Programming)简介
上一章学习了BTP架构图,实操创建Directory/Subaccount,BTP的内部组成,BTP Cockpit。 SAP学习笔记 - 开发10 - BTP架构图,实操创建Directory/Subaccount,BTP的内部组成,BTP Cockpit-CSDN博客 本章继续学习S…...

数据防泄密安全:企业稳健发展的守护盾
在数字化时代,数据已成为企业最核心的资产之一。无论是客户信息、财务数据,还是商业机密,一旦泄露,都可能给企业带来不可估量的损失。近年来,数据泄露事件频发,如Facebook用户数据泄露、Equifax信用数据外泄…...

MySQL之基础索引
目录 引言 1、创建索引 2、索引的原理 2、索引的类型 3、索引的使用 1.添加索引 2.删除索引 3.删除主键索引 4.修改索引 5.查询索引 引言 当一个数据库里面的数据特别多,比如800万,光是创建插入数据就要十几分钟,我们查询一条信息也…...
Openshift节点Disk pressure
OpenShift 监控以下指标,并定义以下垃圾回收的驱逐阈值。请参阅产品文档以更改任何驱逐值。 nodefs.available 从 cadvisor 来看,该node.stats.fs.available指标表示节点文件系统(所在位置)上有多少可用(剩余…...

拉丁方分析
本文是实验设计与分析(第6版,Montgomery著傅珏生译)第4章随机化区组,拉丁方,以及有关的设计第4.2节的python解决方案。本文尽量避免重复书中的理论,着于提供python解决方案,并与原书的运算结果进行对比。您…...
Pomelo知识框架
一、Pomelo 基础概念 Pomelo 简介 定位:分布式游戏服务器框架(网易开源)。 特点:高并发、可扩展、多进程架构、支持多种通信协议(WebSocket、TCP等)。 适用场景:MMO RPG、实时对战、社交游戏等…...

软考软件设计师中级——软件工程笔记
1.软件过程 1.1能力成熟度模型(CMM) 软件能力成熟度模型(CMM)将软件过程改进分为以下五个成熟度级别,每个级别都定义了特定的过程特征和目标: 初始级 (Initial): 软件开发过程杂乱无章…...
基于事件驱动和策略模式的差异化处理方案
一、支付成功后事件驱动 1、支付成功事件 /*** 支付成功事件** author ronshi* date 2025/5/12 14:40*/ Getter Setter public class PaymentSuccessEvent extends ApplicationEvent {private static final long serialVersionUID 1L;private ProductOrderDO productOrderDO;…...

5.5.1 WPF中的动画2-基于路径的动画
何为动画?一般只会动。但所谓会动,还不仅包括位置移动,还包括角度旋转,颜色变化,透明度增减。动画本质上是一个时间段内某个属性值(位置、颜色等)的变化。因为属性有很多数据类型,它们变化也需要多种动画类比如: BooleanAnimationBase\ ByteAnimationBase\DoubleAnima…...
计算机网络:手机和基站之间的通信原理是什么?
手机与基站之间的通信是无线通信技术的核心应用之一,涉及复杂的物理层传输、协议交互和网络管理机制。以下从技术原理、通信流程和关键技术三个层面深入解析这一过程: 一、蜂窝网络基础架构 1. 蜂窝结构设计 基本原理:将服务区域划分为多个六边形“蜂窝小区”,每个小区由*…...
PostgreSQL常用DML操作的锁类型归纳
DML锁类型分析 本文对PostgreSQL的insert、 update、 truncate、 delete等常用DML操作的锁类型进行了归纳类比: 包括是否排他、 共享、 表级、 行级等的总结。 truncate :access exclusive mode(block all read/write)、table-le…...
Apache Flink 与 Flink CDC:概念、联系、区别及版本演进解析
Apache Flink 与 Flink CDC:概念、联系、区别及版本演进解析 在实时数据处理和流式计算领域,Apache Flink 已成为行业标杆。而 Flink CDC(Change Data Capture) 作为其生态中的重要组件,为数据库的实时变更捕获提供了强大的能力。 本文将从以下几个方面进行深入讲解: 什…...
数学复习笔记 8
前言 成为一个没有感情的刷题机器就可以变得很强了。 逆矩阵的运算 随便算一下就算出来了,没啥难的。主要是用天然可交换的矩阵来算。有三个天然可交换的矩阵,某矩阵和单位阵,该矩阵和它的伴随矩阵,该矩阵和它的逆矩阵。一定要…...
FunASR:语音识别与合成一体化,企业级开发实战详解
简介 FunASR是由阿里巴巴达摩院开源的高性能语音识别工具包,它不仅提供语音识别(ASR)功能,还集成了语音端点检测(VAD)、标点恢复、说话人分离等工业级模块,形成了完整的语音处理解决方案。 FunASR支持离线和实时两种模式,能够高效处理多语言音频,并提供高精度的识别结果。…...
rust-candle学习笔记11-实现一个简单的自注意力
参考:about-pytorch 定义ScaledDotProductAttention结构体: use candle_core::{Result, Device, Tensor}; use candle_nn::{Linear, Module, linear_no_bias, VarMap, VarBuilder, ops};struct ScaledDotProductAttention {wq: Linear,wk: Linear,wv: …...
读入csv文件写入MySQL
### 使用 Spark RDD 读取 CSV 文件并写入 MySQL 的实现方法 #### 1. 环境准备 在使用 Spark 读取 CSV 文件并写入 MySQL 数据库之前,需要确保以下环境已配置完成: - 添加 Maven 依赖项以支持 JDBC 连接。 - 配置 MySQL 数据库连接参数,包括 …...

Andorid之TabLayout+ViewPager
文章目录 前言一、效果图二、使用步骤1.主xml布局2.activity代码3.MyTaskFragment代码4.MyTaskFragment的xml布局5.Adapter代码6.item布局 总结 前言 TabLayoutViewPager功能需求已经是常见功能了,我就不多解释了,需要的自取。 一、效果图 二、使用步骤…...
C++GO语言微服务之用户信息处理②
目录 01 03-获取用户信息-上 02 04-获取用户信息-下 03 05-更新用户名实现 01 06-中间件简介和中间件类型 02 07-中间件测试和模型分析 03 08-中间件测试案例和小结 04 09-项目使用中间件 01 03-获取用户信息-上 ## Cookie操作 ### 设置Cookie go func (c *Context) …...

26考研——中央处理器_指令流水线_流水线的冒险与处理 流水线的性能指标 高级流水线技术(5)
408答疑 文章目录 六、指令流水线流水线的冒险与处理结构冒险数据冒险延迟执行相关指令采用转发(旁路)技术load-use 数据冒险的处理 控制冒险 流水线的性能指标流水线的吞吐率流水线的加速比 高级流水线技术超标量流水线技术超长指令字技术超流水线技术 …...
Java 与 Go 语言对比
Java 和 Go (Golang) 是两种流行的编程语言,各有其设计哲学和应用场景。以下是它们的详细对比: 1. 基本特性 特性JavaGo诞生时间1995 (Sun Microsystems)2009 (Google)设计目标“Write Once, Run Anywhere”简洁、高效的系统编程语言语言类型面向对象多…...