您的位置:首页 > 运维架构 > Linux

基于Gpio的Linux字符型驱动设计--…

2014-01-26 16:01 218 查看
流水灯Linux驱动步骤

第一步:编写字符设备驱动

第二步:加载

第三步:编写应用程序测试设备驱动

第一步:编写流水灯Linux驱动
 在/linux-3.2/driver/char/sep4020_char/

下面新建一个sep4020_flowled.c􀂃

内容如下:

#define KEY_MAJOR 249

#define LED_ON 1

#define LED_OFF 2

struct led_dev

{

struct cdev cdev;

unsigned char value;

};

struct led_dev *leddev;
打开和关闭操作
􀂃open和release函数会在设备打开和关闭时被调用,open的时候对设备进行初始化

static int sep4020_flowled _open(struct inode * inode, struct file
* filp)

{

     
sep4020_flowled_setup();

     
……

}

static int sep4020_flowled _release(struct inode * inode, struct
file * filp)

{

    
……

    return
0;

}

写入和读出操作

static int sep4020_flowled _write(struct file *file, const char
* buffer,size_t count, loff_t *ppos)

{

    
return 0;

}

static int sep4020_flowled _read(struct file *file, const char *
buffer,size_t count, loff_t * ppos)

{

    
return 0;

}

设备操作

int sep4020_flowled_ioctl(struct inode *inode, struct file
*filp, unsigned int cmd, unsigned long arg)

{

    struct
led_dev *dev = filp->private_data;

    unsigned int
i,j;

    switch
(cmd)

    {

     
case LED_ON:

             
j=i;

              
 if(j<6)

                
 dev->value
|=1<<j;

              
 else dev->value
>>=1;

          
 *(volatile unsigned long*)GPIO_PORTE_DATA_V =
dev->value; //flow led is open;

           
i++;

        
break;

    
case LED_OFF:

            
dev->value = 0;

          
*(volatile unsigned long*)GPIO_PORTE_DATA_V = 0; //flow led is
close;

        
break;

    
default:

    
return -ENOTTY;

   }

   return 0;

}

设备初始化

static int __init sep4020_flowled _init(void)

{

//申请设备号

      
dev_t devno = MKDEV(KEY_MAJOR, 0);

      
if(KEY_MAJOR)

      
result = register_chrdev_region(devno, 1, "sep4020_flowled");

 

      
leddev = kmalloc(sizeof(struct led_dev),GFP_KERNEL);

          
if (!leddev)

             
{

                 
result = -ENOMEM;

                  
goto fail_malloc;

             
}

   
//硬件初始化,推荐在open中实现

   
//sep4020_flowled_setup();

   
//字符设备注册

     
cdev_init(&(leddev->cdev),
&sep4020_flowled_fops);

      
leddev->cdev.owner = THIS_MODULE;

     
err = cdev_add(&leddev->cdev, devno,
1);// 创建设备文件

 return 0;

    
fail_malloc: unregister_chrdev_region(devno,1);

 return result;

}

设备注销

static void __exit sep4020_flowled_exit(void)

{

//删除设备文件

       
cdev_del(&leddev->cdev);

       
kfree(leddev);

       
unregister_chrdev_region(MKDEV(KEY_MAJOR, 0),1);//注销设备

       
unregister_chrdev(Led_Major, DEVICE_NAME);

}

module_init(sep4020_flowled _init); //向Linux系统记录设备初始化的函数名称

module_exit(sep4020_flowled_exit); //向Linux系统记录设备退出的函数名称

修改Kconfig和Makefile
􀂃

在相应的字符型驱动的目录顶部的Kconfig中添加如下语句:

config SEP4020_FLOWLED

tristate "sep4020 flowed led"

􀂃

在相同目录底下的Makefile中添加如下语句:

obj-$(CONFIG_SEP4020_FLOWLED) += sep4020_flowled.o

 

第二步:驱动程序的加载

Linux内核有2种加载驱动程序的方法:

􀂃

静态:

   
Linux系统启动时,通过代码自身加载模块.这种方式称为静态编译入内核, 驱动程序开发完毕后一般使用这种方式.

􀂃

动态:

   
Linux系统启动后,通过insmod等命令加载模块.这种方式称为动态加载,驱动程序开发调试过程中一般使用这种方式.

方法1:驱动程序以驱动模块加载
􀂃

打开终端,进入Linux根目录,输入命令make
menuconfig
􀂃

进入device drivers->character
device->sep4020 char devices->sep4020
key driver

􀂃

使用空格键将sep4020_flowed选择成M

􀂃

运行make 命令,编译通过后当前目录下就生成名为sep4020_flowled.ko的驱动程序

     模块动态加载
#insmod
sep4020_flowled.ko  􀂃驱动程序模块插入内核

#cat
/proc/devices           
查看是否载入,如果载入成功会显示你的设备名称sep4020_flowled

#rmmod
sep4020_flowled.ko    
从内核移除设备

    
动态加载在开发板端的具体操作如下:

(1)将开发板上电,并将sep4020_flowled.ko拷贝到网络文件系统/demo/目录下面

􀂃

(2)在/dev/目录下创建一个设备节点flowled

    
/dev # mknod flowled c 249 0

􀂃

(3)驱动程序模块插入内核

    
insmod sep4020_flowled.ko

􀂃

(4)#cat /proc/devices

查看是否载入,如果载入成功会显示你的设备名称sep4020_flowled

方法2:静态编译进内核
􀂃

打开终端,进入Linux根目录,输入命令make menuconfig

􀂃

进入device drivers->character
device->sep4020 char devices->sep4020
key driver

􀂃

使用空格键将sep4020_flowed选择成*

􀂃

运行make 命令,编译通过后就将流水灯驱动编译进内核了

􀂃

执行mkimage指令重新生成新的能被uboot引导的内核

静态编译开发板端的操作:

􀂃

(1)将重新编译好的内核重新拷贝至tftp目录下,重新开发板上电

􀂃

(2)在/dev/目录下创建一个设备节点flowled

# mknod /dev/flowled c 249 0

第三步:编译应用程序
#include
<stdio.h>

#define OPEN 1

#define CLOSE 2

int main(int argc,char **argv)

{

     
int fd;

    
int i,j;

    
fd = open("/dev/flowled",0);

    
if(fd == -1)

    {

    
printf("wrong\r\n");

    
exit(-1);

    
}

    for(j=0;
j<41; j++)

     
{

       
ioctl(fd,OPEN,0);

       
for(i=0; i<1000000; i++);

     
}

  close(fd);

   return 0;

 }

利用arm-linux-gcc将其编译为可执行的二进制文件:

􀂃

指令如下:arm-linux-gcc–o flowledflowled.c

􀂃

将编译好的flowled文件拷贝至nfs文件夹下
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: