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:\users\administrator\desktop\linux-3.3-digilent\include\linux):#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.\n");
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.\n");
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 .\n");
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\n"); ret = device_create_file(pwm_driver_device, &dev_attr_pwm_duty);
if (ret < 0) //将pwm模块的物理地址映射到虚拟地址上 也就是EDK中分配的地址
printk("failed to create pwm_duty endpoint\n"); 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!\n");
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.\n");
}

/* 这两行指定驱动程序的初始化函数和卸载函数 */
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

zedboard 驱动理解的更多相关文章

  1. 基于Minifilter框架的文件过滤驱动理解

    概述 Minifilter即File System Minifilter Drivers,是Windows为了简化第三方开发人员开发文件过滤驱动而提供的一套框架,这个框架依赖于一个称之为Filter ...

  2. DDD领域驱动理解

    在理解领域驱动的时候,网上很多大谈理论的文章,这种对于初学者不是太容易接受.根据我自己的学习经历,建议按照如下几个步骤学习: 粗略的看一遍领域驱动的理论,做到心中有形,知道领域驱动是什么,解决什么问题 ...

  3. Binder驱动理解

    1.Binder的三层架构 2.BC.BR的理解 通信模型 Binder协议包含在IPC数据中,分为两类: BINDER_COMMAND_PROTOCOL:binder请求码,以"BC_&q ...

  4. 宋宝华:Linux设备驱动框架里的设计模式之——模板方法(Template Method)

    本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) 前言 <设计模式>这本经典 ...

  5. 安卓高级6 SnackBar

    引言 文/李牧羊(简书作者) 原文链接:http://www.jianshu.com/p/2654e6bda3b1 著作权归作者所有,转载请联系作者获得授权,并标注"简书作者". ...

  6. 适合初学者的嵌入式Linux计划

    俗话说万事开头难,刚开始的时候,你是否根本就不知如何开始,上网查资料被一堆堆新名词搞的找不到北,去图书馆看书也是找不到方向?又是arm,又是linux,又是uboot头都大了,不知道自己究竟从哪里开始 ...

  7. zedboard上首个驱动实践——Led

    // led驱动 *myled.c*//头文件 #include<linux/module.h> //最基本的文件,支持动态添加和卸载模块 #include<linux/kernel ...

  8. 浅谈我对DDD领域驱动设计的理解

    从遇到问题开始 当人们要做一个软件系统时,一般总是因为遇到了什么问题,然后希望通过一个软件系统来解决. 比如,我是一家企业,然后我觉得我现在线下销售自己的产品还不够,我希望能够在线上也能销售自己的产品 ...

  9. IDDD 实现领域驱动设计-理解领域和子域

    上一篇:<IDDD 实现领域驱动设计-一个简单业务用例的回顾和理解> 在<实现领域驱动设计>第二章的前半部分内容中,提到领域和子域的概念,并且作者把这两者又进行了细致的区分,其 ...

随机推荐

  1. Linux下校验下载文件的完整性(MD5,SHA1,PGP)

    查看: Linux下校验下载文件的完整性(MD5,SHA1,PGP) http://blog.useasp.net/archive/2014/03/29/use-md5-sha1-or-pgp-to- ...

  2. Spring MVC学习笔记 01

    applicationcontext.xml的配置 <?xml version="1.0" encoding="UTF-8" ?> <bean ...

  3. GOF设计模式之1:单例设计模式

    1.单例设计模式核心作用: 保证一个类只有一个实例,并且提供了访问该实例的全局访问点 2.常见应用场景: window的任务管理器 项目中读取配置文件一般也是一个单例模式 数据库连接池的设计也是采用单 ...

  4. Android(java)学习笔记62:继承Thread类创建线程类

    package cn.itcast_02; /* * 该类要重写run()方法,为什么呢? * 不是类中的所有代码都需要被线程执行的. * 而这个时候,为了区分哪些代码能够被线程执行,java提供了T ...

  5. VS2013 添加文件头部注释模板

    在看视频的时候发现,视频中每次新建一个类文件 都会自动生成一串 头部的注释:

  6. 用Chrome浏览器模拟手机,android,iphone,ipad访问网站

    很多网站都通过User-Agent来判断浏览器类型,如果是3G手机,显示手机页面内容,如果是普通浏览器,显示普通网页内容.谷歌Chrome浏览 器,可以很方便地用来当3G手机模拟器.在Windows的 ...

  7. div/span等获取焦点问题(tabindex属性的简单理解)

    1.先看问题 当我们要对一个div/span元素获取焦点的时候,直接对$("#div1").focus()是不能实现效果的,比如下图: 当点击输入框进行输入后,在点击区域弹出选择地 ...

  8. hdu 4745 动态规划

    思路:特水的一个最长回文子序列动态规划.比赛时硬卡第一题,49WA后终于AC,可惜没时间做这题,结果成绩也就可想而知了.兔子跳一样权值的石头,并且一个正跳,一个反跳,这不就是个回文子序列吗?????! ...

  9. 【CSS3】---盒模型margin、padding及border

    盒模型--边框 盒子模型的边框就是围绕着内容及补白的线,这条线你可以设置它的粗细.样式和颜色(边框三个属性). 如下面代码为 div 来设置边框粗细为 2px.样式为实心的.颜色为红色的边框: div ...

  10. 关于在asp.net的web页面中的全局变量问题

    在asp.net的web页面中是不是没有全局变量?有的,在Class类内部的都是,只不过在WebWofm程式中跟WinForm和Console程式有些区别,当页面刷新时,它们的值不会保持,依然会再次初 ...