STM32中断系统回顾

  1. 中断向量表
  2. NVIC(内嵌向量中断控制器)
  3. 中断使能
  4. 中断服务函数

中断向量表

中断向量表是一个表,表里面存放的是中断向量。
中断服务程序的入口地址或存放中断服务程序的首地址成为中断向量,因此中断向量表是一系列中断服务程序入口地址组成的表。
中断服务程序在中断向量表中的位置是由半导体厂商定好的,当某个中断被触发以后就会自动跳转到中断向量表中对应的中断服务程序入口地址处。

中断向量表在整个程序的最前面,如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 LowPriority 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_BASE0x08000000UL#define VECT_TAB_OFFSET0x0

基本都是将中断向量表设置到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个异常中断。

  1. 复位中断(Reset),CPU复位后就会进入复位中断,我们可以在复位中断服务函数里面做一些初始化工作,比如初始化SP指针,DDR等。
  2. 未定义指令中断(Undefined Instuction),如果指令不能识别的话就会产生此中断。
  3. 软中断(Software Interrupt,SWI),由SWI指令引起的中断,Linux的系统调用会用SWI指令来引起软中断,通过软中断来陷入到内核空间。
  4. 指令预取中止中断(Prefetch Abort),预取指令出错的时候会产生此中断。
  5. 数据访问中止中断(Data Abort),访问数据出错的时候会产生此中断。
  6. IRQ中断:芯片外设中断都会引起此中断发生。
  7. FIQ中断:如果需要快速处理中断的话就可以使用此中断。

Cortex-A内核CPU的所有外部中断都属于这个IRQ中断,当任意一个外部中断发生的时候都会触发IRQ中断。在IRQ中断服务函数里面就可以读取指定的寄存器来判断发生的具体是什么中断,进而根据具体的中断做出
相应的处理。

.global _start_start:ldr pc, =Reset_Handler/* 复位中断 */ldr pc, =Undefined_Handler/* 未定义中断 */ldr pc, =SVC_Handler/* SVC(Supervisor)中断 */ldr pc, =PrefAbort_Handler/* 预取终止中断 */ldr pc, =DataAbort_Handler/* 数据终止中断 */ldrpc, =NotUsed_Handler/* 未使用中断*/ldr pc, =IRQ_Handler/* IRQ中断 */ldr pc, =FIQ_Handler/* FIQ(快速中断)未定义中断 */

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将总多的中断源分为三类:

  1. SPI(Shared Peripheral Interrupt),共享中断,所有Core共享的中断,所有外部中断都属于SPI中断。比如按键中断、串口中断等等,这些中断所有的 Core 都可以处理,不限定特定 Core。
  2. PPI(Private Peripheral Interrupt),私有中断, GIC 是支持多核的,每个核肯定有自己独有的中断。这些独有的中断肯定是要指定的核心处理,因此这些中断就叫做私有中断。
  3. SGI(Software-generated Interrupt),软件中断,由软件触发引起的中断,通过向寄存器GICD_SGIR 写入数据来触发,系统会使用 SGI 中断来完成多核之间的通信。

中断ID

中断源很多,为了区分这些不同的中断源肯定要给他们分配一个唯一的ID,这些ID就是中断ID。每一个 CPU 最多支持 1020 个中断 ID,中断 ID 号为 ID0~ID1019。这 1020 个 ID 包含了 PPI、SPI 和 SGI。

  1. ID0~ID15:这 16 个 ID 分配给 SGI。
  2. ID16~ID31:这 16 个 ID 分配给 PPI。
  3. ID32~ID1019:这 988 个 ID 分配给 SPI,像 GPIO 中断、串口中断等这些外部中断。

I.MX6U 的总共使用了 128 个中断 ID,加上前面属于 PPI 和 SGI 的 32 个 ID,I.MX6U 的中断源共有 128+32=160个。

在MCIMX6Y2C.h中,定义了一个枚举类型IRQn_Type

