加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長(zhǎng)期合作伙伴
立即加入
  • 正文
    • 11.3  GPIO驅(qū)動(dòng)程序?qū)嵗?/span>
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

嵌入式Linux設(shè)備驅(qū)動(dòng)開(kāi)發(fā)之:GPIO驅(qū)動(dòng)程序?qū)嵗?/h1>

2013/09/13
2
閱讀需 34 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

?

11.3??GPIO驅(qū)動(dòng)程序?qū)嵗?/h2>

11.3.1??GPIO工作原理

FS2410開(kāi)發(fā)板的S3C2410處理器具有117個(gè)多功能通用I/O(GPIO)端口管腳,包括GPIO?8個(gè)端口組,分別為GPA(23個(gè)輸出端口)、GPB(11個(gè)輸入/輸出端口)、GPC(16個(gè)輸入/輸出端口)、GPD(16個(gè)輸入/輸出端口)、GPE(16個(gè)輸入/輸出端口)、GPF(8個(gè)輸入/輸出端口)、GPH(11個(gè)輸入/輸出端口)。根據(jù)各種系統(tǒng)設(shè)計(jì)的需求,通過(guò)軟件方法可以將這些端口配置成具有相應(yīng)功能(例如:外部中斷或數(shù)據(jù)總線)的端口。

為了控制這些端口,S3C2410處理器為每個(gè)端口組分別提供幾種相應(yīng)的控制寄存器。其中最常用的有端口配置寄存器(GPACON?~?GPHCON)和端口數(shù)據(jù)寄存器(GPADAT?~?GPHDAT)。因?yàn)榇蟛糠諭/O管腳可以提供多種功能,通過(guò)配置寄存器(PnCON)設(shè)定每個(gè)管腳用于何種目的。數(shù)據(jù)寄存器的每位將對(duì)應(yīng)于某個(gè)管腳上的輸入或輸出。所以通過(guò)對(duì)數(shù)據(jù)寄存器(PnDAT)的位讀寫(xiě),可以進(jìn)行對(duì)每個(gè)端口的輸入或輸出。

在此主要以發(fā)光二極管(LED)和蜂鳴器為例,討論GPIO設(shè)備的驅(qū)動(dòng)程序。它們的硬件驅(qū)動(dòng)電路原理圖如圖11.4所示。

?????????????????

圖11.4??LED(左)和蜂鳴器(右)的驅(qū)動(dòng)電路原理圖

在圖11.4中,可知使用S3C2410處理器的通用I/O口GPF4、GPF5、GPF6和GPF7分別直接驅(qū)動(dòng)LED?D12、D11、D10以及D9,而使用GPB0端口驅(qū)動(dòng)蜂鳴器。4個(gè)LED分別在對(duì)應(yīng)端口(GPF4~GPF7)為低電平時(shí)發(fā)亮,而蜂鳴器在GPB0為高電平時(shí)發(fā)聲。這5個(gè)端口的數(shù)據(jù)流方向均為輸出。

在表11.15中,詳細(xì)描述了GPF的主要控制寄存器。GPB的相關(guān)寄存器的描述與此類似,具體可以參考S3C2410處理器數(shù)據(jù)手冊(cè)。

表11.15 GPF端口(GPF0-GPF7)的主要控制寄存器

寄存器

地址

R/W

功能

初始值

GPFCON

0x56000050

R/W

配置GPF端口組

0x0

GPFDAT

0x56000054

R/W

GPF端口的數(shù)據(jù)寄存器

未定義

GPFUP

0x56000058

R/W

GPF端口的取消上拉寄存器

0x0

GPFCON

描述

GPF7

[15:14]

00?=?輸入??01?=?輸出??10?=?EINT7??11?=?保留

GPF6

[13:12]

00?=?輸入??01?=?輸出??10?=?EINT6??11?=?保留

GPF5

[11:10]

00?=?輸入??01?=?輸出??10?=?EINT5??11?=?保留

GPF4

[9:8]

00?=?輸入??01?=?輸出??10?=?EINT4??11?=?保留

GPF3

[7:6]

00?=?輸入??01?=?輸出??10?=?EINT3??11?=?保留

GPF2

[5:4]

00?=?輸入??01?=?輸出??10?=?EINT2??11?=?保留

GPF1

[3:2]

00?=?輸入??01?=?輸出??10?=?EINT1??11?=?保留

GPF0

[1:0]

00?=?輸入??01?=?輸出??10?=?EINT0??11?=?保留

