zoukankan      html  css  js  c++  java
  • zedboard上首个驱动实践——Led

    //  led驱动  *myled.c*
    //
    头文件 #include<linux/module.h> //最基本的文件,支持动态添加和卸载模块 #include<linux/kernel.h> //内核相关文件 #include<linux/fs.h> //包括文件操作相关struct的定义(struct file_operations和struct inode),MINOR、MAJOR的头文件 #include<linux/init.h> //初始化头文件 #include<linux/delay.h> //延时头文件 #include<asm/uaccess.h> //包括copy_to_user、copy_from_user等内核访问用户进程内存地址的函数定义 #include<asm/irq.h> //与处理器相关的中断 #include<asm/io.h> //包括ioremap、iowrite等内核访问IO内存等函数的定义 #include<asm/arch/regs-gpio.h> //与处理器相关的IO口操作 #include<asm/hardware.h> //与处理器相关的硬件 #include<linux/device.h> //包括device、class等结构的定义 #include<linux/slab.h> //包括kcalloc、kzalloc内存分配函数的定义 #include<linux/semaphore.h> //使用信号量必须的头文件 #include<linux/spinlock.h> //自旋锁 //定义变量 #define DEVICE "myled" static struct class * myled_class; static struct class * myled_class_dev; int major; volatile unsigned long * led_reg = NULL; //open函数 //这个函数一般包括硬件的相关设置、初始化等,比如GPIO的属性。不过zedboard的gpio在硬件定制中已经设置属性,故此函数不需要添加 static int myled_open(struct inode * inode,struct file * file) {   printk("Open LED_DRV ");   return 0; } //write函数 static ssize_t myled_write(struct file * file,const char _ _user * buf,size_t count,loff_t * ppos) {   int val;   printk("Open MY_LED_write ");   copy_from_user(&val,buf,count);//从用户空间赋值数据到内核空间   * led_reg = val;   return 0; } //file_operations结构体 static struct file_operations myled_fops={   .owner = THIS_MODULE,   .open = myled_open,   .write = myled_write, };//注意这个分号不能少 //驱动初始化函数 static int myled_init(void) {   major=register_chrdev(0,"myled",&myled_fops);   myled_class = class_create(THIS_MODULE,"myled");   myled_class_dev = device_create(myled_class,NULL,MKDEV(major,0),NULL,"myled");   led_reg = (volatile unsigned long *)ioremap(0x6a000000,32);   * led_reg = 0x55;   printk("Open LED_init ");   return 0; }
    //驱动卸载函数 static int myled_exit(void) {   unregister_chrdev(major,"myled");   device_unregister(myled_class_dev);   class_destroy(myled_class);   iounmap(led_reg);   printk("MY_LED_exit ");   return 0; } //驱动加载和卸载入口函数 module_init(myled_init); module_exit(meled_exit); MODULE_LICENSE("GPL");

      驱动程序myled.c编写完成之后,需要对其进行编译,为了方便编译程序,需要编写一个Makefile文件

    Makefile文件
    KERN_SRC = /zedboard/linux-digilent-3.6-digilent-13.01
    boj-m:=myled.o
    all:
      make -C $ (KERN_SRC) M='pwd' modules
    clean:
      make -C $ (KERN_SRC) M='pwd='clean
    //在zedboard目录下新建driver文件夹,并将以上myled.c和Makefile文件放到该文件夹
    mkdir driver
    //进入driver目录,编译驱动,完成后会生成myled.ko驱动模块文件
    cd driver
    mak ARCH=arm  CROSS_COMPILE=arm-xilinx-linux-gnueabi- 
    //驱动设计完成后,需要将其添加到设备树中
    //打开设备树文件,并添加以下大号斜黑体内容
    gedit arch/arm/boot/dts/digileng-zed.dts
    spi-speed-hz = <4000000>;
    spi-sclk-gpio = <&ps7_gpio_0 59 0 >;
    spi-sdin-gpio = <&ps7_gpio_0 60 0 >;
    };
    myled{
    compatible =  "dglnt,myled-1.00.a";
    reg = <0x6a000000 0x10000>;
          };
       };      
    };
    //重新生成设备树dtb文件
     ./scripts/dtc/dtc -I dts -O dtb -o .../devicetree.dtb   arch/arm/boot/dts/digilent-zed.dts
    //将生成的设备树文件复制到SD卡的boot分区,接下来就可以进行加载驱动测试

    简单测试驱动:
    1.将SD卡插入PC,在ubuntu下降生成的myled.ko文件复制到SD卡的rootfs分区的home目录,然后启动zedboard;
    2.启动linaro后,在串口终端里进入home目录,并使用insmod命令加载驱动程序;
     cd /home/
    insmod myled.ko
    3.如果要卸载驱动,执行以下命令;
    rmmod myled
    应用程序调用驱动测试:
    1.首先要编写一个简单的上位机测试程序ledtest.c,实现对LED的控制。
    #include<sys/types.h>
    #include<sys/stat.h>
    #include<fcntl.h>
    #include<stdio.h>
    
    int main(int argc,char * * argv)
    {
      int fd;
      int val = 0xAA;
      fd = open("/dev/myled",O_RDWR);
      if(fd<0)
      {
        printf("error,can't open
    ");
        return 0;
      }
      write(fd,&val,4);
      return 0;
    }

    其中fd=open就是打开myled这个设备,val是输出到led的值,最后通过write将其值写入到led寄存器

    2.将ledtest.c复制到driver目录下,并对其编译
    arm-xilinx-linux-gnueabi-gcc   -o   ledtest   ledtest.c
    3.编译完成后,同样将生成的ledtest可执行文件复制到SD卡的rootfs分区的home目录下
    4.启动zedboard,在串口下执行如下命令即完成了驱动测试
    cd   /home
    insmod myled.ko
    ./ledtest
    最后,总结一下编写驱动的一般步骤:

    1.查看原理图,理解设备的工作原理;
    2.定义主设备号;
    3.实现初始化和卸载函数,实现对驱动的注册和注销;
    4.设计所需要的文件操作,即file_operations结构;
    5.实现所需的文件操作调用,如read,write函数等;
    6.实现中断服务,用request_irq向内核注册(可选);
    7.编写Makefile文件;
    8.独立编译驱动,并修改设备树文件,最终使用insmod命令进行动态加载;或者直接把驱动编译进内核;
    9.测试驱动,编写应用程序。
    
    
    
    



  • 相关阅读:
    爬虫那些事儿---爬虫选择策略
    爬虫那些事儿--Http返回码
    【珍藏】linux 同步IO: sync、fsync与fdatasync
    perf学习-linux自带性能分析工具
    进程调度原理
    phpmyadmin 免登陆
    请为main函数提供返回值
    悬挂else引发的问题
    PhpMyAdmin导入数据库大小限制?
    linux内核Makefile整体分析
  • 原文地址:https://www.cnblogs.com/ylsm-kb/p/9062246.html
Copyright © 2011-2022 走看看