您的位置:首页 > 其它

LED灯驱动编写全过程

2012-01-04 21:16 232 查看
led驱动实验步骤:
准备工作(Led驱动):

1 准备测试的工具

2 准备相关字符设备驱动的知识

3 准备相关驱动(LED)文件

4 准备相关的硬件知识,获取硬件开发人员提供的LED接口。

driver/char

ps

led_player 701

kill 701

./ledtest 0 0

./ledtest 0 1

./ledtest 0 2

./ledtest 0 3

./ledtest 1 0

./ledtest 1 1

./ledtest 1 2

./ledtest 1 3

./dxctest 0 0

./dxctest 0 1

led0~led3, GPB5~GPB8

LED开发驱动的步骤:

1 开发myled.c文件存放在虚拟机中的linux-2.6-32.2/drivers/char下

2 在char目录下,修改Makefile,把我的源代码加入我们的编译里面来。

3 在char目录下,修改Kconfig,首先定义为内核模块准备调试驱动

4.1 make menuconfig( 要先在Linux-2.6-32.2中 cp config_mini2440_n35 .config)

4.2 重新编译内核make zImage, 生成zImage文件(注意:要先配好arm-linux-gcc的环境变量-> exprot PATH=$PATH:/usr/local/arm/4.3.2/bin)。

5 在超级终端和dwn软件中,下载zImage开发板

6.1 make modules,产生myled.ko的内核模块。

6.2 通过超级终端,用rz命令下载myled.ko文件到开发板。

7 insmod myled.ko(在超级终端)加载内核模块

8 more /proc/devices查看我们驱动是不是被系统认识

9 如果系统认识驱动,会看到主设备号(默认253),敲“空格”向下移动,就可以看到,记录下来

10 cd /dev

11 mknod myled c 253 0 (c为字符设备,253是主设备号,0是 次设备号)

12 ls led

13 cd /

14 ps

15 kill 701

rz(从电脑传输驱动测试文件testled到开发板)

chmod 777 testled

16 ./testled 0 0(0 0可以是0,1的任何组合)

(12 make menuconfig,把M改为*,make zImage)

写代码:

1 内核模块的要素完成

2 初始化函数,确认主设备号,次设备号。

3 初始化函数,分配内存

4 初始化函数,安装cdev

5 实现file操作函数

obj-$(CONFIG_MYLED_MINI2440) += myled.o

int main()

fp = open("/dev/dfsgdsg", 0)

ioctl(fp, atoi(argv[1]), atoi(argv[2]));

return;

arm-linux-gcc 54te.c -o dxctest

具体操作:

1 做测试工具arm-linux-gcc编译 ---testled

open,close,ioctl

2 把内核模块的代码拷贝过来,做一定的修改。

3 初始化函数增加主次设备号申请的代码

led_major,led_minor,dev

4 初始化函数增加申请内存空间的代码

(cdev *)led_device

5 初始化函数增加字符设备初始化代码

cdev_init cdev_add

led_device led_fops

6 exit函数代码完成

7 增加led_fops定义

8 实现led_fops所定义的函数接口

open,release,ioctl

9 拷贝所有.h文件

10 修改Makefile

CONFIG_XXX myled.o

11 修改Kconfig

config XXX

12 make menuconfig 选中我们的配置项为M

13 make zImage ---zImage

14 make modules ---myled.ko

15 开发板环境完成(dnw里USB OK)

16 下载zImage

more /proc/version检查一下

17 通过rz命令下载testled,myled.ko

18 chmod 777 testled

19 ps查看led-player进程号(701)

20 kill 701杀死进程(灯停住不动,状态固定)

21 insmod ./myled.ko

22 more /proc/devices确认主设备号(253)

23 cd /dev

mknod (myled 测试工具) c 主 次

24 ./testled 0 0(0,1 1,0 1,1)

现象:单独控制

led驱动代码:(myled_driver.c)

#include <linux/module.h>

#include <linux/autoconf.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/fcntl.h> /* O_ACCMODE */

#include <linux/cdev.h> /* cdev...*/

#include <asm/io.h> /* writel(),readl()... */

#include <asm/system.h> /* cli(), *_flags */

#include <asm/uaccess.h> /* copy_*_user */

#include <linux/wait.h> /* wake_up_interruptible()... */

#include <linux/delay.h> /* udelay() */

#include <linux/miscdevice.h>

#include <asm/irq.h>

#include <mach/regs-gpio.h>

#include <mach/hardware.h>

#include <linux/mm.h>

#include <linux/moduleparam.h>

#include <linux/ioctl.h>

#include <linux/string.h>

#include <linux/list.h>

#include <linux/pci.h>

#include <linux/gpio.h>

#include <asm/atomic.h>

#include <asm/unistd.h>

#define DEVICE_NAME "myled" //宏定义设备名称

static int led_major = 0; //初始化主设备号