GPFDAT

描述

GPF[7:0]

[7:0]

每位對(duì)應(yīng)于相應(yīng)的端口,若端口用于輸入,則可以通過(guò)相應(yīng)的位讀取數(shù)據(jù);若端口用于輸出,則可以通過(guò)相應(yīng)的位輸出數(shù)據(jù);若端口用于其他功能,則其值無(wú)法確定。

GPFUP

描述

GPF[7:0]

[7:0]

0:向相應(yīng)端口管腳賦予上拉(pull-up)功能

1:取消上拉功能?

為了驅(qū)動(dòng)LED和蜂鳴器,首先通過(guò)端口配置寄存器將5個(gè)相應(yīng)寄存器配置為輸出模式。然后通過(guò)對(duì)端口數(shù)據(jù)寄存器的寫(xiě)操作,實(shí)現(xiàn)對(duì)每個(gè)GPIO設(shè)備的控制(發(fā)亮或發(fā)聲)。在下一個(gè)小節(jié)中介紹的驅(qū)動(dòng)程序中,s3c2410_gpio_cfgpin()函數(shù)和s3c2410_gpio_pullup()函數(shù)將進(jìn)行對(duì)某個(gè)端口的配置,而s3c2410_gpio_setpin()函數(shù)實(shí)現(xiàn)向數(shù)據(jù)寄存器的某個(gè)端口的輸出。

?

11.3.2??GPIO驅(qū)動(dòng)程序

GPIO驅(qū)動(dòng)程序代碼如下所示:

/*?gpio_drv.h?*/

#ifndef?????FS2410_GPIO_SET_H

#define?????FS2410_GPIO_SET_H

#include????<linux/ioctl.h>

#define?????GPIO_DEVICE_NAME???????"gpio"

#define?????GPIO_DEVICE_FILENAME??"/dev/gpio"

#define?????LED_NUM??????????????????4

#define?????GPIO_IOCTL_MAGIC???????'G'

#define?????LED_D09_SWT?????????????_IOW(GPIO_IOCTL_MAGIC,?0,?unsigned?int)

#define?????LED_D10_SWT?????????????_IOW(GPIO_IOCTL_MAGIC,?1,?unsigned?int)

#define?????LED_D11_SWT?????????????_IOW(GPIO_IOCTL_MAGIC,?2,?unsigned?int)

#define?????LED_D12_SWT?????????????_IOW(GPIO_IOCTL_MAGIC,?3,?unsigned?int)

#define?????BEEP_SWT?????????????????_IOW(GPIO_IOCTL_MAGIC,?4,?unsigned?int)

#define?????LED_SWT_ON??????????????0

#define?????LED_SWT_OFF?????????????1

#define?????BEEP_SWT_ON?????????????1

#define?????BEEP_SWT_OFF????????????0

#endif?/*?FS2410_GPIO_SET_H?*/

/*?gpio_drv.c?*/

#include?<linux/config.h>

#include?<linux/module.h>

#include?<linux/moduleparam.h>

#include?<linux/init.h>

#include?<linux/kernel.h>???/*?printk()?*/

#include?<linux/slab.h>????????/*?kmalloc()?*/

#include?<linux/fs.h>???????/*?everything...?*/

#include?<linux/errno.h>????/*?error?codes?*/

#include?<linux/types.h>????/*?size_t?*/

#include?<linux/mm.h>

#include?<linux/kdev_t.h>

#include?<linux/cdev.h>

#include?<linux/delay.h>

#include?<linux/device.h>

#include?<asm/io.h>

#include?<asm/uaccess.h>

#include?<asm/arch-s3c2410/regs-gpio.h>

#include?"gpio_drv.h"

static?int?major?=?0;?/*?采用字符設(shè)備號(hào)的動(dòng)態(tài)分配?*/

module_param(major,?int,?0);?/*?以參數(shù)的方式可以指定設(shè)備的主設(shè)備號(hào)*/

void?s3c2410_gpio_cfgpin(unsigned?int?pin,?unsigned?int?function)

