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 frequencyfor (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 XPSoutl(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 cyclefor (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_deviceif (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 addresspwm_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.oelseKERNEL_DIR := <YOUR_DIR>/ZedBoard/Kernel/Digilent-linux-3.3PWD := $(shell pwd)all:$(MAKE) -C $(KERNEL_DIR) SUBDIRS=$(PWD) modules ARCH=armclean:rm *.o *.ko *.mod.cendif

<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. pandas数据排序sort_values后面inplace=True与inplace=False的实例驱动理解

    目 录 1 引子 2 inplace参数理论理解 3 inplace参数实例驱动理解 3.1 inplace = True 3.2 inplace = False 1 引子 Series 的排序: S ...

  2. linux 串口驱动 理解,linux 串口驱动 理解

    linux 串口 驱动 理解 一.核心数据结构 串口驱动有3个核心数据结构,它们都定义在 1.uart_driver uart_driver包含了串口设备名.串口驱动名.主次设备号.串口控制台(可选) ...

  3. Linux candence spi驱动理解

    本文测试平台为zedboard,使用PS端SPI外设.根据wiki_xilinx中的说明,此驱动为 candence_spi.c ,现对此驱动程序做一个简单的分析.wiki_xilinx 中 SPI ...

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

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

  5. linux tf 卡驱动理解

    mmc 驱动框架 梳理tf卡读取异常重启逻辑问题进展: a. 查找代码发现,在mmc_blk_issue_rw_rq函数中可以找到数据读取数据异常时的处理机制,其中部分代码如下:static int ...

  6. zedboard Linux JTAG驱动解决There is no current hw_target问题

    zedboard Linux JTAG驱动解决There is no current hw_target问题 由 FIND · 2017年4月10日 29 看过 Introduction 本文介绍了在 ...

  7. [转]zedboard Linux JTAG驱动解决There is no current hw_target问题

    原文地址 : https://www.findhao.net/easycoding/1921?utm_source=tuicool&utm_medium=referral zedboard L ...

  8. wince下SD卡驱动开发

    WinCE 5.0下面SD卡驱动的开发.这是我做的第一个项目,当时做这个项目花费了相当的时间和精力,搞的我精疲力尽.几乎可以说当时对WinCE一点都不懂.也不知道从何处下手,就东看西看.东改西改,改的 ...

  9. Linux 内核自带的 LED 灯驱动

    系列文章 I.MX6ULL 手册查找使用方法 实战点亮LED(寄存器版) I.MX6ULL 手册查找使用方法 实战点亮LED(固件库版本) linux 字符设备驱动实战 linux LED设备驱动文件 ...

最新文章

  1. 3-flutter 项目结构 资源 依赖
  2. 令人迷惑的ATT的jmp:直接跳转和间接跳转 [转]
  3. python异常处理类源码_Flask源码异常处理问题
  4. Linux-Shell 快捷键
  5. 剖析Docker Swarm和Mesos:是什么?如何结合?有什么优势?
  6. 笔试题--Multicore简答题(下)
  7. 使用Gradle构建Spring源码
  8. WIN7 VS2005 安装wince6.0教程(不管是X86还是X64,我都尝试成功了)
  9. OpenCV 3.0 高动态范围图像
  10. 叉积 微分 恒等式_单摆-微分方程浅谈
  11. 阿基米德螺旋线lisp_CAD画阿基米德螺旋线程序
  12. linux之getcwd函数解析,Linux 中C语言getcwd()函数的用法
  13. 日语バズる中文怎么翻译?
  14. c语言时间函数怎么用,C语言时间函数应用
  15. Android系统字体加载流程
  16. goland集成golint
  17. 解决win7系统重启后ip丢失问题,即每次电脑重启都要重新设置ip地址,重启后ip地址没了
  18. 跌倒智能监测警报系统市场现状及未来发展趋势分析
  19. python公立,农历转换
  20. ESP32开发之旅——人体感应传感器HC-SR501

热门文章

  1. 一级路由器静态路由访问二级路由器的方法二
  2. 管道通信的基本流程和代码
  3. 基于服务器部署的OCR在线识别应用
  4. 关于仿古砖的历史,你知道多少?
  5. 故障:不能 demote 域控制器
  6. 网络服务器未运行是什么原因是,Win7系统网络诊断提示诊断策略服务未运行怎么办?...
  7. Codeforces Round #645 (Div. 2)
  8. 如何做一名优秀的下属
  9. docer启动一个容器时的过程
  10. 数据分析应关注AARRR模型的哪些指标