IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> ARM NVIC GIC -> 正文阅读

[嵌入式]ARM NVIC GIC

最近做Cortex-A53与M3集成研究,先将中断相关记录一下,文档主要参考的是正点原子 I.MX6U嵌入式Linux驱动开发指南V1.5.pdf

NVIC

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

1、中断向量表

中断向量表是一个表,这个表里面存放的是中断向量。中断服务程序的入口地址或存放中断服务程序的首地址成为中断向量,因此中断向量表是一系列中断服务程序入口地址组成的表。这些中断服务程序(函数)在中断向量表中的位置是由半导体厂商定好的,当某个中断被触发以后就会自动跳转到中断向量表中对应的中断服务程序(函数)入口地址处。中断向量表在整个程序的最前面,比如 STM32F103 的中断向量表如下所示:

摘自startup_stm32f10x_hd.s

__Vectors       DCD     __initial_sp               ; Top of Stack
                DCD     Reset_Handler              ; Reset Handler
                DCD     NMI_Handler                ; NMI Handler
                DCD     HardFault_Handler          ; Hard Fault Handler
                DCD     MemManage_Handler          ; MPU Fault Handler
                DCD     BusFault_Handler           ; Bus Fault Handler
                DCD     UsageFault_Handler         ; Usage Fault Handler
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     SVC_Handler                ; SVCall Handler
                DCD     DebugMon_Handler           ; Debug Monitor Handler
                DCD     0                          ; Reserved
                DCD     PendSV_Handler             ; PendSV Handler
                DCD     SysTick_Handler            ; SysTick Handler

                ; External Interrupts
                DCD     WWDG_IRQHandler            ; Window Watchdog
                DCD     PVD_IRQHandler             ; PVD through EXTI Line detect
                DCD     TAMPER_IRQHandler          ; Tamper
                DCD     RTC_IRQHandler             ; RTC
                DCD     FLASH_IRQHandler           ; Flash
                DCD     RCC_IRQHandler             ; RCC
                DCD     EXTI0_IRQHandler           ; EXTI Line 0
                DCD     EXTI1_IRQHandler           ; EXTI Line 1
                DCD     EXTI2_IRQHandler           ; EXTI Line 2
                DCD     EXTI3_IRQHandler           ; EXTI Line 3
                DCD     EXTI4_IRQHandler           ; EXTI Line 4
                DCD     DMA1_Channel1_IRQHandler   ; DMA1 Channel 1
                DCD     DMA1_Channel2_IRQHandler   ; DMA1 Channel 2
                DCD     DMA1_Channel3_IRQHandler   ; DMA1 Channel 3
                DCD     DMA1_Channel4_IRQHandler   ; DMA1 Channel 4
                DCD     DMA1_Channel5_IRQHandler   ; DMA1 Channel 5
                DCD     DMA1_Channel6_IRQHandler   ; DMA1 Channel 6
                DCD     DMA1_Channel7_IRQHandler   ; DMA1 Channel 7
                DCD     ADC1_2_IRQHandler          ; ADC1 & ADC2
                DCD     USB_HP_CAN1_TX_IRQHandler  ; USB High Priority or CAN1 TX
                DCD     USB_LP_CAN1_RX0_IRQHandler ; USB Low  Priority or CAN1 RX0
                DCD     CAN1_RX1_IRQHandler        ; CAN1 RX1
                DCD     CAN1_SCE_IRQHandler        ; CAN1 SCE
                DCD     EXTI9_5_IRQHandler         ; EXTI Line 9..5
                DCD     TIM1_BRK_IRQHandler        ; TIM1 Break
                DCD     TIM1_UP_IRQHandler         ; TIM1 Update
                DCD     TIM1_TRG_COM_IRQHandler    ; TIM1 Trigger and Commutation
                DCD     TIM1_CC_IRQHandler         ; TIM1 Capture Compare
                DCD     TIM2_IRQHandler            ; TIM2
                DCD     TIM3_IRQHandler            ; TIM3
                DCD     TIM4_IRQHandler            ; TIM4
                DCD     I2C1_EV_IRQHandler         ; I2C1 Event
                DCD     I2C1_ER_IRQHandler         ; I2C1 Error
                DCD     I2C2_EV_IRQHandler         ; I2C2 Event
                DCD     I2C2_ER_IRQHandler         ; I2C2 Error
                DCD     SPI1_IRQHandler            ; SPI1
                DCD     SPI2_IRQHandler            ; SPI2
                DCD     USART1_IRQHandler          ; USART1
                DCD     USART2_IRQHandler          ; USART2
                DCD     USART3_IRQHandler          ; USART3
                DCD     EXTI15_10_IRQHandler       ; EXTI Line 15..10
                DCD     RTCAlarm_IRQHandler        ; RTC Alarm through EXTI Line
                DCD     USBWakeUp_IRQHandler       ; USB Wakeup from suspend
                DCD     TIM8_BRK_IRQHandler        ; TIM8 Break
                DCD     TIM8_UP_IRQHandler         ; TIM8 Update
                DCD     TIM8_TRG_COM_IRQHandler    ; TIM8 Trigger and Commutation
                DCD     TIM8_CC_IRQHandler         ; TIM8 Capture Compare
                DCD     ADC3_IRQHandler            ; ADC3
                DCD     FSMC_IRQHandler            ; FSMC
                DCD     SDIO_IRQHandler            ; SDIO
                DCD     TIM5_IRQHandler            ; TIM5
                DCD     SPI3_IRQHandler            ; SPI3
                DCD     UART4_IRQHandler           ; UART4
                DCD     UART5_IRQHandler           ; UART5
                DCD     TIM6_IRQHandler            ; TIM6
                DCD     TIM7_IRQHandler            ; TIM7
                DCD     DMA2_Channel1_IRQHandler   ; DMA2 Channel1
                DCD     DMA2_Channel2_IRQHandler   ; DMA2 Channel2
                DCD     DMA2_Channel3_IRQHandler   ; DMA2 Channel3
                DCD     DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & Channel5
