LED灯驱动编写全过程

 led驱动实验步骤:

准备工作(Led驱动):
1    准备测试的工具
2    准备相关字符设备驱动的知识
3    准备相关驱动(LED)文件
4    准备相关的硬件知识,获取硬件开发人员提供的LED接口。


driver/char
ps
led_player 701
kill 701
./ledtest 0 0
./ledtest 0 1
./ledtest 0 2
./ledtest 0 3
./ledtest 1 0
./ledtest 1 1
./ledtest 1 2
./ledtest 1 3

./dxctest 0 0
./dxctest 0 1

led0~led3, GPB5~GPB8


LED开发驱动的步骤:
1     开发myled.c文件存放在虚拟机中的linux-2.6-32.2/drivers/char下
2     在char目录下,修改Makefile,把我的源代码加入我们的编译里面来。
3     在char目录下,修改Kconfig,首先定义为内核模块准备调试驱动
4.1   make menuconfig( 要先在Linux-2.6-32.2中 cp config_mini2440_n35 .config)
4.2   重新编译内核make zImage, 生成zImage文件(注意:要先配好arm-linux-gcc的环境变量-> exprot PATH=$PATH:/usr/local/arm/4.3.2/bin)。
5     在超级终端和dwn软件中,下载zImage开发板
6.1    make modules,产生myled.ko的内核模块。
6.2   通过超级终端,用rz命令下载myled.ko文件到开发板。
7      insmod myled.ko(在超级终端)加载内核模块
8      more /proc/devices查看我们驱动是不是被系统认识
9      如果系统认识驱动,会看到主设备号(默认253),敲“空格”向下移动,就可以看到,记录下来
10    cd /dev
11    mknod myled c 253 0  (c为字符设备,253是主设备号,0是 次设备号)
12    ls led
13    cd /
14    ps
15    kill 701
      rz(从电脑传输驱动测试文件testled到开发板)
      chmod 777 testled
 16   ./testled 0 0(0 0可以是0,1的任何组合)


(12  make menuconfig,把M改为*,make zImage)

写代码:
1     内核模块的要素完成
2     初始化函数,确认主设备号,次设备号。
3     初始化函数,分配内存
4     初始化函数,安装cdev
5     实现file操作函数

obj-$(CONFIG_MYLED_MINI2440) += myled.o

int main()
   fp = open("/dev/dfsgdsg", 0)
   ioctl(fp, atoi(argv[1]), atoi(argv[2]));
return;

arm-linux-gcc 54te.c -o dxctest

 

具体操作:

1   做测试工具arm-linux-gcc编译   ---testled
      open,close,ioctl
2   把内核模块的代码拷贝过来,做一定的修改。
3   初始化函数增加主次设备号申请的代码
    led_major,led_minor,dev
4   初始化函数增加申请内存空间的代码
    (cdev *)led_device
5   初始化函数增加字符设备初始化代码
    cdev_init  cdev_add
    led_device  led_fops
6   exit函数代码完成
7   增加led_fops定义
8   实现led_fops所定义的函数接口
    open,release,ioctl
9   拷贝所有.h文件
10  修改Makefile
    CONFIG_XXX   myled.o
11  修改Kconfig
    config XXX
12  make menuconfig 选中我们的配置项为M
13  make zImage       ---zImage
14  make modules      ---myled.ko
15  开发板环境完成(dnw里USB OK)
16  下载zImage
    more /proc/version检查一下
17  通过rz命令下载testled,myled.ko
18  chmod 777 testled
19  ps查看led-player进程号(701)
20  kill 701杀死进程(灯停住不动,状态固定)
21  insmod ./myled.ko
22  more /proc/devices确认主设备号(253)
23  cd /dev
    mknod (myled 测试工具) c 主 次
24  ./testled 0 0(0,1  1,0 1,1)
    现象:单独控制

 

led驱动代码:(myled_driver.c)

#include <linux/module.h>
#include <linux/autoconf.h>
#include <linux/init.h>
#include <linux/kernel.h>            /* printk() */
#include <linux/slab.h>             /* kmalloc() */
#include <linux/fs.h>             /* everything... */
#include <linux/errno.h>            /* error codes */
#include <linux/types.h>            /* size_t */
#include <linux/fcntl.h>            /* O_ACCMODE */
#include <linux/cdev.h>                    /* cdev...*/
#include <asm/io.h>                        /* writel(),readl()... */
#include <asm/system.h>             /* cli(), *_flags */
#include <asm/uaccess.h>            /* copy_*_user */
#include <linux/wait.h>                    /* wake_up_interruptible()... */
#include <linux/delay.h>                   /* udelay() */
#include <linux/miscdevice.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/mm.h>
#include <linux/moduleparam.h>
#include <linux/ioctl.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/gpio.h>
#include <asm/atomic.h>
#include <asm/unistd.h>

#define DEVICE_NAME   "myled"  //宏定义设备名称

static int led_major =   0;  //初始化主设备号
static int led_minor =   0;  //初始化次设备号
struct cdev  *led_device;  //定义cdev结构体指针

