Cortex-M0中斷控制和系統控制(二)


轉載:https://aijishu.com/a/1060000000237975

每一個外部中斷都有一個對應的優先級寄存器,Cortex-M0中NVIC-IPR共有8個寄存器,而每個寄存器管理4個IRQ中斷,所以M0的IRQ中斷源最多只支持32個,再加上16個內核中斷,也就是說M0最多48個中斷源。

表1.png

表2.png

Cortex-M0采用Armv6-M架構,優先級寄存器配置位有8位,但是有效位只有最高2位,這個地方很多人使用了Cortex-M3后一直也認為Cortex-M0也是最高3或4位有效位,在arm官方資料中有對比兩個版本的差別。因此Cortex-M0可編程優先級有4個,加上3個固定的優先級(復位、NMI、HardFault),Cortex-M0總共有7個中斷優先級。

image1.png

Cortex-M0內核的中斷優先級寄存器是以最高位(MSB)對齊的,並且只支持字傳輸,每次訪問都會同時涉及4個中斷優先級寄存器。見下圖:

表3.png

因為Bit0 - Bit5沒有使用,所以如果沒有進行寫操作讀出都為0。

由於不同的 Cortex-M 系列,其中斷優先級是不一樣的,所以在 CMSIS 庫中的頭文件中可以查看優先級的數量 \_\_NVIC\_PRIO\_BITS。

中斷優先級寄存器的編程應該在中斷使能之前,其通常是在程序開始時完成的。arm官方資料提示應該避免在中斷使能之后改變中斷優先級,因為這種情況的結果在ARMv6-M系統結構是不可預知的,並且不被Cortex-M0處理器支持。Cortex-M3/M4處理器的情況又有所不同,他們都支持中斷優先級的動態切換。Cortex-M3處理器和Cortex-M0處理器的另外一個區別是,Cortex-M3訪問中斷優先級寄存器時支持字節或半字傳輸,因此可以每次只設置一個寄存器。如果需要改變優先級,程序中需要關閉中斷后再重新設置中斷優先級寄存器。

在 Cortex-M內核中,一個中斷的優先級數值越低,邏輯優先級卻越高。比如,中斷優先級為2的中斷可以搶占中斷優先級為3的中斷,但反過來就不行。換句話說,中斷優先級2比中斷優先級3的優先級更高。

Cortex-M0處理器對中斷嵌套的支持無需任何軟件干預,如果MCU已經在運行一個中斷,而有了新的更高優先級的中斷請求,正在運行的中斷將會被暫停,轉而執行更高優先級的中斷,高優先級中斷執行完成后又回到原來的低優先級中斷。如果出現兩個同一優先級的中斷,則是判斷誰開始發起中斷請求,MCU會先執行同一優先級中首先發起請求的中斷。

MM32F0130系列中斷向量表:

