欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Linux2.6.33 自己动手写驱动 LinuxF#网络应用C#C++ 

程序员文章站 2022-07-05 21:50:29
...

Linux2.6.33 自己动手写驱动

一、GPIO驱动编写和测试

1GPIO的这点事儿

GPIOGeneral-Purpose IO ports,通用的IO端口。一般的微处理器芯片都提供通用的可编程IO端口,用户可以通过配置寄存器将其配置成输入、输出或者其他特殊功能模式。

通用IO端口一般都可以实现按位操作,即用户可以针对IO端口的每一位(以下简称IO位)进行操作。

GPIO端口输出的高低电平可以通过控制一组LED发光二极管来加以验证,这里,我们截取TE2440-DEV-I教学板中的四个发光二极管做实验。

应用S3C2440GPF4-GPF7共四个IO位,各自控制一个发光二极管,分别对应D1-D4,硬件原理如图6.1所示。

<shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></path><lock v:ext="edit" aspectratio="t"></lock></shapetype><shape id="图片_x0020_1" o:spid="_x0000_i1026" type="#_x0000_t75" o:bordertopcolor="black" o:borderleftcolor="black" o:borderbottomcolor="black" o:borderrightcolor="black" style="visibility: visible; width: 371.25pt; height: 137.25pt; mso-wrap-style: square"><font size="3"><imagedata src="file:///C:/DOCUME~1/IBM/LOCALS~1/Temp/msohtmlclip1/01/clip_image001.emz" o:title="" gain="192753f" grayscale="t" bilevel="t"></imagedata><bordertop type="single" width="4"></bordertop><borderleft type="single" width="4"></borderleft><borderbottom type="single" width="4"></borderbottom><borderright type="single" width="4"></borderright></font></shape>

6.1 IO控制LED原理图

原理图分析:

(1) 四个发光二极管采用共阳极的连接方法,即四个发光二极管的阳极连接在一起,并连接到3.3V电源。

(2) 发光二极管的负极各自连接一个1K限流电阻,再分别连接到S3C2440GPF4-GPF7

思考:为什么要接一个1K的限流电阻呢?

顾名思义,串接限流电阻就是为了显示通过发光二极管的电流,从而达到减少功耗或者满足端口对最大电流的限制。

一般发光二极管的点亮电流为5mA~10mATE2440采用贴片发光二极管,1K限流电阻,驱动电压为3.3V,发光二极管压降为1.6V,那么发光二极管的电流大约为1.7mA。发光二极管已经能点亮了,如果希望更亮一些,可以将限流电阻减小,但是二极管的电流不能超多ARM芯片IO口的最大驱动电流。

(3) 根据电路原理可知,当GPF4-GPF7输出低电平时,由于发光二极管两端加上电压,则发光二极管点亮;当GPF4-GPF7输出高电平只,由于发光二极管两端压差为0,则发光二极管熄灭。

思考:发光二极管为什么会亮呢?

发光二极管在其两端的电压差超出其导通压降时开始工作,普通发光二极管的导通压降一般为1.6V~2.1V,同时,工作电流要满足该二极管的工作电流。满足电压和电流的要求,该二极管就可以发光了。

二极管的正负极可以用万用表的二极管档量出来,如果表上有了一点多的读数,红表笔接的发光二极管的正极,黑表笔接的就是发光二极管的负极。

(4) 我们可以通过程序控制GPF4-GPF7有规律的输出高低电平,则实现发光二极管有规律的亮灭。

2、驱动怎样编写

了解的硬件的概念以后,我们开始我们的驱动编写工作。

然后再在内核源码的“drivers/char/”目录下新建一个名为“TopElec_GPIO.c”的文件,作为我们的驱动文件。内容如下:

/*************************************

NAME:TopElec_GPIO.c

COPYRIGHT:www.top-elec.com

Ver1.00 2010/05/19

*************************************/

#include <linux/miscdevice.h>

#include <linux/delay.h>

#include <asm/irq.h>

#include <mach/regs-gpio.h>

#include <mach/hardware.h>

#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/init.h>

#include <linux/mm.h>

#include <linux/fs.h>

#include <linux/types.h>

#include <linux/delay.h>

#include <linux/moduleparam.h>

#include <linux/slab.h>

#include <linux/errno.h>

#include <linux/ioctl.h>

#include <linux/cdev.h>

#include <linux/string.h>

#include <linux/list.h>

#include <linux/pci.h>

#include <asm/uaccess.h>

#include <asm/atomic.h>

#include <asm/unistd.h>

#include <linux/gpio.h>

#define DEVICE_NAME "GPIO-Control"

#define S3C2410_GPFCON S3C2410_GPIOREG(0x50)

#define S3C2410_GPFDAT S3C2410_GPIOREG(0x54)

#define S3C2410_GPFUP S3C2410_GPIOREG(0x58)

#define S3C2410_GPF4 S3C2410_GPIONO(S3C2410_GPIO_BANKF, 4)

#define S3C2410_GPF5 S3C2410_GPIONO(S3C2410_GPIO_BANKF, 5)

#define S3C2410_GPF6 S3C2410_GPIONO(S3C2410_GPIO_BANKF, 6)

#define S3C2410_GPF7 S3C2410_GPIONO(S3C2410_GPIO_BANKF, 7)

#define S3C2410_GPF4_OUTP (0x01 << 8)

#define S3C2410_GPF5_OUTP (0x01 << 10)

#define S3C2410_GPF6_OUTP (0x01 << 12)

#define S3C2410_GPF7_OUTP (0x01 << 14)

/* 应用程序执行ioctl(fd, cmd, arg)时的第2个参数 */

