开云-BPO行业整合方案提供者
专业化、科技化、国际化;高标准、广覆盖、全流程
了解更多__disable_irq() 和 __enable_irq()界说在哪? 时候:2024-12-14 19:56:24 手机看文章
扫描二维码随时随地手机看文章
前段时候一工程师向我咨询了一个问题,问我为何他的MCU KEIL工程代码里没有找到__disable_irq() 和 __enable_irq()的具体界说,是否是有问题。
直接在工程里搜刮,确切只能在cmsis_armcc.h文件里看到下面的两处注释申明,并没有这俩函数的具体界说。
可是假如直接去挪用这俩函数的话,编译又不会报错,那末这俩函数的界说到底在哪呢?
__disable_irq() 和 __enable_irq() 是所谓的intrinsic函数,编译器主动辨认并替代为相干的指令,它们实际上是编译器的一部门,现实的界说位在arm_compat.h 文件中(位在KEIL的安装目次里),
static__inline__unsignedint__attribute__((__always_inline__,__nodebug__))__disable_irq(void){unsignedintcpsr; #if__ARM_ARCH =6 #ifdefined(__ARM_ARCH_PROFILE) __ARM_ARCH_PROFILE=='M' __asm____volatile__("mrs%[cpsr],primask\n" "cpsidi\n" :[cpsr] "=r"(cpsr)); return cpsr 0x1; #else/*!defined(__ARM_ARCH_PROFILE)||__ARM_ARCH_PROFILE!='M'*/ __asm____volatile__("mrs%[cpsr],cpsr\n" "cpsidi\n" :[cpsr] "=r"(cpsr)); return cpsr 0x80; #endif #else/*__ARM_ARCH 6 */ unsignedinttmp;__asm____volatile__( "mrs%[cpsr],CPSR\n" "bic%[tmp],%[cpsr],#0x80\n" "msrCPSR_c,%[tmp]\n" :[tmp]"=r"(tmp),[cpsr]"=r"(cpsr)); return cpsr 0x80; #endif }
#if(defined(__ARM_ARCH_PROFILE) __ARM_ARCH_PROFILE=='M' \ __ARM_ARCH==6)||__ARM_ARCH_8M_BASE__static__inline__void__attribute__((unavailable( "intrinsicnotsupportedforthisarchitecture")))__enable_fiq(void); #else//(!defined(__ARM_ARCH_PROFILE)||__ARM_ARCH_PROFILE!='M'|| //__ARM_ARCH!=6) !__ARM_ARCH_8M_BASE__static__inline__void__attribute__((__always_inline__,__nodebug__))__enable_fiq(void){ #if__ARM_ARCH =6 __asm____volatile__("cpsief"); #else/*__ARM_ARCH 6 */ unsignedinttmp;__asm____volatile__( "mrs%[tmp],CPSR\n" "bic%[tmp],%[tmp],#0x40\n" "msrCPSR_c,%[tmp]\n" :[tmp]"=r"(tmp)); #endif } #endif
焦点是 cpsie i 和 cpsid i 这两个指令。
cps全称change processor state,即改变PRIMASK这个寄放器值
ie: interrupt enable. 中止使能,即PRIMASK.PM设置为0
id: interrupt disable. 中止封闭,即PRIMASK.PM设置为1
__enable_irq()函数挪用cpsie i指令。
__disable_irq()函数除挪用cpsid i 指令,同时返回了PRIMASK的值,即假如返回值为 0,则暗示中止在挪用该函数之前是使能的;假如返回值为1,则暗示中止在挪用函数之前是禁用的。
需要留意的是:假如之前开启了相干外设的中止功能,在挪用__disable_irq()函数关中止后,这时候假如有中止触发,那末不会去进行中止响应。可是在挪用__enable_irq()开启中止后,MCU会当即处置之前触发的中止。这申明__disable_irq()只是制止CPU去响应中止,没有真实的去屏障中止的触发,傍边断产生后,响应的寄放器会将中止标记置位,在__enable_irq()开启中止后,因为响应的中止标记没有清空,因此还会触发中止。
以下述代码为例,法式中利用了一个GPIO中止,当按键按下时翻转一次LED。现实测试假如在挪用__disable_irq()后、__enable_irq()之前的这3s时候内按下按键,其实不会进入中止翻转LED,固然这时候中止标记位已发生了。
可是挪用__enable_irq()以后就会马上进入到中止办事函数中。
intmain(void){/*设置装备摆设系统时钟*/system_clock_config();/*Systick初始化*/std_delay_init();/*LED初始化*/led_init();/*EXTI初始化*/exti_init();__disable_irq();std_delayms(3000);__enable_irq(); while (1){}}/***@briefEXTI4_15中止办事函数*@retval无*/voidEXTI4_15_IRQHandler(void){/*读取EXTI通道中止挂起状况*/ if (std_exti_get_pending_status(EXTI_LINE_GPIO_PIN13)){/*断根EXTI通道中止挂起状况*/std_exti_clear_pending(EXTI_LINE_GPIO_PIN13);LED1_TOGGLE();}}
说到这里你可能还留意到还__NVIC_DisableIRQ(IRQn_Type IRQn)、__NVIC_EnableIRQ(IRQn_Type IRQn) 这俩函数
/**\briefDisableInterrupt\detailsDisablesadevicespecificinterrupt in theNVICinterruptcontroller.\param[in]IRQnDevicespecificinterruptnumber.\noteIRQnmustnotbenegative.*/__STATIC_INLINEvoid__NVIC_DisableIRQ(IRQn_TypeIRQn){ if ((int32_t)(IRQn) =0){NVIC- ICER[0U]=(uint32_t)(1UL (((uint32_t)IRQn) 0x1FUL)); __DSB(); __ISB(); } }
/**\briefEnableInterrupt\detailsEnablesadevicespecificinterrupt in theNVICinterruptcontroller.\param[in]IRQnDevicespecificinterruptnumber.\noteIRQnmustnotbenegative.*/__STATIC_INLINEvoid__NVIC_EnableIRQ(IRQn_TypeIRQn){ if ((int32_t)(IRQn) =0){NVIC- ISER[0U]=(uint32_t)(1UL (((uint32_t)IRQn) 0x1FUL)); } }
这俩函数和上述函数的区分是,上面的两个函数是开关全局的中止,这俩函数是针对某特定的中止。
可是有一点不异的是,假如在挪用__NVIC_DisableIRQ以后产生了中止事务,当挪用__NVIC_EnableIRQ(IRQn_Type IRQn)以后仍是会进入到中止处置。
综上disable函数只是不响应中止,其实不会影响中止的发生,在disable状况下假如产生中止则会挂起,比及enable后知足前提仍是会被履行。假如不但愿此现象产生,那末需要再enable前断根失落相干外设模块中止挂起要求标记。
假如想真正制止中止的发生的话,还得从泉源上设置装备摆设相干外设的寄放器关失落中止才行。
欲知详情,请下载word文档 下载文档