typedef enum IRQn {

    NonMaskableInt_IRQn             = -14,                                  ///< 2 Non Maskable Interrupt
    HardFault_IRQn                  = -13,                                  ///< 3 Cortex-M0 Hard Fault Interrupt
    MemoryManagement_IRQn           = -12,                                  ///< 4 Cortex-M0 Memory Management Interrupt
    BusFault_IRQn                   = -11,                                  ///< 5 Cortex-M0 Bus Fault Interrupt
    UsageFault_IRQn                 = -10,                                  ///< 6 Cortex-M0 Usage Fault Interrupt
    SVC_IRQn                        = -5,                                   ///< 11 Cortex-M0 SV Call Interrupt
    DebugMonitor_IRQn               = -4,                                   ///< 12 Cortex-M0 Debug Monitor Interrupt
    PendSV_IRQn                     = -2,                                   ///< 14 Cortex-M0 Pend SV Interrupt
    SysTick_IRQn                    = -1,                                   ///< 15 Cortex-M0 System Tick Interrupt
    WWDG_IWDG_IRQn                  = 0,                                    ///< WatchDog Interrupt
    WWDG_IRQn                       = 0,                                    ///< Window WatchDog Interrupt
    PVD_IRQn                        = 1,                                    ///< PVD through EXTI Line detect Interrupt
    BKP_IRQn                        = 2,                                    ///< BKP through EXTI Line Interrupt
    RTC_IRQn                        = 2,                                    ///< RTC through EXTI Line Interrupt
    FLASH_IRQn                      = 3,                                    ///< FLASH Interrupt
    RCC_CRS_IRQn                    = 4,                                    ///< RCC & CRS Interrupt
    RCC_IRQn                        = 4,                                    ///< RCC Interrupt
    EXTI0_1_IRQn                    = 5,                                    ///< EXTI Line 0 and 1 Interrupts
    EXTI2_3_IRQn                    = 6,                                    ///< EXTI Line 2 and 3 Interrupts
    EXTI4_15_IRQn                   = 7,                                    ///< EXTI Line 4 to 15 Interrupts
    HWDIV_IRQn                      = 8,                                    ///< HWDIV Global Interrupt
    DMA1_Channel1_IRQn              = 9,                                    ///< DMA1 Channel 1 Interrupt
    DMA1_Channel2_3_IRQn            = 10,                                   ///< DMA1 Channel 2 and Channel 3 Interrupts
    DMA1_Channel4_5_IRQn            = 11,                                   ///< DMA1 Channel 4 and Channel 5 Interrupts
    ADC_COMP_IRQn                   = 12,                                   ///< ADC & COMP Interrupts
    COMP_IRQn                       = 12,                                   ///< COMP Interrupts
    ADC_IRQn                        = 12,                                   ///< ADC Interrupts
    ADC1_IRQn                       = 12,                                   ///< ADC Interrupts
    TIM1_BRK_UP_TRG_COM_IRQn        = 13,                                   ///< TIM1 Break, Update, Trigger and Commutation Interrupts
    TIM1_CC_IRQn                    = 14,                                   ///< TIM1 Capture Compare Interrupt
    TIM2_IRQn                       = 15,                                   ///< TIM2 Interrupt
    TIM3_IRQn                       = 16,                                   ///< TIM3 Interrupt
    TIM14_IRQn                      = 19,                                   ///< TIM14 Interrupt
    TIM16_IRQn                      = 21,                                   ///< TIM16 Interrupt
    TIM17_IRQn                      = 22,                                   ///< TIM17 Interrupt
    I2C1_IRQn                       = 23,                                   ///< I2C1 Interrupt
    SPI1_IRQn                       = 25,                                   ///< SPI1 Interrupt
    SPI2_IRQn                       = 26,                                   ///< SPI1 Interrupt
    UART1_IRQn                      = 27,                                   ///< UART1 Interrupt
    UART2_IRQn                      = 28,                                   ///< UART2 Interrupt
    CAN_IRQn                        = 30,                                   ///< CAN Interrupt
    USB_IRQn                        = 31,                                   ///< USB Interrupt
} IRQn_Type;

設置中斷優先級的流程:先讀一個字,再修改對應字節,最后整個字寫回。

1.1 C代碼
void__NVIC_SetPriority()
{
    unsigned long temp;                              //定義一個臨時變量
    temp = *(volatile unsigned long)(0xE000E400); //讀取IRP0值
    temp &= (0xFF00FFFF |(0xC0 << 16));            //修改中斷#2優先級為0xC0
    *(volatile unsigned long)(0xE000E400) = temp; //設置IPR0
}
1.2 匯編代碼

在程序中可以一次設置多個中斷優先級。

void__NVIC_SetPriority()
{
    LDR R0, =0xE000E100   ;  //設置使能中斷寄存器地址
    MOVS R1, #0x4         ;  //中斷#2
    STR R1, [R0]          ;  //使能#2中斷
    LDR R0, =0xE000E200   ;  //設置掛起中斷寄存器地址
    MOVS R1, #0x4         ;  //中斷#2
    STR R1, [R0]          ;  //掛起#2中斷
    LDR R0, =0xE000E280   ;  //設置清除中斷掛起寄存器地址
    MOVS R1, #0x4         ;  //中斷#2
    STR R1, [R0]          ;  //清除#2的掛起狀態
}
1.3 CMSIS標准設備驅動函數
//設置中斷優先級
__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
    if ((int32_t)(IRQn) >= 0) {
        NVIC->IP[_IP_IDX(IRQn)]  = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)]  & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
                                    (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn)));
    }
    else {
        SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
                                    (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn)));
    }
}

這里的參數IRQn為中斷ID號,可以為負,也可以為正。當IRQn為負時,設置系統異常的優先級,當IRQn大於等於0時,設置外設中斷優先級,芯片廠商會提供中斷向量表IRQn\_Type,應用層只需要調用即可;priority是0、1、2、3,函數內部會自動移位到對應的優先級最高2位。

方法一:
void NVIC_SetPriority(TIM1_CC_IRQn, 3) ; //設置#14中斷的優先級為0xC0
方法二:
void NVIC_Config(void)
{    NVIC_InitTypeDef NVIC_InitStructure;

    NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

設置好中斷優先級后,用戶還可以讀取當前已經設置的中斷優先級。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM