非也 发表于 2015-4-20 15:45:25

TQ210 LED驱动+流水灯(转)

本帖最后由 非也 于 2015-4-21 09:45 编辑

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/nfsboot/rootfs中/mnt目录下;在超级终端上控制开发板。挂载好nfs文件系统:#mount –t nfs 10.10.84.41:/home/share/nfsboot/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 <linux/miscdevice.h>
#include <linux/input.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <mach/map.h>
#include <mach/gpio.h>
//#include <mach/gpio-bank.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-core.h>
#include <plat/gpio-cfg.h>
#include <plat/gpio-cfg-helpers.h>
#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, cmd);
         //s3c_gpio_setpin(gpio_table, 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, "GPC0_3");
         if(err)
         {
                   printk(KERN_ERR "failed to request GPC0_3 for LVDS PWDN pin\n");
      return err;
         }
         err = gpio_request(gpio_table, "GPC0_4");
         if(err)
         {
                   printk(KERN_ERR "failed to request GPC0_4 for LVDS PWDN pin\n");
      return err;
         }
         printk(KERN_INFO " leds opened\n");
         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, 1);
                            //s3c_gpio_setpin(gpio_table, 1);
                            return 0;
                   case IOCTL_GPIO_OFF:
                            // 设置指定引脚的输出电平为0
                            gpio_direction_output(gpio_table, 0);
                            //s3c_gpio_setpin(gpio_table, 0);
                            return 0;
                   default:
                            return -EINVAL;
         }
}
static int tq210_gpio_close(struct inode *inode, struct file *file)
{
         gpio_free(gpio_table);
         gpio_free(gpio_table);
         printk(KERN_INFO "TQ210 LEDs driver successfully close\n");
         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, "GPC0_3");
         if(err)
         {
                   printk(KERN_ERR "failed to request GPC0_3 for LVDS PWDN pin\n");
      return err;
         }
         err = gpio_request(gpio_table, "GPC0_4");
         if(err)
         {
                   printk(KERN_ERR "failed to request GPC0_4 for LVDS PWDN pin\n");
      return err;
         }
         for (i = 0; i < sizeof(gpio_table)/sizeof(unsigned long); i++)
         {
                   //gpio_request(gpio_table,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 probed\n");
         #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);
         gpio_free(gpio_table);
         printk(KERN_INFO "TQ210 LEDs driver successfully exit\n");
}
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<stdio.h>
#include<fcntl.h>
#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 wrong\n");
                   printf("USE:\n");
                   printf("\t\t./program\tled-number\ton/off\n");
                   return -1;
         }
    //led_no = strtoul(argv,0,0) -1;//its wrong to set like this
         led_no = strtoul(argv,0,0);//operate the led_1 by input 1 and led_2 by input 2
    printf("111111\n");
    if(!strcmp(argv,"on"))//turn on the led
    {
      ioctl(fd,IOCTL_LED_ON,led_no);
                   printf("you want the %d on\n",led_no);
    }
    else if(!strcmp(argv,"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<stdio.h>
#include<fcntl.h>
#include <signal.h>
//#include <time.h>
#include <sys/time.h>
#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 wrong\n");
                   printf("USE:\n");
                   printf("\t./program\t<right/left/both>\t<1/2/3>\n");
                   printf("\t3:slow;2:faster;1:fastest\n");
                   printf("\teg: ./led_flow\tleft\t1\n\tlet the led light start from left and the speed is the fastest\n");
                   return -1;
         }
      
         if(!strcmp(argv,"1"))
         delay_grade = 1;//20ms
         else if (!(argv,"2"))
         delay_grade = 15;//300ms
         else if(!(argv,"3"))
         delay_grade = 50;//1s
         else
                   delay_grade = 30;//600ms
                  
    if(!strcmp(argv,"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 on\n",led_no);
                            delay(delay_grade);
                            ioctl(fd,IOCTL_LED_OFF,led_no);
                   }
    }
    else if(!strcmp(argv,"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),"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);
         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;
}

源文出处:http://www.armbbs.net/home.php?mod=space&uid=27960&do=blog&id=361

jevin 发表于 2017-1-7 19:04:48

好东西,学习学习,收藏

jevin 发表于 2017-1-9 12:29:43

好东西,学习学习,收藏
页: [1]
查看完整版本: TQ210 LED驱动+流水灯(转)