广州网站建设培训学校,一个网站的建设流程有哪些,网站首页轮播,做招聘求职网站文章目录一、驱动相关概念1.什么是驱动2.被驱动设备分类3.设备文件的主设备号和次设备号4.设备驱动整体调用过程二、基于框架编写驱动代码1.驱动代码框架2.驱动代码的编译和测试三、树莓派I/O口驱动的编写1.微机的总线地址、物理地址、虚拟地址介绍2.通过树莓派芯片手册确定需要…
文章目录一、驱动相关概念1.什么是驱动2.被驱动设备分类3.设备文件的主设备号和次设备号4.设备驱动整体调用过程二、基于框架编写驱动代码1.驱动代码框架2.驱动代码的编译和测试三、树莓派I/O口驱动的编写1.微机的总线地址、物理地址、虚拟地址介绍2.通过树莓派芯片手册确定需要配置的寄存器3.根据驱动框架编写树莓派Pin4引脚的驱动一、驱动相关概念
1.什么是驱动
Linux内核驱动:是指一段代码这段代码可以驱动底层硬件即驱动就是对底层硬件设备的操作进行封装并向上层提供函数接口。
2.被驱动设备分类
字符设备 指只能一个字节一个字节读写的设备不能随机读取设备内存中的某一数据读取数据需要按照先后顺序。字符设备是面向流的设备常见的字符设备有鼠标、键盘、串口、控制台和LED设备等字符设备驱动程序通常至少要实现open、close、read和write的系统调用字符终端/dev/console和串口/dev/ttyS0以及类似设备就是两个字符设备它们能很好的说明“流”这种抽象概念。块设备 指可以从设备的任意位置读取一定长度数据的设备。块设备包括硬盘、磁盘、U盘和SD卡等。网络设备 网络设备可以是一个硬件设备,如网卡; 但也可以是一个纯粹的软件设备, 比如回环接口(lo).一个网络接口负责发送和接收数据报文。 3.设备文件的主设备号和次设备号
Linux的设备管理是和文件系统紧密结合的各种设备都以文件的形式存放在/dev目录下称为设备文件应用程序可以打开、关闭和读写这些设备文件完成对设备的操作就像操作普通的数据文件一样。为了管理这些设备系统为设备编了号每个设备号又分为主设备号和次设备号。主设备号用来区分不同种类的设备而次设备号用来区分同一类型的多个设备。 一个字符设备或者块设备都有一个主设备号和次设备号。主设备号和次设备号统称为设备号。主设备号用来表示一个特定的驱动程序。次设备号用来表示使用该驱动程序的各设备。例如一个嵌入式系统有两个LED指示灯LED灯需要独立的打开或者关闭。那么可以写一个LED灯的字符设备驱动程序可以将其主设备号注册成5号设备次设备号分别为1和2。这里次设备号就分别表示两个LED灯。 设备文件通常都在 /dev 目录下。
设备号的作用 在内核空间中存在一个驱动链表管理所用设备的驱动。驱动链表主要有两个功能分别为添加编写完驱动程序加载到内核功能和查找调用驱动程序功能。在这些过程中驱动插入链表的顺序由设备号检索这便是设备号的主要作用。
4.设备驱动整体调用过程
1C语言上层调用open函数。open(“dev/pin4”,O_RDWR);调用/dev下的pin4以可读可写的方式打开。对于上层open调用到内核时会发生一次软中断中断号是0X80从用户空间进入到内核空间 2open会调用到system_call(内核函数)system_call会根据/dev/pin4设备名去找出需要的设备号。 3再调到虚拟文件VFS ,调用VFS里的sys_opensys_open会找到在驱动链表里面根据主设备号和次设备号找到引脚4里的open函数引脚4里的open是对寄存器操作及对硬件的操作。
二、基于框架编写驱动代码
1.驱动代码框架
#include linux/fs.h //file_operations声明#include linux/module.h //module_init module_exit声明
#include linux/init.h //__init __exit 宏定义声明
#include linux/device.h //class devise声明
#include linux/uaccess.h //copy_from_user 的头文件
#include linux/types.h //设备号 dev_t 类型声明
#include asm/io.h //ioremap iounmap的头文件static struct class *pin4_class;
static struct device *pin4_class_dev;static dev_t devno; //设备号
static int major 231; //主设备号
static int minor 0; //次设备号
static char *module_namepin4; //模块名static int pin4_open(struct inode *inode,struct file *file)
{printk(pin4_open\n); //内核的打印函数和printf类似return 0;
}static ssize_t pin4_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{printk(pin4_write\n);return 0;
}
static struct file_operations pin4_fops {.owner THIS_MODULE,.open pin4_open,//当应用层调用open函数时内核会调用pin4_open..write pin4_write,//当应用层调用write函数时内核会调用pin4_write.
};int __init pin4_drv_init(void) //真实的驱动入口
{int ret;devno MKDEV(major,minor); //创建设备号ret register_chrdev(major, module_name,pin4_fops); //注册驱动 告诉内核把这个驱动加入到内核驱动的链表中pin4_classclass_create(THIS_MODULE,myfirstdemo);//由代码在dev下自动生成设备pin4_class_dev device_create(pin4_class,NULL,devno,NULL,module_name); //创建设备文件return 0;
}void __exit pin4_drv_exit(void)
{device_destroy(pin4_class,devno);class_destroy(pin4_class);unregister_chrdev(major, module_name); //卸载驱动}module_init(pin4_drv_init); //入口
module_exit(pin4_drv_exit);
MODULE_LICENSE(GPL v2); 2.驱动代码的编译和测试
1进入Linux源码树目录下的驱动目录因为驱动的是字符设备所以进入的是驱动目录下的char目录。/home/zh/SYSTEM/linux-rpi-4.14.y/drivers/char 2将驱动代码放到上述目录下 3修改Makefile文件 在字符驱动目录下 打开Makefile文件并以模块的方式将驱动载入 4模块编译 进入源码树目录进行模块化编译键入 ARCHarm CROSS_COMPILEarm-linux-gnueabihf- KERNELkernel7 make modules5将编译好的驱动模块传到树莓派中
scp ./drivers/char/pin4driver.ko pi192.168.169.221:/home/pi加载内核驱动模块,在dev/目录下生成pin4驱动 sudo insmod pin4driver.kormmod pin4driver.ko //卸载驱动模块6给pin4驱动加权限
sudo chmod 666 /dev/pin47驱动程序测试 pin4test.c #include sys/types.h
#include sys/stat.h
#include fcntl.h
#include stdio.h
#include unistd.h
#include string.h
int main(int argc, char const *argv[])
{/* code */int fd;fd open(/dev/pin4,O_RDWR);write(fd,hello,strlen(hello));return 0;
}执行测试程序后用dmesg 查看内核打印信息发现打印了驱动函数的内容 三、树莓派I/O口驱动的编写
这里以驱动树莓派pin4引脚置0或置1为例。
1.微机的总线地址、物理地址、虚拟地址介绍
1总线地址 地址总线Address Bus是一种计算机总线是CPU或有DMA能力的单元用来沟通这些单元想要访问读取/写入计算机内存组件/地方的物理地址。 地址总线决定了cpu所能访问的最大内存空间的大小即cpu能访问的内存范围。 比如装了32位的win 7 系统内存8G可系统最大只能识别3.29G所以要使用4G以上大内存就要用windows x64位系统。装了32位的操作系统CPU的访问范围是2^32 bit,就是4194304kbit就是4G。树莓派也是32位 一个G的内存但它只能访问949M剩下的另作他用。 2物理地址 在存储器里以字节为单位存储信息为正确地存放或取得信息每一个字节单元给以一个唯一的存储器地址称为物理地址Physical Address又叫实际地址或绝对地址。
物理地址它是在地址总线上以电子形式存在的使得数据总线可以访问主存的某个特定存储单元的内存地址。在和虚拟内存的计算机中物理地址这个术语多用于区分虚拟地址。尤其是在使用内存管理单元MMU转换内存地址的计算机中虚拟和物理地址分别指在经MMU转换之前和之后的地址。 3虚拟地址 虚拟地址顾名思义即为逻辑地址基于算法的地址。
CPU启动保护模式后程序运行在虚拟地址空间中。注意并不是所有的“程序”都是运行在虚拟地址中。CPU在启动的时候是运行在实模式的Bootloader以及内核在初始化页表之前并不使用虚拟地址而是直接使用物理地址的。 如果CPU寄存器中的分页标志位被设置那么执行内存操作的机器指令时CPU准确来说是MMU即Memory Management Unit内存管理单元会自动根据页目录和页表中的信息把虚拟地址转换成物理地址完成该指令。 使用了分页机制之后4G的地址空间被分成了固定大小的页每一页或者被映射到物理内存或者被映射到硬盘上的交换文件中或者没有映射任何东西。对于一般程序来说4G的地址空间只有一小部分映射了物理内存大片大片的部分是没有映射任何东西。物理内存也被分页来映射地址空间。
2.通过树莓派芯片手册确定需要配置的寄存器
在BCM2835芯片手册的第六章描述了General Purpose I/O (GPIO)外设相关寄存器。 这里驱动pin4引脚需要用到的寄存器有 1.GPIO Function Select Registers (GPFSELn) 功能选择寄存器 该寄存器共有五组每个寄存器都有32位以GPIO Alternate function select register 0为例其中 29-0位 每三位对于一个引脚比如29-27对应的是GPIO Pin 9,26-24对应的是GPIO Pin 8且这三位取不同的值代表该三位对应的引脚选择不同的功能。比如当29-27位为000时表示GPIO Pin 9是输入功能29-27位为001时表示GPIO Pin 9是输出的功能。 2.GPIO Pin Output Set Registers (GPSETn) 置位寄存器 该寄存器共两组每个寄存器都有32位将寄存器某一位置1即将对应的引脚置1。 3.GPIO Pin Output Clear Registers (GPCLRn) 清0寄存器 与置位寄存器用法一至将对应位数引脚置0. 4.所需寄存器的地址说明 在编写驱动程序时IO空间的起始地址位0X3F000000加上GPIO的偏移量0X200000因此GPIO的物理地址是从0X3F200000开始的而编程所需的地址是虚拟地址需要通过MMU内存虚拟化管理将地址映射到虚拟地址上
3.根据驱动框架编写树莓派Pin4引脚的驱动
驱动代码 pin4driver.c
#include linux/fs.h //file_operations声明
#include linux/module.h //module_init module_exit声明
#include linux/init.h //__init __exit 宏定义声明
#include linux/device.h //class devise声明
#include linux/uaccess.h //copy_from_user 的头文件
#include linux/types.h //设备号 dev_t 类型声明
#include asm/io.h //ioremap iounmap的头文件static struct class *pin4_class;
static struct device *pin4_class_dev;static dev_t devno; //设备号
static int major 231; //主设备号
static int minor 0; //次设备号
static char *module_namepin4; //模块名//首先定义所要用的寄存器为了防止地址被编译器优化需要用到volatile关键字
volatile unsigned int *GPFSEL0 NULL;
volatile unsigned int *GPSET0 NULL;
volatile unsigned int *GPCLR0 NULL;static int pin4_open(struct inode *inode,struct file *file)
{printk(pin4_open\n); //内核的打印函数和printf类似//配置引脚4的寄存器将其配置为输出模式,即将GPFSEL0寄存器的第14-12位配置成001*GPFSEL0 0XFFFF9FFF; //将第14,13位置0*GPFSEL0 | 0X00001000; //将第12位置1return 0;
}static ssize_t pin4_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{int usercmd;printk(pin4_write\n);copy_from_user(usercmd,buf,count);//获取应用层write函数写入的内容if(usercmd 1){printk(set 1\n);*GPSET0 |(0x1 4); //将Pin4引脚置1}else if (usercmd 0){printk(set 0\n);*GPCLR0 |(0X1 4);//将Pin4引脚置0}else{printk(undo\n);}return 0;
}static struct file_operations pin4_fops {.owner THIS_MODULE,.open pin4_open,//当应用层调用open函数时内核会调用pin4_open..write pin4_write,//当应用层调用write函数时内核会调用pin4_write.
};int __init pin4_drv_init(void) //真实的驱动入口
{int ret;devno MKDEV(major,minor); //创建设备号ret register_chrdev(major, module_name,pin4_fops); //注册驱动 告诉内核把这个驱动加入到内核驱动的链表中pin4_classclass_create(THIS_MODULE,myfirstdemo);//由代码在dev下自动生成设备pin4_class_dev device_create(pin4_class,NULL,devno,NULL,module_name); //创建设备文件GPFSEL0 (volatile unsigned int *)ioremap(0X3f200000,4);//需要将物理地址映射位虚拟地址 ipremap第一个参数需要被映射的物理地址。第二个参数位映射的字节数GPSET0 (volatile unsigned int *)ioremap(0X3f20001C,4);//通过芯片手册可以看到该寄存器在基础地址上偏移了1CGPCLR0 (volatile unsigned int *)ioremap(0X3f200028,4);//通过芯片手册可以看到该寄存器在基础地址上偏移了28return 0;
}void __exit pin4_drv_exit(void)
{iounmap(GPFSEL0);iounmap(GPSET0);iounmap(GPCLR0);device_destroy(pin4_class,devno);class_destroy(pin4_class);unregister_chrdev(major, module_name); //卸载驱动
}module_init(pin4_drv_init); //入口
module_exit(pin4_drv_exit);
MODULE_LICENSE(GPL v2);
测试代码 pin4test.c
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include stdio.h
#include unistd.h
#include string.h
int main(int argc, char const *argv[])
{int fd,cmd;fd open(/dev/pin4,O_RDWR);printf(inout 0 ro 1 , 0 :Pin4 Set 0,1:Pin4 Set 1\n);scanf(%d,cmd);printf(cmd %d \n,cmd);write(fd,cmd,1);return 0;
}
将驱动代码编译后生成驱动模块放置在树莓派上进行测试
ARCHarm CROSS_COMPILEarm-linux-gnueabihf- KERNELkernel7 make modules将生成的驱动模块拷贝至树莓派
scp ./drivers/char/pin4driver.ko pi192.168.66.221:/home/pi在树莓派上安装驱动并给驱动权限
sudo insmod pin4driver.ko
sudo chmod 666 /dev/pin4运行测试程序 文章转载自: http://www.morning.kmldm.cn.gov.cn.kmldm.cn http://www.morning.wnnts.cn.gov.cn.wnnts.cn http://www.morning.rkhhl.cn.gov.cn.rkhhl.cn http://www.morning.cniedu.com.gov.cn.cniedu.com http://www.morning.frzdt.cn.gov.cn.frzdt.cn http://www.morning.tllhz.cn.gov.cn.tllhz.cn http://www.morning.xbtlt.cn.gov.cn.xbtlt.cn http://www.morning.ksgjy.cn.gov.cn.ksgjy.cn http://www.morning.kbdrq.cn.gov.cn.kbdrq.cn http://www.morning.hlshn.cn.gov.cn.hlshn.cn http://www.morning.bsqkt.cn.gov.cn.bsqkt.cn http://www.morning.gwsdt.cn.gov.cn.gwsdt.cn http://www.morning.yqpck.cn.gov.cn.yqpck.cn http://www.morning.nzkc.cn.gov.cn.nzkc.cn http://www.morning.rylr.cn.gov.cn.rylr.cn http://www.morning.smggx.cn.gov.cn.smggx.cn http://www.morning.ghqyr.cn.gov.cn.ghqyr.cn http://www.morning.zxhhy.cn.gov.cn.zxhhy.cn http://www.morning.swimstaracademy.cn.gov.cn.swimstaracademy.cn http://www.morning.hlrtzcj.cn.gov.cn.hlrtzcj.cn http://www.morning.sdhmn.cn.gov.cn.sdhmn.cn http://www.morning.kzcz.cn.gov.cn.kzcz.cn http://www.morning.poapal.com.gov.cn.poapal.com http://www.morning.qgwpx.cn.gov.cn.qgwpx.cn http://www.morning.tkxyx.cn.gov.cn.tkxyx.cn http://www.morning.lxlzm.cn.gov.cn.lxlzm.cn http://www.morning.khxwp.cn.gov.cn.khxwp.cn http://www.morning.tgmfg.cn.gov.cn.tgmfg.cn http://www.morning.lmfmd.cn.gov.cn.lmfmd.cn http://www.morning.hffjj.cn.gov.cn.hffjj.cn http://www.morning.yhxhq.cn.gov.cn.yhxhq.cn http://www.morning.hjlwt.cn.gov.cn.hjlwt.cn http://www.morning.fygbq.cn.gov.cn.fygbq.cn http://www.morning.bdypl.cn.gov.cn.bdypl.cn http://www.morning.srtw.cn.gov.cn.srtw.cn http://www.morning.fqtzn.cn.gov.cn.fqtzn.cn http://www.morning.kkysz.cn.gov.cn.kkysz.cn http://www.morning.nchlk.cn.gov.cn.nchlk.cn http://www.morning.cnkrd.cn.gov.cn.cnkrd.cn http://www.morning.kwqwp.cn.gov.cn.kwqwp.cn http://www.morning.rdlrm.cn.gov.cn.rdlrm.cn http://www.morning.fpqsd.cn.gov.cn.fpqsd.cn http://www.morning.qrwnj.cn.gov.cn.qrwnj.cn http://www.morning.phzrq.cn.gov.cn.phzrq.cn http://www.morning.wpsfc.cn.gov.cn.wpsfc.cn http://www.morning.gcszn.cn.gov.cn.gcszn.cn http://www.morning.kkysz.cn.gov.cn.kkysz.cn http://www.morning.knnhd.cn.gov.cn.knnhd.cn http://www.morning.gtbjc.cn.gov.cn.gtbjc.cn http://www.morning.sxbgc.cn.gov.cn.sxbgc.cn http://www.morning.fbqr.cn.gov.cn.fbqr.cn http://www.morning.qggm.cn.gov.cn.qggm.cn http://www.morning.jrtjc.cn.gov.cn.jrtjc.cn http://www.morning.dcdhj.cn.gov.cn.dcdhj.cn http://www.morning.gzgwn.cn.gov.cn.gzgwn.cn http://www.morning.hsdhr.cn.gov.cn.hsdhr.cn http://www.morning.jngdh.cn.gov.cn.jngdh.cn http://www.morning.djxnw.cn.gov.cn.djxnw.cn http://www.morning.ljzqb.cn.gov.cn.ljzqb.cn http://www.morning.rlsd.cn.gov.cn.rlsd.cn http://www.morning.xbkcr.cn.gov.cn.xbkcr.cn http://www.morning.dpppx.cn.gov.cn.dpppx.cn http://www.morning.zkzjm.cn.gov.cn.zkzjm.cn http://www.morning.lfcnj.cn.gov.cn.lfcnj.cn http://www.morning.wnqfz.cn.gov.cn.wnqfz.cn http://www.morning.lkxzb.cn.gov.cn.lkxzb.cn http://www.morning.ydxx123.cn.gov.cn.ydxx123.cn http://www.morning.rtsd.cn.gov.cn.rtsd.cn http://www.morning.0small.cn.gov.cn.0small.cn http://www.morning.jlthz.cn.gov.cn.jlthz.cn http://www.morning.lfttb.cn.gov.cn.lfttb.cn http://www.morning.mnwsy.cn.gov.cn.mnwsy.cn http://www.morning.dpsgq.cn.gov.cn.dpsgq.cn http://www.morning.tsdqr.cn.gov.cn.tsdqr.cn http://www.morning.phgz.cn.gov.cn.phgz.cn http://www.morning.jfbpf.cn.gov.cn.jfbpf.cn http://www.morning.dbbcq.cn.gov.cn.dbbcq.cn http://www.morning.pctsq.cn.gov.cn.pctsq.cn http://www.morning.rfpq.cn.gov.cn.rfpq.cn http://www.morning.hgsylxs.com.gov.cn.hgsylxs.com