//下面的两个数组是处理器相关的信息
static unsigned long led_table [] = {
 S3C2410_GPB(5),
 S3C2410_GPB(6),
 S3C2410_GPB(7),
 S3C2410_GPB(8),
};
static unsigned int led_cfg_table [] = {
 S3C2410_GPIO_OUTPUT,
 S3C2410_GPIO_OUTPUT,
 S3C2410_GPIO_OUTPUT,
 S3C2410_GPIO_OUTPUT,
};

//设备打开函数
static int myled_open(struct inode *inode, struct file *filp)
{
    int i;
   
 for (i = 0; i < 4; i++) {
  s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);
  s3c2410_gpio_setpin(led_table[i], 0);
 }

 return 0;
}
//设备关闭函数
static int myled_release(struct inode *inode, struct file *filp)
{
 return 0;
}
//设备操作函数
static int myled_ioctl (struct inode *inode, struct file *filp,
  unsigned int cmd, unsigned long arg)
{
 switch(cmd) {
 case 0:
 case 1:
  if (arg > 4) {
   return -EINVAL;
  }
  s3c2410_gpio_setpin(led_table[arg], !cmd);
  
  return 0;
 default:
  return -EINVAL;
 }
}

struct file_operations led_fops =    //字符驱动和内核的接口:file_operations结构体
{                                    //字符驱动只要实现一个file_operations结构体,并注册到内核中,内核就有了操作此设备的能力。
 .owner =    THIS_MODULE,       //指向模块自身。
 .open =     myled_open,       //打开设备
 .release =  myled_release,    //关闭设备
 .ioctl = myled_ioctl,        //操作设备
};

static void __exit my_led_exit(void)    //模块结束函数
{
 //MKDEV是因为要重新通过主次设备号合成一个设备号,后面注销时用,
 //以前在模块入口函数里的设备号已经不能用了,函数不同了,而led_major, led_minor是全局变量
 dev_t devno = MKDEV(led_major, led_minor); //通过主次设备号获得设备号

 if (led_device){
  /* Get rid of our char dev entries */ 
  cdev_del(led_device); //删除设备

  kfree(led_device);  //释放内存
  led_device = NULL;
 }

 /* cleanup_module is never called if registering failed */
 unregister_chrdev_region(devno, 1);    //取消注册设备号
    return;
}

static int __init my_led_init(void)  //模块入口函数
{
 int result = 0;
 dev_t dev = 0;   //初始化设备号

 result = alloc_chrdev_region(&dev, led_minor, 1, DEVICE_NAME);/*自动分配设备号
      参数分别是获取的设备号(输出参数),第一个次设备号,次设备号数量,设备名称 */
 led_major = MAJOR(dev);  //通过设备号提取主设备号
 if (result < 0) {
  printk(KERN_WARNING "wfet_kb: can't get major %d\n", led_major);
  return result;
 } 
 
 led_device = kmalloc(sizeof(struct cdev), GFP_KERNEL);  //为设备分配内存
 if (!led_device) {
  result = -ENOMEM;
        unregister_chrdev_region(dev, 1);
  return result;
 }
 memset(led_device, 0, sizeof(struct cdev)); //清空内存
 
 cdev_init(led_device, &led_fops);  //字符设备初始化函数:把为设备分配的内存与操作设备的结构相关联
 led_device->owner = THIS_MODULE;
 result = cdev_add (led_device, dev, 1);  //设备增加
 if (result) {
  printk(KERN_NOTICE "Error %d adding LED device, major_%d", result, MAJOR(dev));
  kfree(led_device);
        unregister_chrdev_region(dev, 1);
  return result;
 }
 
    return 0;
}


module_init(my_led_init);  //模块入口函数
module_exit(my_led_exit);  //模块出口函数

MODULE_LICENSE("GPL");

 

测试的应用程序(testled.c):

#include<stdio.h>
int main(int argc,char *argv[])
{
 int fp;
 if(argc<2)
 {
  printf("argc error\n");
  return 0;
 }
 fp=open("/dev/myled",0);
 if(fp<0)
 {
  printf("Open error\n");
  return 0;
 }
 printf("test:%d\n",atoi(argv[1]));
 if(atoi(argv[1])<8)
 {
  ioctl(fp,(atoi(argv[1])-atoi(argv[1])/2),(atoi(argv[1])/2));
 }
 if(atoi(argv[1])==8)
 {
   ioctl(fp,0,0);
                 ioctl(fp,0,1);
                 ioctl(fp,0,2);
                 ioctl(fp,0,3);

 }
 if(atoi(argv[1])==9)
 {
                 ioctl(fp,1,0);
                 ioctl(fp,1,1);
                 ioctl(fp,1,2);
                 ioctl(fp,1,3);
 }
 if(atoi(argv[1])==10)
 {
                 ioctl(fp,0,0);
                 ioctl(fp,0,1);
 }
        if(atoi(argv[1])==11)
        {
                 ioctl(fp,1,0);
                 ioctl(fp,1,1);
        }
        if(atoi(argv[1])==12)
        {
                 ioctl(fp,0,2);
                 ioctl(fp,0,3);
        }
        if(atoi(argv[1])==13)
        {
                 ioctl(fp,1,2);
                 ioctl(fp,1,3);
        }
 
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值