LED字符设备驱动

 一、实验环境

开发机环境

          操作系统:ubuntu 10.10

          交叉编译环境:arm-linux-gcc 4.4.1,安装位置 /usr/local/arm/4.4.1/

          6410板子内核源码路径:/work/linux-2.6.36.2-v1.05/      

目标板环境:OK6410-A     linux2.6.36



二、实验原理

         控制LED是最简单的一件事情,我们学习LED驱动程序,就相当于学习其他编程语言是的“hello world”程序一样,是一个入门的程序。

         学习驱动程序,必须要对硬件有所了解,接下来看几个与硬件相关的材料。



     

                                           OK6410  LED原理图



     

                                              OK6410  LED原理图



从上面的原理图可以得知,LED与CPU引脚的连接方法如下,低电平点亮。

     LED1 -GPM0

     LED2 -GPM1

     LED3 -GPM2

     LED4 -GPM3

     

从数据手册可以找到相应的控制方法。这里我们以LED1为例,介绍一下LED1的操作方法,其他的类似,请大家自行分析。



通过上面可以得知,需要先将GPM0设置为输出方式。将相应的寄存器进行配置。
然后将GPMDAT寄存器的第0位置0灯亮,置1灯灭。



三、实验步骤

1、编写驱动程序

driver_led.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h> /* copy_to_user,copy_from_user */
#include <linux/miscdevice.h> 
#include <linux/pci.h> 
#include <mach/map.h> 
#include <mach/regs-gpio.h> 
#include <mach/gpio-bank-m.h> 
#include <plat/gpio-cfg.h>

//#define LED_MAJOR 240
#define DEVICE_NAME "ok6410_leds"
int led_open (struct inode *inode,struct file *filp)

{
        unsigned tmp;  
         tmp = readl(S3C64XX_GPMCON);  
        tmp = (tmp & ~(0x7U<<1))|(0x1U);  
         writel(tmp, S3C64XX_GPMCON);
        printk("#########open######\n");
        return 0;
}

ssize_t led_read (struct file *filp, char __user *buf, size_t count,loff_t *f_pos)
{
        printk("#########read######\n");
        return count;
}


ssize_t led_write (struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)
{
        char wbuf[10];
        unsigned tmp;  
        printk("#########write######\n");
        copy_from_user(wbuf,buf,count);
        switch(wbuf[0])
        {
                case 0:  //off
                        tmp = readl(S3C64XX_GPMDAT);  
                                  tmp |= (0x1U);  
                                  writel(tmp, S3C64XX_GPMDAT);
                        break;
                case 1:  //on
                        tmp = readl(S3C64XX_GPMDAT);  
                                  tmp &= ~(0x1U);  
                                  writel(tmp, S3C64XX_GPMDAT);
                        break;
                default :
                        break;
        }
        return count;
}

int led_release (struct inode *inode, struct file *filp)
{
        printk("#########release######\n");
        return 0;
}
struct file_operations led_fops ={
        .owner = THIS_MODULE,
        .open = led_open,
        .read = led_read,
        .write = led_write,
        .release = led_release,
};
static struct miscdevice misc = {   
    //次设备号,注意不要与/proc/misc中已有杂项设备次设备号冲突   
    //MISC_DYNAMIC_MINOR来动态获取次设备号   
    .minor = MISC_DYNAMIC_MINOR,   
    //设备名称   
    .name = DEVICE_NAME,   
    .fops = &led_fops,   
};

 


int __init led_init (void)
{        int rc;
        printk ("Test led dev\n");
        rc=misc_register(&misc);
        if (rc <0)
        {
                printk ("register %s char dev error\n","led");
                return -1;
        }
        printk ("ok!\n");
        return 0;
}

void __exit led_exit (void)
{
         misc_deregister(&misc);
        printk ("module exit\n");
        return ;
}

module_init(led_init);
module_exit(led_exit);


Makefile文件

ifneq ($(KERNELRELEASE),)

obj-m := ok6410_led_new.o

else
 
KDIR := /home/doublechen/forlinx/linux-2.6.36.2-v1.05
all:
 make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:
 rm -f *.ko *.o *.mod.o *.mod.c *.symvers  modul*

endif



2、编写测试程序

test.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main (void)
{
        int fd;
        char buf[10]={0,1};
        fd = open("/dev/ok6410_leds",O_RDWR);
        if (fd < 0)
        {
                printf ("Open /dev/my_led file error\n");
                return -1;
        }       
        while(1)
        {
                write(fd,&buf[0],1);
                sleep(1);
                write(fd,&buf[1],1);
                sleep(1);
        }
        close (fd);
        return 0;

}





3、编译驱动程序与测试程序

      编译驱动程序

      #make

      编译测试程序

      #arm-linux-gcc  test.c  -o  test


4、将程序下载到开发板

       将开发板的IP地址修改,与主机在同一个网段。确保PC的tftp服务开启。

      下载程序到开发板

        SMDK6410#   tftp -l /lib/modules/2.6.36.2/driver_led.ko -r driver_led.ko  -g  192.168.1.111        192.168.1.111为服务器IP

        SMDK6410#   tftp -l test  -r test  -g  192.168.1.111         



5、测试

        加载驱动   #insmod  /lib/modules/2.6.36.2/driver_led.ko

        测试  ./test

        [root@FORLINX6410]# ./test
      此时可以看到OK6410板子上的LED0在闪烁。

       卸载驱动  #rmmod   driver_led

 

你可能感兴趣的:(struct,Module,File,user,测试,makefile)