led驱动_led灯驱动 - CSDN
  • LED驱动电路设计

    2020-07-30 23:31:46
    本书全面、系统地阐述了LED照明基础知识及LED照明驱动电路设计,按室内照明应用给出了LED球泡灯、LED日光灯、LED筒灯、LED日光灯支架、LED平板灯等许多典型LED驱动电源设计与应用实例。本书共含7个项目,l4个任务。...
  • LED驱动程序设计

    2019-05-13 17:25:01
    S3C2440 GPIO 通用输入输出接口的简称, S2440一共有130个GPIO口,分为A~J共9组:GPA,GPB,GPC……GPJ;通过设置相应的寄存器,可以选择某个GPIO口是用于输入,输出还是特定其他特殊功能。例如可以设置GPH6口用于输入...

    S3C2440 GPIO

    通用输入输出接口的简称
    S2440一共有130个GPIO口,分为A~J共9组:GPA,GPB,GPC……GPJ;通过设置相应的寄存器,可以选择某个GPIO口是用于输入,输出还是特定其他特殊功能。例如可以设置GPH6口用于输入输出,或者是串口;
    每组GPIO(GPA-GPJ),都可以通过3个寄存器来控制与访问,这三个寄存器分别是

    • GPxCON:GPIO配置寄存器------两位
    • GPxDAT:GPIO数据寄存器------一位
    • GPxUP:上拉电阻控制寄存器–一位
      GPxCON设置示例:
      在这里插入图片描述

    LED驱动程序设计

    程序:
    在这里插入图片描述

    #include "def.h"
    #include "option.h"
    #include "2440addr.h"     
    #include "2440lib.h"
    #include "2440slib.h"      
    //================================
    //延时函数
    void dely(U32 tt)
    {
       U32 i;
       for(;tt>0;tt--)
       {
         for(i=0;i<10000;i++){}
       }
    }
       
    
    int Main(int argc, char **argv)
    {
    	int i;
    	U8 key;
    	U32 mpll_val=0;
    	int data;
      
    	mpll_val = (92<<12)|(1<<4)|(1);
    	
    	//init FCLK=400M, so change MPLL first
    	ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);
    	ChangeClockDivider(key, 12);    
    
    	//ChangeClockDivider(1,1);    // 1:2:4    FCLK:HCLK:PCLK
        // rCLKDIVN=0x4;    //  1:4:4
        //ChangeMPllValue(82,2,1);     //FCLK=135.0Mhz     
    	//ChangeMPllValue(82,1,1);     //FCLK=180.0Mhz     
        //ChangeMPllValue(161,3,1);    //FCLK=202.8Mhz 
        //ChangeMPllValue(117,1,1);    //FCLK=250.0Mhz 
        //ChangeMPllValue(122,1,1);    //FCLK=260.0Mhz 
        //ChangeMPllValue(125,1,1);    //FCLK=266.0Mhz 
        //ChangeMPllValue(127,1,1);    //FCLK=270.0Mhz  
        
        //MMU_EnableICache();
        //MMU_EnableDCache();
        
        MMU_DisableICache();
        MMU_DisableDCache();
    
    //设置GPIO的模式,GPIOB全部引脚
        rGPBCON = 0x155555;
       
    //设置数据0110   
       	data = 0x06;
       	while(1)
       	{
    //数据左移五位,011000000,2,3为暗
       		rGPBDAT = (data<<5);
       		dely(120);
       		data =~data;
    	}
       
       return 0;
    }
    

    按键驱动程序设计

    ARM中断控制系统

    展开全文
  • LED驱动我要实现三个操作:配置、开灯和关灯,所以我先要实现这几个硬件操作函数。 其实这些在我介绍IO内存时已经实现了(5th_mm_2/3rd/test.c),我只是稍作了一点修改,改了一下内存的数据类型,其实没什么大...

    一、实现硬件操作函数


    一般的,我写驱动的时候,我会先确定一些基本的硬件操作函数能够使用。LED驱动我要实现三个操作:配置、开灯和关灯,所以我先要实现这几个硬件操作函数。

    其实这些在我介绍IO内存时已经实现了(5th_mm_2/3rd/test.c),我只是稍作了一点修改,改了一下内存的数据类型,其实没什么大出入。

    /*5th_mm_4/1st/test.c*/

    1 #include

    2 #include

    3

    4 #include

    5 #include

    6

    7 unsigned long virt, phys;

    8 unsigned long gpecon, gpedat, gpeup; //其实我就改了这里的数据类型,其实都是用来存放地址

    9 unsigned long reg; //没有多大的影响。

    10 struct resource *led_resource;

    11

    12 void s3c_led_config(void) //还将函数的名字改成好听点

    13 {

    14 reg = ioread32(gpecon);

    15 reg &= ~(3 << 24);

    16 reg |= (1 << 24);

    17 iowrite32(reg, gpecon);

    18

    19 reg = ioread32(gpeup);

    20 reg &= ~(3 << 12);

    21 iowrite32(reg, gpeup);

    22 }

    23

    24 void s3c_led_on(void)

    25 {

    26 reg = ioread32(gpedat);

    27 reg &= ~(1 << 12);

    28 iowrite32(reg, gpedat);

    29 }

    30

    31 void s3c_led_off(void)

    32 {

    33 reg = ioread32(gpedat);

    34 reg |= (1 << 12);

    35 iowrite32(reg, gpedat);

    36 }

    37

    38 void init_led_device(void)

    39 {

    40 phys = 0x56000000;

    41 virt = (unsigned long)ioremap(phys, 0x0c);

    42

    43 gpecon = virt + 0x40;

    44 gpedat = virt + 0x44;

    45 gpeup = virt + 0x48;

    46 }

    47

    48 static int __init test_init(void) //模块初始化函数

    49 {

    50 init_led_device();

    51

    52 led_resource = request_mem_region(phys, 0x0c, "LED_MEM");

    53 if(NULL == led_resource){

    54 printk("request mem error!\n");

    55 return - ENOMEM;

    56 }

    57

    58 s3c_led_config();

    59 s3c_led_on();

    60 printk("hello led!\n");

    61 return 0;

    62 }

    63

    64 static void __exit test_exit(void) //模块卸载函数

    65 {

    66 if(NULL != led_resource){

    67 s3c_led_off();

    68 iounmap((void *)virt);

    69 release_mem_region(phys, 0x0c);

    70 }

    71 printk("bye\n");

    72 }

    73

    74 module_init(test_init);

    75 module_exit(test_exit);

    76

    77 MODULE_LICENSE("GPL");

    78 MODULE_AUTHOR("xoao bai");

    79 MODULE_VERSION("v0.1");

    至于验证我就不做了,效果还是一样,加载模块灯亮,卸载模块灯灭。



    二、面向对象思想——定义一个LED的结构体


    上面的函数中,一大堆的全局变量实在让人看起来不舒服。我在第三章字符设备的文中介绍过,把这些变量定义在一个结构体中,方便以后引用,如函数传参

    /*5th_mm_4/2nd/test.c*/

    7 struct _led_t{

    8 //hardware obb

    9 unsigned long virt, phys;

    10 unsigned long gpecon, gpedat, gpeup;

    11 unsigned long reg;

    12 struct resource *led_resource;

    13

    14 void (*config)(struct _led_t *); //这里把LED驱动的三个操作函数指针也放进去

    15 void (*on)(struct _led_t *);

    16 void (*off)(struct _led_t *);

    17 };

    根据上面定义的数据结构,我再修改一下1st目录的程序,就成了2nd目录中的函数。现在函数做了两步:

    1)实现硬件的基本操作。

    2)定义了一个面向对象数据类型。



    三、实现硬件设备初始化函数和注销函数


    在对硬件进程操作(配置,开灯、关灯)之前,需要先进行IO内存映射等操作,前面的函数写得很零散,这里我整理了一下:

    1)当插入模块时,需要进行一些内存映射等设备初始化操作,使用函数init_led_device

    2)当卸载模块时,需要进行一些硬件注销操作,使用函数eixt_led_device


    接下来就要封装这两个函数:

    /*5th_mm_4/3rd/test.c */

    45 int init_led_device(struct _led_t *led)

    46 {

    47 led->phys = 0x56000000; //1指定物理地址

    48

    49 led->led_resource = request_mem_region(led->phys, 0x0c, "LED_MEM");

    50 if(NULL == led->led_resource){ //2申请内存区域

    51 return - 1;

    52 }

    53

    54 led->virt = (unsigned long)ioremap(led->phys, 0x0c); //3内存映射

    55

    56 led->gpecon = led->virt + 0x40; //4指定寄存器地址

    57 led->gpedat = led->virt + 0x44;

    58 led->gpeup = led->virt + 0x48;

    59

    60 led->config = s3c_led_config; //5将操作函数也放进结构体成员

    61 led->on = s3c_led_on;

    62 led->off = s3c_led_off;

    63

    64 return 0;

    65 }

    66

    67 void exit_led_device(struct _led_t *led)

    68 {

    69 if(NULL != led->led_resource){

    70 iounmap((void *)led->virt);

    71 release_mem_region(led->phys, 0x0c);

    72 }

    73 }

    74

    75 struct _led_t my_led;

    76

    77 static int __init test_init(void) //模块初始化函数

    78 {

    79 if (-1 == init_led_device(&my_led)){ //加载模块时就调用init_led_device

    80 printk("request mem error!\n");

    81 return - ENOMEM;

    82 }

    83

    84 my_led.config(&my_led); //这里调用操作函数是多于了,我迟点会放在ioctl

    85 my_led.on(&my_led); //这里只不过加载时候灯亮一下,让我知道加载成功

    86 printk("hello led!\n");

    87 return 0;

    88 }

    89

    90 static void __exit test_exit(void) //模块卸载函数

    91 {

    92 my_led.off(&my_led);

    93 exit_led_device(&my_led); //卸载时调用exit_led_device

    94 printk("bye\n");

    95 }

    至于验证我就不做了,效果还是一样,加载模块灯亮,卸载模块灯灭。



    四、实现字符设备的申请,即模块与内核的接口


    需要实现ioctl功能,首先要这个设备需要先注册,使用字符设备注册的知识:

    字符设备注册三步曲:

    /*5th_mm_4/4th/test.c*/

    18 struct _led_t{

    19 //hardware obb

    20 unsigned long virt, phys;

    21 unsigned long gpecon, gpedat, gpeup;

    22 unsigned long reg;

    23 struct resource *led_resource;

    24

    25 void (*config)(struct _led_t *);

    26 void (*on)(struct _led_t *);

    27 void (*off)(struct _led_t *);

    28

    29 //kernel oob

    30 dev_t devno; //往结构体添加了两个成员

    31 struct cdev led_cdev;

    32 };

    。。。。。。

    90 struct _led_t my_led;

    91 struct file_operations s3c_led_fops = {

    92 //暂时还是空的

    93 };

    94

    95 static int __init led_driver__init(void) //模块初始化函数

    96 {

    97 int ret;

    98

    99 ret = init_led_device(&my_led);

    100 if (ret){

    101 P_DEBUG("request mem error!\n");

    102 ret = - ENOMEM;

    103 goto err0;

    104 }

    105

    106 ret = alloc_chrdev_region(&my_led.devno, 0, 1, "s3c_led_driver"); //1申请cdev

    107 if (ret){

    108 P_DEBUG("alloc chrdev failed!\n");

    109 goto err1;

    110 }

    111 P_DEBUG("major[%d], minor[%d]\n", MAJOR(my_led.devno), MINOR(my_led.devno));

    112

    113 cdev_init(&my_led.led_cdev, &s3c_led_fops); //2初始化cdev

    114

    115 ret = cdev_add(&my_led.led_cdev, my_led.devno, 1); //3添加cdev

    116 if (ret){

    117 P_DEBUG("cdev_add failed!\n");

    118 goto err2;

    119 }

    120

    121 my_led.config(&my_led);

    122 my_led.on(&my_led);

    123 P_DEBUG("hello led!\n");

    124 return 0;

    125

    126 err2:

    127 unregister_chrdev_region(my_led.devno, 1);

    128 err1:

    129 exit_led_device(&my_led);

    130 err0:

    131 return ret;

    132 }

    133

    134 static void __exit led_driver__exit(void) //模块卸载函数

    135 {

    136 my_led.off(&my_led);

    137

    138 unregister_chrdev_region(my_led.devno, 1); //卸载是注销cdev结构

    139 exit_led_device(&my_led);

    140 P_DEBUG("bye\n");

    141 }


    这里就可以验证一下了:

    [root: 4th]# insmod test.ko

    [led_driver__init]major[253], minor[0] //申请成功的设备号

    [led_driver__init]hello led!

    [root: 4th]# rmmod test

    [led_driver__exit]bye

    既然设备申请成功,接下来就是要实现系统调用接口了。



    五、实现系统调用对应的函数ioctl


    在这里,我需要实现的内容是,在应用层使用ioctl系统调用,可以操作LED配置、打开和关闭。接下来实现文件操作结构体中的ioctl

    1首先要定义命令:

    /*5th_mm_4/5th/led_ioctl.h*/

    1 #ifndef _LED_H

    2 #define _LED_H

    3

    4 #define LED_MAGIC 'x'

    5 #define LED_CONF _IO(LED_MAGIC, 0)

    6 #define LED_ON _IO(LED_MAGIC, 1)

    7 #define LED_OFF _IO(LED_MAGIC, 2)

    8

    9 #endif /* _LED_H */

    2接着实现文件操作结构体中的ioctl

    /*5th_mm_4/5th/led_driver.c */ //这里我把文件的名字改了

    92 int s3c_led_ioctl(struct inode *node, struct file *filp, unsigned int cmd, unsign ed long args)

    93 {

    94 int ret;

    95 struct _led_t *dev = container_of(node->i_cdev, struct _led_t, led_cdev);

    96 switch(cmd){

    97 case LED_CONF:

    98 dev->config(dev);

    99 break;

    100 case LED_ON:

    101 dev->on(dev);

    102 break;

    103 case LED_OFF:

    104 dev->off(dev);

    105 break;

    106 default:

    107 P_DEBUG("unknow cmd!\n");

    108 ret = - EINVAL;

    109 goto err0;

    110 }

    111 return 0;

    112

    113 err0:

    114 return ret;

    115 }

    116

    117 struct _led_t my_led;

    118 struct file_operations s3c_led_fops = {

    119 .ioctl = s3c_led_ioctl, //一定要加上。打开和关闭操作我不实现,使用默认的

    120 };

    3接着实现应用层函数:

    1 #include

    2 #include

    3 #include

    4 #include

    5 #include

    6 #include

    7

    8 #include "led_ioctl.h"

    9

    10 int main(int argc, char *argv[])

    11 {

    12 int fd;

    13 fd = open("/dev/led_driver", O_RDWR);

    14 if(fd < 0){

    15 perror("open");

    16 return -1;

    17 }

    18

    19 ioctl(fd, LED_CONF);

    20

    21 if(!strncasecmp("on", argv[1], 3))

    22 ioctl(fd, LED_ON);

    23

    24 if(!strncasecmp("off", argv[1], 3))

    25 ioctl(fd, LED_OFF);

    26

    27

    28 return 0;

    29 }

    验证一下:

    [root: 5th]# insmod led_driver.ko

    [led_driver__init]major[253], minor[0]

    [led_driver__init]hello led!

    [root: 5th]# mknod /dev/led_driver c 253 0

    [root: 5th]# ./app on //亮灯

    [root: 5th]# ./app off //灭灯

    [root: 5th]# rmmod led_driver

    [led_driver__exit]bye


    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


    六、使用信号量


    其实在单处理器非抢占内核下,是没有必要使用到内核同步机制的,这里使用信号量来限制只能同时一个进程打开并操作led设备文件。实现的方法就是在打开的时候使用信号量:

    /*5th_mm_4/6th/led_driver.c*/

    20 struct _led_t{

    21 //hardware obb

    22 unsigned long virt, phys;

    23 unsigned long gpecon, gpedat, gpeup;

    24 unsigned long reg;

    25 struct resource *led_resource;

    26

    27 void (*config)(struct _led_t *);

    28 void (*on)(struct _led_t *);

    29 void (*off)(struct _led_t *);

    30

    31 //kernel oob

    32 dev_t devno;

    33 struct cdev led_cdev;

    34 struct semaphore led_sem; //非抢占下,其实单纯使用一个标志flag来实现也行,

    35 }; //文件打开减一,关闭加一,flag不为零时可打开。

    。。。。。。。。

    63 int init_led_device(struct _led_t *led)

    64 {

    65 led->phys = 0x56000000;

    66

    67 led->led_resource = request_mem_region(led->phys, 0x0c, "LED_MEM");

    68 if(NULL == led->led_resource){

    69 return - 1;

    70 }

    71

    72 led->virt = (unsigned long)ioremap(led->phys, 0x0c);

    73

    74 led->gpecon = led->virt + 0x40;

    75 led->gpedat = led->virt + 0x44;

    76 led->gpeup = led->virt + 0x48;

    77

    78 led->config = s3c_led_config;

    79 led->on = s3c_led_on;

    80 led->off = s3c_led_off;

    81

    82 sema_init(&led->led_sem, 1);

    83

    84 return 0;

    85 }

    。。。。。。。

    120 int s3c_led_open (struct inode *node, struct file *filp)

    121 {

    122 struct _led_t *dev = container_of(node->i_cdev, struct _led_t, led_cdev);

    123 filp->private_data = dev;

    124

    125 if (down_trylock(&dev->led_sem)){ //获得锁

    126 P_DEBUG("led busy!\n");

    127 return - EBUSY;

    128 }

    129

    130 return 0;

    131 }

    132

    133 int s3c_led_release (struct inode *node, struct file *filp)

    134 {

    135 struct _led_t *dev = filp->private_data;

    136 up(&dev->led_sem); //释放锁

    137 return 0;

    138 }

    139

    140

    141 struct _led_t my_led;

    142 struct file_operations s3c_led_fops = {

    143 .ioctl = s3c_led_ioctl,

    144 .open = s3c_led_open,

    145 .release = s3c_led_release,

    146 };

    为了验证,修改一下应用程序,使程序陷入死循环不退出:

    /*5th_mm_4/6th/app.c*/

    2 #include

    3 #include

    4 #include

    5 #include

    6 #include

    7

    8 #include "led_ioctl.h"

    9

    10 int main(int argc, char *argv[])

    11 {

    12 int fd;

    13 fd = open("/dev/led_driver", O_RDWR);

    14 if(fd < 0){

    15 perror("open");

    16 return -1;

    17 }

    18

    19 ioctl(fd, LED_CONF);

    20

    21 if(!strncasecmp("on", argv[1], 3))

    22 ioctl(fd, LED_ON);

    23

    24 if(!strncasecmp("off", argv[1], 3))

    25 ioctl(fd, LED_OFF);

    26

    27 while(1)

    28 {

    29 ;

    30 }

    31

    32 close(fd);

    33 return 0;

    34 }

    也来验证一下:

    [root: 6th]# insmod led_driver.ko

    [led_driver__init]major[253], minor[0]

    [led_driver__init]hello led!

    [root: 6th]# mknod /dev/led_driver c 253 0

    [root: 6th]# ./app on & //后台开灯

    [root: 6th]# ./app off //在灭灯

    [s3c_led_open]led busy! //灭灯进程无法打开设备文件,返回错误

    open: Device or resource busy

    [root: 6th]# rmmod led_driver

    [led_driver__exit]bye


    这样,一个简单的LED驱动就实现了,大家也可以尝试将my_led结构体通过kmalloc来申请,我只是觉得这个结构体占用的空间不多,就把这个步骤免了。



    七、总结


    上面的驱动我是按以下顺序写的:

    1)实现硬件操作config,on.off

    2)定义面向对象数据结构

    3)定义硬件初始化操作

    4)实现字符设备注册

    5)实现ioctl等字符设备操作

    6)实现信号量限制打开文件个数


    上面介绍了我写驱动函数的步骤,其实最先的步骤应该是定义面向对象的数据结构,在开始实现其他的函数操作,只不过我之前已经将部分的硬件操作函数写好了,所以就稍稍改了前三步的步骤。接下来总结一下:

    顺序不是一成不变的,但无论怎么写,也要按照从底层到上层,逐个逐个往上封装。

    当然,这个驱动只是我结合了之前学的知识写的,内核中的驱动不可能这么简单,

    展开全文
  • 九、编写led驱动

    2019-08-07 19:02:13
    led.c 1 #include <linux/init.h> 2 #include <linux/module.h> 3 #include <linux/cdev.h> 4 #include <linux/fs.h> 5 #include <linux/io.h> 6 7 #define GP...

    led.c

     1 #include <linux/init.h>
     2 #include <linux/module.h>
     3 #include <linux/cdev.h>
     4 #include <linux/fs.h>
     5 #include <linux/io.h>
     6 
     7 #define GPMCON    0x7F008820
     8 #define GPMDAT    0x7F008824
     9 
    10 static int * __gp_gpmdat;
    11 
    12 static int led_open (struct inode *p_inode, struct file *p_file)
    13 {
    14     int *p_gpmcon = NULL;
    15 
    16     p_gpmcon = ioremap(GPMCON, 4);
    17     writel(0x1111, p_gpmcon);
    18 
    19     __gp_gpmdat = ioremap(GPMDAT, 4);
    20 
    21     return 0;
    22 }
    23 
    24 static long led_ioctl (struct file *p_file, unsigned int cmd, unsigned long arg)
    25 {
    26     switch (cmd) {
    27     case 0:
    28         writel(0x0, __gp_gpmdat);
    29         break;
    30     
    31     case 1:
    32         writel(0xF, __gp_gpmdat);
    33         break;
    34 
    35     default:
    36         return -1;
    37     }
    38     return 0;
    39 }
    40 
    41 static struct cdev led_dev;
    42 static struct file_operations fops = {
    43     .open = led_open,
    44     .unlocked_ioctl = led_ioctl,
    45 };
    46 dev_t devno;
    47 
    48 static __init int led_init (void)
    49 {
    50     cdev_init(&led_dev, &fops);
    51     alloc_chrdev_region(&devno, 0, 1, "myled");
    52     cdev_add(&led_dev, devno, 1);
    53 
    54     return 0;
    55 }
    56 
    57 static __exit void led_exit (void)
    58 {
    59     cdev_del(&led_dev);
    60     unregister_chrdev_region(devno, 1);
    61 }
    62 
    63 module_init(led_init);
    64 module_exit(led_exit);
    65 
    66 MODULE_LICENSE("GPL");

    led_app.c

     1 #include <unistd.h>
     2 #include <sys/ioctl.h>
     3 #include <stdio.h>
     4 #include <sys/types.h>
     5 #include <sys/stat.h>
     6 #include <fcntl.h>
     7 
     8 int main(int argc, const char *argv[])
     9 {
    10     int fd, cmd;
    11 
    12     if (argc != 2) {
    13         printf(".example: ./led_app 0\n");
    14         return;
    15     }
    16 
    17     cmd = atoi(argv[1]);
    18 
    19     fd = open("/dev/myled", O_RDWR);
    20 
    21     ioctl(fd, cmd);
    22     
    23     return 0;
    24 }

    Makefile

     1 obj-m := led.o
     2 KDIR = /home/linux/zkf/6410/urbetter-linux2.6.28-v1.0/
     3 
     4 all:
     5     make -C $(KDIR) $(objs) M=$(PWD) modules CROSS_COMPILE=arm-none-linux-gnueabi- ARCH=arm
     6     arm-none-linux-gnueabi-gcc led_app.c -o led_app
     7     sudo cp led.ko ~/zkf/6410/rootfs/home/test
     8     sudo cp led_app ~/zkf/6410/rootfs/home/test
     9 clean:
    10     rm *.o *.symvers *.mod.c *.order

      make之后会生成led.ko和led_app两个要用到的文件,在Makefile中已经将他们复制到了开发板挂载目录中。在开发板终端中输入命令:insmod led.ko 之后输入命令:cat /proc/devices 可以看到myled主设备号为251

      输入命令:mknod /dev/myled c 251 0

      之后便能执行应用程序led_app了,执行 ./led_app 0 则点亮所有LED,执行 ./led_app 1 则熄灭所有LED。

      

    转载于:https://www.cnblogs.com/Suzkfly/p/10317562.html

    展开全文
  • led 驱动

    2019-04-23 18:18:26
    通过ioctrl 来将应用程序的命令传递到驱动中的 struct file_operation 中的 unlocked_ioctl 方法中,判断命令进行相应的操作。 在通用的头文件中定义ioctrl的命令 #define LED_ON _IO('l',1) #define LED_OFF _IO('...

    1. 程序思路:

    通过ioctrl 来将应用程序的命令传递到驱动中的 struct file_operation 中的 unlocked_ioctl 方法中,判断命令进行相应的操作。
    在通用的头文件中定义ioctrl的命令

    #define LED_ON 	_IO('l',1)
    #define LED_OFF _IO('l',2)
    

    我们想在应用程序中这样来操作led

    int main(int argc, const char *argv[])
    {
    	int fd = open("/dev/led", O_RDWR); // 打开设备节点
    	if(fd<0) {
    		perror("open");
    		return -1;
    	}
    	puts("app open end");
    
    	while(1) {
    		ioctl(fd, LED_ON); // 打开灯
    		sleep(2);
    		ioctl(fd, LED_OFF); // 关闭灯
    		sleep(2);
    	}
    
    	close(fd);
    	puts("app close end");
    	return 0;
    }
    

    那驱动中我们就要实现字符设备的 struct file_operation的 unlocked_ioctl 方法

    static long led_ioctl (struct file *filep, unsigned int cmd, unsigned long argv)
    {
    	switch(cmd)
    	{
    		case LED_ON:
    			printk("LED_ON\n");
    			led_on();
    			break;
    		case LED_OFF:
    			printk("LED_OFF\n");
    			led_off();
    			break;
    		default:
    			return -EINVAL;
    	}
    	return 0;
    }
    
    struct file_operations led_fops = {
    	.owner=THIS_MODULE,
    	.open = led_open,
    	.release =led_release,
    	.unlocked_ioctl = led_ioctl,
    };
    

    当然,对于要操作硬件IO,需要将IO寄存器ioremap地址空间映射到内核空间上来。。
    在4412开发板上的实现的led可以控制的驱动代码如下:
    驱动: fs4412_led.c

    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/fs.h>
    #include <linux/cdev.h>
    #include "fs4412_led.h"
    #include <asm/io.h>
    
    #define LED_MA 250
    #define LED_MI 0
    
    #define GPX2CON 0x11000c40
    #define GPX2DAT 0x11000c44
    
    MODULE_LICENSE("GPL");
    
    static unsigned int * gpx2con =NULL;
    static unsigned int * gpx2dat =NULL;
    
    struct cdev cdev;
    
    dev_t devno=MKDEV(LED_MA, LED_MI);
    
    
    static void led_on(void)
    {
    	writel(readl(gpx2dat) |(0x1<<7),gpx2dat); 
    	return ;
    }
    static void led_off(void)
    {
    	writel(readl(gpx2dat) & (~(0x1<<7)) ,gpx2dat); 
    	return ;
    }
    static	int led_open (struct inode * inodep, struct file *filep)
    {
    	printk("led_open\n");
    	return 0;
    }
    
    static int led_release (struct inode *inodep, struct file *filep)
    {
    	printk("led_release\n");
    	return 0;
    
    }
    
    static long led_ioctl (struct file *filep, unsigned int cmd, unsigned long argv)
    {
    	switch(cmd)
    	{
    		case LED_ON:
    			printk("LED_ON\n");
    			led_on();
    			break;
    		case LED_OFF:
    			printk("LED_OFF\n");
    			led_off();
    			break;
    		default:
    			return -EINVAL;
    	}
    	return 0;
    }
    
    struct file_operations led_fops = {
    	.owner=THIS_MODULE,
    	.open = led_open,
    	.release =led_release,
    	.unlocked_ioctl = led_ioctl,
    };
    
    static int led_init(void)
    {
    	unsigned int ret = 0;
    	printk("led_init start \n");
    	
    	ret = register_chrdev_region(devno, 1, "fs4412_led_device");
    	if(ret<0)
    	{
    		printk("register_chrdev_region error\n");
    		return ret;
    	}
    
    	cdev.owner = THIS_MODULE;
    	cdev_init(&cdev, &led_fops);
    	ret = cdev_add(&cdev, devno, 1);
    	if(ret < 0)
    	{
    		printk("cdev_add error\n");
    		goto err1;
    	}
    
    	gpx2con = ioremap(GPX2CON, 4);
    	if(NULL == gpx2con)
    	{
    		printk("ioremap(GPX2CON) error\n");
    		goto err2;
    	}
    
    	gpx2dat = ioremap(GPX2DAT, 4);
    	if(NULL == gpx2dat)
    	{
    		printk("ioremap(GPX2DAT) error\n");
    		goto err3;
    	}
    
    	writel((readl(gpx2con) & (~(0xf<<28))) | (0x1<<28) ,gpx2con); 
    	writel(readl(gpx2dat) & (~(0x1<<7)) ,gpx2dat); 
    
    	printk("led_init end \n");
    	return 0;
    
    err3:
    	iounmap(gpx2con);
    err2:
    	cdev_del(&cdev);
    err1:
    	 unregister_chrdev_region(devno,1);
    	
    	 return ret;
    	
    }
    static void led_exit(void)
    {
    	printk("led_exit start \n");
    	
    	iounmap(gpx2dat);
    	iounmap(gpx2con);
    
    	cdev_del(&cdev);
    	unregister_chrdev_region(devno,1);
    	printk("led_exit end \n");
    	return ;
    }
    module_init(led_init);
    module_exit(led_exit);
    

    头文件:fs4412_led.h

    #ifndef __FS4412_LED_H__
    #define __FS4412_LED_H__
    
    #define LED_ON 	_IO('l',1)
    #define LED_OFF _IO('l',2)
    
    #endif
    

    Makefile 文件

    $(warning KERNELRELEASE=$(KERNELRELEASE))
    ifeq ($(KERNELRELEASE),)
    
    KERNELDIR ?= /home/qin/linux-3.14-fs4412/
    
    #KERNELDIR ?= /lib/modules/$(shell uname -r)/build  
    PWD := $(shell pwd)
    
    modules:
    	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
    	arm-linux-gcc led_test.c -o led_test.out 
    	cp fs4412_led.ko  led_test.out /source/rootfs/
    
    clean:
    	rm -rf *.out *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module* modules*
    
    .PHONY: modules modules_install clean
    
    else
        obj-m := fs4412_led.o
    endif
    
    
    

    应用层测试用的代码: led_test.c

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>
    #include "fs4412_led.h"
    
    int main(int argc, const char *argv[])
    {
    	int fd = open("/dev/led", O_RDWR); // 打开设备节点
    	if(fd<0) {
    		perror("open");
    		return -1;
    	}
    	puts("app open end");
    
    	while(1) {
    		ioctl(fd, LED_ON); // 打开灯
    		sleep(2);
    		ioctl(fd, LED_OFF); // 关闭灯
    		sleep(2);
    	}
    
    	close(fd);
    	puts("app close end");
    	return 0;
    }
    

    2. 可能出现的问题:

    [root@lip ~]# rmmod
    rmmod: can’t change directory to ‘/lib/modules’: No such file or directory
    [root@lip ~]# mkdir /lib/modules
    [root@lip ~]# rmmod led
    rmmod: can’t change directory to ‘3.4.112’: No such file or directory
    [root@lip ~]# mkdir /lib/modules/3.4.112
    [root@lip ~]# rmmod led
    led_exit is load

    这个问题是删除模块提示 can’t change directory to ‘/lib/modules’: No such file or directory 错误,解决的办法就是 提示不能 改变到 /lib/modules ,是因为没有这个文件夹,我们新建这个文件夹,又提示没有 3.4.112 这个文件夹,我们继续新建这个文件夹,解决。

    3. 用到platform总线的 led 驱动:

    根据platform的结构,将设备的资源单独放到设备中,在设备中
    在模块的入口函数中注册一个platform的设备
    在这里插入图片描述
    在驱动侧注册驱动结构体
    在这里插入图片描述
    其中的 platform_driver.driver.name 的名字 跟 platform_device.name 做比对。probe方法中实现

    1. io 资源的映射
    2. 注册字符设备,创建设备节点

    remove方法中进行反操作

    1. 设备节点注销
    2. 类注销
    3. 字符设备注销

    在这里插入图片描述在这里插入图片描述

    展开全文
  • 由于linux内核支持LED驱动框架并且有通用的LED驱动,因此这里只需按照驱动要求添加设备树节点就可以了,不用我们自己重写LED驱动。这一节先在设备树中添加一个LED节点,重新编译设备树测试效果,然后对内核中drivers...
  • LED驱动电源是把交流供电或者其它直流电源转换为LED灯具可用的恒压或恒流的特定电源,LED驱动电源是LED照明灯具的核心组件之一,其性能和可靠性直接决定了LED照明灯具的使用效果和寿命。为了能够更好地应用在LED照明...
  • linux 下的led驱动

    2018-04-06 12:56:43
    已经入门单片机的初学者都知道,led驱动是最简单的驱动之一,单片机入门资料经常以流水灯或跑马灯的例子来展示单片机的使用方法。下面以飞思卡尔16位单片机MC9S12XS128为例,让我们来看一下单片机是怎么实现对led...
  • 上一节我们写出了简单的可以操控硬件的单个led驱动。 本节我们主要给出利用多个次设备号,来实现多个led驱动的注册。 同时来使用下gpiolib库,来使用一些专用于gpio的操作。   下面是主要代码片段。 其作用是...
  • Linux驱动入门(三)Led驱动 Linux驱动入门(四)轮询实现按键驱动 Linux驱动入门(五)中断实现按键驱动 Linux驱动入门(六)poll机制实现按键驱动 Linux驱动入门(七)使用定时器防按键抖动 Linux驱动入门(三)...
  • 一、LED驱动 1、对led驱动的测试 对于向led这样的设备模型,系统认为所有的设备都是挂接在总线上的,而要使设备工作,就需要相应的驱动。设备模型会产生一个虚拟的文件系统——sysfs,它给用户提供了一个从用户空间...
  • 本来打算写一下NAND驱动和网卡驱动及USB驱动的,突然发现好长时间不写驱动,写驱动的套路都忘的差不多了,而且以前写的驱动程序都不够模块化,想复用的话还需要做些修改,所以,还是先写一下LED驱动,熟悉一下套路,...
  • 内核自带LED驱动移植

    2017-04-26 19:14:26
    在fl2440的内核中,本身已经有了LED驱动,我们要根据自己的需求将它使能即可,重要的是如何找到需要修改的位置,如何修改。在前面分析过我们自己写的驱动代码,内核中自带的驱动原理也大概相似,首先在make ...
  • 本文的led驱动是基于tiny6410的四个led驱动,用字符设备的驱动模块,而不是混杂设备驱动模块来编写,本人在使用混杂设备方法编写的时候led灯第二个始终无法实现控制开和关现在还在纠结中。 一下图片是开发板手册...
  • LED驱动电源EMI整改方案 2 LED驱动电源EMI整改方案(2012-4-30 21:36)   1MHZ以内----以差模干扰为主   1.增大X电容量;   2.添加差模电感;   3.小功率电源可采用PI型滤波器处理(建议靠近变压器的...
  • LED驱动—LP55231

    2018-07-16 22:21:00
    LED驱动,严格来说需要恒流源控制,通过调节电流大小来调整LED亮度。一般情况下会用模拟器件搭建,但,精度、准确度、稳定性等方面有所欠缺。以目前集成电路的技术,首要考虑会是集成芯片,推荐一款本人在项目中使用...
  • 1、网上很多的LED驱动几乎都是2.6的内核版本,但是3.0内核和2.6的内核驱动编写有很多地方是不同的在2.6上能运行的设备驱动不一定能在3.0内核上运行。这对于刚刚踏入驱动大门人,急于想了解LED驱动是什么样的,他是...
  • TPS61042是一个高度集成的带PWM亮度调节的恒流LED驱动IC,设计者利用此IC可简单高效的设计出稳定的4颗、6颗、8颗LED恒流驱动电路。 仅有0.1uA关断电流,38uA静态电流,非常适合低电压、电池供电等低功耗类应用。 ...
  • 本文基于华清4412开发板,讲解如何从零开始编写led驱动程序和测试程序。首先介绍一下该4412开发板的led硬件原理图。从原理图上我们可以看出,让led点亮的条件是往对应端口送高电平,熄灭的条件是送低电平。从上面这...
  • 1、市场褒贬不一的LED驱动IC-AMC7150 在当时AMC7150还是不错的,我想了想还是提提,它有个很重要的因数就是价格,有不到2元的市场价格,是你采用它的理由。AMC7150目前有几十家可以直接替换的IC型号,价格战会无法...
1 2 3 4 5 ... 20
收藏数 38,881
精华内容 15,552
关键字:

led驱动