{?/*?對(duì)某個(gè)管腳進(jìn)行配置(輸入/輸出/其他功能)*/

?????unsigned?long?base?=?S3C2410_GPIO_BASE(pin);?/*?獲得端口的組基地址*/

?????unsigned?long?shift?=?1;

?????unsigned?long?mask?=?0x03;?/*?通常用配置寄存器的兩位表示一個(gè)端口*/

?????unsigned?long?con;

?????unsigned?long?flags;

?????if?(pin?<?S3C2410_GPIO_BANKB)?

?????{???

????????shift?=?0;

????????mask??=?0x01;?/*?在GPA端口中用配置寄存器的一位表示一個(gè)端口*/

?????}???

?????mask?<<=?(S3C2410_GPIO_OFFSET(pin)?<<?shift);

?????local_irq_save(flags);?/*?保存現(xiàn)場(chǎng),保證下面一段是原子操作?*/

?????con?=?__raw_readl(base?+?0x00);

?????con?&=?~mask;

????con?|=?function;

????__raw_writel(con,?base?+?0x00);?/*?向配置寄存器寫(xiě)入新配置數(shù)據(jù)?*/

????local_irq_restore(flags);?/*?恢復(fù)現(xiàn)場(chǎng)?*/

}

void?s3c2410_gpio_pullup(unsigned?int?pin,?unsigned?int?to)?

{?/*?配置上拉功能?*/

????unsigned?long?base?=?S3C2410_GPIO_BASE(pin);?/*?獲得端口的組基地址*/

????unsigned?long?offs?=?S3C2410_GPIO_OFFSET(pin);/*?獲得端口的組內(nèi)偏移地址?*/

????unsigned?long?flags;

????unsigned?long?up;?

????

????if?(pin?<?S3C2410_GPIO_BANKB)

????{

????????return;

????}

????local_irq_save(flags);

????up?=?__raw_readl(base?+?0x08);

????up?&=?~(1?<<?offs);

????up?|=?to?<<?offs;

????__raw_writel(up,?base?+?0x08);?/*?向上拉功能寄存器寫(xiě)入新配置數(shù)據(jù)*/

????local_irq_restore(flags);

}

void?s3c2410_gpio_setpin(unsigned?int?pin,?unsigned?int?to)

{?/*?向某個(gè)管腳進(jìn)行輸出?*/

????unsigned?long?base?=?S3C2410_GPIO_BASE(pin);

????unsigned?long?offs?=?S3C2410_GPIO_OFFSET(pin);

????unsigned?long?flags;

????unsigned?long?dat;

????local_irq_save(flags);

????dat?=?__raw_readl(base?+?0x04);

????dat?&=?~(1?<<?offs);

????dat?|=?to?<<?offs;

????__raw_writel(dat,?base?+?0x04);?/*?向數(shù)據(jù)寄存器寫(xiě)入新數(shù)據(jù)*/

????local_irq_restore(flags);

}

int?gpio_open?(struct?inode?*inode,?struct?file?*filp)

{?/*?open操作函數(shù):進(jìn)行寄存器配置*/

????s3c2410_gpio_pullup(S3C2410_GPB0,?1);?/*?BEEP*/????

????s3c2410_gpio_pullup(S3C2410_GPF4,?1);?/*?LED?D12?*/????

????s3c2410_gpio_pullup(S3C2410_GPF5,?1);?/*?LED?D11?*/????

????s3c2410_gpio_pullup(S3C2410_GPF6,?1);?/*?LED?D10?*/????

????s3c2410_gpio_pullup(S3C2410_GPF7,?1);?/*?LED?D9?*/????

????s3c2410_gpio_cfgpin(S3C2410_GPB0,?S3C2410_GPB0_OUTP);

????s3c2410_gpio_cfgpin(S3C2410_GPF4,?S3C2410_GPF4_OUTP);

????s3c2410_gpio_cfgpin(S3C2410_GPF4,?S3C2410_GPF5_OUTP);

????s3c2410_gpio_cfgpin(S3C2410_GPF4,?S3C2410_GPF6_OUTP);

????s3c2410_gpio_cfgpin(S3C2410_GPF4,?S3C2410_GPF7_OUTP);

????return?0;

}

ssize_t?gpio_read(struct?file?*file,?char?__user?*buff,?

????????????????????????????????????????????????????size_t?count,?loff_t?*offp)

{?/*?read操作函數(shù):沒(méi)有實(shí)際功能*/

????return?0;

}

ssize_t?gpio_write(struct?file?*file,?const?char?__user?*buff,?

?????????????????????????????????????????????????????size_t?count,?loff_t?*offp)

{?/*?write操作函數(shù):沒(méi)有實(shí)際功能*/

????return?0;

}

int?switch_gpio(unsigned?int?pin,?unsigned?int?swt)

