STM32/M3/M0关于开关总中断的问题

 

 

 

NVIC 共支持 1 至 240 个外部中断输入(通常外部中断写作 IRQs)。 具体的数值由芯片厂商在设计芯片时决定。此外, NVIC 还支持一个“永垂不朽”的不可屏蔽中断(NMI)输入。NMI 的实际功能亦由芯片制造商决定。在某些情况下, NMI 无法由外部中断源控制。

在 STM32/Cortex-M3 中是通过改变 CPU 的当前优先级来允许或禁止中断。​  

异常掩蔽寄存器PRIMASK位只允许 NMI 和 hard  fault 异常,其他中断/异常都被屏蔽(当前 CPU 优先级=0,为可编程优先级中的最高优先级) 。 

该寄存器可以通过 MRS 和 MSR 以下例方式访问:

​1. 关中断MOV R0, #1

             MSR PRIMASK, R0

​2. 开中断MOV R0, #0

             MSR PRIMASK, R0 ​

此外,还可以通过CPS指令快速完成上述功能:​

CPSID I;//PRIMASK=1 ; 关中断

CPSIE  I;//PRIMASK=0 ; 开中断

CPSID F;//FAULTMASK=1, ; 关异常

CPSIE  F;//FAULTMASK=0 ; 开异常

异常掩蔽寄存器FAULTMASK位:只允许 NMI,其他所有中断/异常都被屏蔽(当前 CPU 优先级=-1)。注意的是,FAULTMASK会在异常退出时自动清零。

掩蔽寄存器虽然能一手遮天,却都动不了NMI,因为NMI是用在最危急的情况下的。因此系统为它开出单行道,无需挂号只是不要迟到。

​在 STM32 固件库中(stm32f10x_nvic.c 和 stm32f10x_nvic.h) 定义了四个函数操作 PRIMASK 位和FAULTMASK 位,改变 CPU 的当前优先级,从而达到控制所有中断的目的。   

​下面两个函数等效于关闭总中断:  

​void NVIC_SETPRIMASK(void);   void NVIC_SETFAULTMASK(void);   

​下面两个函数等效于开放总中断:  

​void NVIC_RESETPRIMASK(void);   void NVIC_RESETFAULTMASK(void);  

 上面两组函数要成对使用,不能交叉使用。 

 例如: 第一种方法(常用): NVIC_SETPRIMASK();   //关闭总中断  

                                ​NVIC_RESETPRIMASK();//开放总中断   

​第二种方法:  NVIC_SETFAULTMASK();      //关闭总中断  

               ​      NVIC_RESETFAULTMASK();    //开放总中断

在 3.0 的库中上述库函数已经没有​,可以用下列方法实现:

​#define CLI()      __set_PRIMASK(1)  

​#define SEI()      __set_PRIMASK(0) 

或者在编译器里使用:

__disable_irq();   // 关闭总中断

​__enable_irq();    // 开启总中断​

补充1:​异常掩蔽寄存器BASEPRI

在更精巧的设计中,需要对中断掩蔽进行更细腻的控制——只掩蔽优先级低于某一阈值的中断(它们的优先级在数字上大于等于某个数)。那么这个数存储在哪里?就存储在BASEPRI中。

不过,如果往BASEPRI中写0,则另当别论——BASEPRI将停止掩蔽任何中断。

如果你需要掩蔽所有优先级不高于0x60的中断,则可以如下编程:

​MOV R0, #0x60

MSR BASEPRI, R0

​如果需要取消 BASEPRI 对中断的掩蔽,则示例代码如下:

​MOV R0, #0

MSR BASEPRI, R0

补充2:关闭全局中断时需要注意的问题(未验证是否确有此问题)

STM32在使用时有时需要禁用全局中断​。但测试发现一个问题,在关闭总中断后,如果有中断触发,虽然此时不会引发中断,但在调用__enable_irq()开启总中断后,MCU会立即处理之前触发的中断。这说明__disable_irq()只是禁止CPU去响应中断,没有真正的去屏蔽中断的触发,中断发生后,相应的寄存器会将中断标志置位,在__enable_irq()开启中断后,由于相应的中断标志没有清空,因而还会触发中断。

所以要想禁止所有中断,必须对逐个模块的中断进行Disable操作,由于每个模块中断源有很多,对逐个中断Disable的话比较复杂,较为简单的方法是通过XXX_ClearITPendingBit()清除中断标志或者直接通过XXX_DeInit()来清除寄存器的状态。这样在__enable_irq()开启总中断后,MCU就不会响应之前触发的中断了。

 

原文链接:

http://blog.sina.com.cn/s/blog_a0c22cfd0102x0bj.html

你可能感兴趣的:(XOS)