TQ210 LED驱动及测试 1. 编写led驱动1.1 在系统中创建目录/home/share/led/ #mkdir –p /home/share/led 进入led目录 #cd /home/share/led 1.2创建源码文件led_driver.c #vim led_driver.c 源码内容见附件一。 保存退出. 1.3创建并编辑Makefile 在该目录下创建Makefile文件,将驱动程序编译成模块。 #vim Makefile 内容如下: oj-m +=led_driver.o CURRENT_PATH := /home/share/led LINUX_KERNEL ?= /home/share/learning/linux-2.6.35 #LINUX_KERNEL_PATH := $(LINUX_KERNEL) default: $(MAKE) -C $(LINUX_KERNEL) m=$(CURRENT_PATH) modules clean: $(MAKE) -C $(LINUX_KERNEL) M=$(CURRENT_PATH) clean 2. 编译TQ210使用天嵌提供交叉编译器,路径:/home/share/tmp/opt/EmbedSky/4.4.6/bin 在该目录下直接make即可 #make 3. 测试led驱动测试代码:见附件二 使用交叉编译工具编译程序: # arm-linux-gcc -o led_test led_test.c 将生成的可执行程序led_test复制到nfs文件系统/home/share/nf***oot/rootfs中/mnt目录下; 挂载好nfs文件系统: #mount –t nfs 10.10.84.41:/home/share/nf***oot/rootfs –o nolock /mnt 进入挂载在/mnt 目录下的nfs文件系统内并且进入内部/mnt目录下: #cd /mnt //此目录是开发版的子目录 #cd /mnt //此目录是挂载的宿主机上的nfs文件系统的子目录 执行可执行文件: # ./led_test 出现段错误提示,原因参数不正确,还需要输入led的序号,以及开关指令。测试程序没有做好参数检查,所以会段错误在代码中对argc进行判断即可。 #./led_test 2 on //打开第二个led #./led_test 2 off //关掉第二个led 开发板上两个LED灯均能正确控制,至此led驱动及测试代码试验完成。 附件一led驱动源码/*********************************************************************************** * drivers/char/tq210_leds.c * 功能简要: * 该驱动注册一个字符设备“/dev/led”, 用于2个LED。 * 函数简介: * static void tq210_debug_leds(unsigned int cmd,unsigned long arg),用于内核驱动调试 * 提供的外部接口: * ioctol(struct inode *inode,struct file *file,unsigned int brightness); * 用于LED的亮,灭。 * 调用实例: * 提供控制台,命令式的测试程序。 * *************************************************************************************/ #include #include #include #include #include #include //#include #include #define DEVICE_NAME "led" /* 应用程序执行ioctl(fd, cmd, arg)时的第2个参数 */ /*the second parameter that application program execute*/ #define IOCTL_GPIO_ON 1 #define IOCTL_GPIO_OFF 0 /* 用来指定LED所用的GPIO引脚 */ /*appoint the pin the LED will use*/ static unsigned long gpio_table [] = { S5PV210_GPC0(3), S5PV210_GPC0(4), }; /* 用来指定GPIO引脚的功能:输出 */ /*appoint the function of the pin:out put*/ static unsigned int gpio_cfg_table [] = { S3C_GPIO_SFN(1), S3C_GPIO_SFN(1), }; //static char gpio_name[][]={{"GPC0_3"},{"GPC0_4"}}; #ifdef CONFIG_TQ210_DEBUG_LEDS static void tq210_debug_leds(unsigned int cmd,unsigned long arg) { gpio_direction_output(gpio_table[arg], cmd); //s3c_gpio_setpin(gpio_table[arg], cmd); } static void toggle_led(unsigned int cmd,unsigned long arg) { int loop=0; printk("%s : led %ld toggle now: n",__func__,arg); for(;loop<11;loop++) { cmd = loop%2; printk("leds %d %s n",arg+1,(cmd)?"on":"o ff"); tq210_debug_leds(cmd,arg); mdelay(1000); } } #endif /** *函数功能:打开/dev/led设备,设备名是:/dev/led *fuction:open /dev/led device ,devce name: /dev/led **/ static int tq210_gpio_open(struct inode *inode, struct file *file) { int i; int err; err = gpio_request(gpio_table[0], "GPC0_3"); if(err) { printk(KERN_ERR "failed to request GPC0_3 for LVDS PWDN pinn"); return err; } err = gpio_request(gpio_table[1], "GPC0_4"); if(err) { printk(KERN_ERR "failed to request GPC0_4 for LVDS PWDN pinn"); return err; } printk(KERN_INFO " leds openedn"); for (i = 0; i < sizeof(gpio_table)/sizeof(unsigned long); i++) { s3c_gpio_cfgpin(gpio_table, gpio_cfg_table); gpio_direction_output(gpio_table, 0); //s3c_gpio_setpin(gpio_table, 0); } #ifdef CONFIG_TQ210_DEBUG_LEDS for (i = 0; i < sizeof(gpio_table)/sizeof(unsigned long); i++) { toggle_led(1,i); } #endif return 0; } /** *函数功能:用于控制led的亮灭 *fuction:control the led /turn on & turn off *控制字为cmd,arg为控制哪个灯的亮灭取值范围为0-1:cmd为IOCTL_GPIO_ON时亮,cmd为IOCTL_GPIO_OFF为灭 *control byte is cmd; arg appointed which led wile be turn on or off,it can be 0 and 1;IOCTL_GPIO_ON:turn on,IOCTL_GPIO_OFF:turn off. **/ static long tq210_gpio_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { arg -= 1; if (arg > sizeof(gpio_table)/sizeof(unsigned long)) { return -EINVAL; } switch(cmd) { case IOCTL_GPIO_ON: // 设置指定引脚的输出电平为1 gpio_direction_output(gpio_table[arg], 1); //s3c_gpio_setpin(gpio_table[arg], 1); return 0; case IOCTL_GPIO_OFF: // 设置指定引脚的输出电平为0 gpio_direction_output(gpio_table[arg], 0); //s3c_gpio_setpin(gpio_table[arg], 0); return 0; default: return -EINVAL; } } static int tq210_gpio_close(struct inode *inode, struct file *file) { gpio_free(gpio_table[0]); gpio_free(gpio_table[1]); printk(KERN_INFO "TQ210 LEDs driver successfully closen"); return 0; } /*驱动接口设置*/ /*setting the interface of the driver*/ static struct file_operations dev_fops = { .owner = THIS_MODULE, .ioctl = tq210_gpio_ioctl, .open = tq210_gpio_open, .release = tq210_gpio_close, }; /*设备结构的设置*/ /*setting the architecture of the device*/ static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops, }; /*初始化设备,配置对应的IO,以及注册设备*/ /*init the device, config the right IO and register the device*/ static int __init dev_init(void) { int ret; int i; int err; #ifdef CONFIG_TQ210_DEBUG_LEDS err = gpio_request(gpio_table[0], "GPC0_3"); if(err) { printk(KERN_ERR "failed to request GPC0_3 for LVDS PWDN pinn"); return err; } err = gpio_request(gpio_table[1], "GPC0_4"); if(err) { printk(KERN_ERR "failed to request GPC0_4 for LVDS PWDN pinn"); return err; } for (i = 0; i < sizeof(gpio_table)/sizeof(unsigned long); i++) { //gpio_request(gpio_table[0],gpio_name); s3c_gpio_cfgpin(gpio_table, gpio_cfg_table);//配置管脚为输出config the pin to out put gpio_direction_output(gpio_table, 0); //s3c_gpio_setpin(gpio_table, 0);//设置管脚为低电平config the pin to low level s3c_gpio_setpull(gpio_table, S3C_GPIO_PULL_NONE); } #endif ret = misc_register(&misc); printk(KERN_INFO "TQ210 LEDs driver successfully probedn"); #ifdef CONFIG_TQ210_DEBUG_LEDS for (i = 0; i < sizeof(gpio_table)/sizeof(unsigned long); i++) { toggle_led(1,i); } #endif return ret; } /*注销设备*/ /*log out the device*/ static void __exit dev_exit(void) { misc_deregister(&misc); gpio_free(gpio_table[0]); gpio_free(gpio_table[1]); printk(KERN_INFO "TQ210 LEDs driver successfully exitn"); } module_init(dev_init); module_exit(dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("www.embedsky.com"); MODULE_DESCRIPTION("LEDS' Driver"); 附件二 led测试源码/*FILENAME:led_test.c *AUTHOR:Michael Li *DATE:2013-06-03 *DESCRIPTION:the test of the led driver * */ #include #include #define DEVICENAME "/dev/led" #define IOCTL_LED_ON 1 #define IOCTL_LED_OFF 0 int main(int argc, char **argv) { FILE *fd; int led_no = 0; fd = (FILE *)open(DEVICENAME,0); if(argc < 3) { printf("The arguments you input are wrongn"); printf("USE:n"); printf("tt./programtled-numberton/offn"); return -1; } //led_no = strtoul(argv[1],0,0) -1;//its wrong to set like this led_no = strtoul(argv[1],0,0);//operate the led_1 by input 1 and led_2 by input 2 printf("111111n"); if(!strcmp(argv[2],"on"))//turn on the led { ioctl(fd,IOCTL_LED_ON,led_no); printf("you want the %d onn",led_no); } else if(!strcmp(argv[2],"off"))//turn off the led { ioctl(fd,IOCTL_LED_OFF,led_no); } else printf("error!n"); return 0; } 附件三:流水灯/*FILENAME:led_test.c *AUTHOR:Michael Li *DATE:2013-06-03 *DESCRIPTION:the test of the led driver,please refer to the label "usage:" below. * */ #include #include #include //#include #include #define DEVICENAME "/dev/led" #define IOCTL_LED_ON 1 #define IOCTL_LED_OFF 0 void sigoutime(); void timer_init(); void delay(int time); int time_1= 0; int main(int argc, char **argv) { FILE *fd; int led_no = 0; int i = 0; fd = (FILE *)open(DEVICENAME,0); int delay_grade = 0; timer_init(); usage: if(argc < 3) { printf("The arguments you input are wrongn"); printf("USE:n"); printf("t./programtt<1/2/3>n"); printf("t3:slow;2:faster;1:fastestn"); printf("teg: ./led_flowtleftt1ntlet the led light start from left and the speed is the fastestn"); return -1; } if(!strcmp(argv[2],"1")) delay_grade = 1;//20ms else if (!(argv[2],"2")) delay_grade = 15;//300ms else if(!(argv[2],"3")) delay_grade = 50;//1s else delay_grade = 30;//600ms if(!strcmp(argv[1],"left"))//turn on the led { for(i=0;i<40;i++) { if((i%2)!=0) { led_no = 1; } else led_no = 2; ioctl(fd,IOCTL_LED_ON,led_no); printf("you want the %d onn",led_no); delay(delay_grade); ioctl(fd,IOCTL_LED_OFF,led_no); } } else if(!strcmp(argv[1],"right"))//turn off the led { for(i=0;i<20;i++) { if((i%2)==0) { led_no = 1; } else led_no = 2; ioctl(fd,IOCTL_LED_ON,led_no); delay(delay_grade); ioctl(fd,IOCTL_LED_OFF,led_no); } } else if(!strcmp(argv[1]),"both") { for(i=0;i<50;i++) { ioctl(fd,IOCTL_LED_ON,1); ioctl(fd,IOCTL_LED_ON,2); delay(delay_grade);//delay 0.8s ioctl(fd,IOCTL_LED_OFF,1); ioctl(fd,IOCTL_LED_OFF,2); delay(delay_grade);//delay 0.8s } } else printf("error!n"); close(fd); return 0; } void delay(int time) { while(time_1 time_1 = 0; //you must clean the time_1 every time you sign a time return; } void timer_init() //内核定时器初始化函数 { struct itimerval value; //(1)定义类型为itimerval的结构体变量 signal(SIGALRM, sigoutime);//注册信号的处理函数 value.it_value.tv_sec = 0;//秒——设置第一次运行sigroutine函数时间 value.it_value.tv_usec = 100000;//微妙——设置为0 value.it_interval.tv_sec = 0;//秒——设置间隔运行sigroutine函数的时间(实际定时) value.it_interval.tv_usec = 20000;//微妙———设置为20ms setitimer(ITIMER_REAL, &value, NULL); //(2)设置 “真实计时器“参数 } void sigoutime() { time_1++; return; }
|