关于__irq的使用

本文解析了__irq标识在不同编译器中的作用及应用,介绍了如何正确使用这一标识来实现中断函数的功能,特别是在ARM系统中断嵌套的场景下。

 来源:http://wenku.baidu.com/view/efeca9a5f524ccbff12184fd.html

__irq为一个标识,用来表示一个函数是否为中断函数。对于不同的编译器,__irq在函数名中的位置不一样,例如:
ADS编译器中:

void __irq IRQ_Eint0(void);


Keil编译器中:

void IRQ_Eint0(void) __irq;


但是其意义一样,它所完成的任务是标识该函数为中断函数,在编译器编译是调用此函数时,先保护函数入口现场,然后执行中断函数,函数执行完毕,恢复中断现场,这整个过程不需要用户重新编写代码来完成,由编译器自动完成。因而这也给不具备中断嵌套功能的ARM系统带来了问题,若使用 __irq 时有中断嵌套产生,这现场保护就会混乱。在前一篇日志“LPC2000系列中断嵌套处理”中,自己编写中断入口现场保护代码,并不使用 __irq 标识符号,就是这个原因。


总结如下:
1、若不想自己编写中断入口现场保护代码,而且使用中无中断嵌套,在中断函数中用 __irq 来标识我们的中断函数,否则出错;
2、若程序中要使用中断嵌套,对于无中断嵌套功能的ARM来说,一定要自己编写中断入口现场保护代码,而且不能用 __irq 标识我们的中断函数,否则出错。

arzhiy
2007-01-30

<think>我们正在讨论的是STM32开发中的中断控制函数。根据引用[1]的内容,我们知道在ARM Cortex-M处理器中: - `__disable_irq()` 用于禁用所有可屏蔽中断(通过设置PRIMASK寄存器为1)。 - 与之对应的,`__enable_irq()` 用于重新使能这些中断(通过设置PRIMASK寄存器为0)。 因此,在STM32开发中,与`__disable_irq`对应的函数是`__enable_irq`,它们是一对用于控制中断的使能和禁用的函数。 ### 作用 - `__disable_irq()`: 禁用所有可屏蔽中断(IRQ),但不会影响不可屏蔽中断(NMI)和硬件错误异常等。它通过设置PRIMASK寄存器为1来实现。 - `__enable_irq()`: 使能所有可屏蔽中断,将PRIMASK寄存器设置为0。 ### 使用方法 这两个函数通常用于保护临界区代码,即一段不能被中断打断的代码。使用方法如下: ```c __disable_irq(); // 进入临界区,关闭中断 // 执行临界区代码(例如,对全局变量的操作,硬件寄存器的操作等) __enable_irq(); // 离开临界区,打开中断 ``` ### 注意事项 1. **嵌套使用**:`__disable_irq`和`__enable_irq`是通过操作PRIMASK寄存器实现的,而PRIMASK只有一位,因此它们不支持嵌套。也就是说,如果在调用`__disable_irq`之后再次调用`__disable_irq`,那么PRIMASK已经为1,再次禁用中断不会有额外效果。但是,如果在中间调用了`__enable_irq`,则会直接使能中断,即使之前禁用了多次。因此,在嵌套的临界区中,应该使用其他支持嵌套的中断控制函数(如`__disable_irq`和`__enable_irq`的替代方案,或者使用`BASEPRI`寄存器)。 2. **使用场景**:这两个函数适用于对执行时间要求非常严格的临界区,因为它们只是简单的设置寄存器,执行速度很快。但是,由于它们不支持嵌套,所以在复杂的代码中需要谨慎使用。 3. **与FAULTMASK的区别**:引用[1]中提到了`__set_FAULTMASK(1)`,它比`__disable_irq()`更强大,会屏蔽几乎所有异常(除了NMI)。因此,除非在系统崩溃前执行关键操作,否则不推荐使用。而`__disable_irq`和`__enable_irq`是常规的中断控制方法。 4. **编译器内置函数**:在CMSIS中,这些函数通常由编译器提供,例如在Keil MDK中,它们是编译器内置函数(intrinsics)。因此,在使用时,需要包含相应的头文件(如`core_cm3.h`、`core_cm4.h`等)。 ### 示例代码 以下是一个简单的示例,展示如何在STM32中使用这两个函数: ```c #include "stm32f4xx.h" // 包含STM32的头文件,里面会包含CMSIS核心头文件 void Critical_Section_Example(void) { // 进入临界区,禁用中断 __disable_irq(); // 这里执行临界区代码 // 例如,修改一个全局变量,这个变量会被中断服务程序访问 global_counter++; // 离开临界区,使能中断 __enable_irq(); } ``` ### 替代函数 如果你需要支持嵌套的临界区保护,可以使用以下函数(也是CMSIS提供的): - `uint32_t __get_PRIMASK(void);`:获取当前PRIMASK的值。 - `void __set_PRIMASK(uint32_t priMask);`:设置PRIMASK的值。 这样,你可以保存和恢复中断状态: ```c uint32_t primask; primask = __get_PRIMASK(); // 保存当前中断状态 __disable_irq(); // 禁用中断 // 临界区代码 __set_PRIMASK(primask); // 恢复之前的中断状态 ``` 这种方法允许嵌套,因为每次禁用中断前先保存状态,退出时恢复状态,这样内层临界区的开启不会影响外层。 ### 总结 - `__disable_irq()` 和 `__enable_irq()` 是STM32开发中用于快速禁用和使能可屏蔽中断的函数。 - 它们操作的是PRIMASK寄存器,因此不支持嵌套。 - 在需要嵌套的场合,应该使用保存和恢复PRIMASK值的方法。 --- §§相关问题§§ 1. 在STM32中,如何实现可嵌套的中断禁用? 2. `__disable_irq`和`HAL_NVIC_DisableIRQ`有什么区别? 3. 在中断服务程序中,使用`__disable_irq`会导致什么问题?</think>在STM32开发中(基于ARM Cortex-M处理器),`__disable_irq()` 和 `__enable_irq()` 是一对用于控制中断的核心函数,它们直接操作处理器的中断掩码寄存器: ### 作用及原理 1. **`__disable_irq()`** - 禁用所有**可屏蔽中断**(IRQ) - 原理:将处理器的 `PRIMASK` 寄存器设为 `1` - 影响范围: ✓ 屏蔽常规中断(如GPIO、定时器等) ✗ **不影响**不可屏蔽中断(NMI) ✗ **不影响**硬件错误异常 ✗ **不影响**系统服务调用(SVC)[^1] 2. **`__enable_irq()`**(`__disable_irq`的逆向操作) - 启用所有可屏蔽中断 - 原理:将 `PRIMASK` 寄存器清零(设为 `0`) ```c // 典型使用场景(临界区保护) __disable_irq(); // 进入临界区前关闭中断 /* 执行关键操作(如共享资源访问) */ __enable_irq(); // 离开临界区后恢复中断 ``` ### 使用要点 1. **嵌套支持** - Cortex-M允许嵌套调用,但需严格配对: ```c __disable_irq(); // 第一次禁用(PRIMASK=1) __disable_irq(); // 冗余调用(无效果) __enable_irq(); // 第一次启用(PRIMASK=0) // 错误:多调用一次__enable_irq()将导致不可预测行为! ``` 2. **与`FAULTMASK`的区别** | **特性** | `__disable_irq()` | `__set_FAULTMASK(1)` | |------------------|-------------------------|-------------------------| | **屏蔽范围** | 仅常规中断 | 所有异常(含硬件错误) | | **优先级影响** | 无 | 提升到-1(最高) | | **自动清除** | 否 | 异常退出时自动清除 | | **使用场景** | 常规临界区保护 | 系统崩溃前的紧急操作 | 3. **最佳实践** - 临界区代码尽量简短(微秒级) - 禁止在中断服务程序(ISR)中调用 - 与`__enable_irq()`严格配对使用 - 优先使用HAL库的`HAL_NVIC_DisableIRQ()`管理单个中断 ### 示例场景 ```c volatile uint32_t counter; // 共享资源 void CriticalOperation(void) { __disable_irq(); // STEP1: 关中断 counter += 1; // STEP2: 安全更新共享变量 __enable_irq(); // STEP3: 开中断 } // 错误示例(未配对) void UnsafeFunction() { __disable_irq(); if(condition) return; // 提前返回导致中断永久关闭! __enable_irq(); } ``` > ⚠️ 注意:STM32CubeIDE中需包含 `core_cm4.h`(或对应内核头文件)才能使用这些函数[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值