资源描述
Linux LED 设备驱动实验1.1 实验目的 (1)了解 LED 原理及其与 S3C2410 的接口电路设计 (2)了解S3C2410芯片的 I/O 端口配置方法 (3)通过S3C2410芯片的 GPF4 端口控制 Super-ARM主板上 D1 的亮灭 (4)掌握 LED 驱动的编写及测试过程,进而熟悉开发简单字符设备驱动的方法 1.2 实验原理 (1)LED 接口电路 由于单只 LED 管的工作电压低(大约在 1.52V) ,个别需达到 4V,同时工作电流仅为 15mA,因此可以用 CPU 的通用输入输出管脚(GPIO)直接控制 LED 的亮灭。 LED 的接口电路如下图1所示:图1 LED接口电路1.3 实验任务 本实验的最终目的是实现Super-ARM平台上的 LED 驱动。包含以下几个任务: (1)编写 LED 设备驱动程序,驱动程序中手动定义设备名称及主设备号,这个设备号必须是系统尚未使用的设备号,笔者这里暂用 212,你也可以尝试用别的数字。当然最好的方法是动态分配设备号,如果使用这种方法,在/dev 目录下为 LED 设备建立设备节点的时候,需要先从/proc/devices 文件中获取该设备的主设备号。在驱动程序中还要实现与 LED 相应的 I/O 配置,以及读写设备的接口函数等。 (2)将驱动编译成模块,并实现模块的加载及卸载。 (3)编写驱动的测试程序,在程序中实现打开 LED 设备,控制 LED 设备一亮一灭,关闭 LED 设备等。1.4 实验步骤 编写 led.c文件 建立 led目录: #mkdir /gdut2410/led 进入led目录,在该目录下建立两个子目录driver 和 test ,前者用来存放驱动程序,后者用来存放驱动测试程序: #cd /gdut2410/led #mkdir driver test 进入驱动程序目录,建立设备驱动文件 led.c: cd driver gedit led.c LED 驱动程序如代码清单5-1 所示:代码清单 5-1 LED驱动程序 led.c /* 头文件 * #include #include #include #include #include #include #include #include #include #include #include #include /* 定义设备结构体及相关宏 * #define DEVICE_NAME led /定义设备名 #define DEVICE_MAJOR 212 /手动定义 LED 设备的主设备号为 212 static int led_major = DEVICE_MAJOR ; #define LED1 S3C2410_GPF4 /定义LED1 对应 S3C2410 的 GPF4 端口 #define LED1_OUTP S3C2410_GPF4_OUTP #define LED_ON 0 /给端口低电平(0)时,LED 亮 #define LED_OFF 1 /给端口高电平(1)时,LED 灭 /定义 LED 设备结构体 struct s3c2410_led_dev struct cdev cdev; /LED 设备对应一个字符设备结构体 int status; /LED 状态标识,0 代表灭,1 代表亮 ; static struct s3c2410_led_dev dev; /* 函数声明 * void s3c2410_led_InitIO(void); /初始化 IO 端口的函数/* 函数定义 * /* = s3c2410_led _InitIO() 描述 : 初始化 IO 端口 参数 : 无 返回值 : 无 = */ void s3c2410_led_InitIO(void) int i; /配置 LED 对应的端口为输出 s3c2410_gpio_cfgpin(LED1, LED1_OUTP); /配置 LED 初始为熄灭状态 s3c2410_gpio_setpin(LED1, LED_OFF); /* = s3c2410_led_open() 描述 : 打开设备 参数 : 返回值 : 0 = */ static int s3c2410_led_open(struct inode *inode,struct file *filp) return 0; /* = s3c2410_led_release() 描述 : 注销设备 参数 : 返回值 : 0 = */ static int s3c2410_led_release(struct inode *inode,struct file *filp) return 0; /* = s3c2410_led_ioctl() 描述 : IO 控制函数,通过 LED_ON 和 LED_OFF命令控制 LED 的亮灭 参数 : cmd:用户控制命令,包括 LED_ON 和LED_OFF 返回值 : 0 = */static int s3c2410_led_ioctl(struct inode *inode,struct file *filp, unsigned int cmd,unsigned long arg) switch(cmd) case LED_ON: s3c2410_gpio_setpin(LED1, LED_ON); dev.status = 1; break; case LED_OFF: s3c2410_gpio_setpin(LED1, LED_OFF); dev.status = 0; break; default: return -EINVAL; return 0; /* = s3c2410_led_read() 描述 : 读函数,读取 LED 的状态 参数 : buffer: 用来存储读取的 LED 状态; count: 用来记录用户读取了多少个字符 返回值 : count = */ static ssize_t s3c2410_led_read(struct file *filp,char *buffer, ize_t count,loff_t *ppos) put_user(dev.status,(int *)buffer); /读取 LED 状态 return 1; /* = s3c2410_led_write() 描述 : 写操作函数,本实例中不做任何事 参数 : 返回值 : count = */ static ssize_t s3c2410_led_write(struct file *filp,char *buffer, size_t count,loff_t *ppos) get_user(dev.status,(int *)buffer); if(dev.status = 0) /灭 s3c2410_gpio_setpin(LED1, LED_OFF); else if(dev.status = 1)/亮 s3c2410_gpio_setpin(LED1, LED_ON); return 1; /* = s3c2410_led_fops 描述 : 文件操作结构体,实现 s3c2410_button_open()等函数与 open()等系统调 用的连接 参数 : 无 返回值 : 无 = */ static struct file_operations s3c2410_led_fops = .owner = THIS_MODULE, .open = s3c2410_led_open, .release = s3c2410_led_release, .ioctl = s3c2410_led_ioctl,.read = s3c2410_led_read, .write = s3c2410_led_write, ; /* = led_setup_cdev() 描述 : 安装 LED 设备的功能函数,在设备加载模块里面调用 参数 : 无 返回值 : 无 = */ static void led_setup_cdev(void) int err ,devno = MKDEV (led_major , 0); cdev_init(&dev.cdev,&s3c2410_led_fops); dev.cdev.owner = THIS_MODULE; dev.cdev.ops = &s3c2410_led_fops; /建立设备文件操作与系统调用之间的连接 err = cdev_add(&dev.cdev,devno,1); /向系统添加该设备 if(err) printk(Error %d adding LED %d,err); /* = s3c2410_led_init() 描述 : 模块加载,IO 及相关变量初始化 参数 : 无 返回值 : 无 = */ static int s3c2410_led_init(void) int result; dev_t devno = MKDEV(led_major,0);/根据主设备号得到dev_t类型的设备号 devno if(led_major) /如果手动分配了主设备号 result = register_chrdev_region(devno,1,DEVICE_NAME); /向系统申请该设备号 else /否则动态获取设备号 result = alloc_chrdev_region(&devno ,0 ,1,DEVICE_NAME); led_major = MAJOR(devno); if(result 0) return result; led_setup_cdev(); / 注册 LED 设备 s3c2410_led_InitIO(); / 初始化 IO 端口 / initialize the vals; dev.status = 0; /LED 的初始状态是灭printk(DEVICE_NAME initializedn); return 0; /* = s3c2410_led_exit() 描述 : 模块卸载函数 参数 : 无 返回值 : 无 = */ static void s3c2410_led_exit(void) cdev_del(&dev.cdev); /注销设备 unregister_chrdev_region(MKDEV(led_major,0),1); /释放设备号 module_init(s3c2410_led_init); module_exit(s3c2410_led_exit); MODULE_LICENSE(GPL); /设备许可 编写Makefile文件在主机的/gdut2410/led/driver 目录下#cd /gdut2410/led/driver# vi Makefile 在该文件中加入以下内容: (其中 KDIR 是内核目录,读者要根据自己的内核所在目录来设置)obj-m := led.o KDIR := /gdut2410/kernel/linux-2.6.24 PWD := $(shell pwd) default: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules # 编译 #make 编译完成后,该目录下会生成 led.ko文件,该文件就是编译成功的模块文件,然后把led.ko拷贝到nfs共享目录。 创建设备 进入/gdut2410/rootfs/rootfs/dev 目录,创建设备,设备名为 led,属于字符型设备,主设备号是 212,次设备号是 0。 (要与 led.c文件中的定义相符) : # cd /gdut2410/rootfs/rootfs/dev # mknod led c 212 0 加载模块 在宿主机上运行 minicom,打开实验箱电源,加载完 U-Boot,内核和文件系统之后按回车键进入目标机 shell 控制台,在控制台中输入nfs挂载命令:#mount -t nfs -o nolock 192.168.1.10:/mnt/nfs /mnt/nfs /这里根据自己实际情况设置目录然后执行内核模块加载命令: #insmod mnt/nfs/led.ko 如果输出“led initialized” ,表示led设备驱动加载成功 编写测试文件 led_test.c 进入宿主机的/gdut2410/led/test目录,编辑测试文件led_test.c: cd /gdut2410/led/test gedit led_test.c 在测试文件中加入代码清单 5-2所示的内容: 代码清单5-2 LED 驱动测试文件 led_test.c #include #include #include #include sys/types.h #include sys/ioctl.h #include stdlib.h #include termios.h #include sys/stat.h #include fcntl.h #include sys/time.h #define LED_ON 0 #define LED_OFF 1int main() int fd,i,j; int led_status = 0; /初始状态为熄灭 fd = open(/dev/led, O_RDWR); /打开设备 if (fd 0) /如果打开设备失败,退出 perror(open device led failed !); exit(1); printf(led test show. press ctrl+c to exit n); ioctl(fd,LED_OFF); while(1)/主循环 read (fd,&led_status,1); /读取 LED1 的当前状态到 led_status if(led_status =0) /如果是灭的 ioctl(fd,LED_ON); /点亮 else if(led_status =1) /如果是亮的 ioctl(fd,LED_OFF); /熄灭 printf(led: on and offn); for(i=0;i300;i+) for(j=0;j10000;j+); close(fd); /关闭设备 return 0; 该测试程序实现了控制 Super-ARM实验箱上的 D1 一亮一灭的功能。 编译测试程序 执行下面的命令: #gcc -o led_test led_test.c 该命令的意思是使用的交叉编译器 arm-linux-gcc 对驱动程序 led_test.c 进行编译,编译成功后在 test 目录下会生成目标机的可执行文件led_test,然后把led_test拷贝到nfs共享目录(根据自己实际设置情况)。 运行测试程序 在目标机的控制台中输入: #cd /mnt/nfs#./ led_test 可以看到控制台会打印出一行信息: “led test show. press ctrl+c to exit ” 。按“ctrl+c”可以退出测试程序。 测试程序运行时,目标机的led灯 D1 一亮一灭,同时,在控制台输出的信息如下: / # insmod /mnt/nfs/led.ko led initialized / # ./mnt/nfs/led_test led test show. press ctrl+c to exit led: on and off led: on and off led: on and off led: on and off 卸载模块 rmmod led.ko 卸载了模块以后,测试程序便不能正常运行了,如果运行会输出如下信息:“open device led: No such device or address”
展开阅读全文