__Vectors_End

中断向量表都是链接到代码的最前面,比如一般 ARM 处理器都是从地址 0X00000000 开始执行指令的,那么中断向量表就是从 0X00000000 开始存放的。上面第 1 行的“__initial_sp”就是第一条中断向量,存放的是栈顶指针,接下来是第 2 行复位中断复位函数 Reset_Handler 的入口地址,依次类推,直到第 27 行的最后一个中断服务函数 DMA2_Channel4_5_IRQHandler 的入口地址,这样 STM32F103 的中断向量表就建好了。
我们说 ARM 处理器都是从地址 0X00000000 开始运行的,但是我们学习 STM32 的时候代码是下载到 0X8000000 开始的存储区域中。因此中断向量表是存放到 0X8000000 地址处的,而不是 0X00000000,这样不是就出错了吗?为了解决这个问题,Cortex-M 架构引入了一个新的概念——中断向量表偏移,通过中断向量表偏移就可以将中断向量表存放到任意地址处,中断向量表偏移配置在函数 SystemInit 中完成,通过向 SCB_VTOR 寄存器写入新的中断向量表首地址即可,

void SystemInit (void)
{
	RCC->CR |= (uint32_t)0x00000001;

	/* 省略其它代码 */
#ifdef VECT_TAB_SRAM
	SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET;
#else
	SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
#endif
}

第 8 行和第 10 行就是设置中断向量表偏移,第 8 行是将中断向量表设置到 RAM 中,第10 行是将中断向量表设置到 ROM 中,基本都是将中断向量表设置到 ROM 中,也就是地址0X8000000 处。第 10 行用到了 FALSH_BASE 和 VECT_TAB_OFFSET,这两个都是宏,定义如下所示:

#define FLASH_BASE ((uint32_t)0x08000000)
#define VECT_TAB_OFFSET 0x0

因此第 10 行的代码就是:SCB->VTOR=0X080000000,中断向量表偏移设置完成。通过上面的讲解我们了解了两个跟 STM32 中断有关的概念:中断向量表和中断向量表偏移,那么这个跟 I.MX6U 有什么关系呢?因为 I.MX6U 所使用的 Cortex-A7 内核也有中断向量表和中断向量表偏移,而且其含义和 STM32 是一模一样的!只是用到的寄存器不同而已,概念完全相同!

2、NVIC(内嵌向量中断控制器)

中断系统得有个管理机构,对于 STM32 这种 Cortex-M 3内核的单片机来说这个管理机构叫做 NVIC,全称叫做 Nested Vectored Interrupt Controller。关于 NVIC 本教程不作详细的讲解,既然 Cortex-M 内核有个中断系统的管理机构—NVIC,那么 I.MX6U 所使用的 Cortex-A7 内核是不是也有个中断系统管理机构?答案是肯定的,不过 Cortex-A 内核的中断管理机构不叫做NVIC,而是叫做 GIC,全称是 general interrupt controller,后面我们会详细的讲解 Cortex-A 内核的 GIC。

