《ARM Linux开发-warewin 2G/3G无线传输(DTU)和路由器—笔记》
GPIO通用型输入输出(General Purpose I/O)的简称,或总线扩展器,利用工业标准I2C、SMBus或SPI接口简化了I/O口的扩展。当微控制器或芯片组没有足够的I/O端口,或当系统需要采用远端串行通信或控制时,GPIO产品能够提供额外的控制和监视功能。
以AT91SAM9260平台为例,使用GPIO进行以下步骤:
1、内核中添加驱动
把写好的驱动文件gpio9261.c和gpio9261.h件拷贝到linux 内核/linux-2.6.36/drivers/char/目录下,更改此目录中的Makefile和Kconfig文件:
(1)在Makefile文件中适当位置添加一行
obj-$(CONFIG_AT9261_GPIO) += gpio9261.o
(2)在Kconfig文件适当位置添加
config AT9261_GPIO
tristate "AT91SAM9261 User GPIO/LED support"
depends on ARCH_AT91
(3)# make menuconfig 配置内核
选中此项character devices->
AT91SAM9261 User GPIO/LED support
(4)驱动文件中控制管脚方向的函数如下:
static int gpio_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, int arg)
{
int *pionum = &arg;
switch(cmd)
{
case GPIO_DIR_INPUT: //设置管脚方向为输入
at91_set_GPIO_periph(*pionum, 0);
gpio_direction_input(*pionum);
break;
case GPIO_DIR_OUTPUT_HIGH: //设置管脚方向为输出并置为高电平
at91_set_GPIO_periph(*pionum, 0);
gpio_direction_output(*pionum, 1);
break;
case GPIO_DIR_OUTPUT_LOW: 设置管脚方向为输出并置为低电平
at91_set_GPIO_periph(*pionum, 0);
gpio_direction_output(*pionum, 0);
break;
case GPIO_SET_HIGH:
at91_set_gpio_value(*pionum, 1); //置管脚为高电平
break;
case GPIO_SET_LOW: //置管脚为低电平
at91_set_gpio_value(*pionum, 0);
break;
case GPIO_GET: //读出该管脚电平状态
return at91_get_gpio_value(*pionum);
break;
default:
return -1;
}
return 0;
}
2、重新编译内核
把编译生成的内核下载到设备上,系统运行后在终端运行:
# cd /dev
# ls
/dev目录下会看到生成的/dev/gpio设备节点,如下图所示:
图3.6 GPIO设备结点图
3、应用程序中使用GPIO
根据CPU的的情况选择可用的管脚,避开复用的管脚、以免使用有冲突。应用程序中应包含管脚定义的文件:#include <mach/at91_pio.h>。
应用程序中使用GPIO前需要先打开GPIO设备/dev/gpio,然后便可使用ioctl()函数操作管脚,使用完闭后要关闭GPIO设备。如以下程序:
#define CG_MODULE_POWER AT91_PIN_PB30
#define CG_BOARD_POWER AT91_PIN_PA0
#define CG_LINK_LED AT91_PIN_PC10
#define CG_ACT_LED AT91_PIN_PC6
#define CG_PWR_LED AT91_PIN_PC5
Void start_gpio(void){
int fd;
fd = open("/dev/gpio", 0);
if (fd < 0)
{
perror("Failed to open gpio");
}
ioctl(fd, GPIO_DIR_OUTPUT_HIGH,CG_PWR_LED);
ioctl(fd, GPIO_DIR_OUTPUT_LOW,CG_ACT_LED);
ioctl(fd, GPIO_DIR_OUTPUT_LOW,CG_LINK_LED);
ioctl(fd, GPIO_DIR_OUTPUT_HIGH,CG_MODULE_POWER);
ioctl(fd, GPIO_DIR_OUTPUT_LOW,CG_BOARD_POWER);
close(fd);
}