
在 STM32/Cortex-M3 中是通过改变 CPU 的当前优先级来允许或禁止中断。 PRIMASK 位:只允许 NMI 和 hard fault 异常,其他中断/ 异常都被屏蔽(当前 CPU 优先级=0)。 FAULTMASK 位:只允许 NMI,其他所有中断/异常都被屏蔽(当前 CPU 优先级=-1)。 在 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(); //开放总中断 常常使用 NVIC_SETPRIMASK(); // Disable Interrupts NVIC_RESETPRIMASK(); // Enable Interrupts 1 在CORE_CM3.H中根据不同编译器有不同的语句 #if defined ( __CC_ARM ) /*------------------RealView Compiler -----------------*/ /* ARM armcc specific functions */ #define __enable_fault_irq __enable_fiq #define __disable_fault_irq __disable_fiq #define __NOP __nop #define __WFI __wfi /*IAR ICC Compiler*/ __disable_irq() ; __enable_irq() ; /*IAR ICC Compiler*/ #elif (defined (__GNUC__)) /*------------------ GNU Compiler ---------------------*/ /* GNU gcc specific functions */ static __INLINE void __enable_irq() { __ASM volatile ("cpsie i"); } 二 其它 __asm void INT_DIS(void) { CPSID f BX r14 /*LR*/ } /*************开启中断************************/ __asm void INT_EN(void) { CPSIE f BX r14/*LR*/ } cpsid i 关中断,但是不关硬fault 和NMI cpsid f 连硬fault也关了,只剩下NMI/*MCU上电初始化读取参数期间尝试关闭ALL中断,所以用的F,读取参数完成后再开启中断,进入主程序不用再用F中断*/ MDK的话可以直接书写(好像不对这是对应IAR): __disable_irq(); 相当于 CPSID I __enable_irq(); 相当于 CPSIE I __disable_fiq(); 相当于 CPSID F __enable_fiq(); 相当于 CPSIE F 其实最正规的做法是用CMSIS库里面的(跨平台) void __set_FAULTMASK(uint32_t faultMask); void __set_PRIMASK(uint32_t priMask); STM32在使用时有时需要禁用全局中断,比如MCU在升级过程中需禁用外部中断,防止升级过程中外部中断触发导致升级失败。 ARM MDK中提供了如下两个接口来禁用和开启总中断: __disable_irq(); // 关闭总中断 __enable_irq(); // 开启总中断 测试发现这样一个问题,在关闭总中断后,如果有中断触发,虽然此时不会引发中断,但在调用__enable_irq()开启总中断后,MCU会立即处理之前触发的中断。这说明__disable_irq()只是禁止CPU去响应中断,没有真正的去屏蔽中断的触发,中断发生后,相应的寄存器会将中断标志置位,在__enable_irq()开启中断后,由于相应的中断标志没有清空,因而还会触发中断。所以要想禁止所有中断,必须对逐个模块的中断进行Disable操作,由于每个模块中断源有很多,对逐个中断Disable的话比较复杂,较为简单的方法是通过XXX_ClearITPendingBit()清除中断标志或者直接通过XXX_DeInit()来清除寄存器的状态。这样在__enable_irq()开启总中断后,MCU就不会响应之前触发的中断了。 软件重启MCU与半主机调试 /* ################################## Reset function ############################################ */ /** * @brief Initiate a system reset request. * * Initiate a system reset request to reset the MCU */ static __INLINE void NVIC_SystemReset(void) /* ##################################### Debug In/Output function ########################################### */ static __INLINE void __disable_irq() { __ASM volatile ("cpsid i"); } static __INLINE void __enable_fault_irq() { __ASM volatile ("cpsie f"); } static __INLINE void __disable_fault_irq() { __ASM volatile ("cpsid f"); } 在NVIC中 |