3、中断使能

要使用某个外设的中断,肯定要先使能这个外设的中断,以 STM32F103 的 USART1:

  	//Usart1 NVIC 配置
  	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;		//设置中断源,类型参考 enum IRQn,stm32f10x.h
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;	//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;			//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器

上述代码就是使能USART1中断,同理,如果要使用 I.MX6U 的某个中断的话也需要使能其对应的中断。

4、中断服务函数

我们使用中断的目的就是为了使用中断服务函数,当中断发生以后中断服务函数就会被调用,我们要处理的工作就可以放到中断服务函数中去完成。同样以 STM32F103 的 USART1 为例,其中断服务函数如下所示:

void USART1_IRQHandler(void)                	//串口1中断服务程序
{
	u8 Res;
#if SYSTEM_SUPPORT_OS 		//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntEnter();    
#endif
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
	{
		Res =USART_ReceiveData(USART1);	//读取接收到的数据
		
		if((USART_RX_STA&0x8000)==0)//接收未完成
		{
			if(USART_RX_STA&0x4000)//接收到了0x0d
			{
				if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
				else USART_RX_STA|=0x8000;	//接收完成了 
			}
			else //还没收到0X0D
			{	
				if(Res==0x0d)
					USART_RX_STA|=0x4000;
				else
				{
					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
					USART_RX_STA++;
					if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收	  
				}		 
			}
		}   		 
     } 
#if SYSTEM_SUPPORT_OS 	//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntExit();  											 
#endif
} 

其中USART有如下具体中断,都跳转到同一个中断服务函数,然后再获取具体的中断源头USART_GetITStatus

#define USART_IT_PE                          ((uint16_t)0x0028)
#define USART_IT_TXE                         ((uint16_t)0x0727)
#define USART_IT_TC                          ((uint16_t)0x0626)
#define USART_IT_RXNE                        ((uint16_t)0x0525)
#define USART_IT_IDLE                        ((uint16_t)0x0424)
#define USART_IT_LBD                         ((uint16_t)0x0846)
#define USART_IT_CTS                         ((uint16_t)0x096A)
#define USART_IT_ERR                         ((uint16_t)0x0060)
#define USART_IT_ORE                         ((uint16_t)0x0360)
#define USART_IT_NE                          ((uint16_t)0x0260)
#define USART_IT_FE                          ((uint16_t)0x0160)

延伸IAP

在这里插入图片描述Reset_Handler

; Reset handler
Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  __main
                IMPORT  SystemInit
                LDR     R0, =SystemInit
                BLX     R0               
                LDR     R0, =__main
                BX      R0
                ENDP

在这里插入图片描述代码: IAP bootloader.

GICv2

1、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 个核。ARM 会根据 GIC 版本的不同研发出不同的 IP 核,那些半导体厂商直接购买对应的 IP 核即可,比如 ARM 针对 GIC V2 就开发出了 GIC400 这个中断控制器 IP 核。当 GIC 接收到外部中断信号以后就会报给 ARM 内核,但是ARM 内核只提供了四个信号给 GIC 来汇报中断情况:VFIQ、VIRQ、FIQ 和 IRQ,
请添加图片描述GIC 接收众多的外部中断,然后对其进行处理,最终就只通过四个信号报给 ARM 内核,这四个信号的含义如下:

VFIQ:虚拟快速 FIQ
VIRQ:虚拟快速 IRQ
FIQ:快速中断 IRQ
IRQ:外部中断 IRQ

VFIQ 和 VIRQ 是针对虚拟化的,我们讨论虚拟化,剩下的就是 FIQ 和 IRQ 了
在这里插入图片描述

左侧部分就是中断源,中间部分就是 GIC 控制器,最右侧就是中断控制器向处理器内核发送中断信息。我们重点要看的肯定是中间的 GIC 部分,GIC 将众多的中断源分为分为三类:
1、SPI(Shared Peripheral Interrupt),共享中断,顾名思义,所有 Core 共享的中断,这个是最常见的,那些外部中断都属于 SPI 中断(注意!不是 SPI 总线那个中断) 。比如按键中断、串口中断等等,这些中断所有的 Core 都可以处理,不限定特定 Core。
2、PPI(Private Peripheral Interrupt),私有中断,我们说了 GIC 是支持多核的,每个核肯定有自己独有的中断。这些独有的中断肯定是要指定的核心处理,因此这些中断就叫做私有中断。
3、SGI(Software-generated Interrupt),软件中断,由软件触发引起的中断,通过向寄存器GICD_SGIR 写入数据来触发,系统会使用 SGI 中断来完成多核之间的通信

