__disable_irq() 和 __enable_irq()定义在哪?
共 9625字,需浏览 20分钟
·
2024-07-23 17:21
点击关注公众号,Java干货及时送达
static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
__disable_irq(void) {
unsigned int cpsr;
#if __ARM_ARCH >= 6
#if defined(__ARM_ARCH_PROFILE) && __ARM_ARCH_PROFILE == 'M'
__asm__ __volatile__("mrs %[cpsr], primask\n"
"cpsid i\n"
: [cpsr] "=r"(cpsr));
return cpsr & 0x1;
#else /* !defined(__ARM_ARCH_PROFILE) || __ARM_ARCH_PROFILE != 'M' */
__asm__ __volatile__("mrs %[cpsr], cpsr\n"
"cpsid i\n"
: [cpsr] "=r"(cpsr));
return cpsr & 0x80;
#endif
#else /* __ARM_ARCH < 6 */
unsigned int tmp;
__asm__ __volatile__(
"mrs %[cpsr], CPSR\n"
"bic %[tmp], %[cpsr], #0x80\n"
"msr CPSR_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(
"intrinsic not supported for this architecture"))) __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__("cpsie f");
#else /* __ARM_ARCH < 6 */
unsigned int tmp;
__asm__ __volatile__(
"mrs %[tmp], CPSR\n"
"bic %[tmp], %[tmp], #0x40\n"
"msr CPSR_c, %[tmp]\n"
: [tmp]"=r"(tmp));
#endif
}
#endif
-
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()之后就会立刻进入到中断服务函数中。
int main(void)
{
/* 配置系统时钟 */
system_clock_config();
/* Systick初始化 */
std_delay_init();
/* LED初始化 */
led_init();
/* EXTI初始化 */
exti_init();
__disable_irq();
std_delayms(3000);
__enable_irq();
while (1)
{
}
}
/**
* @brief EXTI4_15中断服务函数
* @retval 无
*/
void EXTI4_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) 这俩函数
/**
\brief Disable Interrupt
\details Disables a device specific interrupt in the NVIC interrupt controller.
\param [in] IRQn Device specific interrupt number.
\note IRQn must not be negative.
*/
__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn)
{
if ((int32_t)(IRQn) >= 0)
{
NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));
__DSB();
__ISB();
}
}
/**
\brief Enable Interrupt
\details Enables a device specific interrupt in the NVIC interrupt controller.
\param [in] IRQn Device specific interrupt number.
\note IRQn must not be negative.
*/
__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn)
{
if ((int32_t)(IRQn) >= 0)
{
NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));
}
}
这俩函数和上述函数的区别是,上面的两个函数是开关全局的中断,这俩函数是针对某特定的中断。