当前位置: 首页 > java >正文

深入理解用于中断控制的特殊寄存器

之前在介绍 Cortex-M3 特殊寄存器的文章中提到了中断/异常屏蔽寄存器,具体可参见下文:

资深嵌入式工程师的自我修养 —— Cortex-M3 特殊寄存器

其中包括 PRIMASK、FAULTMASK 和 BASEMASK 寄存器。这些寄存器都用于异常或中断的屏蔽,本文就来详细理解下这些寄存器的操作细节。

PRIMASK

在许多应用中,可能都需要暂时禁止所有中断以执行一些时序关键的任务,此时就可以使用 PRIMASK 寄存器。需要注意的是 PRIMASK 寄存器只能在特权等级下访问。

PRIMASK 用于禁止除了 NMI 和 HardFault 外的所有异常,它实际上是将当前优先级改为 0(最高的可编程等级)。如果用 C 编程,可以使用 CMSIS-Core 提供的函数来设置和清除 PRIMASK:

void __enable_irq(); // 清除 PRIMASK
void __disable_irq(); // 设置 PRIMASK
void __set_PRIMASK(uint32_t priMask); // 设置 PRIMASK 为特定值
uint32_t __get_PRIMASK(void); // 读取 PRIMASK 的数值

对于汇编编程,可以利用 CPS(修改处理器状态)指令修改 PRIMASK 寄存器数值。

CPSIE I ; 清除 PRIMASK (使能中断)
CPSID I ; Set PRIMASK (禁止中断)

PRIMASK 寄存器还可通过 MRS 和 MSR 指令访问,例如:

MOVS R0, #1
MSR PRIMASK, R0 ;将 1 写入 PRIMASK 禁止所有中断

以及:

MOVS R0, #0
MSR PRIMASK, R0 ;将 0 写入 PRIMASK 以使能中断

当 PRIMASK 置位时,所有的错误事件都会触发 HardFault 异常

FAULTMASK

从行为来说,FAULTMASK 和 PRIMASK 很类似,只是它实际上会将当前优先级修改为 -1,这样即使是 HardFault 也会被屏蔽。当 FAULTMASK 置位时,只有 NMI 异常处理才能执行。

从用法来说,FAULTMASK 用于将配置的错误处理(如 MemManage、总线错误和使用错误)的优先级提升到 -1(这里指的是在某个错误处理运行期间,置位 FAULTNASK,此时这个错误处理的优先级就被提升到了 -1 ,并且在此期间其他错误处理都不会响应),这样,这些处理就可以使用 HardFault 的一些特殊性。其中包括:

  • 旁路 MPU

  • 忽略用于设备/内存探测的数据总线错误

将优先级提升到 -1 后,FAULTMASK 可在可配置的错误处理执行期间,阻止其他异常或中断处理的执行。(关于错误处理的更深入概念会在以后的文章中详细说明)

FAULTMASK 寄存器只能在特权状态访问,不过不能在 NMI 和 HardFault 处理中设置。若在 C 语言编程中使用符合 CMSIS 的设备驱动,则可以使用下面的 CMSIS-Core 函数来设置和清除 FAULTMASK:

void __enable_fault_irq(void);  // 清除 FAULTMASK
void __disable_fault_irq(void); // 设置 FAULTMASK 以禁用中断
void __set_FAULTMASK(uint32_t faultMask);
uint32_t __get_FAULTMASK(void);

对于汇编语言,可以利用 CPS 指令修改 FAULTMASK 的当前状态:

CPSIE F ; 清除 FAULTMASK
CPSID F ; 设置 FAULTMASK

还可以利用 MRS 和 MSR 指令访问 FAULTMASK 寄存器:

MOVS R0, #1
MSR FAULTMASK, R0 ; 将 1 写入 FAULTMASK 禁止所有中断

以及

MOVS R0, #0
MSR FAULTMASK, R0 ; 将 0 写入 FAULTMASK 使能中断

FAULTMASK 会在退出异常处理时被自动清除,从 NMI 处理中退出时除外。由于这个特性,FAULTMASK 就有了一个有趣的用法:若要在低优先级的异常处理中触发一个高优先级的异常(NMI 除外),但此时想在低优先级处理完成后再进行高优先级的处理,可以按如下步骤:

  • 设置 FAULTMASK 禁止所有中断和异常(NMI异常除外)

  • 设置高优先级中断或异常的挂起状态

  • 退出当前处理

由于在 FAULTMASK 置位时,挂起的高优先级异常处理无法执行,高优先级的异常就会在 FAULTMASK 被清除前继续保持挂起状态,低优先级处理完后才会将其清除。因此,可以强制让高优先级处理在低优先级处理结束后才开始执行。

