实验五基于ARM的模块方式驱动程序实验【实验目的】1.掌握Linux 系统下设备驱动程序的作用与编写技巧2.掌握Linux 驱动程序模块加载和卸载的方法3.了解Linux 内核中的makefile和kconfig文件【实验内容】1.基于s3c2440 开发板编写led 驱动程序。
2.将编写好的led驱动加入linux内核中,修改makefile和kconfig文件,配置和编译内核。
3.编写关于led 的测试程序,交叉编译后运行,控制led 灯的亮灭。
【预备知识】1.了解ARM9处理器结构和Linux 系统结构2.熟练掌握C语言。
【实验设备和工具】⏹硬件:ARM嵌入式开发平台,PC机Pentium100 以上。
⏹软件:PC机Linux操作系统+MINICOM+AMRLINUX 开发环境【实验原理】⏹linux设备驱动程序⏹驱动的模块式加载和卸载⏹编译模块⏹装载和卸载模块⏹led 驱动的原理在本开发板上有八个led指示灯,从下往上分别为LED0-LED7。
这八个led灯都是接的芯片上的gpio口(通用功能输入输出口)。
在本实验的开发板硬件设计中,当led 灯对应的gpio的电平为低时,led灯被点亮;当led灯对应的gpio的电平为高时,led灯灭。
本驱动的作用就是通过设置对应gpio口的电平来控制led 的亮灭。
因为ARM 芯片内的GPIO口都是复用的,即它可以被配置为多种不同的功能,本实验是使用它的普通的I/O口的输出功能,故需要对每个GPIO口进行配置。
在内核中已经定义了对GPIO口进行配置的函数,我们只需要调用这些函数就可以完成对GPIO口的配置。
【实验步骤】实验程序运行效果:程序会提示:“p leaseenterthe led stat us”输入与希望显示的led状态对应的ledstatus值(输入十进制值即可),观察led 的显示情况。
例如:⏹输入数字“3”,对应的二进制数字为00000011故点亮LED2~LED7⏹输入数字“4”,对应的二进制数字为00000100故点亮LED0,LED1,LED3~LED7【实验结果和程序】C语言程序:#include<linux/config.h>#include<linux/module.h>#include<linux/kernel.h>#include<linux/devfs_fs_kernel.h>#include<linux/fs.h>#include<linux/init.h>#include<linux/device.h>#include<linux/cdev.h>#include<asm/hardware.h>#include<asm/delay.h>#include<asm/uaccess.h>#include<asm/arch/regs-gpio.h>#include<asm/arch/hardware.h>#defineDEVICE_NAME "s3c2440-led"static intLedMajor=231;staticintLedMinor=0;static charledstatus=0xff;staticstructclass*s3c2440_class;staticstructcdev *s3c2440_led_cdev;/******************************************************************************** ************************** Function name:Update_led()**Descriptions :update the led status**Input :NONE**Output :NONE******************************************************************************* *************************/staticvoid Update_led(void){if(ledstatus&0x01)s3c2410_gpio_setpin(S3C2410_GPC7,1); //LED0灭elses3c2410_gpio_setpin(S3C2410_GPC7,0); //LED0亮if(ledstatus&0x02)s3c2410_gpio_setpin(S3C2410_GPC5,1); //LED1灭elses3c2410_gpio_setpin(S3C2410_GPC5,0); //LED1亮if(ledstatus&0x04)s3c2410_gpio_setpin(S3C2410_GPH9,1); //LED2灭elses3c2410_gpio_setpin(S3C2410_GPH9,0); //LED2亮if(ledstatus&0x08)s3c2410_gpio_setpin(S3C2410_GPB4,1); //LED3灭elses3c2410_gpio_setpin(S3C2410_GPB4,0); //LED3亮if(ledstatus&0x10)s3c2410_gpio_setpin(S3C2410_GPG5,1); //LED4灭elses3c2410_gpio_setpin(S3C2410_GPG5,0); //LED4亮if(ledstatus&0x20)s3c2410_gpio_setpin(S3C2410_GPG6,1); //LED5灭elses3c2410_gpio_setpin(S3C2410_GPG6,0); //LED5亮if(ledstatus&0x40)s3c2410_gpio_setpin(S3C2410_GPG7,1); //LED6灭elses3c2410_gpio_setpin(S3C2410_GPG7,0); //LED6亮if(ledstatus&0x80)s3c2410_gpio_setpin(S3C2410_GPG8,1); //LED7灭elses3c2410_gpio_setpin(S3C2410_GPG8,0); //LED7亮}staticssize_ts3c2440_Led_write(structfile*file,constchar*buffer,size_tcount,loff_t*ppos) {copy_from_user(&ledstatus,buffer,sizeof(ledstatus));Update_led();printk("write: led=0x%x,count=%d\n",ledstatus,count);returnsizeof(ledstatus);}staticints3c2440_Led_open(structinode*inode,struct file *filp){printk("led device open\n");return 0;}staticints3c2440_Led_release(structinode*inode,struct file*filp){printk("led device release\n");return 0;}staticstructfile_operationss3c2440_fops={.owner=THIS_MODULE,.open=s3c2440_Led_open,.write=s3c2440_Led_write,.release=s3c2440_Led_release,};staticintinits3c2440_Led_init(void){int ret;dev_ts3c2440_leds_devno;/*configure the gpiofor leds*/s3c2410_gpio_cfgpin(S3C2410_GPG5,S3C2410_GPIO_OUTPUT);s3c2410_gpio_cfgpin(S3C2410_GPG6,S3C2410_GPIO_OUTPUT);s3c2410_gpio_cfgpin(S3C2410_GPG7,S3C2410_GPIO_OUTPUT);s3c2410_gpio_cfgpin(S3C2410_GPG8,S3C2410_GPIO_OUTPUT);s3c2410_gpio_cfgpin(S3C2410_GPC7,S3C2410_GPIO_OUTPUT);s3c2410_gpio_cfgpin(S3C2410_GPC5,S3C2410_GPIO_OUTPUT);s3c2410_gpio_cfgpin(S3C2410_GPH9,S3C2410_GPIO_OUTPUT);s3c2410_gpio_cfgpin(S3C2410_GPB4,S3C2410_GPIO_OUTPUT);Update_led();/*registerthe devnumber*/s3c2440_leds_devno=MKDEV(LedMajor,LedMinor);ret=register_chrdev_region(s3c2440_leds_devno, 1,DEVICE_NAME);/*registerthe chardevice*/s3c2440_led_cdev=cdev_alloc(); if(s3c2440_led_cdev!= NULL){cdev_init (s3c2440_led_cdev, &s3c2440_fops);s3c2440_led_cdev->owner=THIS_MODULE;if(cdev_add(s3c2440_led_cdev, s3c2440_leds_devno, 1))printk(KERN_NOTICE "Something wrong when addings3c2440_led_cdev!\n");elseprintk("Success addings3c2440_led_cdev!\n");}/*create the device node in /dev*/s3c2440_class =class_create(THIS_MODULE, "led_class");class_device_create(s3c2440_class, NULL, s3c2440_leds_devno, NULL, DEVICE_NAME);printk(DEVICE_NAME " initialized\n");return 0;}staticvoid exits3c2440_Led_exit(void){cdev_del(s3c2440_led_cdev);class_device_destroy(s3c2440_class, MKDEV(LedMajor,LedMinor));class_destroy(s3c2440_class);printk(DEVICE_NAME " removed\n");}module_init(s3c2440_Led_init);module_exit(s3c2440_Led_exit);【思考题】1. 设备驱动程序的功能是什么?答:设备驱动的功能就是将系统提供的调用映射到作用于实际硬件的和设备相关的操作上。