嵌入式Linux裸机开发(五)中断管理

news2024/7/6 17:56:43

系列文章目录


文章目录

  • 系列文章目录
  • 前言
  • STM32 中断系统
  • IMX6U中断控制
    • 8个中断
    • GIC中断控制器
      • GIC介绍
      • 中断ID
      • GIC逻辑分块
      • GIC协处理器
    • 中断使能
    • 中断优先级
  • 重点代码分析
    • 官方SDK函数
    • start.S文件
    • 自行编写中断驱动文件


前言

最近在学习中发现,学Linux嵌入式不仅是对Linux的学习熟悉,而且还是对Cortex-A内核的学习掌握
没怎么看懂,内容太多了,我觉得暂时先搞清楚一些原理概念以及简单的外部函数接口就行,内部可能在后续的学习中进行钻研


STM32 中断系统

STM32 的中断系统主要有以下几个关键点:
①、 中断向量表。
②、 NVIC(内嵌向量中断控制器)。
③、 中断使能。
④、 中断服务函数。

中断向量表是一个表,这个表里面存放的是中断向量。中断向量表是一系列中断服务程序入口地址组成的表。
由半导体厂商定好的,当某个中断被触发以后就会自动跳转到中断向量表中对应的中断服务程序(函数)入口地址处。
中断向量表在整个程序的最前面,如 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     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_2
                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     0                          ; Reserved
                DCD     I2C1_EV_IRQHandler         ; I2C1 Event
                DCD     I2C1_ER_IRQHandler         ; I2C1 Error
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     SPI1_IRQHandler            ; SPI1
                DCD     0                          ; Reserved
                DCD     USART1_IRQHandler          ; USART1
                DCD     USART2_IRQHandler          ; USART2
                DCD     0                          ; Reserved
                DCD     EXTI15_10_IRQHandler       ; EXTI Line 15..10
                DCD     RTC_Alarm_IRQHandler        ; RTC Alarm through EXTI Line
                DCD     USBWakeUp_IRQHandler       ; USB Wakeup from suspend
__Vectors_End

中断向量表都是链接到代码的最前面,比如一般 ARM 处理器都是从地址 0X00000000 开始执行指令的,那么中断向量表就是从 0X00000000 开始存放的。

“__initial_sp”就是第一条中断向量,存放的是栈顶指针
复位中断复位函数 Reset_Handler 的入口地址

ARM 处理器都是从地址 0X00000000 开始运行,但是我们是下载到 0X8000000 开始的存储区域中,Cortex-M 架构引入了中断向量表偏移,中断向量表偏移配置在函数 SystemInit 中完成,通过向 SCB_VTOR 寄存器写入新的中断向量表首地址即可。

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

	/* 省略其它代码 */

 #ifdef VECT_TAB_SRAM
 	SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET;     //将中断向量表设置到 RAM 中
 #else
 	SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;     //将中断向量表设置到 ROM 中
 #endif
}

#define FLASH_BASE ((uint32_t)0x08000000)

对于Cortex-M来说:
中断使能:

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);

中断服务函数:
要处理的工作就可以放到中断服务函数中去完成

/* 外部中断 2 服务程序 */
void EXTI2_IRQHandler(void)
{
/* 中断处理代码 */
}

IMX6U中断控制

Cortex-M 内核有个中断系统的管理机构—NVIC(Nested Vectored Interrupt Controller)
Cortex-A7 内核有个中断系统管理机构——GIC(general interrupt controller)

8个中断

Cortex-A内核有8个异常中断:
在这里插入图片描述
其中还包括一个未使用中断,实际只有七个中断。

对于 Cortex-M 内核来说,中断向量表列举出了一款芯片所有的中断向量,包括芯片外设的所有中断。