{?/*?向5個(gè)端口中的一個(gè)輸出ON/OFF值?*/

????if?(!((pin?<=?S3C2410_GPF7)?&&?(pin?>=?S3C2410_GPF4))?

?????????????????????&&?(pin?!=?S3C2410_GPB0))

????{

????????printk("Unsupported?pin");

????????return?1;?

????}

????s3c2410_gpio_setpin(pin,?swt);

????return?0;

}

?

static?int?gpio_ioctl(struct?inode?*inode,?struct?file?*file,?

??????????????????????????????????????unsigned?int?cmd,?unsigned?long?arg)

{?/*?ioctl函數(shù)接口:主要接口的實(shí)現(xiàn)。對(duì)5個(gè)GPIO設(shè)備進(jìn)行控制(發(fā)亮或發(fā)聲)?*/

????unsigned?int?swt?=?(unsigned?int)arg;

????switch?(cmd)?

????{

????????case?LED_D09_SWT:

????????{

????????????switch_gpio(S3C2410_GPF7,?swt);????

????????}

????????break;

????????case?LED_D10_SWT:

????????{

????????????switch_gpio(S3C2410_GPF6,?swt);

????????}

????????break;

????????case?LED_D11_SWT:

????????{

????????????switch_gpio(S3C2410_GPF5,?swt);

????????}

????????break;

????????case?LED_D12_SWT:

????????{

????????????switch_gpio(S3C2410_GPF4,?swt);

????????}

????????break;

????????case?BEEP_SWT:

????????{

????????????switch_gpio(S3C2410_GPB0,?swt);

????????????break;

????????}

????????default:

????????{

????????????printk("Unsupported?commandn");

????????????break;

????????}

????}

????return?0;

}

static?int?gpio_release(struct?inode?*node,?struct?file?*file)

{?/*?release操作函數(shù),熄滅所有燈和關(guān)閉蜂鳴器?*/

????switch_gpio(S3C2410_GPB0,?BEEP_SWT_OFF);

????switch_gpio(S3C2410_GPF4,?LED_SWT_OFF);

????switch_gpio(S3C2410_GPF5,?LED_SWT_OFF);

????switch_gpio(S3C2410_GPF6,?LED_SWT_OFF);

????switch_gpio(S3C2410_GPF7,?LED_SWT_OFF);

????return?0;

}

static?void?gpio_setup_cdev(struct?cdev?*dev,?int?minor,

????????struct?file_operations?*fops)

{?/*?字符設(shè)備的創(chuàng)建和注冊(cè)?*/

????int?err,?devno?=?MKDEV(major,?minor);????

????cdev_init(dev,?fops);

????dev->owner?=?THIS_MODULE;

????dev->ops?=?fops;

????err?=?cdev_add?(dev,?devno,?1);

????if?(err)

????{

????????printk?(KERN_NOTICE?"Error?%d?adding?gpio?%d",?err,?minor);

????}

}

static?struct?file_operations?gpio_fops?=?

{?/*?gpio設(shè)備的file_operations結(jié)構(gòu)定義?*/

????.owner???=?THIS_MODULE,

????.open????=?gpio_open,????????/*?進(jìn)行初始化配置*/

????.release?=?gpio_release,????/*?關(guān)閉設(shè)備*/

????.read????=?gpio_read,????????

????.write???=?gpio_write,

????.ioctl???=?gpio_ioctl,????????/*?實(shí)現(xiàn)主要控制功能*/

};

static?struct?cdev?gpio_devs;

static?int?gpio_init(void)

{

????int?result;

????dev_t?dev?=?MKDEV(major,?0);

????if?(major)

????{?/*?設(shè)備號(hào)的動(dòng)態(tài)分配?*/

????????result?=?register_chrdev_region(dev,?1,?GPIO_DEVICE_NAME);

????}

????else?

????{?/*?設(shè)備號(hào)的動(dòng)態(tài)分配?*/

????????result?=?alloc_chrdev_region(&dev,?0,?1,?GPIO_DEVICE_NAME);

????????major?=?MAJOR(dev);

????}

????if?(result?<?0)?

????{

????????printk(KERN_WARNING?"Gpio:?unable?to?get?major?%dn",?major);

????????return?result;

????}

????gpio_setup_cdev(&gpio_devs,?0,?&gpio_fops);

????printk("The?major?of?the?gpio?device?is?%dn",?major);

????return?0;

}

?

static?void?gpio_cleanup(void)

{

????cdev_del(&gpio_devs);?/*?字符設(shè)備的注銷?*/

????unregister_chrdev_region(MKDEV(major,?0),?1);?/*?設(shè)備號(hào)的注銷*/

????printk("Gpio?device?uninstalledn");

}

