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

本文介绍了一种在Linux环境下开发流水灯驱动的方法,包括字符设备驱动编写、驱动加载及应用程序测试等步骤。提供了详细的代码示例及加载流程。

流水灯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文件夹下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值