Cortex-A7中断详解(一)
STM32中斷系統回顧
中斷向量表
中斷向量表是一個表,表里面存放的是中斷向量。
中斷服務程序的入口地址或存放中斷服務程序的首地址成為中斷向量,因此中斷向量表是一系列中斷服務程序入口地址組成的表。
中斷服務程序在中斷向量表中的位置是由半導體廠商定好的,當某個中斷被觸發以后就會自動跳轉到中斷向量表中對應的中斷服務程序入口地址處。
中斷向量表在整個程序的最前面,如STM32F103 的中斷向量表如下所示:
__Vectors DCD __initial_sp ; Top of StackDCD Reset_Handler ; Reset HandlerDCD NMI_Handler ; NMI HandlerDCD HardFault_Handler ; Hard Fault HandlerDCD MemManage_Handler ; MPU Fault HandlerDCD BusFault_Handler ; Bus Fault HandlerDCD UsageFault_Handler ; Usage Fault HandlerDCD 0 ; ReservedDCD 0 ; ReservedDCD 0 ; ReservedDCD 0 ; ReservedDCD SVC_Handler ; SVCall HandlerDCD DebugMon_Handler ; Debug Monitor HandlerDCD 0 ; ReservedDCD PendSV_Handler ; PendSV HandlerDCD SysTick_Handler ; SysTick Handler; External InterruptsDCD WWDG_IRQHandler ; Window WatchdogDCD PVD_IRQHandler ; PVD through EXTI Line detectDCD TAMPER_IRQHandler ; TamperDCD RTC_IRQHandler ; RTCDCD FLASH_IRQHandler ; FlashDCD RCC_IRQHandler ; RCCDCD EXTI0_IRQHandler ; EXTI Line 0DCD EXTI1_IRQHandler ; EXTI Line 1DCD EXTI2_IRQHandler ; EXTI Line 2DCD EXTI3_IRQHandler ; EXTI Line 3DCD EXTI4_IRQHandler ; EXTI Line 4DCD DMA1_Channel1_IRQHandler ; DMA1 Channel 1DCD DMA1_Channel2_IRQHandler ; DMA1 Channel 2DCD DMA1_Channel3_IRQHandler ; DMA1 Channel 3DCD DMA1_Channel4_IRQHandler ; DMA1 Channel 4DCD DMA1_Channel5_IRQHandler ; DMA1 Channel 5DCD DMA1_Channel6_IRQHandler ; DMA1 Channel 6DCD DMA1_Channel7_IRQHandler ; DMA1 Channel 7DCD ADC1_2_IRQHandler ; ADC1 & ADC2DCD USB_HP_CAN1_TX_IRQHandler ; USB High Priority or CAN1 TXDCD USB_LP_CAN1_RX0_IRQHandler ; USB Low Priority or CAN1 RX0DCD CAN1_RX1_IRQHandler ; CAN1 RX1DCD CAN1_SCE_IRQHandler ; CAN1 SCEDCD EXTI9_5_IRQHandler ; EXTI Line 9..5DCD TIM1_BRK_IRQHandler ; TIM1 BreakDCD TIM1_UP_IRQHandler ; TIM1 UpdateDCD TIM1_TRG_COM_IRQHandler ; TIM1 Trigger and CommutationDCD TIM1_CC_IRQHandler ; TIM1 Capture CompareDCD TIM2_IRQHandler ; TIM2DCD TIM3_IRQHandler ; TIM3DCD TIM4_IRQHandler ; TIM4DCD I2C1_EV_IRQHandler ; I2C1 EventDCD I2C1_ER_IRQHandler ; I2C1 ErrorDCD I2C2_EV_IRQHandler ; I2C2 EventDCD I2C2_ER_IRQHandler ; I2C2 ErrorDCD SPI1_IRQHandler ; SPI1DCD SPI2_IRQHandler ; SPI2DCD USART1_IRQHandler ; USART1DCD USART2_IRQHandler ; USART2DCD USART3_IRQHandler ; USART3DCD EXTI15_10_IRQHandler ; EXTI Line 15..10DCD RTC_Alarm_IRQHandler ; RTC Alarm through EXTI LineDCD USBWakeUp_IRQHandler ; USB Wakeup from suspendDCD TIM8_BRK_IRQHandler ; TIM8 BreakDCD TIM8_UP_IRQHandler ; TIM8 UpdateDCD TIM8_TRG_COM_IRQHandler ; TIM8 Trigger and CommutationDCD TIM8_CC_IRQHandler ; TIM8 Capture CompareDCD ADC3_IRQHandler ; ADC3DCD FSMC_IRQHandler ; FSMCDCD SDIO_IRQHandler ; SDIODCD TIM5_IRQHandler ; TIM5DCD SPI3_IRQHandler ; SPI3DCD UART4_IRQHandler ; UART4DCD UART5_IRQHandler ; UART5DCD TIM6_IRQHandler ; TIM6DCD TIM7_IRQHandler ; TIM7DCD DMA2_Channel1_IRQHandler ; DMA2 Channel1DCD DMA2_Channel2_IRQHandler ; DMA2 Channel2DCD DMA2_Channel3_IRQHandler ; DMA2 Channel3DCD DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & Channel5 __Vectors_End中斷向量表都是鏈接到代碼的最前面,比如一般ARM處理器都是從地址0x00000000開始執行指令的,那么中斷向量表就是從0x00000000開始存放的。
__initial_sp就是第一條中斷向量,存放的是棧頂指針,接下來是第2行復位中斷服務函數Reset_Handler的入口地址,最后一行是中斷服務函數DMA2_Channel4_5_IRQHandler的入口地址,這樣STM32F103的中斷向量表就建好了。
雖然ARM處理器都是從地址0x00000000開始運行的,但是我們學習STM32的時候代碼是下載到0x8000000開始的存儲區域中,因此中斷向量表存放到了0x8000000地址處。
因此,Cortex-M架構引入了中斷向量表偏移,通過中斷向量表偏移就可以將中斷向量表存放到任意地址處。
#ifdef VECT_TAB_SRAMSCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */ #elseSCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */ #endif中斷向量表偏移配置在函數SystemInit中完成,通過SCB->VTOR寄存器寫入新的中斷向量表首地址即可。
#define FLASH_BASE 0x08000000UL #define VECT_TAB_OFFSET 0x0基本都是將中斷向量表設置到ROM中,也就是地址0x8000000處。
NVIC(內嵌向量中斷控制器)
- Cortex-M內核有中斷系統的管理機構-NVIC
- Cortex-A7內核的中斷管理機構——GIC:general interrupt controller
中斷使能
要使用某個外設的中斷,肯定要先使能這個外設的中斷,以STM32F103的PE2這個IO為例,假如我們要使用PE2的輸入中斷肯定要使用如下代碼來使能對應的中斷。使能PE2對應的EXTI2中斷。
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中斷通道 NVIC_Init(&NVIC_InitStructure);中斷服務函數
我們使用中斷的目的就是為了使用中斷服務函數,當中斷發生以后中斷服務函數就會被調用,我們要處理的工作就可以放到中斷服務函數中去完成。同樣以 STM32F103 的 PE2 為例,其中斷服務函數如下所示:
void EXTI2_IRQHandler(void) {/* 中斷處理代碼 */ }當 PE2 引腳的中斷觸發以后就會調用其對應的中斷處理函數 EXTI2_IRQHandler,我們可以在函數 EXTI2_IRQHandler 中添加中斷處理代碼。同理,I.MX6U 也有中斷服務函數,當某個外設中斷發生以后就會調用其對應的中斷服務函數。
Cortex-A7中斷系統簡介
Cortex-A7的中斷向量表也在代碼的最前面,其內核有8個異常中斷。
Cortex-A內核CPU的所有外部中斷都屬于這個IRQ中斷,當任意一個外部中斷發生的時候都會觸發IRQ中斷。在IRQ中斷服務函數里面就可以讀取指定的寄存器來判斷發生的具體是什么中斷,進而根據具體的中斷做出
相應的處理。
GIC控制器簡介
STM32(Cortex-M)的中斷控制器叫做NVIC,I.MX6U(Cortex-A)的中斷控制器叫做GIC。
GIC 是 ARM 公司給 Cortex-A/R 內核提供的一個中斷控制器,類似 Cortex-M 內核中的NVIC。目前 GIC 有 4 個版本:V1~V4,V1 是最老的版本,已經被廢棄了。V2~V4 目前正在大量的使用。GIC V2 是給 ARMv7-A 架構使用的,比如 Cortex-A7、Cortex-A9、Cortex-A15 等,V3 和 V4 是給 ARMv8-A/R 架構使用的,也就是 64 位芯片使用的。I.MX6U 是Cortex-A 內核的,因此我們主要講解 GIC V2。GIC V2 最多支持 8 個核。
當GIC接收到外部中斷信號以后就會報給ARM內核,但是ARM內核只提供了4個信號給GIC來匯報中斷情況:VFIQ、VIRQ、FIQ和IRQ。
GIC 接收眾多的外部中斷,然后對其進行處理,最終就只通過四個信號
報給 ARM 內核,這四個信號的含義如下:
- VFIQ:虛擬快速 FIQ。
- VIRQ:虛擬外部 IRQ。
- FIQ:快速中斷 IRQ。
- IRQ:外部中斷 IRQ。
左側部分就是中斷源,中間部分就是GIC控制器,最右側就是中斷控制器向處理器內核發送中斷信息。
GIC將總多的中斷源分為三類:
中斷ID
中斷源很多,為了區分這些不同的中斷源肯定要給他們分配一個唯一的ID,這些ID就是中斷ID。每一個 CPU 最多支持 1020 個中斷 ID,中斷 ID 號為 ID0~ID1019。這 1020 個 ID 包含了 PPI、SPI 和 SGI。
I.MX6U 的總共使用了 128 個中斷 ID,加上前面屬于 PPI 和 SGI 的 32 個 ID,I.MX6U 的中斷源共有 128+32=160個。
在MCIMX6Y2C.h中,定義了一個枚舉類型IRQn_Type
GIC邏輯分塊
GIC架構分成了兩個邏輯塊:Distributor和CPU Interface,也就是分發器端和CPU接口端。
- Distributor(分發器端):此邏輯塊負責處理各個中斷事件的分發問題,也就是中斷事件應該發送到哪個CPU Interface上去。分發器收集所有的中斷源,可以控制每個中斷的優先級,它總是將優先級最高的中斷事件發送到CPU接口端。分發器端要做的主要工作是:
- CPU Interface(CPU接口端):與CPU Core相連接,也就是分發器和CPU Core之間的橋梁。主要工作:
在core_ca7.h定義了GIC結構體,此結構體里面的寄存器分為了分發器端和CPU接口端。
typedef struct{uint32_t RESERVED0[1024];__IOM uint32_t D_CTLR; /*!< Offset: 0x1000 (R/W) Distributor Control Register */__IM uint32_t D_TYPER; /*!< Offset: 0x1004 (R/ ) Interrupt Controller Type Register */__IM uint32_t D_IIDR; /*!< Offset: 0x1008 (R/ ) Distributor Implementer Identification Register */uint32_t RESERVED1[29];__IOM uint32_t D_IGROUPR[16]; /*!< Offset: 0x1080 - 0x0BC (R/W) Interrupt Group Registers */uint32_t RESERVED2[16];__IOM uint32_t D_ISENABLER[16]; /*!< Offset: 0x1100 - 0x13C (R/W) Interrupt Set-Enable Registers */uint32_t RESERVED3[16];__IOM uint32_t D_ICENABLER[16]; /*!< Offset: 0x1180 - 0x1BC (R/W) Interrupt Clear-Enable Registers */uint32_t RESERVED4[16];__IOM uint32_t D_ISPENDR[16]; /*!< Offset: 0x1200 - 0x23C (R/W) Interrupt Set-Pending Registers */uint32_t RESERVED5[16];__IOM uint32_t D_ICPENDR[16]; /*!< Offset: 0x1280 - 0x2BC (R/W) Interrupt Clear-Pending Registers */uint32_t RESERVED6[16];__IOM uint32_t D_ISACTIVER[16]; /*!< Offset: 0x1300 - 0x33C (R/W) Interrupt Set-Active Registers */uint32_t RESERVED7[16];__IOM uint32_t D_ICACTIVER[16]; /*!< Offset: 0x1380 - 0x3BC (R/W) Interrupt Clear-Active Registers */uint32_t RESERVED8[16];__IOM uint8_t D_IPRIORITYR[512]; /*!< Offset: 0x1400 - 0x5FC (R/W) Interrupt Priority Registers */uint32_t RESERVED9[128];__IOM uint8_t D_ITARGETSR[512]; /*!< Offset: 0x1800 - 0x9FC (R/W) Interrupt Targets Registers */uint32_t RESERVED10[128];__IOM uint32_t D_ICFGR[32]; /*!< Offset: 0x1C00 - 0xC7C (R/W) Interrupt configuration registers */uint32_t RESERVED11[32];__IM uint32_t D_PPISR; /*!< Offset: 0x1D00 (R/ ) Private Peripheral Interrupt Status Register */__IM uint32_t D_SPISR[15]; /*!< Offset: 0x1D04 - 0xD3C (R/ ) Shared Peripheral Interrupt Status Registers */uint32_t RESERVED12[112];__OM uint32_t D_SGIR; /*!< Offset: 0x1F00 ( /W) Software Generated Interrupt Register */uint32_t RESERVED13[3];__IOM uint8_t D_CPENDSGIR[16]; /*!< Offset: 0x1F10 - 0xF1C (R/W) SGI Clear-Pending Registers */__IOM uint8_t D_SPENDSGIR[16]; /*!< Offset: 0x1F20 - 0xF2C (R/W) SGI Set-Pending Registers */uint32_t RESERVED14[40];__IM uint32_t D_PIDR4; /*!< Offset: 0x1FD0 (R/ ) Peripheral ID4 Register */__IM uint32_t D_PIDR5; /*!< Offset: 0x1FD4 (R/ ) Peripheral ID5 Register */__IM uint32_t D_PIDR6; /*!< Offset: 0x1FD8 (R/ ) Peripheral ID6 Register */__IM uint32_t D_PIDR7; /*!< Offset: 0x1FDC (R/ ) Peripheral ID7 Register */__IM uint32_t D_PIDR0; /*!< Offset: 0x1FE0 (R/ ) Peripheral ID0 Register */__IM uint32_t D_PIDR1; /*!< Offset: 0x1FE4 (R/ ) Peripheral ID1 Register */__IM uint32_t D_PIDR2; /*!< Offset: 0x1FE8 (R/ ) Peripheral ID2 Register */__IM uint32_t D_PIDR3; /*!< Offset: 0x1FEC (R/ ) Peripheral ID3 Register */__IM uint32_t D_CIDR0; /*!< Offset: 0x1FF0 (R/ ) Component ID0 Register */__IM uint32_t D_CIDR1; /*!< Offset: 0x1FF4 (R/ ) Component ID1 Register */__IM uint32_t D_CIDR2; /*!< Offset: 0x1FF8 (R/ ) Component ID2 Register */__IM uint32_t D_CIDR3; /*!< Offset: 0x1FFC (R/ ) Component ID3 Register */__IOM uint32_t C_CTLR; /*!< Offset: 0x2000 (R/W) CPU Interface Control Register */__IOM uint32_t C_PMR; /*!< Offset: 0x2004 (R/W) Interrupt Priority Mask Register */__IOM uint32_t C_BPR; /*!< Offset: 0x2008 (R/W) Binary Point Register */__IM uint32_t C_IAR; /*!< Offset: 0x200C (R/ ) Interrupt Acknowledge Register */__OM uint32_t C_EOIR; /*!< Offset: 0x2010 ( /W) End Of Interrupt Register */__IM uint32_t C_RPR; /*!< Offset: 0x2014 (R/ ) Running Priority Register */__IM uint32_t C_HPPIR; /*!< Offset: 0x2018 (R/ ) Highest Priority Pending Interrupt Register */__IOM uint32_t C_ABPR; /*!< Offset: 0x201C (R/W) Aliased Binary Point Register */__IM uint32_t C_AIAR; /*!< Offset: 0x2020 (R/ ) Aliased Interrupt Acknowledge Register */__OM uint32_t C_AEOIR; /*!< Offset: 0x2024 ( /W) Aliased End Of Interrupt Register */__IM uint32_t C_AHPPIR; /*!< Offset: 0x2028 (R/ ) Aliased Highest Priority Pending Interrupt Register */uint32_t RESERVED15[41];__IOM uint32_t C_APR0; /*!< Offset: 0x20D0 (R/W) Active Priority Register */uint32_t RESERVED16[3];__IOM uint32_t C_NSAPR0; /*!< Offset: 0x20E0 (R/W) Non-secure Active Priority Register */uint32_t RESERVED17[6];__IM uint32_t C_IIDR; /*!< Offset: 0x20FC (R/ ) CPU Interface Identification Register */uint32_t RESERVED18[960];__OM uint32_t C_DIR; /*!< Offset: 0x3000 ( /W) Deactivate Interrupt Register */} GIC_Type;GIC_Type就是GIC控制器,列舉出了GIC控制器的所有寄存器,可以通過結構體 GIC_Type 來訪問 GIC 的所有寄存器。
__IOM uint32_t D_CTLR; /* Offset: 0x1000 (R/W) */,分發器端相關寄存器,其相對于GIC基地址偏移為0x1000,因此我們獲取到GIC基地址以后只需要加上0x1000即可訪問GIC分發器端寄存器。
__IOM uint32_t C_CTLR; /*!< Offset: 0x2000 (R/W) CPU Interface Control Register */,CPU接口端相關寄存器,其相對于GIC基地址的偏移為0x2000,同樣的,獲取到 GIC 基地址以后只需要加上 0X2000 即可訪問 GIC 的 CPU 接口段寄存器。
總結
以上是生活随笔為你收集整理的Cortex-A7中断详解(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 京东商品推荐系统
- 下一篇: 记一次欢聚时代面试经历