<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          __disable_irq() 和 __enable_irq()定義在哪?

          共 9625字,需瀏覽 20分鐘

           ·

          2024-07-23 17:21

          點(diǎn)擊關(guān)注公眾號(hào),Java干貨及時(shí)送達(dá)

              

          前段時(shí)間,一位工程師向我咨詢了一個(gè)問(wèn)題,問(wèn)我為什么他的MCU KEIL工程代碼里沒(méi)有找到__disable_irq() 和 __enable_irq()的具體定義,是不是有問(wèn)題。
          直接在工程里搜索,確實(shí)只能在cmsis_armcc.h文件里看到下面的兩處注釋說(shuō)明,并沒(méi)有這倆函數(shù)的具體定義。
          可是,如果直接去調(diào)用這倆函數(shù)的話,編譯又不會(huì)報(bào)錯(cuò),那么這倆函數(shù)的定義到底在哪呢?
          __disable_irq() 和 __enable_irq() 是所謂的intrinsic函數(shù),編譯器自動(dòng)識(shí)別并替換為相關(guān)的指令,它們其實(shí)是編譯器的一部分,實(shí)際的定義位于arm_compat.h 文件中(位于KEIL的安裝目錄里),
          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
          核心是 cpsie i 和 cpsid i 這兩個(gè)指令。
          • cps全稱change processor state,即改變PRIMASK這個(gè)寄存器值
          • ie: interrupt enable. 中斷使能,即PRIMASK.PM設(shè)置為0
          • id: interrupt disable. 中斷關(guān)閉,即PRIMASK.PM設(shè)置為1

          __enable_irq()函數(shù)調(diào)用cpsie i指令。

          __disable_irq()函數(shù)除調(diào)用cpsid i 指令,同時(shí)返回了PRIMASK的值,即如果返回值為 0,則表示中斷在調(diào)用該函數(shù)之前是使能的;如果返回值為1,則表示中斷在調(diào)用函數(shù)之前是禁用的。

          需要注意的是:如果之前開(kāi)啟了相關(guān)外設(shè)的中斷功能,在調(diào)用__disable_irq()函數(shù)關(guān)中斷后,這時(shí)如果有中斷觸發(fā),那么不會(huì)去進(jìn)行中斷響應(yīng)。但是在調(diào)用__enable_irq()開(kāi)啟中斷后,MCU會(huì)立即處理之前觸發(fā)的中斷。這說(shuō)明__disable_irq()只是禁止CPU去響應(yīng)中斷,沒(méi)有真正的去屏蔽中斷的觸發(fā),當(dāng)中斷發(fā)生后,相應(yīng)的寄存器會(huì)將中斷標(biāo)志置位,在__enable_irq()開(kāi)啟中斷后,由于相應(yīng)的中斷標(biāo)志沒(méi)有清空,因而還會(huì)觸發(fā)中斷。

          以下述代碼為例,程序中使用了一個(gè)GPIO中斷,當(dāng)按鍵按下時(shí)翻轉(zhuǎn)一次LED。實(shí)際測(cè)試如果在調(diào)用__disable_irq()后、__enable_irq()之前的這3s時(shí)間內(nèi)按下按鍵,并不會(huì)進(jìn)入中斷翻轉(zhuǎn)LED,雖然這時(shí)中斷標(biāo)志位已經(jīng)產(chǎn)生了。

          但是,調(diào)用__enable_irq()之后就會(huì)立刻進(jìn)入到中斷服務(wù)函數(shù)中。

          int main(void)
          {      
              /* 配置系統(tǒng)時(shí)鐘 */
              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中斷服務(wù)函數(shù)
          * @retval 無(wú)
          */
          void EXTI4_15_IRQHandler(void)
          {
              /* 讀取EXTI通道中斷掛起狀態(tài) */
              if (std_exti_get_pending_status(EXTI_LINE_GPIO_PIN13))
              {
                  /* 清除EXTI通道中斷掛起狀態(tài) */
                  std_exti_clear_pending(EXTI_LINE_GPIO_PIN13);
                  LED1_TOGGLE();
              }
          }

          說(shuō)到這里你可能還注意到還有__NVIC_DisableIRQ(IRQn_Type IRQn)、__NVIC_EnableIRQ(IRQn_Type IRQn) 這倆函數(shù)

          /**
            \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));
            }
          }

          這倆函數(shù)和上述函數(shù)的區(qū)別是,上面的兩個(gè)函數(shù)是開(kāi)關(guān)全局的中斷,這倆函數(shù)是針對(duì)某特定的中斷。

          但有一點(diǎn)相同的是,如果在調(diào)用__NVIC_DisableIRQ之后發(fā)生了中斷事件,當(dāng)調(diào)用__NVIC_EnableIRQ(IRQn_Type IRQn)之后還是會(huì)進(jìn)入到中斷處理。
          綜上disable函數(shù)只是不響應(yīng)中斷,并不會(huì)影響中斷的產(chǎn)生,在disable狀態(tài)下如果發(fā)生中斷則會(huì)掛起,等到enable后滿足條件還是會(huì)被執(zhí)行。如果不希望此現(xiàn)象發(fā)生,那么需要再enable前清除掉相關(guān)外設(shè)模塊中斷掛起請(qǐng)求標(biāo)志。
          如果想真正禁止中斷的產(chǎn)生的話,還得從源頭上配置相關(guān)外設(shè)的寄存器關(guān)掉中斷才行。
                  

            

                     

                      

          1、Vue誕生10年,創(chuàng)始人尤雨溪推動(dòng)“銹化”——通過(guò)Rust提升Web基礎(chǔ)設(shè)施性能

          2、上班摸魚(yú)?不可能!卡內(nèi)基梅隆準(zhǔn)博士生開(kāi)發(fā)一款 AI 程序:監(jiān)控電腦屏幕,一分心就吼你

          3、Crowdstrike更新導(dǎo)致全球Windows大面積藍(lán)屏死機(jī)

          4、Rust即將進(jìn)入前十:中贏、大贏、還是特大贏?

          5、SpringBoot實(shí)現(xiàn)分布式驗(yàn)證碼登錄方案

          6、Wireshark 抓包過(guò)濾命令大全,不會(huì)抓包的網(wǎng)工不是好網(wǎng)工!

          點(diǎn)

          點(diǎn)

          點(diǎn)點(diǎn)

          點(diǎn)在看

          瀏覽 33
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  在线永久 | 亚洲精品成人无码七嶋舞 | 一区二区成人电影 | 大鸡巴视频在线 | 色老板亚洲 |