Cortex-A 内核 CPU 的所有外部中断都属于这个 IRQ 中断,当任意一个外部中断发生的时候都会触发 IRQ 中断。在 IRQ 中断服务函数里面就可以读取指定的寄存器来判断发生的具体是什么中断,进而根据具体的中断做出相应的处理。
在这里插入图片描述
①、复位中断(Rest), CPU 复位以后就会进入复位中断,我们可以在复位中断服务函数里面做一些初始化工作,比如初始化 SP 指针、 DDR 等等。
②、未定义指令中断(Undefined Instruction),如果指令不能识别的话就会产生此中断。
③、软中断(Software Interrupt,SWI),由 SWI 指令引起的中断, Linux 的系统调用会用 SWI指令来引起软中断,通过软中断来陷入到内核空间。
④、指令预取中止中断(Prefetch Abort),预取指令的出错的时候会产生此中断。
⑤、数据访问中止中断(Data Abort),访问数据出错的时候会产生此中断。
⑥、 IRQ 中断(IRQ Interrupt),外部中断,前面已经说了,芯片内部的外设中断都会引起此中断的发生。
⑦、 FIQ 中断(FIQ Interrupt),快速中断,如果需要快速处理中断的话就可以使用此中断。

常用复位中断和IRQ中断,实际需要编写的只有复位中断服务函数 Reset_Handler 和 IRQ 中断服务函数 IRQ_Handler,其它的中断本暂时没用到,所以都是死循环。

GIC中断控制器

GIC介绍

GIC目前有V1-V4,V1太老淘汰了,GIC V2 是给 ARMv7-A 架构使用的,比如 Cortex-A7、 Cortex-A9、 Cortex-A15 等,V3 和 V4 是给 ARMv8-A/R 架构使用的,也就是 64 位芯片使用的。ARM 会根据 GIC 版本的不同研发出不同的 IP 核,那些半导体厂商直接购买对应的 IP 核即可,ARM 针对 GIC V2 就开发出了 GIC400 这个中断控制器 IP 核。当 GIC 接收到外部中断信号以后就会报给 ARM 内核,但是ARM 内核只提供了四个信号给 GIC 来汇报中断情况: VFIQ、 VIRQ、 FIQ 和 IRQ。

VFIQ:虚拟快速 FIQ。VIRQ:虚拟外部 IRQ。FIQ:快速中断 IRQ。IRQ:外部中断 IRQ。
VFIQ 和 VIRQ 是针对虚拟化的,不管,只看IRQ
在这里插入图片描述
①、 SPI(Shared Peripheral Interrupt),共享中断,所有 Core 共享的中断,那些外部中断都属于 SPI 中断。比如按键中断、串口中断等等,这些中断所有的 Core 都可以处理,不限定特定 Core。
②、 PPI(Private Peripheral Interrupt),私有中断, GIC 是支持多核的,每个核肯定有自己独有的中断。这些独有的中断肯定是要指定的核心处理。
③、 SGI(Software-generated Interrupt),软件中断,由软件触发引起的中断,通过向寄存器GICD_SGIR 写入数据来触发,系统会使用 SGI 中断来完成多核之间的通信。

中断ID

每一个 CPU 最多支持 1020 个中断 ID,中断 ID 号为 ID0~ID1019。这 1020 个 ID 包含了 PPI、 SPI 和 SGI。

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

I.MX6U 的总共使用了 128 个SPI中断,以及 PPI 和 SGI 的 32 个 ID,一共160个

中断ID全部都在参考手册的第三章:
在这里插入图片描述
移植的官方SDK(Software Development Kit)中就有所有中断ID的枚举
在这里插入图片描述

GIC逻辑分块

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

Distributor(分发器端):中断事件应该发送到哪个 CPU 接口,将优先级最高的中断事件发送到 CPU 接口端
全局中断使能控制。控制每一个中断的使能或者关闭。设置每个中断的优先级。设置每个中断的目标处理器列表。设置每个外部中断的触发模式:电平触发或边沿触发。设置每个中断属于组 0 还是组 1。

