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