2、中断 ID

中断源有很多,为了区分这些不同的中断源肯定要给他们分配一个唯一 ID,这些 ID 就是中断 ID。每一个 CPU 最多支持 1020 个中断 ID,中断 ID 号为 ID0~ID1019。这 1020个 ID 包含了 PPI、SPI 和 SGI,那么这三类中断是如何分配这 1020 个中断 ID 的呢?这 1020 个 ID 分配如下:
ID0~ID15:这 16 个 ID 分配给 SGI。
ID16~ID31:这 16 个 ID 分配给 PPI。
ID32~ID1019:这 988 个 ID 分配给 SPI,像 GPIO 中断、串口中断等这些外部中断 ,至于具体到某个 ID 对应哪个中断那就由半导体厂商根据实际情况去定义了。比如 I.MX6U的总共使用了 128 个中断 ID,加上前面属于 PPI 和 SGI 的 32 个 ID, I.MX6U 的中断源共有 128+32=160个,这 128 个中断 ID 对应的中断在《I.MX6ULL 参考手册》的“3.2 Cortex A7 interrupts”小节NXP 官方 SDK中的文件 MCIMX6Y2C.h,在此文件中定义了一个枚举类型 IRQn_Type,此枚举类型就枚举出了 I.MX6U 的所有中断,代码如下所示:

/** Interrupt Number Definitions */
#define NUMBER_OF_INT_VECTORS 160                /**< Number of interrupts in the Vector table */

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/**< hasRegInstance(`PWM1`)?`Cumulative interrupt line for PWM1. Logical OR of rollover, compare, and FIFO waterlevel crossing interrupts.`:`Reserved`) */
  PWM2_IRQn                    = 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;

3、GIC 逻辑分块

GIC 架构分为了两个逻辑块: Distributor 和 CPU Interface,也就是分发器端和 CPU 接口端。
这两个逻辑块的含义如下:
Distributor(分发器端):从上图可以看出,此逻辑块负责处理各个中断事件的分发问题,也就是中断事件应该发送到哪个 CPU Interface 上去。分发器收集所有的中断源,可以控制每个中断的优先级,它总是将优先级最高的中断事件发送到 CPU 接口端。分发器端要做的主要工作如下:
1、全局中断使能控制。
2、控制每一个中断的使能或者关闭。
3、设置每个中断的优先级。
4、设置每个中断的目标处理器列表。
5、设置每个外部中断的触发模式:电平触发或边沿触发。
6、设置每个中断属于组 0 还是组 1。
CPU Interface(CPU 接口端):CPU 接口端听名字就知道是和 CPU Core 相连接的,因此在图 17.1.3.2 中每个 CPU Core 都可以在 GIC 中找到一个与之对应的 CPU Interface。CPU 接口端就是分发器和 CPU Core 之间的桥梁,CPU 接口端主要工作如下:
1、使能或者关闭发送到 CPU Core 的中断请求信号。
2、应答中断。
3、通知中断处理完成。
4、设置优先级掩码,通过掩码来设置哪些中断不需要上报给 CPU Core。
5、定义抢占策略。
6、当多个中断到来的时候,选择优先级最高的中断通知给 CPU Core。

文件 core_ca7.h 定义了 GIC 结构体,此结构体里面的寄存器分为了分发器端和 CPU 接口端,寄存器定义如下所示:

/*
 * GIC寄存器描述结构体,
 * 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/ )文件 core_ca7.h 定义了 GIC 结构体,此结构体里面的寄存器分为了分
发器端和 CPU 接口端,寄存器定义如下所示: 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 的所有寄存器。
第 5 行是 GIC 的分发器端相关寄存器,其相对于 GIC 基地址偏移为 0X1000,因此我们获取到 GIC 基地址以后只需要加上 0X1000 即可访问 GIC 分发器端寄存器。
第 51 行是 GIC 的 CPU 接口端相关寄存器,其相对于 GIC 基地址的偏移为 0X2000,同样的,获取到 GIC 基地址以后只需要加上 0X2000 即可访问 GIC 的 CPU 接口段寄存器。

主要通过CP15协处理来操作GIC

中断使能

中断使能包括两部分,一个是 IRQ 或者 FIQ 总中断使能,另一个就是 ID0~ID1019 这 1020个中断源的使能。

1、IRQ 和 FIQ 总中断使能

IRQ 和 FIQ 分别是外部中断和快速中断的总开关,就类似家里买的进户总电闸,然后ID0~ID1019 这 1020 个中断源就类似家里面的各个电器开关。要想开电视,那肯定要保证进户总电闸是打开的,因此要想使用 I.MX6U 上的外设中断就必须先打开 IRQ 中断(本教程不使用FIQ)。在“6.3.2 程序状态寄存器”小节已经讲过了,寄存器 CPSR 的 I=1 禁止 IRQ,当 I=0 使能 IRQ;F=1 禁止 FIQ,F=0 使能 FIQ。我们还有更简单的指令来完成 IRQ 或者 FIQ 的使能和禁止:

指令描述
cpsid i禁止 IRQ 中断
cpsie i使能 IRQ 中断
cpsid f禁止 FIQ 中断
cpsie f使能 FIQ 中断

2、ID0~ID1019 中断使能和禁止

GIC 寄存器 GICD_ISENABLERn 和 GICD_ ICENABLERn 用来完成外部中断的使能和禁止,对于 Cortex-A7 内核来说中断 ID 只使用了 512 个。一个 bit 控制一个中断 ID 的使能,那么就需要 512/32=16 个 GICD_ISENABLER 寄存器来完成中断的使能。同理,也需要 16 个GICD_ICENABLER 寄存器来完成中断的禁止。其中GICD_ISENABLER0 的 bit[15:0]对应ID15~0 的 SGI 中断,GICD_ISENABLER0 的 bit[31:16]对应 ID31~16 的 PPI 中断。剩下的GICD_ISENABLER1 ~ GICD_ISENABLER15 就是控制 SPI 中断的。

中断优先级设置

1、优先级数配置

学过 STM32 都知道 Cortex-M 的中断优先级分为抢占优先级和子优先级,两者是可以配置的。同样的 Cortex-A7 的中断优先级也可以分为抢占优先级和子优先级,两者同样是可以配置的。Cortex-A7 最多可以支持 256 个优先级,数字越小,优先级越高!半导体厂商自行决定选择多少个优先级。I.MX6U 选择了 32 个优先级。在使用中断的时候需要初始化 GICC_PMR 寄存器,此寄存器用来决定使用几级优先级 ,寄存器结构如图 17.1.6.1 所示:
请添加图片描述
GICC_PMR 寄存器只有低 8 位有效,这 8 位最多可以设置 256 个优先级,其他优先级数设置如表
请添加图片描述
I.MX6U 支持 32 个优先级,所以 GICC_PMR 要设置为 0b11111000。

2、抢占优先级和子优先级位数设置

抢占优先级和子优先级各占多少位是由寄存器 GICC_BPR 来决定的
请添加图片描述寄存器 GICC_BPR 只有低 3 位有效,其值不同,抢占优先级和子优先级占用的位数也不同,配置如表
在这里插入图片描述为了简单起见,一般将所有的中断优先级位都配置为抢占优先级,比如 I.MX6U 的优先级位数为 5(32 个优先级),所以可以设置 Binary point 为 2,表示 5 个优先级位全部为抢占优先级。

3、优先级设置

前面已经设置好了 I.MX6U 一共有 32 个抢占优先级,数字越小优先级越高。具体要使用某个中断的时候就可以设置其优先级为0~31。某个中断 D的中断优先级设置由寄存器D_IPRIORITYR 来完成,前面说了 Cortex-A7 使用了 512 个中断 ID,每个中断 ID 配有一个优先级寄存器,所以一共有 512 个 D_IPRIORITYR 寄存器。如果优先级个数为32的话,使用寄存器 D_IPRIORITYR 的 bit7:4 来设置优先级,也就是说实际的优先级要左移 3 位。比如要设置ID40 中断的优先级为 5,示例代码如下:
GICD_IPRIORITYR[40] = 5 << 3;
有关优先级设置的内容就讲解到这里,优先级设置主要有三部分:

1、设置寄存器 GICC_PMR,配置优先级个数,比如 I.MX6U 支持 32 级优先级。
2、设置抢占优先级和子优先级位数,一般为了简单起见,会将所有的位数都设置为抢占 优先级。
3、设置指定中断 ID 的优先级,也就是设置外设优先级。

代码: link.

参考
代码: I.MX6U嵌入式Linux驱动开发指南V1.5.pdf.

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-08-15 15:45:24  更:2021-08-15 15:47:00 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 2:17:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计