typedef enum IRQn {/* Auxiliary constants */NotAvail_IRQn= -128, /**< Not available device specific interrupt *//* Core interrupts */Software0_IRQn = 0,/**< Cortex-A7 Software Generated Interrupt 0 */Software1_IRQn = 1,/**< Cortex-A7 Software Generated Interrupt 1 */Software2_IRQn = 2,/**< Cortex-A7 Software Generated Interrupt 2 */Software3_IRQn = 3,/**< Cortex-A7 Software Generated Interrupt 3 */Software4_IRQn = 4,/**< Cortex-A7 Software Generated Interrupt 4 */Software5_IRQn = 5,/**< Cortex-A7 Software Generated Interrupt 5 */Software6_IRQn = 6,/**< Cortex-A7 Software Generated Interrupt 6 */Software7_IRQn = 7,/**< Cortex-A7 Software Generated Interrupt 7 */Software8_IRQn = 8,/**< Cortex-A7 Software Generated Interrupt 8 */Software9_IRQn = 9,/**< Cortex-A7 Software Generated Interrupt 9 */Software10_IRQn= 10, /**< Cortex-A7 Software Generated Interrupt 10 */Software11_IRQn= 11, /**< Cortex-A7 Software Generated Interrupt 11 */Software12_IRQn= 12, /**< Cortex-A7 Software Generated Interrupt 12 */Software13_IRQn= 13, /**< Cortex-A7 Software Generated Interrupt 13 */Software14_IRQn= 14, /**< Cortex-A7 Software Generated Interrupt 14 */Software15_IRQn= 15, /**< Cortex-A7 Software Generated Interrupt 15 */VirtualMaintenance_IRQn= 25, /**< Cortex-A7 Virtual Maintenance Interrupt */HypervisorTimer_IRQn = 26, /**< Cortex-A7 Hypervisor Timer Interrupt */VirtualTimer_IRQn= 27, /**< Cortex-A7 Virtual Timer Interrupt */LegacyFastInt_IRQn = 28, /**< Cortex-A7 Legacy nFIQ signal Interrupt */SecurePhyTimer_IRQn= 29, /**< Cortex-A7 Secure Physical Timer Interrupt */NonSecurePhyTimer_IRQn = 30, /**< Cortex-A7 Non-secure Physical Timer Interrupt */LegacyIRQ_IRQn = 31, /**< Cortex-A7 Legacy nIRQ Interrupt *//* Device specific interrupts */IOMUXC_IRQn= 32, /**< General Purpose Register 1 from IOMUXC. Used to notify cores on exception condition while boot. */DAP_IRQn = 33, /**< Debug Access Port interrupt request. */SDMA_IRQn= 34, /**< SDMA interrupt request from all channels. */TSC_IRQn = 35, /**< TSC interrupt. */SNVS_IRQn= 36, /**< Logic OR of SNVS_LP and SNVS_HP interrupts. */LCDIF_IRQn = 37, /**< LCDIF sync interrupt. */RNGB_IRQn= 38, /**< RNGB interrupt. */CSI_IRQn = 39, /**< CMOS Sensor Interface interrupt request. */PXP_IRQ0_IRQn= 40, /**< PXP interrupt pxp_irq_0. */SCTR_IRQ0_IRQn = 41, /**< SCTR compare interrupt ipi_int[0]. */SCTR_IRQ1_IRQn = 42, /**< SCTR compare interrupt ipi_int[1]. */WDOG3_IRQn = 43, /**< WDOG3 timer reset interrupt request. */Reserved44_IRQn= 44, /**< Reserved */APBH_IRQn= 45, /**< DMA Logical OR of APBH DMA channels 0-3 completion and error interrupts. */WEIM_IRQn= 46, /**< WEIM interrupt request. */RAWNAND_BCH_IRQn = 47, /**< BCH operation complete interrupt. */RAWNAND_GPMI_IRQn= 48, /**< GPMI operation timeout error interrupt. */UART6_IRQn = 49, /**< UART6 interrupt request. */PXP_IRQ1_IRQn= 50, /**< PXP interrupt pxp_irq_1. */SNVS_Consolidated_IRQn = 51, /**< SNVS consolidated interrupt. */SNVS_Security_IRQn = 52, /**< SNVS security interrupt. */CSU_IRQn = 53, /**< CSU interrupt request 1. Indicates to the processor that one or more alarm inputs were asserted. */USDHC1_IRQn= 54, /**< USDHC1 (Enhanced SDHC) interrupt request. */USDHC2_IRQn= 55, /**< USDHC2 (Enhanced SDHC) interrupt request. */SAI3_RX_IRQn = 56, /**< SAI3 interrupt ipi_int_sai_rx. */SAI3_TX_IRQn = 57, /**< SAI3 interrupt ipi_int_sai_tx. */UART1_IRQn = 58, /**< UART1 interrupt request. */UART2_IRQn = 59, /**< UART2 interrupt request. */UART3_IRQn = 60, /**< UART3 interrupt request. */UART4_IRQn = 61, /**< UART4 interrupt request. */UART5_IRQn = 62, /**< UART5 interrupt request. */eCSPI1_IRQn= 63, /**< eCSPI1 interrupt request. */eCSPI2_IRQn= 64, /**< eCSPI2 interrupt request. */eCSPI3_IRQn= 65, /**< eCSPI3 interrupt request. */eCSPI4_IRQn= 66, /**< eCSPI4 interrupt request. */I2C4_IRQn= 67, /**< I2C4 interrupt request. */I2C1_IRQn= 68, /**< I2C1 interrupt request. */I2C2_IRQn= 69, /**< I2C2 interrupt request. */I2C3_IRQn= 70, /**< I2C3 interrupt request. */UART7_IRQn = 71, /**< UART-7 ORed interrupt. */UART8_IRQn = 72, /**< UART-8 ORed interrupt. */Reserved73_IRQn= 73, /**< Reserved */USB_OTG2_IRQn= 74, /**< USBO2 USB OTG2 */USB_OTG1_IRQn= 75, /**< USBO2 USB OTG1 */USB_PHY1_IRQn= 76, /**< UTMI0 interrupt request. */USB_PHY2_IRQn= 77, /**< UTMI1 interrupt request. */DCP_IRQ_IRQn = 78, /**< DCP interrupt request dcp_irq. */DCP_VMI_IRQ_IRQn = 79, /**< DCP interrupt request dcp_vmi_irq. */DCP_SEC_IRQ_IRQn = 80, /**< DCP interrupt request secure_irq. */TEMPMON_IRQn = 81, /**< Temperature Monitor Temperature Sensor (temperature greater than threshold) interrupt request. */ASRC_IRQn= 82, /**< ASRC interrupt request. */ESAI_IRQn= 83, /**< ESAI interrupt request. */SPDIF_IRQn = 84, /**< SPDIF interrupt. */Reserved85_IRQn= 85, /**< Reserved */PMU_IRQ1_IRQn= 86, /**< Brown-out event on either the 1.1, 2.5 or 3.0 regulators. */GPT1_IRQn= 87, /**< Logical OR of GPT1 rollover interrupt line, input capture 1 and 2 lines, output compare 1, 2, and 3 interrupt lines. */EPIT1_IRQn = 88, /**< EPIT1 output compare interrupt. */EPIT2_IRQn = 89, /**< EPIT2 output compare interrupt. */GPIO1_INT7_IRQn= 90, /**< INT7 interrupt request. */GPIO1_INT6_IRQn= 91, /**< INT6 interrupt request. */GPIO1_INT5_IRQn= 92, /**< INT5 interrupt request. */GPIO1_INT4_IRQn= 93, /**< INT4 interrupt request. */GPIO1_INT3_IRQn= 94, /**< INT3 interrupt request. */GPIO1_INT2_IRQn= 95, /**< INT2 interrupt request. */GPIO1_INT1_IRQn= 96, /**< INT1 interrupt request. */GPIO1_INT0_IRQn= 97, /**< INT0 interrupt request. */GPIO1_Combined_0_15_IRQn = 98, /**< Combined interrupt indication for GPIO1 signals 0 - 15. */GPIO1_Combined_16_31_IRQn= 99, /**< Combined interrupt indication for GPIO1 signals 16 - 31. */GPIO2_Combined_0_15_IRQn = 100,/**< Combined interrupt indication for GPIO2 signals 0 - 15. */GPIO2_Combined_16_31_IRQn= 101,/**< Combined interrupt indication for GPIO2 signals 16 - 31. */GPIO3_Combined_0_15_IRQn = 102,/**< Combined interrupt indication for GPIO3 signals 0 - 15. */GPIO3_Combined_16_31_IRQn= 103,/**< Combined interrupt indication for GPIO3 signals 16 - 31. */GPIO4_Combined_0_15_IRQn = 104,/**< Combined interrupt indication for GPIO4 signals 0 - 15. */GPIO4_Combined_16_31_IRQn= 105,/**< Combined interrupt indication for GPIO4 signals 16 - 31. */GPIO5_Combined_0_15_IRQn = 106,/**< Combined interrupt indication for GPIO5 signals 0 - 15. */GPIO5_Combined_16_31_IRQn= 107,/**< Combined interrupt indication for GPIO5 signals 16 - 31. */Reserved108_IRQn = 108,/**< Reserved */Reserved109_IRQn = 109,/**< Reserved */Reserved110_IRQn = 110,/**< Reserved */Reserved111_IRQn = 111,/**< Reserved */WDOG1_IRQn = 112,/**< WDOG1 timer reset interrupt request. */WDOG2_IRQn = 113,/**< WDOG2 timer reset interrupt request. */KPP_IRQn = 114,/**< Key Pad interrupt request. */PWM1_IRQn= 115,/**= 116,/**< hasRegInstance(`PWM2`)?`Cumulative interrupt line for PWM2. Logical OR of rollover, compare, and FIFO waterlevel crossing interrupts.`:`Reserved`) */PWM3_IRQn= 117,/**< hasRegInstance(`PWM3`)?`Cumulative interrupt line for PWM3. Logical OR of rollover, compare, and FIFO waterlevel crossing interrupts.`:`Reserved`) */PWM4_IRQn= 118,/**< hasRegInstance(`PWM4`)?`Cumulative interrupt line for PWM4. Logical OR of rollover, compare, and FIFO waterlevel crossing interrupts.`:`Reserved`) */CCM_IRQ1_IRQn= 119,/**< CCM interrupt request ipi_int_1. */CCM_IRQ2_IRQn= 120,/**< CCM interrupt request ipi_int_2. */GPC_IRQn = 121,/**< GPC interrupt request 1. */Reserved122_IRQn = 122,/**< Reserved */SRC_IRQn = 123,/**< SRC interrupt request src_ipi_int_1. */Reserved124_IRQn = 124,/**< Reserved */Reserved125_IRQn = 125,/**< Reserved */CPU_PerformanceUnit_IRQn = 126,/**< Performance Unit interrupt ~ipi_pmu_irq_b. */CPU_CTI_Trigger_IRQn = 127,/**< CTI trigger outputs interrupt ~ipi_cti_irq_b. */SRC_Combined_IRQn= 128,/**< Combined CPU wdog interrupts (4x) out of SRC. */SAI1_IRQn= 129,/**< SAI1 interrupt request. */SAI2_IRQn= 130,/**< SAI2 interrupt request. */Reserved131_IRQn = 131,/**< Reserved */ADC1_IRQn= 132,/**< ADC1 interrupt request. */ADC_5HC_IRQn = 133,/**< ADC_5HC interrupt request. */Reserved134_IRQn = 134,/**< Reserved */Reserved135_IRQn = 135,/**< Reserved */SJC_IRQn = 136,/**< SJC interrupt from General Purpose register. */CAAM_Job_Ring0_IRQn= 137,/**< CAAM job ring 0 interrupt ipi_caam_irq0. */CAAM_Job_Ring1_IRQn= 138,/**< CAAM job ring 1 interrupt ipi_caam_irq1. */QSPI_IRQn= 139,/**< QSPI1 interrupt request ipi_int_ored. */TZASC_IRQn = 140,/**< TZASC (PL380) interrupt request. */GPT2_IRQn= 141,/**< Logical OR of GPT2 rollover interrupt line, input capture 1 and 2 lines, output compare 1, 2 and 3 interrupt lines. */CAN1_IRQn= 142,/**< Combined interrupt of ini_int_busoff,ini_int_error,ipi_int_mbor,ipi_int_txwarning and ipi_int_waken */CAN2_IRQn= 143,/**< Combined interrupt of ini_int_busoff,ini_int_error,ipi_int_mbor,ipi_int_txwarning and ipi_int_waken */Reserved144_IRQn = 144,/**< Reserved */Reserved145_IRQn = 145,/**< Reserved */PWM5_IRQn= 146,/**< Cumulative interrupt line. OR of Rollover Interrupt line, Compare Interrupt line and FIFO Waterlevel crossing interrupt line */PWM6_IRQn= 147,/**< Cumulative interrupt line. OR of Rollover Interrupt line, Compare Interrupt line and FIFO Waterlevel crossing interrupt line */PWM7_IRQn= 148,/**< Cumulative interrupt line. OR of Rollover Interrupt line, Compare Interrupt line and FIFO Waterlevel crossing interrupt line */PWM8_IRQn= 149,/**< Cumulative interrupt line. OR of Rollover Interrupt line, Compare Interrupt line and FIFO Waterlevel crossing interrupt line */ENET1_IRQn = 150,/**< ENET1 interrupt */ENET1_1588_IRQn= 151,/**< ENET1 1588 Timer interrupt [synchronous] request. */ENET2_IRQn = 152,/**< ENET2 interrupt */ENET2_1588_IRQn= 153,/**< MAC 0 1588 Timer interrupt [synchronous] request. */Reserved154_IRQn = 154,/**< Reserved */Reserved155_IRQn = 155,/**< Reserved */Reserved156_IRQn = 156,/**< Reserved */Reserved157_IRQn = 157,/**< Reserved */Reserved158_IRQn = 158,/**< Reserved */PMU_IRQ2_IRQn= 159 /**< Brown-out event on either core, gpu or soc regulators. */} IRQn_Type;

