日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux gpio设备驱动程序,嵌入式Linux设备驱动开发之:GPIO驱动程序实例-嵌入式系统-与非网...

發布時間:2024/7/19 linux 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux gpio设备驱动程序,嵌入式Linux设备驱动开发之:GPIO驱动程序实例-嵌入式系统-与非网... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

11.3??GPIO驅動程序實例

11.3.1??GPIO工作原理

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

為了控制這些端口,S3C2410處理器為每個端口組分別提供幾種相應的控制寄存器。其中最常用的有端口配置寄存器(GPACON?~?GPHCON)和端口數據寄存器(GPADAT?~?GPHDAT)。因為大部分I/O管腳可以提供多種功能,通過配置寄存器(PnCON)設定每個管腳用于何種目的。數據寄存器的每位將對應于某個管腳上的輸入或輸出。所以通過對數據寄存器(PnDAT)的位讀寫,可以進行對每個端口的輸入或輸出。

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

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

圖11.4??LED(左)和蜂鳴器(右)的驅動電路原理圖

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

在表11.15中,詳細描述了GPF的主要控制寄存器。GPB的相關寄存器的描述與此類似,具體可以參考S3C2410處理器數據手冊。

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

寄存器

地址

R/W

功能

初始值

GPFCON

0x56000050

R/W

配置GPF端口組

0x0

GPFDAT

0x56000054

R/W

GPF端口的數據寄存器

未定義

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]

每位對應于相應的端口,若端口用于輸入,則可以通過相應的位讀取數據;若端口用于輸出,則可以通過相應的位輸出數據;若端口用于其他功能,則其值無法確定。

GPFUP

描述

GPF[7:0]

[7:0]

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

1:取消上拉功能

為了驅動LED和蜂鳴器,首先通過端口配置寄存器將5個相應寄存器配置為輸出模式。然后通過對端口數據寄存器的寫操作,實現對每個GPIO設備的控制(發亮或發聲)。在下一個小節中介紹的驅動程序中,s3c2410_gpio_cfgpin()函數和s3c2410_gpio_pullup()函數將進行對某個端口的配置,而s3c2410_gpio_setpin()函數實現向數據寄存器的某個端口的輸出。

11.3.2??GPIO驅動程序

GPIO驅動程序代碼如下所示:

/*?gpio_drv.h?*/

#ifndef?????FS2410_GPIO_SET_H

#define?????FS2410_GPIO_SET_H

#include????

#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?

#include?

#include?

#include?

#include????/*?printk()?*/

#include?????????/*?kmalloc()?*/

#include????????/*?everything...?*/

#include?????/*?error?codes?*/

#include?????/*?size_t?*/

#include?

#include?

#include?

#include?

#include?

#include?

#include?

#include?

#include?"gpio_drv.h"

static?int?major?=?0;?/*?采用字符設備號的動態分配?*/

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

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

{?/*?對某個管腳進行配置(輸入/輸出/其他功能)*/

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

unsigned?long?shift?=?1;

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

unsigned?long?con;

unsigned?long?flags;

if?(pin?

{

shift?=?0;

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

}

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

local_irq_save(flags);?/*?保存現場,保證下面一段是原子操作?*/

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

con?&=?~mask;

con?|=?function;

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

local_irq_restore(flags);?/*?恢復現場?*/

}

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

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

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

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

unsigned?long?flags;

unsigned?long?up;

if?(pin?

{

return;

}

local_irq_save(flags);

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

up?&=?~(1?<

up?|=?to?<

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

local_irq_restore(flags);

}

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

{?/*?向某個管腳進行輸出?*/

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?<

dat?|=?to?<

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

local_irq_restore(flags);

}

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

{?/*?open操作函數:進行寄存器配置*/

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操作函數:沒有實際功能*/

return?0;

}

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

size_t?count,?loff_t?*offp)

{?/*?write操作函數:沒有實際功能*/

return?0;

}

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

{?/*?向5個端口中的一個輸出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函數接口:主要接口的實現。對5個GPIO設備進行控制(發亮或發聲)?*/

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?command\n");

break;

}

}

return?0;

}

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

{?/*?release操作函數,熄滅所有燈和關閉蜂鳴器?*/

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)

{?/*?字符設備的創建和注冊?*/

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設備的file_operations結構定義?*/

.owner???=?THIS_MODULE,

.open????=?gpio_open,????????/*?進行初始化配置*/

.release?=?gpio_release,????/*?關閉設備*/

.read????=?gpio_read,

.write???=?gpio_write,

.ioctl???=?gpio_ioctl,????????/*?實現主要控制功能*/

};

static?struct?cdev?gpio_devs;

static?int?gpio_init(void)

{

int?result;

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

if?(major)

{?/*?設備號的動態分配?*/

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

}

else

{?/*?設備號的動態分配?*/

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

major?=?MAJOR(dev);

}

if?(result?

{

printk(KERN_WARNING?"Gpio:?unable?to?get?major?%d\n",?major);

return?result;

}

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

printk("The?major?of?the?gpio?device?is?%d\n",?major);

return?0;

}

static?void?gpio_cleanup(void)

{

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

unregister_chrdev_region(MKDEV(major,?0),?1);?/*?設備號的注銷*/

printk("Gpio?device?uninstalled\n");

}

module_init(gpio_init);

module_exit(gpio_cleanup);

MODULE_AUTHOR("David");

MODULE_LICENSE("Dual?BSD/GPL");

下面列出GPIO驅動程序的測試用例:

/*?gpio_test.c?*/

#include?

#include?

#include?

#include?

#include?

#include?

#include?

#include?"gpio_drv.h"

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

{?/*指定LED發亮一段時間之后熄滅它*/

led_no?%=?4;

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

sleep(time);

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

}

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

{/*?開蜂鳴器一段時間之后關閉*/

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

sleep(time);

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

}

int?main()

{

int?i?=?0;

int?dev_fd;

/*?打開gpio設備?*/

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

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

{

printf("Cann't?open?gpio?device?file\n");

exit(1);

}

while(1)

{

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

led_timer(dev_fd,?i,?1);

beep_timer(dev_fd,?1);

}

close(dev_fd);

return?0;

}

具體運行過程如下所示。首先編譯并加載驅動程序:

$?make?clean;make?/*?驅動程序的編譯*/

$?insmod?gpio_drv.ko?/*?加載gpio驅動?*/

$?cat?/proc/devices?/*?通過這個命令可以查到gpio設備的主設備號?*/

$?mknod?/dev/gpio??c??252??0??/*?假設主設備號為252,?創建設備文件節點*/

然后編譯并運行驅動測試程序:

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

$?./gpio_test

運行結果為4個LED輪流閃爍,同時蜂鳴器以一定周期發出聲響。

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的linux gpio设备驱动程序,嵌入式Linux设备驱动开发之:GPIO驱动程序实例-嵌入式系统-与非网...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。