STM32开关总中断
引用 http://www.amobbs.com/forum.php?mod=viewthread&tid=5397451
在 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中