完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>
1、中断是什么?
中断系统是一个处理器重要的组成部分,中断系统极大的提高了 CPU 的执行效率 2、STM32中断系统和 Cortex-M(STM32)中断系统的异同 STM32 的中断系统主要有以下几个关键点: ①、 中断向量表。 ②、 NVIC(内嵌向量中断控制器)。 ③、 中断使能。 ④、 中断服务函数。 2.1、中断向量表 中断向量表是一个表,这个表里面存放的是中断向量。中断服务程序的入口地址或存放中断服务程序的首地址成为中断向量,因此中断向量表是一系列中断服务程序入口地址组成的表。这些中断服务程序(函数)在中断向量表中的位置是由半导体厂商定好的,当某个中断被触发以后就会自动跳转到中断向量表中对应的中断服务程序(函数)入口地址处。中断向量表在整个程序的最前面,比如 STM32F103 的中断向量表如下所示: __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 DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & l5 上表就是 STM32F103 的中断向量表,中断向量表都是链接到代码的最前面,比如一般 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.2、NVIC(内嵌向量中断控制器) 中断系统得有个管理机构,对于 STM32 这种 Cortex-M 内核的单片机来说这个管理机构叫做 NVIC,全称叫做 Nested Vectored Interrupt Controller。关于 NVIC 本教程不作详细的讲解,既然 Cortex-M 内核有个中断系统的管理机构—NVIC,那么 I.MX6U 所使用的 Cortex-A7 内核是不是也有个中断系统管理机构?答案是肯定的,不过 Cortex-A 内核的中断管理机构不叫做NVIC,而是叫做 GIC,全称是 general interrupt controller。 2.3、中断使能 要使用某个外设的中断,肯定要先使能这个外设的中断,以 STM32F103 的 PE2 这个 IO 为例,假如我们要使用 PE2 的输入中断肯定要使用如下代码来使能对应的中断: NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2, NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //子优先级 2 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道 NVIC_Init(&NVIC_InitStructure); 上述代码就是使能 PE2 对应的 EXTI2 中断,同理,如果要使用 I.MX6U 的某个中断的话也需要使能其对应的中断。 2.4、中断服务函数 我们使用中断的目的就是为了使用中断服务函数,当中断发生以后中断服务函数就会被调用,我们要处理的工作就可以放到中断服务函数中去完成。同样以 STM32F103 的 PE2 为例,其中断服务函数如下所示: /* 外部中断 2 服务程序 */ void EXTI2_IRQHandler(void) { /* 中断处理代码 */ } 当PE2 引脚的中断触发以后就会调用其对应的中断处理函数 EXTI2_IRQHandler,我们可以在函数 EXTI2_IRQHandler 中添加中断处理代码。同理, I.MX6U 也有中断服务函数,当某个外设中断发生以后就会调用其对应的中断服务函数。 3、Cortex-A7 中断系统详解 3.1、Cortex-A7 中断系统简介 跟 STM32 一样, Cortex-A7 也有中断向量表,中断向量表也是在代码的最前面。 CortexA7 内核有 8 个异常中断,这 8 个异常中断的中断向量表如下表所示: [tr]向量地址终端类型中断模式[/tr]
在上图中,左侧的 Software0_IRQn~PMU_IRQ2_IRQ 这些都是 I.MX6U 的中断,他们都属于 IRQ 中断。当图左侧这些中断中任意一个发生的时候 IRQ 中断都会被触发,所以我们需要在 IRQ 中断服务函数中判断究竟是左侧的哪个中断发生了,然后再做出具体的处理。 在 中断系统表中一共有 7 个中断,简单介绍一下这 7 个中断: [tr]中断描述[/tr]
断的中断服务函数。 首先我们要根据表 的内容来创建中断向量表,中断向量表处于程序最开始的地方,比如我们前面例程的 start.S 文件最前面,中断向量表如下: .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 /* 数据终止中断 */ ldr pc, =NotUsed_Handler /* 未使用中断 */ ldr pc, =IRQ_Handler /* IRQ 中断 */ ldr pc, =FIQ_Handler /* FIQ(快速中断)未定义中断 */ /* 复位中断 */ Reset_Handler: /* 复位中断具体处理过程 */ /* 未定义中断 */ Undefined_Handler: ldr r0, =Undefined_Handler bx r0 /* SVC 中断 */ SVC_Handler: ldr r0, =SVC_Handler bx r0 /* 预取终止中断 */ PrefAbort_Handler: ldr r0, =PrefAbort_Handler bx r0 /* 数据终止中断 */ DataAbort_Handler: ldr r0, =DataAbort_Handler bx r0 /* 未使用的中断 */ NotUsed_Handler: ldr r0, =NotUsed_Handler bx r0 /* IRQ 中断!重点!!!!! */ IRQ_Handler: /* 复位中断具体处理过程 */ FIQ_Handler: ldr r0, =FIQ_Handler bx r0 第 4 到 11 行是中断向量表,当指定的中断发生以后就会调用对应的中断复位函数,比如复位中断发生以后就会执行第 4 行代码,也就是调用函数 Reset_Handler,函数 Reset_Handler就是复位中断的中断复位函数,其它的中断同理。 第 14 到 50 行就是对应的中断服务函数,中断服务函数都是用汇编编写的,我们实际需要编写的只有复位中断服务函数 Reset_Handler 和 IRQ 中断服务函数 IRQ_Handler,其它的中断本教程没有用到,所以都是死循环。在编写复位中断复位函数和 IRQ 中断服务函数之前我们还需要了解一些其它的知识,否则的话就没法编写。 3.2、GIC 控制器简介 3.2.1、 GIC 控制器总览 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 个核。 ARM 会根据 GIC 版本的不同研发出不同的 IP 核,那些半导体厂商直接购买对应的 IP 核即可,比如 ARM 针对 GIC V2 就开发出了 GIC400 这个中断控制器 IP 核。当 GIC 接收到外部中断信号以后就会报给 ARM 内核,但是ARM 内核只提供了四个信号给 GIC 来汇报中断情况: VFIQ、 VIRQ、 FIQ 和 IRQ,他们之间的关系如图所示: 在上图中, GIC 接收众多的外部中断,然后对其进行处理,最终就只通过四个信号报给 ARM 内核,这四个信号的含义如下:
图中左侧部分就是中断源,中间部分就是 GIC 控制器,最右侧就是中断控制器向处理器内核发送中断信息。我们重点要看的肯定是中间的 GIC 部分, GIC 将众多的中断源分为分为三类:
中断源有很多,为了区分这些不同的中断源肯定要给他们分配一个唯一 ID,这些 ID 就是中断 ID。每一个 CPU 最多支持 1020 个中断 ID,中断 ID 号为 ID0~ID1019。这 1020 个 ID 包含了 PPI、 SPI 和 SGI,那么这三类中断是如何分配这 1020 个中断 ID 的呢?这 1020 个 ID 分配如下:
[tr]IRQID中断源描述[/tr]
NXP 官方 SDK中的文件 MCIMX6Y2C.h,在此文件中定义了一个枚举类型 IRQn_Type,此枚举类型就枚举出了 I.MX6U 的所有中断,代码如下所示: 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.3.3、 GIC 逻辑分块 GIC 架构分为了两个逻辑块: Distributor 和 CPU Interface,也就是分发器端和 CPU 接口端。这两个逻辑块的含义如下: Distributor(分发器端) : 从GICV2 的逻辑图中可以看出,此逻辑块负责处理各个中断事件的分发问题,也就是中断事件应该发送到哪个 CPU Interface 上去。分发器收集所有的中断源,可以控制每个中断的优先级,它总是将优先级最高的中断事件发送到 CPU 接口端。分发器端要做的主要工作如下:
①、使能或者关闭发送到 CPU Core 的中断请求信号。 ②、应答中断。 ③、通知中断处理完成。 ④、设置优先级掩码,通过掩码来设置哪些中断不需要上报给 CPU Core。 ⑤、定义抢占策略。 ⑥、当多个中断到来的时候,选择优先级最高的中断通知给 CPU Core。 构体里面的寄存器分为了分发器端和 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 的所有寄存器。 第 5 行是 GIC 的分发器端相关寄存器,其相对于 GIC 基地址偏移为 0X1000,因此我们获取到 GIC 基地址以后只需要加上 0X1000 即可访问 GIC 分发器端寄存器。 第 51 行是 GIC 的 CPU 接口端相关寄存器,其相对于 GIC 基地址的偏移为 0X2000,同样的,获取到 GIC 基地址以后只需要加上 0X2000 即可访问 GIC 的 CPU 接口段寄存器。那么问题来了? GIC 控制器的寄存器基地址在哪里呢?这个就需要用到 Cortex-A 的 CP15 协处理器了 3.3、CP15 协处理器 关 于 CP15 协处理 器和其 相关寄存 器的详细 内容 请参考下 面两份文 档: 《 ARMArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf》 第 1469 页“B3.17 Oranizationof the CP15 registers in a VMSA implementation”。《Cortex-A7 Technical ReferenceManua.pdf》 第55 页“Capter 4 System Control”。 CP15 协处理器一般用于存储系统管理,但是在中断中也会使用到, CP15 协处理器一共有16 个 32 位寄存器。 CP15 协处理器的访问通过如下几个指令完成: [tr]指令描述[/tr]
MCR{cond} p15,
假如我们要将 CP15 中 C0 寄存器的值读取到 R0 寄存器中,那么就可以使用如下命令: MRC p15, 0, r0, c0, c0, 01 CP15 协处理器有 16 个 32 位寄存器, c0~c15 3.3.1、c0 寄存器 CP15 协处理器有 16 个 32 位寄存器, c0~c15,在使用 MRC 或者 MCR 指令访问这 16 个 寄存器的时候,指令中的 CRn、 opc1、 CRm 和 opc2 通过不同的搭配,其得到的寄存器含义是 不同的。比如 c0 在不同的搭配情况下含义如下图所示: 在图中当 MRC/MCR 指令中的 CRn=c0, opc1=0, CRm=c0, opc2=0 的时候就表示此时的 c0 就是 MIDR 寄存器,也就是主 ID 寄存器,这个也是 c0 的基本作用。对于 Cortex-A7内核来说, c0 作为 MDIR 寄存器的时候其含义如图所示: 在图中各位所代表的含义如下: [tr]位含义[/tr]
c1 寄存器同样通过不同的配置,其代表的含义也不同,如图所示: 在图中当 MRC/MCR 指令中的 CRn=c1, opc1=0, CRm=c0, opc2=0 的时候就表示此时的 c1 就是 SCTLR 寄存器,也就是系统控制寄存器,这个是 c1 的基本作用。 SCTLR 寄存器主要是完成控制功能的,比如使能或者禁止 MMU、 I/D Cache 等, c1 作为 SCTLR 寄存器的时候其含义如下图所示: SCTLR 的位比较多,我们就只看本次会用到的几个位: [tr]位描述[/tr]
MRC p15, 0,, c1, c0, 0 ;读取 SCTLR 寄存器,数据保存到 Rt 中。MCR p15, 0,, c1, c0, 0 ;将 Rt 中的数据写到 SCTLR(c1)寄存器中。123.3.3、 c12 寄存器 c12 寄存器通过不同的配置,其代表的含义也不同,如图所示: 在上图中当 MRC/MCR 指令中的 CRn=c12, opc1=0, CRm=c0, opc2=0 的时候就表示此时 c12 为 VBAR 寄存器,也就是向量表基地址寄存器。设置中断向量表偏移的时候就需要将新的中断向量表基地址写入 VBAR 中,比如在前面的例程中,代码链接的起始地址为0X87800000,而中断向量表肯定要放到最前面,也就是 0X87800000 这个地址处。所以就需要设置 VBAR 为 0X87800000,设置命令如下: ldr r0, =0X87800000 ; r0=0X87800000MCR p15, 0, r0, c12, c0, 0 ;将 r0 里面的数据写入到 c12 中,即 c12=0X87800000123.3.4、c15 寄存器 c15 寄存器也可以通过不同的配置得到不同的含义 在图中,我们需要 c15 作为 CBAR 寄存器,因为 GIC 的基地址就保存在 CBAR中,我们可以通过如下命令获取到 GIC 基地址: MRC p15, 4, r1, c15, c0, 0 ; 获取 GIC 基础地址,基地址保存在 r1 中。1 获取到 GIC 基地址以后就可以设置 GIC 相关寄存器了,比如我们可以读取当前中断 ID,当前中断 ID 保存在 GICC_IAR 中,寄存器 GICC_IAR 属于 CPU 接口端寄存器,寄存器地址相对于 CPU 接口端起始地址的偏移为 0XC,因此获取当前中断 ID 的代码如下: MRC p15, 4, r1, c15, c0, 0 ;获取 GIC 基地址ADD r1, r1, #0X2000 ;GIC 基地址加 0X2000 得到 CPU 接口端寄存器起始地址LDR r0, [r1, #0XC] ;读取 CPU 接口端起始地址+0XC 处的寄存器值,也就是寄存器GIC_IAR 的值12343.3.5、 总结 [tr]寄存器作用[/tr]
中断使能包括两部分,一个是 IRQ 或者 FIQ 总中断使能,另一个就是 ID0~ID1019 这 1020个中断源的使能。 3.4.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 的使能和禁止,图表所示: [tr]指令描述[/tr]
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 中断的。 3.5、中断优先级设置 3.5.1、优先级数配置 学过 STM32 都知道 Cortex-M 的中断优先级分为抢占优先级和子优先级,两者是可以配置的。同样的 Cortex-A7 的中断优先级也可以分为抢占优先级和子优先级,两者同样是可以配置的。 Cortex-A7 最多可以支持 256 个优先级,数字越小,优先级越高!半导体厂商自行决定选择多少个优先级。 I.MX6U 选择了 32 个优先级。在使用中断的时候需要初始化 GICC_PMR 寄存器,此寄存器用来决定使用几级优先级,寄存器结构如图所示: GICC_PMR 寄存器只有低 8 位有效,这 8 位最多可以设置 256 个优先级,其他优先级数设置如下表所示: [tr]bit[7:0]优先级数[/tr]
3.5.2、抢占优先级和子优先级位数设置 抢占优先级和子优先级各占多少位是由寄存器 GICC_BPR 来决定的, GICC_BPR 寄存器结构如下图所示: 寄存器 GICC_BPR 只有低 3 位有效,其值不同,抢占优先级和子优先级占用的位数也不同,配置如下表所示: [tr]Binary Point抢占优先级域子优先级域描述[/tr]
3.6.3、优先级设置 前面已经设置好了 I.MX6U 一共有 32 个抢占优先级,数字越小优先级越高。具体要使用某个中断的时候就可以设置其优先级为 0~31。某个中断 ID 的中断优先级设置由寄存器D_IPRIORITYR 来完成,前面说了 Cortex-A7 使用了 512 个中断 ID,每个中断 ID 配有一个优先级寄存器,所以一共有 512 个 D_IPRIORITYR 寄存器。如果优先级个数为 32 的话,使用寄存器 D_IPRIORITYR 的 bit7:4 来设置优先级,也就是说实际的优先级要左移 3 位。比如要设置ID40 中断的优先级为 5,示例代码如下: GICD_IPRIORITYR[40] = 5 << 3;13.6.4、总结 优先级设置主要有三部分:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1154 浏览1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1185 浏览1 评论
603 浏览2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
451 浏览2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1099 浏览2 评论
1653浏览9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
318浏览4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
318浏览3评论
310浏览3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
286浏览3评论
小黑屋|手机版|Archiver|德赢Vwin官网(湘ICP备2023018690号)
GMT+8, 2024-8-28 11:07, Processed in 0.731587 second(s), Total 47, Slave 41 queries .
Powered by德赢Vwin官网 网
© 2015bbs.elecfans.com
关注我们的微信
下载发烧友APP
德赢Vwin官网 观察
版权所有 © 湖南华秋数字科技有限公司
德赢Vwin官网 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号