imx6ul 编写中断程序步骤

发布时间 2023-04-18 10:49:07作者: FBshark

①、启动文件 start.s

需要添加一级中断向量表和中断处理函数的框架两部分的内容。

一级中断向量表如下:

3 _start:
4 ldr pc, =Reset_Handler /* 复位中断 */
5 ldr pc, =Undefined_Handler /* 未定义指令中断 */ 
6 ldr pc, =SVC_Handler /* SVC(Supervisor)中断 */ 
7 ldr pc, =PrefAbort_Handler /* 预取终止中断 */ 
8 ldr pc, =DataAbort_Handler /* 数据终止中断 */ 
9 ldr pc, =NotUsed_Handler /* 未使用中断 */ 
10 ldr pc, =IRQ_Handler /* IRQ中断 */ 
11 ldr pc, =FIQ_Handler /* FIQ(快速中断)未定义中断 */

 中断处理函数的框架(以SVC_Handler 为例)如下:

22 /* SVC中断 */ 
23 SVC_Handler: 
24 ldr r0, =SVC_Handler 
25 bx r0

其中 ,进入C语言环境需要 Reset_Handler,中断实验用到了 IRQ_Handler,这两个处理函数有所不同。

Reset_Handler 是 start.s 中要进行的第一个程序,主要用于关闭 I/D Cache,[设置中断向量表偏移],设置堆栈指针,[使能IRQ中断],跳转到 main 函数。(包含方括号的为可选)。

IRQ_Handler 将程序跳转到 system_irqhandler() 函数中(该函数在bsp_int.c由用户中定义),并带一个参数,用于表示是当前的 IRQ 中断号(从 CP15 的C15保存当前中断号, CP15 的结构体在 core_ca7.h 中定义)。

另外,中断号由 NXP 官方在文件 MCIMX6Y2C.h 中定义,范围0~159共计160个,包含了 imx6ul 所有的中断。形如:

3 typedef enum IRQn { 
4 /* Auxiliary constants */ 
5 NotAvail_IRQn = -128, 
6 
7 /* Core interrupts */ 
8 Software0_IRQn = 0, 
9 Software1_IRQn = 1,
...................................
/* Device specific interrupts */ 
33 IOMUXC_IRQn = 32, 
34 DAP_IRQn = 33,
35 SDMA_IRQn = 34,
....................................
157 PMU_IRQ2_IRQn = 159
} IRQn_Type;

这些中断可分为:

  • ID0~ID15:这 16个 ID分配给 SGI。(软件中断,由软件触发的中断)
  • ID16~ID31:这 16个 ID分配给 PPI。(私有中断,需要指定核心的中断)
  • ID32~ID159:这 128个 ID分配给 SPI。(共享中断,所有核心都共享所有外部中断(IRQ)中断都属于 IRQ 中断。

②、中断驱动文件:bsp_int.c、bsp_int.h

在该文件中,设置二级中断向量函数表,承接上文 start.s IRQ中断中跳转的 system_irqhandler() 。

IRQ_Handler 将程序跳转到 system_irqhandler() 函数。

该函数内容如下:

68 void system_irqhandler(unsigned int giccIar) 
69 { 
70 
71 uint32_t intNum = giccIar & 0x3FFUL; 
72
73 /* 检查中断号是否符合要求 */ 
74 if ((intNum == 1020) || (intNum >= NUMBER_OF_INT_VECTORS)) 
75 { 
76    return; 
77 } 
78 
79 irqNesting++; /* 中断嵌套计数器加一 */ 
80 
81 /* 根据传递进来的中断号,在irqTable中调用确定的中断服务函数*/ 
82 irqTable[intNum].irqHandler(intNum, irqTable[intNum].userParam); 
83 
84 irqNesting--; /* 中断执行完成,中断嵌套寄存器减一 */ 
85 
86 }

在该函数体中,用到了中断函数向量表

irqTable[intNum]

因此应该在 bsp_int.h 中定义相关结构体:

typedef void (*system_irq_handler_t) (unsigned int giccIar, void *param);
19 typedef struct _sys_irq_handle 
20 { 
21     system_irq_handler_t irqHandler; /* 中断处理函数 */ 
22     void *userParam; /* 中断处理函数参数 */ 
23 } sys_irq_handle_t;

然后在 bsp_int.c 中定义一个以上面结构体为单元的数组:

static sys_irq_handle_t irqTable[NUMBER_OF_INT_VECTORS];

③、使能中断、设置中断模式(边沿触发类型)函数:bsp_gpio.c

主要编写3个函数:

gpio_intconfig() 用于配置中断相关的设置(边沿触发类型)

gpio_enableint() 用于使能中断

gpio_clearintflags()  用于中断标志位清除函数。

gpio_intconfig() 如下:

/* 
73 * @description : 设置GPIO的中断配置功能
74 * @param - base : 要配置的IO所在的GPIO组。
75 * @param - pin : 要配置的GPIO脚号。
76 * @param – pinInterruptMode: 中断模式,参考gpio_interrupt_mode_t
78 */

void
gpio_intconfig(GPIO_Type* base, unsigned int pin, gpio_interrupt_mode_t pin_int_mode)

其中的中断模式结构体形如:

 gpio_enableint()和 gpio_clearintflags()  如下:

125 void gpio_enableint(GPIO_Type* base, unsigned int pin) 
126 { 
127     base->IMR |= (1 << pin); 
128 }
147 void gpio_clearintflags(GPIO_Type* base, unsigned int pin) 
148 { 
149     base->ISR |= (1 << pin); 
150 }

④、用户中断函数文件:bsp_exti.c、bsp_exti.h

这部分有两个任务:

1. 编写用户中断函数 gpio1_io18_irqhandler(),

2. 在函数向量表中注册  gpio1_io18_irqhandler(),使其相应的中断号相互匹配。

内容如下:

 该函数名应该在  bsp_int.c 中定义的

static sys_irq_handle_t irqTable[NUMBER_OF_INT_VECTORS];

的对应的第GPIO1_Combined_16_31_IRQn 个中断服务函数向量相同。