module_init(gpio_init);

module_exit(gpio_cleanup);

MODULE_AUTHOR("David");

MODULE_LICENSE("Dual?BSD/GPL");???????????

下面列出GPIO驅(qū)動(dòng)程序的測(cè)試用例:

/*?gpio_test.c?*/

#include?<stdio.h>

#include?<stdlib.h>

#include?<unistd.h>

#include?<fcntl.h>

#include?<string.h>

#include?<sys/types.h>

#include?<sys/stat.h>

#include?"gpio_drv.h"

int?led_timer(int?dev_fd,?int?led_no,?unsigned?int?time)

{?/*指定LED發(fā)亮一段時(shí)間之后熄滅它*/

????led_no?%=?4;

????ioctl(dev_fd,?LED_D09_SWT?+?led_no,?LED_SWT_ON);?/*?發(fā)亮*/

????sleep(time);

????ioctl(dev_fd,?LED_D09_SWT?+?led_no,?LED_SWT_OFF);?/*?熄滅?*/

}

int?beep_timer(int?dev_fd,?unsigned?int?time)

{/*?開(kāi)蜂鳴器一段時(shí)間之后關(guān)閉*/

????ioctl(dev_fd,?BEEP_SWT,?BEEP_SWT_ON);?/*?發(fā)聲*/

????sleep(time);

????ioctl(dev_fd,?BEEP_SWT,?BEEP_SWT_OFF);????/*?關(guān)閉?*/

}

int?main()

{

????int?i?=?0;

????int?dev_fd;

????????/*?打開(kāi)gpio設(shè)備?*/

????dev_fd?=?open(GPIO_DEVICE_FILENAME,?O_RDWR?|?O_NONBLOCK);

????if?(?dev_fd?==?-1?)?

????{

????????printf("Cann't?open?gpio?device?filen");

????????exit(1);

????}

????while(1)

????{

????????i?=?(i?+?1)?%?4;

????????led_timer(dev_fd,?i,?1);

????????beep_timer(dev_fd,?1);????????

????}

????close(dev_fd);

????return?0;

}???????????

具體運(yùn)行過(guò)程如下所示。首先編譯并加載驅(qū)動(dòng)程序:

$?make?clean;make?/*?驅(qū)動(dòng)程序的編譯*/

$?insmod?gpio_drv.ko?/*?加載gpio驅(qū)動(dòng)?*/

$?cat?/proc/devices?/*?通過(guò)這個(gè)命令可以查到gpio設(shè)備的主設(shè)備號(hào)?*/

$?mknod?/dev/gpio??c??252??0??/*?假設(shè)主設(shè)備號(hào)為252,?創(chuàng)建設(shè)備文件節(jié)點(diǎn)*/

然后編譯并運(yùn)行驅(qū)動(dòng)測(cè)試程序:

$?arm-linux-gcc?–o?gpio_test??gpio_test.c

$?./gpio_test

運(yùn)行結(jié)果為4個(gè)LED輪流閃爍,同時(shí)蜂鳴器以一定周期發(fā)出聲響。

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

華清遠(yuǎn)見(jiàn)(www.farsight.com.cn)是國(guó)內(nèi)領(lǐng)先嵌入師培訓(xùn)機(jī)構(gòu),2004年注冊(cè)于中國(guó)北京海淀高科技園區(qū),除北京總部外,上海、深圳、成都、南京、武漢、西安、廣州均有直營(yíng)分公司。華清遠(yuǎn)見(jiàn)除提供嵌入式相關(guān)的長(zhǎng)期就業(yè)培訓(xùn)、短期高端培訓(xùn)、師資培訓(xùn)及企業(yè)員工內(nèi)訓(xùn)等業(yè)務(wù)外,其下屬研發(fā)中心還負(fù)責(zé)嵌入式、Android及物聯(lián)網(wǎng)方向的教學(xué)實(shí)驗(yàn)平臺(tái)的研發(fā)及培訓(xùn)教材的出版,截止目前為止已公開(kāi)出版70余本嵌入式/移動(dòng)開(kāi)發(fā)/物聯(lián)網(wǎng)相關(guān)圖書(shū)。企業(yè)理念:專業(yè)始于專注 卓識(shí)源于遠(yuǎn)見(jiàn)。企業(yè)價(jià)值觀:做良心教育、做專業(yè)教育,更要做受人尊敬的職業(yè)教育。