CPU Interface(CPU 接口端):每个 CPU Core 都可以在 GIC 中找到一个与之对应的 CPU Interface
使能或者关闭发送到 CPU Core 的中断请求信号。应答中断。通知中断处理完成。设置优先级掩码,通过掩码来设置哪些中断不需要上报给 CPU Core。定义抢占策略。当多个中断到来的时候,选择优先级最高的中断通知给 CPU Core。

在我们移植的 core_ca7.h 文件里面有定义结构体 GIC_Type,分发器端和 CPU 接口端:
在这里插入图片描述

GIC协处理器

通过 c0 寄存器可以获取到处理器内核信息;通过 c1 寄存器可以使能或禁止 MMU、 I/D Cache 等;通过 c12 寄存器可以设置中断向量偏移;通过 c15 寄存器可以获取 GIC 基地址。(暂时没太理解,后续补充)

中断使能

使用 I.MX6U 上的外设中断就必须先打开 IRQ 中断
寄存器 CPSR 的 I=1 禁止 IRQ,当 I=0 使能 IRQ; F=1 禁止 FIQ, F=0 使能 FIQ。
还可以使用更简单的指令:
在这里插入图片描述
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 中断的。

中断优先级

Cortex-A7 的中断优先级也可以分为抢占优先级和子优先级,两者同样是可以配置的。 GIC 控制器最多可以支持 256 个优先级,数字越小,优先级越高! Cortex-A7 选择了 32 个优先级。

在使用中断的时候需要初始化 GICC_PMR 寄存器:(设置优先级数)
在这里插入图片描述
Cortex-A7内核支持 32 个优先级。

抢占优先级和子优先级位数设置由寄存器 GICC_BPR决定:
在这里插入图片描述
寄存器 GICC_BPR 只有低 3 位有效,其值不同,抢占优先级和子优先级占用的位数也不同:
在这里插入图片描述
有32个抢占优先级,Cortex-A7 使用了 512 个中断 ID
如要设置ID40 中断的优先级为 5:

GICD_IPRIORITYR[40] = 5 << 3

重点代码分析

官方SDK函数

先了解官方SDK包的API函数:

GIC_Init     				//初始化 GIC。
GIC_EnableIRQ 				//使能指定的外设中断。
GIC_DisableIRQ 				//关闭指定的外设中断。
GIC_AcknowledgeIRQ 			//返回中断号。
GIC_DeactivateIRQ 			//无效化指定中断。
GIC_GetRunningPriority 		//获取当前正在运行的中断优先级。
GIC_SetPriorityGrouping 	//设置抢占优先级位数。
GIC_GetPriorityGrouping 	//获取抢占优先级位数。
GIC_SetPriority 			//设置指定中断的优先级。
GIC_GetPriority 			//获取指定中断的优先级。

这些函数都在文件末尾:
在这里插入图片描述

start.S文件

.global _start  				/* 全局标号 */

/*
 * 描述:	_start函数,首先是中断向量表的创建
 * 参考文档:ARM Cortex-A(armV7)编程手册V4.0.pdf P42,3 ARM Processor Modes and Registers(ARM处理器模型和寄存器)
 * 		 	ARM Cortex-A(armV7)编程手册V4.0.pdf P165 11.1.1 Exception priorities(异常)
 */
_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:

	cpsid i						/* 关闭全局中断 */

	/* 关闭I,DCache和MMU    关闭 I/D Cache、 MMU、对齐检测和分支预测
	 * 采取读-改-写的方式。
	 */
	mrc     p15, 0, r0, c1, c0, 0     /* 读取CP15的C1寄存器到R0中       		        	*/
    bic     r0,  r0, #(0x1 << 12)     /* 清除C1寄存器的bit12位(I位),关闭I Cache            	*/
    bic     r0,  r0, #(0x1 <<  2)     /* 清除C1寄存器的bit2(C位),关闭D Cache    				*/
    bic     r0,  r0, #0x2             /* 清除C1寄存器的bit1(A位),关闭对齐						*/
    bic     r0,  r0, #(0x1 << 11)     /* 清除C1寄存器的bit11(Z位),关闭分支预测					*/
    bic     r0,  r0, #0x1             /* 清除C1寄存器的bit0(M位),关闭MMU				       	*/
    mcr     p15, 0, r0, c1, c0, 0     /* 将r0寄存器中的值写入到CP15的C1寄存器中	 				*/

	