#define IOCTL_GPIO_ON 1

#define IOCTL_GPIO_OFF 0

/* 用来指定LED所用的GPIO引脚 */

static unsigned long gpio_table [] =

{

S3C2410_GPF(4),

S3C2410_GPF(5),

S3C2410_GPF(6),

S3C2410_GPF(7),

};

/* 用来指定GPIO引脚的功能:输出 */

static unsigned int gpio_cfg_table [] =

{

//由于2.6.33内核中没有定义GPIO的动作,所以我在上面自己定义了一下。

S3C2410_GPF4_OUTP,

S3C2410_GPF5_OUTP,

S3C2410_GPF6_OUTP,

S3C2410_GPF7_OUTP,

};

static int te2440_gpio_ioctl(

struct inode *inode,

struct file *file,

unsigned int cmd,

unsigned long arg)

{

if (arg > 4)

{

return -EINVAL;

}

switch(cmd)

{

case IOCTL_GPIO_ON:

// 设置指定引脚的输出电平为0

s3c2410_gpio_setpin(gpio_table[arg], 0);

return 0;

case IOCTL_GPIO_OFF:

// 设置指定引脚的输出电平为1

s3c2410_gpio_setpin(gpio_table[arg], 1);

return 0;

default:

return -EINVAL;

}

}

static struct file_operations dev_fops = {

.owner = THIS_MODULE,

.ioctl = te2440_gpio_ioctl,

};

static struct miscdevice misc = {

.minor = MISC_DYNAMIC_MINOR,

.name = DEVICE_NAME,

.fops = &dev_fops,

};

static int __init dev_init(void)

{

int ret;

int i;

for (i = 0; i < 4; i++)

{

s3c2410_gpio_cfgpin(gpio_table[i], gpio_cfg_table[i]);

s3c2410_gpio_setpin(gpio_table[i], 0);

}

ret = misc_register(&misc);

printk (DEVICE_NAME" initialized/n");

return ret;

}

static void __exit dev_exit(void)

{

misc_deregister(&misc);

}

module_init(dev_init);

module_exit(dev_exit);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("www.top-elec.com");

MODULE_DESCRIPTION("GPIO control for Topelec TE2440DEV_I Board");

3、让驱动到内核里混一下

在内核源码中添加对LED 灯驱动的支持,修改同目录下的Kconfig文件,添加如下内容:

config TE2440_GPIO_TEST

tristate "TE2440DEV-I Board GPIO Test(LED TEST)"

depends on ARCH_S3C2440

default y if ARCH_S3C2440

help

GPIO control for TE2440DEV-I Board.

同样的道理,修改同目录下的Makefile文件,修改的内容如下:

obj-$(CONFIG_TE2440_GPIO_TEST) += TopElec_GPIO.o

4、配置和编译内核

进入内核目录,键入make menuconfig命令,进入内核配置菜单,如下图所示:

Diver->chacarter device-> TE2440DEV-I Board GPIO Test 的支持,当然,你也可以选择<M>将驱动编译成模块。

好了,OK,大胆的make吧!

当然可能有错误,因为内核的版本不一致,或是编译器的问题,总之,Linux虽然玩起来和带劲,但是问题也会很多,要有越挫越勇的精神才能成为真正的高手哦!

至于,怎么把内核搞到板子上不在这里就不说了。

5、编写测试程序

/*************************************

NAME:GPIO_TEST.c

COPYRIGHT:www.top-elec.com

*************************************/

#include <stdio.h> /*定义函数要用到的头文件*/

#include <stdlib.h>

#include <unistd.h>

#include <sys/ioctl.h>

int main(int argc, char **argv) /*运行时参数传递,开或关哪个LED*/

{

int on; /*定义led状态变量,1表示灯亮,2表示灯灭*/

int led_no; /*定义led变量--哪个led*/

int fd; /*定义led设备文件描述符的变量*/

if (argc != 3 || sscanf(argv[1], "%d", &led_no) != 1 || sscanf(argv[2],"%d", &on) != 1 ||

on < 0 || on > 1 || led_no < 1 || led_no > 4) /*判断命令输入参数个数*/

{

fprintf(stderr, "Usage: Please enter led number and led status,For example GPIO_TEST 1 0 /n");

exit(1);

}

fd = open("/dev/GPIO-Control", 0); /*为只读打开GPIO-Control设备文件,取出文件描述符*/

if (fd < 0) {

perror("open device /dev/GPIO-Control"); /*如果打开led文件出错,拿不到文件描述符,用perror宏输出错原因及信息*/

exit(1);

}

ioctl(fd, on, (led_no-1)); /*ioctl()函数控制LED,其中fd--是前面打开的LED文件描述符,on--是开关命令01led_no--是哪个LED*/

close(fd);

return 0;

}

顺便这个Makefile文件,看起来专业点:

CROSS=arm-softfloat-linux-gnu-

all:GPIO_TEST

GPIO_TEST:GPIO_TEST.c

$(CROSS)gcc GPIO_TEST.c -o GPIO_TEST

$(CROSS)strip GPIO_TEST

clean:

@rm -vf GPIO_TEST *.o *~

有了上面的两个 make就可以了

最后把测试程序搞的开发板上运行一下:

bash-3.2# ./GPIO_TEST 1 1 意思是D1被点亮

很多资料来源于网络,谢谢网络的上的无私奉献大侠们!

华清远见-嵌入式领域著名讲师 O(_)O 牛牛猛

点击链接加我好友!

http://student.csdn.net/invite.php?u=111047&c=758a60d66d3a92d1

欢迎大家去我CSDN博客上踩踩

我的个人主页