查看: 2101|回复: 1

TQ210 LED驱动+流水灯(转)

[复制链接]
  • TA的每日心情
    奋斗
    2018-3-5 10:57
  • 签到天数: 112 天

    连续签到: 1 天

    [LV.6]常住居民II

    发表于 2015-4-20 16:59:52 | 显示全部楼层 |阅读模式
    分享到:
    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 pinut 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
    *fuctionpen /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 pin\n");
            return err;
             }
             err = gpio_request(gpio_table[1], "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[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 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[0], "GPC0_3");
             if(err)
             {
                       printk(KERN_ERR "failed to request GPC0_3 for LVDS PWDN pin\n");
            return err;
             }
             err = gpio_request(gpio_table[1], "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[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 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[0]);
             gpio_free(gpio_table[1]);
             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[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("111111\n");
        if(!strcmp(argv[2],"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[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<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[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 on\n",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);
             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;
    }

    回复

    使用道具 举报

    该用户从未签到

    发表于 2015-5-4 17:36:15 | 显示全部楼层
    转的也得赞
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条



    手机版|小黑屋|与非网

    GMT+8, 2025-1-27 07:27 , Processed in 0.128918 second(s), 17 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.