BASEPRI

有些情况下,可能只想禁止优先级低于某个特定等级的中断,此时,就可以使用 BASEPRI 寄存器。要实现这个目的,只需简单地将所需的屏蔽优先级写入 BASEPRI 寄存器。例如,要屏蔽优先级小于等于 0x60 的所有异常,则可以将这个数值写入 BASEPRI:

__set_BASEPRI(0x60); // 使用 CMSIS-Core 函数禁用优先级为 0x60~0xFF 的中断

若要使用汇编语言,则可写为:

MOVS R0, #0x60
MSR BASEPRI, R0 ; 禁用优先级为 0x60~0xFF 的中断

当然你也可以读出 BASEPRI 的值:

x = __get_BASEPRI(void); // 读出 BASEPRI 的值

或使用汇编实现:

MRS R0, BASEPRI

如果要取消屏蔽,只需要往 BASEPRI 写 0 即可:

__set_BASEPRI(0x0); // 取消 BASEPRI 屏蔽

或使用汇编:

MOVS R0, #0x0
MSR BASEPRI, R0 ; 取消 BASEPRI 屏蔽

BASEPRI 还可以通过另一个名称访问,即 BASEPRI_MAX。它们实际上是同一个寄存器,不过当使用这个名称访问时,会得到一个条件写操作。BASEPRI 和 BASEPRI_MAX 在硬件上是一个寄存器,不过在汇编中的编码不同。在使用 BASEPRI_MAX 时,处理器会自动比较当前值和新的数值,只有在新的优先级更高时才会允许修改。例如下面的指令序列:

MOVS R0, #0x60
MSR BASEPRI_MAX, R0 ; 禁止优先级为 0x60,0x61... 的中断
MOVS R0, #0xF0
MSR BASEPRI_MAX, R0 ; 由于该优先级低于 0x60,所以本次操作将会被忽略
MOVS R0, #0x40
MSR BASEPRI_MAX, R0 ; 本次写操作会将屏蔽值修改为 0x40

综上,要修改为更低的屏蔽值或禁止屏蔽,应该使用 BASEPRI。BASEPRI或 BASEPRI_MAX 寄存器无法在非特权状态被设置。

最后,与其他优先级寄存器类似,BASEPRI 寄存器的格式受到实际的优先级寄存器宽度影响,如果优先级仅实现了 3 位,则 BASEPRI 可被设置为 0x00、0x20、0x40 ... 0xC0 和 0xE0。

http://www.xdnf.cn/news/10101.html

相关文章:

  • pm2守护进程管理器
  • Word2Vec 生成词向量
  • 【python基础知识】列表简介
  • 会议室钥匙总丢失?换预约功能的智能门锁更安全
  • 如何做好一份技术文档:从信息孤岛到知识图谱的进阶之路
  • 国芯思辰| SC751X替换OPA2354/OPA354/OPA4354可调激光器应用方案
  • 网络编程4-epoll
  • 多模态大语言模型arxiv论文略读(101)
  • 大语言模型中的注意力机制详解
  • gitlib 常见命令
  • 【xmb】内部文档148344596
  • nginx: [emerg] bind() to 0.0.0.0:80 failed (10013: 80端口被占用
  • GEARS以及与基础模型结合
  • 产品更新|数字主线深度解析:华望解决方案助力企业数字化转型
  • Linux入门(十一)进程管理
  • 分布式锁和数据库锁完成接口幂等性
  • 深度学习初探:当机器开始思考(superior哥AI系列第1期)
  • 线程池的详细知识(含有工厂模式)
  • STM32通过rt_hw_hard_fault_exception中的LR寄存器追溯程序问题​
  • 深圳南山沙河社区联合心美行动举办“青少年天赋提升”助青春成长
  • 用于工业设备的高精度仪表放大器“NL9620”开始上市~日本首家!高EMC性能的仪表放大器
  • 使用matlab读取txt文件中的2进制数据
  • 文字转图片的字符画生成工具
  • JavaScript 计算两个日期之间天数的全面指南
  • [网页五子棋][对战模块]前后端交互接口(建立连接、连接响应、落子请求/响应),客户端开发(实现棋盘/棋子绘制)
  • 将Kotti从Pyramid1.0升级到2.0 (失败的记录)
  • CATIA高效工作指南——测量分析篇(一)
  • C++ TCP程序增加TLS加密认证
  • Java本地缓存实现方案全解析:原理、优缺点与应用场景
  • C/C++ 面试复习笔记(2)