GIC逻辑分块

GIC架构分成了两个逻辑块:Distributor和CPU Interface,也就是分发器端和CPU接口端。

  • Distributor(分发器端):此逻辑块负责处理各个中断事件的分发问题,也就是中断事件应该发送到哪个CPU Interface上去。分发器收集所有的中断源,可以控制每个中断的优先级,它总是将优先级最高的中断事件发送到CPU接口端。分发器端要做的主要工作是:
  1. 全局中断使能控制
  2. 控制每一个中断的使能或者关闭
  3. 设置每个中断的优先级
  4. 设置每个中断的目标处理器列表
  5. 设置每个外部中断的触发模式:电平触发或边沿触发
  6. 设置每个中断属于组0还是组1
  • CPU Interface(CPU接口端):与CPU Core相连接,也就是分发器和CPU Core之间的桥梁。主要工作:
  1. 使能或者关闭发送到CPU Core的中断请求信号
  2. 应答中断
  3. 通知中断处理完成
  4. 设置优先级掩码,通过掩码来设置哪些中断不需要上报给CPU Core
  5. 定义抢占策略
  6. 当多个中断到来的时候,选择优先级最高的中断通知给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 */__IMuint32_t D_TYPER;/*!< Offset: 0x1004 (R/ )Interrupt Controller Type Register */__IMuint32_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_tD_IPRIORITYR[512];/*!< Offset: 0x1400 - 0x5FC (R/W) Interrupt Priority Registers */uint32_t RESERVED9[128];__IOM uint8_tD_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];__IMuint32_t D_PPISR;/*!< Offset: 0x1D00 (R/ ) Private Peripheral Interrupt Status Register */__IMuint32_t D_SPISR[15];/*!< Offset: 0x1D04 - 0xD3C (R/ ) Shared Peripheral Interrupt Status Registers */uint32_t RESERVED12[112];__OMuint32_t D_SGIR; /*!< Offset: 0x1F00 ( /W) Software Generated Interrupt Register */uint32_t RESERVED13[3];__IOM uint8_tD_CPENDSGIR[16];/*!< Offset: 0x1F10 - 0xF1C (R/W) SGI Clear-Pending Registers */__IOM uint8_tD_SPENDSGIR[16];/*!< Offset: 0x1F20 - 0xF2C (R/W) SGI Set-Pending Registers */uint32_t RESERVED14[40];__IMuint32_t D_PIDR4;/*!< Offset: 0x1FD0 (R/ ) Peripheral ID4 Register */__IMuint32_t D_PIDR5;/*!< Offset: 0x1FD4 (R/ ) Peripheral ID5 Register */__IMuint32_t D_PIDR6;/*!< Offset: 0x1FD8 (R/ ) Peripheral ID6 Register */__IMuint32_t D_PIDR7;/*!< Offset: 0x1FDC (R/ ) Peripheral ID7 Register */__IMuint32_t D_PIDR0;/*!< Offset: 0x1FE0 (R/ ) Peripheral ID0 Register */__IMuint32_t D_PIDR1;/*!< Offset: 0x1FE4 (R/ ) Peripheral ID1 Register */__IMuint32_t D_PIDR2;/*!< Offset: 0x1FE8 (R/ ) Peripheral ID2 Register */__IMuint32_t D_PIDR3;/*!< Offset: 0x1FEC (R/ ) Peripheral ID3 Register */__IMuint32_t D_CIDR0;/*!< Offset: 0x1FF0 (R/ ) Component ID0 Register */__IMuint32_t D_CIDR1;/*!< Offset: 0x1FF4 (R/ ) Component ID1 Register */__IMuint32_t D_CIDR2;/*!< Offset: 0x1FF8 (R/ ) Component ID2 Register */__IMuint32_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 */__IMuint32_t C_IAR;/*!< Offset: 0x200C (R/ ) Interrupt Acknowledge Register */__OMuint32_t C_EOIR; /*!< Offset: 0x2010 ( /W) End Of Interrupt Register */__IMuint32_t C_RPR;/*!< Offset: 0x2014 (R/ ) Running Priority Register */__IMuint32_t C_HPPIR;/*!< Offset: 0x2018 (R/ ) Highest Priority Pending Interrupt Register */__IOM uint32_t C_ABPR; /*!< Offset: 0x201C (R/W) Aliased Binary Point Register */__IMuint32_t C_AIAR; /*!< Offset: 0x2020 (R/ ) Aliased Interrupt Acknowledge Register */__OMuint32_t C_AEOIR;/*!< Offset: 0x2024 ( /W) Aliased End Of Interrupt Register */__IMuint32_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];__IMuint32_t C_IIDR; /*!< Offset: 0x20FC (R/ ) CPU Interface Identification Register */uint32_t RESERVED18[960];__OMuint32_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 接口段寄存器。