static int led_minor = 0; //初始化次设备号

struct cdev *led_device; //定义cdev结构体指针

//下面的两个数组是处理器相关的信息

static unsigned long led_table [] = {

S3C2410_GPB(5),

S3C2410_GPB(6),

S3C2410_GPB(7),

S3C2410_GPB(8),

};

static unsigned int led_cfg_table [] = {

S3C2410_GPIO_OUTPUT,

S3C2410_GPIO_OUTPUT,

S3C2410_GPIO_OUTPUT,

S3C2410_GPIO_OUTPUT,

};

//设备打开函数

static int myled_open(struct inode *inode, struct file *filp)

{

int i;

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

s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);

s3c2410_gpio_setpin(led_table[i], 0);

}

return 0;

}

//设备关闭函数

static int myled_release(struct inode *inode, struct file *filp)

{

return 0;

}

//设备操作函数

static int myled_ioctl (struct inode *inode, struct file *filp,

unsigned int cmd, unsigned long arg)

{

switch(cmd) {

case 0:

case 1:

if (arg > 4) {

return -EINVAL;

}

s3c2410_gpio_setpin(led_table[arg], !cmd);

return 0;

default:

return -EINVAL;

}

}

struct file_operations led_fops = //字符驱动和内核的接口:file_operations结构体

{ //字符驱动只要实现一个file_operations结构体,并注册到内核中,内核就有了操作此设备的能力。

.owner = THIS_MODULE, //指向模块自身。

.open = myled_open, //打开设备

.release = myled_release, //关闭设备

.ioctl = myled_ioctl, //操作设备

};

static void __exit my_led_exit(void) //模块结束函数

{

//MKDEV是因为要重新通过主次设备号合成一个设备号,后面注销时用,

//以前在模块入口函数里的设备号已经不能用了,函数不同了,而led_major, led_minor是全局变量

dev_t devno = MKDEV(led_major, led_minor); //通过主次设备号获得设备号

if (led_device){

/* Get rid of our char dev entries */

cdev_del(led_device); //删除设备

kfree(led_device); //释放内存

led_device = NULL;

}

/* cleanup_module is never called if registering failed */

unregister_chrdev_region(devno, 1); //取消注册设备号

return;

}

static int __init my_led_init(void) //模块入口函数

{

int result = 0;

dev_t dev = 0; //初始化设备号

result = alloc_chrdev_region(&dev, led_minor, 1, DEVICE_NAME);/*自动分配设备号

参数分别是获取的设备号(输出参数),第一个次设备号,次设备号数量,设备名称 */

led_major = MAJOR(dev); //通过设备号提取主设备号

if (result < 0) {

printk(KERN_WARNING "wfet_kb: can't get major %d\n", led_major);

return result;

}

led_device = kmalloc(sizeof(struct cdev), GFP_KERNEL); //为设备分配内存

if (!led_device) {

result = -ENOMEM;

unregister_chrdev_region(dev, 1);

return result;

}

memset(led_device, 0, sizeof(struct cdev)); //清空内存

cdev_init(led_device, &led_fops); //字符设备初始化函数:把为设备分配的内存与操作设备的结构相关联

led_device->owner = THIS_MODULE;

result = cdev_add (led_device, dev, 1); //设备增加

if (result) {

printk(KERN_NOTICE "Error %d adding LED device, major_%d", result, MAJOR(dev));

kfree(led_device);

unregister_chrdev_region(dev, 1);

return result;

}

return 0;

}

module_init(my_led_init); //模块入口函数

module_exit(my_led_exit); //模块出口函数

MODULE_LICENSE("GPL");

测试的应用程序(testled.c):

#include<stdio.h>

int main(int argc,char *argv[])

{

int fp;

if(argc<2)

{

printf("argc error\n");

return 0;

}

fp=open("/dev/myled",0);

if(fp<0)

{

printf("Open error\n");

return 0;

}

printf("test:%d\n",atoi(argv[1]));

if(atoi(argv[1])<8)

{

ioctl(fp,(atoi(argv[1])-atoi(argv[1])/2),(atoi(argv[1])/2));

}

if(atoi(argv[1])==8)

{

ioctl(fp,0,0);

ioctl(fp,0,1);

ioctl(fp,0,2);

ioctl(fp,0,3);

}

if(atoi(argv[1])==9)

{

ioctl(fp,1,0);

ioctl(fp,1,1);

ioctl(fp,1,2);

ioctl(fp,1,3);

}

if(atoi(argv[1])==10)

{

ioctl(fp,0,0);

ioctl(fp,0,1);

}

if(atoi(argv[1])==11)

{

ioctl(fp,1,0);

ioctl(fp,1,1);

}

if(atoi(argv[1])==12)

{

ioctl(fp,0,2);

ioctl(fp,0,3);

}

if(atoi(argv[1])==13)

{

ioctl(fp,1,2);

ioctl(fp,1,3);

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: