一. GPIO中断
在前几章节试验中我们只是使用到了 GPIO 最基本的输入输出功能,本章我们需要使用
GPIO 的中断功能。接下来,我们可以把按键设置为中断模式。
二. IMX6ULL-GPIO中断设置
设置按键 KEY0 的中断:
1. 首先设置 GPIO的中断触发方式。
参考IMX6ULL参考手册中,第28章节GPIO部分,即GPIO_ICR1或 GPIO_ICR2寄存器。
触发方式有如下四种:低电平触发,高电平触发,上升沿触发,下降沿触发。
对于设置按键中断实验,根据原理图可知,我们设置KEY0,也就是UART1_CTS这个IO为中断下降沿触发。
另外还有一个GPIOx_EDGE_SEL 寄存器。
根据参考手册说明可知,这个寄存器是设置边沿触发的。就是无论上升沿或下降沿都会触发中断。
2. 使能 GPIO对应的中断。
设置GPIO_IMR寄存器。
3. 处理完中断以后,需要清除中断标志位。
清除中断状态寄存器GPIO_ISR寄存器相应的位。GPIO_ISR寄存器相应位写1清零。
4. GIC中断控制器配置
(1) 使能相应的中断ID。
KEY0即为UART1_CTS口,我们需要确认UART1_CTS对应的中断ID。
通过参考手册查询,我们知道UART1_CTS对应于GPIO1_IO18。
通过查参考手册第三章节,我们知道GPIO1_IO18对应的中断ID为67+32 = 99(要加上前面的32个SGI和PPI中断)。
(2) 使能中断优先级。
(3) 注册GPIO1_IO18的中断处理函数。
三. 向GPIO驱动添加中断处理函数
中断处理接口写到 bsp/目录下的 GPIO 的驱动文件 bsp_gpio.c 和 bsp_gpio.h文件。
1. bsp_gpio.h文件添加中断枚举类型
bsp_gpio.h
文件添加枚举,代码如下:
/*描述中断触发类型*/ typedef enum _gpio_intertupt_mode{ kGPIO_NoIntMode = 0U, //无中断功能 kGPIO_IntLowLevel = 1U, //低电平触发 kGPIO_IntHignLevel = 2U, //高电平触发 kGPIO_IntRisingEdge = 3U, //上升沿触发 kGPIO_IntFallingEdge = 4U,//下降沿触发 kGPIO_IntRisingOrFallingEdge = 5U //上升沿/下降沿都可触发 }gpio_interrupt_mode_t; typedef struct _gpio_pin_config{ gpio_pin_direction_t direction; uint8_t output_level; gpio_interrupt_mode_t interruptMode; //中断触发方式 }gpio_pin_config_t;
2. bsp_gpio.c 文件添加中断相关
bsp_gpio.c 文件中添加接口如下:
/* 使能指定GPIO中断 */ void gpio_interrupt_enable(GPIO_Type* base, unsigned int pin) { base->IMR |= (1 << pin); } /* 禁止GPIO的中断功能 */ void gpio_interrupt_disable(GPIO_Type* base, unsigned int pin) { base->IMR &= ~(1 << pin); } /* 设置GPIO的中断配置功能(即GPIO的中断触发方式) */ void gpio_interrupt_config(GPIO_Type* base, unsigned int pin, gpio_interrupt_mode_t trigger_mode) { volatile uint32_t * icr_register = NULL; unsigned int pin_Shift = 0; base->EDGE_SEL &= ~(1 << pin); pin_Shift = pin; if(pin < 16) //判断IO是低16的IO还是高16 { icr_register = &(base->ICR1); } else { icr_register = &(base->ICR2); pin_Shift -= 16; } switch (trigger_mode) { case kGPIO_IntLowLevel: *icr_register &= ~(3 << (pin_Shift*2)); break; case kGPIO_IntHignLevel: *icr_register &= ~(3 << (pin_Shift*2)); *icr_register |= (1 << (pin_Shift*2)); break; case kGPIO_IntRisingEdge: *icr_register &= ~(3 << (pin_Shift*2)); *icr_register |= (2 << (pin_Shift*2)); break; case kGPIO_IntFallingEdge: *icr_register &= ~(1 << (pin_Shift*2)); *icr_register |= (3 << (pin_Shift*2)); break; case kGPIO_IntRisingOrFallingEdge: base->EDGE_SEL |= (1 << pin); break; default: break; } } /* 清除中断标志位 (写1清零)*/ void gpio_clearintflags(GPIO_Type* base, unsigned int pin) { base->ISR |= (1 << pin); }
最后,可以将 gpio_interrupt_config(设置 GPIO的中断配置功能)添加到 gpio初始化接口中,添加如下:
//GPIO的初始化 //设置输入IO/输出IO void gpio_init(GPIO_Type* base, int pin, gpio_pin_config_t* config) { if(kGPIO_DigitalInput == (config->direction)) //输入IO { base->GDIR &= ~(1 << pin); } else //输出IO { base->GDIR |= (1 << pin); //设置默认电平 gpio_pin_write(base, pin, config->output_level); } gpio_interrupt_config(base, pin, config->interruptMode); //中断配置 }
以上就是GPIO的中断功能寄存器的相关配置。中断的使用,需要编写外部中断驱动代码。下一节介绍编写按键中断代码,结合本节代码一起编译运行。