#if 0
	/* 汇编版本设置中断向量表偏移 */
	ldr r0, =0X87800000

	dsb
	isb
	mcr p15, 0, r0, c12, c0, 0
	dsb
	isb
#endif
    
	/* 设置各个模式下的栈指针,
	 * 注意:IMX6UL的堆栈是向下增长的!
	 * 堆栈指针地址一定要是4字节地址对齐的!!!
	 * DDR范围:0X80000000~0X9FFFFFFF
	 */
	/* 进入IRQ模式 */
	mrs r0, cpsr
	bic r0, r0, #0x1f 	/* 将r0寄存器中的低5位清零,也就是cpsr的M0~M4 	*/
	orr r0, r0, #0x12 	/* r0或上0x13,表示使用IRQ模式					*/
	msr cpsr, r0		/* 将r0 的数据写入到cpsr_c中 					*/
	ldr sp, =0x80600000	/* 设置IRQ模式下的栈首地址为0X80600000,大小为2MB */

	/* 进入SYS模式 */
	mrs r0, cpsr
	bic r0, r0, #0x1f 	/* 将r0寄存器中的低5位清零,也就是cpsr的M0~M4 	*/
	orr r0, r0, #0x1f 	/* r0或上0x13,表示使用SYS模式					*/
	msr cpsr, r0		/* 将r0 的数据写入到cpsr_c中 					*/
	ldr sp, =0x80400000	/* 设置SYS模式下的栈首地址为0X80400000,大小为2MB */

	/* 进入SVC模式 */
	mrs r0, cpsr
	bic r0, r0, #0x1f 	/* 将r0寄存器中的低5位清零,也就是cpsr的M0~M4 	*/
	orr r0, r0, #0x13 	/* r0或上0x13,表示使用SVC模式					*/
	msr cpsr, r0		/* 将r0 的数据写入到cpsr_c中 					*/
	ldr sp, =0X80200000	/* 设置SVC模式下的栈首地址为0X80200000,大小为2MB */

	cpsie i				/* 打开全局中断 */
#if 0
	/* 使能IRQ中断 */
	mrs r0, cpsr		/* 读取cpsr寄存器值到r0中 			*/
	bic r0, r0, #0x80	/* 将r0寄存器中bit7清零,也就是CPSR中的I位清零,表示允许IRQ中断 */
	msr cpsr, r0		/* 将r0重新写入到cpsr中 			*/
#endif

	b main				/* 跳转到main函数 			 	*/

