zoukankan      html  css  js  c++  java
  • zedboard 驱动理解

    1 驱动程序的编写

      驱动是LINUX开发的必经之路,应用层对底层的调用经过了库与内核,内核下面才是驱动层,当你在应用程序执行对底层的控制时,驱动程序为你的控制提供了接口,或者说是策略。



    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/fs.h>
    #include <linux/device.h>
    #include <asm/io.h>
    
    


    #define DEVICE_NAME "PWM_MOUDLE"
    #define PWM_MOUDLE_PHY_ADDR 0x6CA00000    //This Address is based XPS 这个地址ISE EDK中分配的地址就是硬件的东东啦
    /* 描述驱动程序的一些信息,不是必须的 */
    MODULE_AUTHOR("Xilinx XUP");             // 驱动程序的作者
    MODULE_DESCRIPTION("PWM moudle dirver"); // 一些描述信息
    MODULE_VERSION("v1.0");
    MODULE_LICENSE("GPL");                   // 遵循的协议


    static int pwm_driver_major;
    static struct class* pwm_driver_class = NULL;
    static struct device* pwm_driver_device = NULL;
    
    unsigned long pwm_fre_addr = 0;		//pwm moulde's frequency visual address
    unsigned long pwm_duty_addr = 0;	//pwm moulde's duty visual address
    static long frequency=0;
    
    
    /*这个结构是字符设备驱动的核心*/
    static struct file_operations pwm_driver_fops = {
        .owner = THIS_MODULE,               /* 这是一个宏,推向编译模块时自动创建的__this_module变量 在Export.h (c:usersadministratordesktoplinux-3.3-digilentincludelinux):#define THIS_MODULE (&__this_module)*/
    };
    static ssize_t sys_pwm_frequency_set (struct device* dev, struct device_attribute* attr, const char* buf, size_t count)
    {
        long value = 0;
        int i;
        frequency=0;
        outl(value,  pwm_fre_addr); //close pwm moudle before we modfiy the frequency
    
        for (i = 0; i < count-1; i++){
            frequency  *= 10;
            frequency += buf[i] - '0';
        }
        if(value>100000000) value=100000000;
        value=100000000/frequency;  // 100Mhz/frequency 100Mhz is set by XPS
    	
        outl(value,  pwm_fre_addr);
        return count;
    } 
    
    

    static ssize_t sys_pwm_duty_set (struct device* dev, struct device_attribute* attr, const char* buf, size_t count) //duty cycle 
    {
        long value = 0;
        int i;
    //
    	outl(value,  pwm_duty_addr); //close pwm moudle before we modfiy the duty cycle
    
        for (i = 0; i < count-1; i++){
            value  *= 10;
            value += buf[i] - '0';
        }
    	if (value>100) value=100;
    	value=100000000/frequency*value/100;
       
        if (value!= 0)
            value = value | 0x80000000;
        	outl(value,  pwm_duty_addr);
    
        return count;
    } 
    static DEVICE_ATTR(pwm_frequency, S_IWUSR, NULL, sys_pwm_frequency_set);
    static DEVICE_ATTR(pwm_duty, S_IWUSR, NULL, sys_pwm_duty_set);
    

    /* 执行insmod xxx.ko时就会执行pwm_driver_module_init()函数 *
    


    static int __init pwm_driver_module_init(void)
    {
        int ret;
        /* 注册字符设备驱动程序
         * 参数为主设备号、设备名字、file_operations结构;
         * 这样,主设备号就和具体的file_operations结构联系起来了,
         * 操作主设备为BUTTON_MAJOR的设备文件时,就会调用s3c24xx_buttons_fops中的相关成员函数
         * BUTTON_MAJOR可以设为0,表示由内核自动分配主设备号
         */
        pwm_driver_major=register_chrdev(0, DEVICE_NAME, &pwm_driver_fops);//内核注册设备驱动
        if (pwm_driver_major < 0){
            printk("failed to register device.
    ");
            return -1;
        }
    
        pwm_driver_class = class_create(THIS_MODULE, "pwm_driver");        //创建PWM设备类
        if (IS_ERR(pwm_driver_class)){
            printk("failed to create pwm moudle class.
    ");
            unregister_chrdev(pwm_driver_major, DEVICE_NAME);
            return -1;
        }
    
        pwm_driver_device = device_create(pwm_driver_class, NULL, MKDEV(pwm_driver_major, 0), NULL, "pwm_device"); //利用pwm_driver设备类创建一个pwm_device
        if (IS_ERR(pwm_driver_device)){
            printk("failed to create device .
    ");
            unregister_chrdev(pwm_driver_major, DEVICE_NAME);
            return -1;
        }
       
        ret = device_create_file(pwm_driver_device, &dev_attr_pwm_frequency);       //在pwm_device设备中创建frequency与duty两个文件
        if (ret < 0)
            printk("failed to create pwm_frequency endpoint
    ");
        
        ret = device_create_file(pwm_driver_device, &dev_attr_pwm_duty);
        if (ret < 0)                                                                //将pwm模块的物理地址映射到虚拟地址上 也就是EDK中分配的地址
            printk("failed to create pwm_duty endpoint
    ");
       
       	pwm_fre_addr = (unsigned long)ioremap(PWM_MOUDLE_PHY_ADDR, sizeof(u32));//To get Custom IP--PWM moudle's virtual address
    	pwm_duty_addr = pwm_fre_addr+4;		
            			
        printk(" pwm driver initial successfully!
    ");
        return 0;
    }


    /*
    执行rmmod xxx.ko时就会执行pwm_driver_module_exit()函数
    */
    static void __exit pwm_driver_module_exit(void)
    {
        device_remove_file(pwm_driver_device, &dev_attr_pwm_frequency);
        device_remove_file(pwm_driver_device, &dev_attr_pwm_duty);
        device_destroy(pwm_driver_class, MKDEV(pwm_driver_major, 0));
        class_unregister(pwm_driver_class);
        class_destroy(pwm_driver_class);
        unregister_chrdev(pwm_driver_major, DEVICE_NAME);
        printk("pwm module exit.
    ");
    }
    
    /* 这两行指定驱动程序的初始化函数和卸载函数 */
    module_init(pwm_driver_module_init);
    module_exit(pwm_driver_module_exit);
    
    

    2驱动程序的编译

     makefile编写

      ifneq ($(KERNELRELEASE),)
      obj-m := pwm_driver.o
      else
      KERNEL_DIR := <YOUR_DIR>/ZedBoard/Kernel/Digilent-linux-3.3
      PWD := $(shell pwd)
      all:
    	$(MAKE) -C $(KERNEL_DIR) SUBDIRS=$(PWD) modules ARCH=arm
      clean:
    	rm *.o *.ko *.mod.c
      endif

    <YOUR_DIR>/ZedBoard/Kernel/Digilent-linux-3.3 是你的路径
    最后make 生成pwm_driver.ko 拷贝到zedboard文件系统上

    3 驱动程序的测试

       加载驱动

       insmod pwm_driver.ko在/dev/ 下可以找到我们注册的设备 pwm_device

      进入/sys/class/..目录  

      在zedboard 的shell上执行 echo 1000 > pwm_frequency  

                                 echo 50    > pwm_duty

    人生天地之间,若白驹之过郤(隙),忽然而已
  • 相关阅读:
    lucene 大量数据搜索的处理方案
    PC总线带宽与内存带宽的计算
    【JavaP6大纲】Dubbo篇:Dubbo特性?
    【JavaP6大纲】Dubbo篇:Dubbo 支持哪些序列化协议?说一下 Hessian 的数据结构?PB 知道吗?为什么 PB 的效率是最高的?
    【JavaP6大纲】Dubbo篇:如何自己设计一个类似 Dubbo 的 RPC 框架?
    【JavaP6大纲】Dubbo篇:Dubbo SPI 和 Java SPI 区别?
    【JavaP6大纲】Dubbo篇:如何基于 Dubbo 进行服务治理、服务降级、失败重试以及超时重试?
    【JavaP6大纲】Dubbo篇:Dubbo 用到哪些设计模式?
    【JavaP6大纲】Dubbo篇:Dubbo 负载均衡策略和集群容错策略都有哪些?动态代理策略呢?
    【JavaP6大纲】MySQL篇:传播行为
  • 原文地址:https://www.cnblogs.com/xiabodan/p/4038633.html
Copyright © 2011-2022 走看看