/* 未定义中断 */
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:
	push {lr}					/* 保存lr地址 */
	push {r0-r3, r12}			/* 保存r0-r3,r12寄存器 */

	mrs r0, spsr				/* 读取spsr寄存器 */
	push {r0}					/* 保存spsr寄存器 */

	mrc p15, 4, r1, c15, c0, 0 /* 从CP15的C0寄存器内的值到R1寄存器中
								* 参考文档ARM Cortex-A(armV7)编程手册V4.0.pdf P49
								* Cortex-A7 Technical ReferenceManua.pdf P68 P138
								*/							
	add r1, r1, #0X2000			/* GIC基地址加0X2000,也就是GIC的CPU接口端基地址 */
	ldr r0, [r1, #0XC]			/* GIC的CPU接口端基地址加0X0C就是GICC_IAR寄存器,
								 * GICC_IAR寄存器保存这当前发生中断的中断号,我们要根据
								 * 这个中断号来绝对调用哪个中断服务函数
								 */
	push {r0, r1}				/* 保存r0,r1 */
	
	cps #0x13					/* 进入SVC模式,允许其他中断再次进去 */
	
	push {lr}					/* 保存SVC模式的lr寄存器 */
	ldr r2, =system_irqhandler	/* 加载C语言中断处理函数到r2寄存器中*/
	blx r2						/* 运行C语言中断处理函数,带有一个参数,保存在R0寄存器中 */

	pop {lr}					/* 执行完C语言中断服务函数,lr出栈 */
	cps #0x12					/* 进入IRQ模式 */
	pop {r0, r1}				
	str r0, [r1, #0X10]			/* 中断执行完成,写EOIR */

	pop {r0}						
	msr spsr_cxsf, r0			/* 恢复spsr */

	pop {r0-r3, r12}			/* r0-r3,r12出栈 */
	pop {lr}					/* lr出栈 */
	subs pc, lr, #4				/* 将lr-4赋给pc */
	
/* FIQ中断 */
FIQ_Handler:

	ldr r0, =FIQ_Handler	
	bx r0									

重点在复位中断和IRQ中断(目前学的比较浅,还不太理解),但是关于下图:
在这里插入图片描述
之前学习过ARM的三级流水过程:(类似下图)
在这里插入图片描述
中断发生保存的是0x2008,所以要跳回到0x2004处执行这条指令,不然漏了这条指令。

自行编写中断驱动文件

irqNesting:中断嵌套计数器
irqTable:中断服务函数数组,大小为 I.MX6U 的中断源个数:160 个
int_init:中断初始化函数,初始化了 GIC,然后初始化了中断服务函数表,最终设置了中断向量表偏移
system_irqtable_init:中断服务函数表初始化函数,初始化 irqTable,给其赋初值
start.S 中调用的 system_irqhandler 函数:根据中断号在中断处理函数表 irqTable 中取出对应的中断处理函数并执行
default_irqhandler: 默认中断处理函数

#include "bsp_int.h"

/* 中断嵌套计数器 */
static unsigned int irqNesting;

/* 中断服务函数表 */
static sys_irq_handle_t irqTable[NUMBER_OF_INT_VECTORS];

/*
 * @description	: 中断初始化函数
 * @param		: 无
 * @return 		: 无
 */
void int_init(void)
{
	GIC_Init(); 						/* 初始化GIC 							*/
	system_irqtable_init();				/* 初始化中断表 							*/
	__set_VBAR((uint32_t)0x87800000); 	/* 中断向量表偏移,偏移到起始地址   				*/
}

/*
 * @description	: 初始化中断服务函数表 
 * @param		: 无
 * @return 		: 无
 */
void system_irqtable_init(void)
{
	unsigned int i = 0;
	irqNesting = 0;
	
	/* 先将所有的中断服务函数设置为默认值 */
	for(i = 0; i < NUMBER_OF_INT_VECTORS; i++)
	{
		system_register_irqhandler((IRQn_Type)i,default_irqhandler, NULL);
	}
}

/*
 * @description			: 给指定的中断号注册中断服务函数 
 * @param - irq			: 要注册的中断号
 * @param - handler		: 要注册的中断处理函数
 * @param - usrParam	: 中断服务处理函数参数
 * @return 				: 无
 */
void system_register_irqhandler(IRQn_Type irq, system_irq_handler_t handler, void *userParam) 
{
	irqTable[irq].irqHandler = handler;
  	irqTable[irq].userParam = userParam;
}

/*
 * @description			: C语言中断服务函数,irq汇编中断服务函数会
 						  调用此函数,此函数通过在中断服务列表中查
 						  找指定中断号所对应的中断处理函数并执行。
 * @param - giccIar		: 中断号
 * @return 				: 无
 */
void system_irqhandler(unsigned int giccIar) 
{

   uint32_t intNum = giccIar & 0x3FFUL;
   
   /* 检查中断号是否符合要求 */
   if ((intNum == 1023) || (intNum >= NUMBER_OF_INT_VECTORS))
   {
	 	return;
   }
 
   irqNesting++;	/* 中断嵌套计数器加一 */

   /* 根据传递进来的中断号,在irqTable中调用确定的中断服务函数*/
   irqTable[intNum].irqHandler(intNum, irqTable[intNum].userParam);
 
   irqNesting--;	/* 中断执行完成,中断嵌套寄存器减一 */

}

/*
 * @description			: 默认中断服务函数
 * @param - giccIar		: 中断号
 * @param - usrParam	: 中断服务处理函数参数
 * @return 				: 无
 */
void default_irqhandler(unsigned int giccIar, void *userParam) 
{
	while(1) 
  	{
   	}
}

还是没怎么看懂,内容太多了,我觉得暂时先搞清楚一些原理概念以及简单的外部函数接口就行,内部可能在后续的学习中进行钻研

gpio内部有中断的设置:
在这里插入图片描述

中断函数写在这里:
在这里插入图片描述
主函数进行初始化:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1077554.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大型组网如何使用BFD提高可靠性

1.当前现网业务存在哪些问题&#xff1f; 2.BFD的工作机制讲解 3.BFD联动静态路由以及OSPF实战 --- BFD - 双向转发检测 - 通用标准 SLA --- 介质无关 协议无关 --- BFD基本原理 --- BFD应用场景配置方式 --- BFD结合OSPF --- BFD结合静态路由 跨网段…

MySQL 面试知识脑图 初高级知识点

脑图下载地址&#xff1a;https://mm.edrawsoft.cn/mobile-share/index.html?uuid18b10870122586-src&share_type1 sql_mode 基本语法及校验规则 ONLY_FULL_GROUP_BY 对于GROUP BY聚合操作&#xff0c;如果在SELECT中的列&#xff0c;没有在GROUP BY中出现&#xff…

【计算机网络】第三章课后习题答案

习题目录&#xff1a; 【3-01】数据链路&#xff08;即逻辑链路&#xff09;与链路&#xff08;即物理链路&#xff09;有何区别&#xff1f;"链路接通了"与"数据链路接通了"的区别何在&#xff1f; 【3-02】数据链路层中的链路控制包括哪些功能&#xf…

Arduino驱动LSM303DLH电子罗盘(惯性测量传感器篇)

目录 1、传感器特性 2、控制器和传感器连线图 3、驱动程序 LSM303DLH电子罗盘传感器集成了3轴磁场,3轴加速度传感器,可以提供倾斜补偿后的输出。LSM303DLH芯片的加速计、磁力计、A/D转化器及信号条理电路集成在一起,通过I2C总线和处理器通信。这样只用一颗芯片就实现了6轴…

Java架构师高并发架构设计

目录 1 导学2 什么是高并发问题3 高并发处理之道4 akf扩展立方体5 细化理念应对高并发5 总结1 导学 本章的主要内容是大型系统架构设计的难点之一,高并发架构设计相关的知识落到实际项目上,就是订单系统的高并发架构设计。我们首先会去学习到底何为高并发问题,先把问题搞清楚…

Typescript 综合笔记:解读一个github中的React 网页

1 repository来源和效果 zhitern/ntu-scse22-0163-web (github.com) 2 核心代码异同&#xff08;相比于初始创建的代码&#xff09; 2.1 index.html 和初始创建的是一样的 2.2 App.css 和初始创建的是一样的 2.3 index.tsx 唯一”不一样“的是紫色部分,tsx文件中多了一个…

【力扣2011】执行操作后的变量值

&#x1f451;专栏内容&#xff1a;力扣刷题⛪个人主页&#xff1a;子夜的星的主页&#x1f495;座右铭&#xff1a;前路未远&#xff0c;步履不停 目录 一、题目描述二、题目分析 一、题目描述 题目链接&#xff1a;执行操作后的变量值 存在一种仅支持 4 种操作和 1 个变量 …

【计算机网络】UDP协议编写群聊天室----附代码

UDP构建服务器 x 预备知识 认识UDP协议 此处我们也是对UDP(User Datagram Protocol 用户数据报协议)有一个直观的认识; 后面再详细讨论. 传输层协议无连接不可靠传输面向数据报 网络字节序 我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的…

YOLOv7损失函数改进:SlideLoss,解决简单样本和困难样本之间的不平衡问题

💡💡💡本文改进:SlideLoss,解决简单样本和困难样本之间的不平衡问题,并使用有效感受野的信息来设计Anchor。 SlideLoss| 亲测在多个数据集能够实现涨点,对小目标、遮挡物性能提升也能够助力涨点。 收录: YOLOv7高阶自研专栏介绍: http://t.csdnimg.cn/tYI0c …

JVM面试题:(二)内存结构和内存溢出、方法区的两种实现

内存结构&#xff1a; 方法区和对是所有线程共享的内存区域&#xff1b;而java栈、本地方法栈和程序员计数器是运行是线程私有 的内存区域。 Java堆&#xff08;Heap&#xff09;,是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内 存区域&#xff0c;在…

软件测试之概念篇(需求,测试用例,BUG描述,产品的生命周期)

目录 1.什么是需求 2.什么是测试用例 3.什么是BUG 4.软件的生命周期 5.测试的生命周期 1.什么是需求 在大多数软件公司&#xff0c;一般会有两部分需求&#xff1a; 用户需求&#xff1a;可以理解为就是甲方提出需求&#xff0c;如果没有甲方&#xff0c;那么就是终端用…

“注释: 爱恨交织的双重标准?解析注释在代码开发中的作用。”

文章目录 每日一句正能量前言观点和故事程序员不写注释的原因是什么如何才能写出漂亮的注释后记 每日一句正能量 水与水之间有距离&#xff0c;但地心下直相牵&#xff0c;人与人之间有距离&#xff0c;但心里时刻挂念&#xff0c;发条短信道声晚安&#xff0c;梦里我们相见。 …

岛屿的数量

题目描述 给你一个由 ‘1’&#xff08;陆地&#xff09;和 ‘0’&#xff08;水&#xff09;组成的的二维网格&#xff0c;请你计算网格中岛屿的数量。 岛屿总是被水包围&#xff0c;并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。 此外&#xff0c;你可以…

Programming abstractions in C阅读笔记:p176-p178

《Programming Abstractions In C》学习第59天&#xff0c;p176-p178总结。 一、技术总结 1.addtive sequences tn tn-1 tn-2 序列&#xff1a;3, 7, 10, 17, 27, 44, 71, 115, 186, 301, 487, 788, 1275, … p177, As a general class, the sequences that follow this…

面试总结-Redis篇章(十二)——Redis是单线程的,为什么还那么快

Redis是单线程的&#xff0c;为什么还那么快 Redis是单线程的&#xff0c;为什么还那么快什么是IO多路复用 阻塞IO非阻塞IOIO多路复用 Redis是单线程的&#xff0c;为什么还那么快 Redis是纯内存操作&#xff0c;执行速度非常快采用单线程&#xff0c;避免不必要的上下文切换可…

【面试经典150 | 哈希表】单词规律

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;哈希表 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结构等内…

mysql面试题34:Hash索引和B+树区别是什么?在设计索引怎么选择?

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:Hash索引和B+树区别是什么?在设计索引怎么选择? 在MySQL中,Hash索引和B+树索引是两种常见的索引类型,他们有以下区别: 数据结构:Hash索引:…

999、Android --问题处理-1

1、打开其他人开发的程序报错 Caused by: org.gradle.api.internal.plugins.PluginApplicationException: Faile to apply plugin […] 解决问题&#xff1a; preoject视图下&#xff0c;文件gradle.properties添加语句 android.overridePathChecktrue

Spring Framework中的org.springframework.stereotype包:为你的应用程序定义“典型”

&#x1f96d;导言&#xff1a; Spring Framework是一个强大的开发框架&#xff0c;它大大简化了Java应用程序的开发和管理。org.springframework.stereotype 注解家族是Spring的核心注解之一&#xff0c;它们允许开发人员定义和标识不同类型的组件&#xff0c;以便Spring能够…

Java | 类、实例初始化 、方法重写规则

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ 类、实例初始化 、方法重写规则 类的初始化过…