




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
设备驱动程序设计正大气象厚德载物MinnanUniversityofScienceandTechnology嵌入式系统原理与应用目录CONTENTS01.驱动开发概述02.内核模块03.字符设备驱动正大气象厚德载物MinnanUniversityofScienceandTechnology01PARTONELinux驱动概述正大气象厚德载物MinnanUniversityofScienceandTechnology正大气象厚德载物MinnanUniversityofScienceandTechnology设备驱动程序(DeviceDriver),简称驱动程序(Driver)。它是一个允许计算机软件与硬件交互的程序。这种程序建立了一个硬件与硬件,硬件与软件形成连接,这样的连接使得硬件设备之间的数据交换成为可能。设备驱动程序是计算机硬件与应用程序的接口,是软件系统与硬件系统沟通的桥梁。字符设备块设备网络设备设备驱动分类02PARTTWO内核模块正大气象厚德载物MinnanUniversityofScienceandTechnology1、字符设备--c正大气象厚德载物MinnanUniversityofScienceandTechnology一、Linux设备驱动分类应用程序和驱动程序进行数据读写时,是以“字节”为单位,按照固定的顺序传输;数据是实时传输,没有缓存。字符设备是没有文件系统的。绝大部分设备驱动是字符设备:LED、BEEP、按键、键盘、触摸屏、摄像头、液晶屏、声卡、IIC、SPI、...应用程序:系统IO函数open("/dev/led_drv",O_RDWR)read()write()ioctl()mmap()close()2、块设备--b正大气象厚德载物MinnanUniversityofScienceandTechnology一、Linux设备驱动分类应用程序和驱动程序之间进行数据读写时,数据是以“块”为单位,1block=1024KB。块设备是有缓存的,块设备是有文件系统的。大容量的存储设备一般都是块设备:nandflash、eMMC、SD、U盘、硬盘、....#cat/proc/partitionsmajorminor#blocksnammcblk0179165536mmcblk0p1应用程序访问块设备[root@GEC6818/]#ls/dev/sda*-lbrw-rw-rw-1rootroot8,0Jan100:11/dev/sda--->U盘1)挂载---块设备是有文件系统的。2)像访问普通文件一样访问块设备的内容。3、网络设备正大气象厚德载物MinnanUniversityofScienceandTechnology一、Linux设备驱动分类网卡类的设备:有线网卡、无线网卡、...,网络设备是没有设备文件的。应用程序:
socket套接字:IP+端口号正大气象厚德载物MinnanUniversityofScienceandTechnology二、内核模块的定义1、linuxkernelmodule2、module编译后会生成一个*.ko安装驱动:#insmodled_drv.ko卸载驱动:#rmmodled_drv.ko查看系统中,已安装的module:#lsmod驱动程序在内核中是独立的模块例如:beep驱动和LED驱动,beep和led间没有任何联系,可以通过应用
程序将两个驱动联系在一起。beep驱动和led驱动各自是独立的module。说明:每个驱动程序都是一个独立模块,每设计一个驱动程序,首先设计一个module,驱动程序是包含在module中。三、Sourceinsight创建工程1、SI设置Options--->DocumentOptions--->DocumentType:CSourceFile:*.c;*.h;*.S;*.s
X86AsmSourceFile:*.asm;*.inc;*.S;*.s2、创建一个工程project-->newproject-->工程文件放在源码包中(I:\GEC6818物联网综合实验箱(多模块版本)-201708\1、嵌入式6818网关平台\源码\kernel6818\kernel6818)addtree(稍微等一下)--->close3、文件的同步project--->synchronizeFiles(同步文件)4、内核源码在kernel中I:\GEC6818物联网综合实验箱(多模块版本)-201708\1、嵌入式6818网关平台\源码\6818GEC\kernelMinnanUniversityofScienceandTechnology正大气象厚德载物四、设计一个module并编译注意:参考内核源码,首先使用sourceinsight创建一个内核源码的工程例子:/drivers/watchdog/mxp_wdt.c1、设计module正大气象厚德载物MinnanUniversityofScienceandTechnology2、Makefile3、编译1、指定安装驱动的入口函数,用宏module_init(安装驱动的入口函数名)2、指定卸载驱动的入口函数,用宏module_exit(卸载驱动的入口函数名)3、定义对应入口函数4、驱动的描述
MODULE_AUTHOR("bobeyfeng@163.com");//作者联系方式MODULE_DESCRIPTION("LEDdriverforGEC6818");//驱动描述MODULE_LICENSE(“GPL”);//GPL协议MODULE_VERSION("V1.0");#include<linux/module.h>#include<linux/kernel.h>#include<linux/init.h>//入口函数--->安装驱动staticint__initgec6818_led_init(void){ printk(“<4>”“gec6818leddriverinit\n”);//内核程序打印printk,应用程序printf return0;}//出口函数--->卸载驱动staticvoid__exitgec6818_led_exit(void){ printk("gec6818leddriverexit\n");}
//驱动程序的入口:#insmodled_drv.ko-->module_init()-->gec6818_led_init()module_init(gec6818_led_init);//驱动程序的出口:#rmmodled_drv.ko--->module_exit()-->gec6818_led_exit()module_exit(gec6818_led_exit);
//module的描述。#modinfoled_drv.koMODULE_AUTHOR("bobeyfeng@163.com");//作者联系方式MODULE_DESCRIPTION("LEDdriverforGEC6818");//驱动描述MODULE_LICENSE(“GPL”);//GPL协议MODULE_VERSION("V1.0");1、设计module正大气象厚德载物MinnanUniversityofScienceandTechnologyINSTALLDIR
=
/tftpboot
ifneq($(KERNELRELEASE),)obj-m:=hello.oelseKERNELDIR:=/home/cw/kernel/CROSS_COMPILE:=/home/cw/6818GEC/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-
PWD:=$(shellpwd)
default:
#mkdir-p$(INSTALLDIR)
$(MAKE)ARCH=armCROSS_COMPILE=$(CROSS_COMPILE)-C$(KERNELDIR)M=$(PWD)modules
#cp--target-dir=$(INSTALLDIR)hello.ko
clean:
rm-rf*.o*.ko*.order.*.cmd*.mod.c*.symversendif2、Makefile---版本1目标:依赖Tab命令3)交叉编译工具2)内核源码的路径1)将源程序的目标文件led_drv.o,编译成一个module(ko)4)当前路径5)向内核源码路径下的Makefile文件传递两个参数,并调用内核源码下的Makefile文件,使用该Makfile中的工具,回到当前路径下,将源程序编译成一个module正大气象厚德载物MinnanUniversityofScienceandTechnology
ROOTFS_DIR=/opt/4412/rootfs
ifeq($(KERNELRELEASE),)
KERNEL_DIR=/home/cw/kernel
CUR_DIR=$(shellpwd)
all:
make-C
$(KERNEL_DIR)M=$(CUR_DIR)modulesclean:
make-C
$(KERNEL_DIR)M=$(CUR_DIR)cleaninstall:
cp-raf*.ko
$(ROOTFS_DIR)/drv_moduleelse
obj-m+=hello.oendif2、Makefile---版本2正大气象厚德载物MinnanUniversityofScienceandTechnology3、编译$make得到.ko下载到实验箱中(实验课)$fileled_drv.koled_drv.ko:ELF32-bitLSBrelocatable,ARM,EABI5version1(SYSV),BuildID[sha1]=04ff90444af056f8c1c04f119c7307950bfe16a5,notstripped$sizeled_drv.kotext data bss dec hex filename344 360 0 704 2c0 led_drv.ko$modinfoled_drv.kofilename:/mnt/hgfs/linux内核驱动/4module/demo/led_drv.koversion:V1.0license:GPLdescription:LEDdriverforGEC6818author:bobeyfeng@163.comsrcversion:5D5F2D6C66A08F289709359depends:vermagic:3.4.39-gecSMPpreemptmod_unloadARMv7p2v8vermagic--->versionmagic(魔数):驱动可以安装的linux版本:3.4.39-gec,其中:-gec--->localversion,配置内核的时候ARMv7---->硬件的版本正大气象厚德载物MinnanUniversityofScienceandTechnology3、编译GEC6818平台:[root@GEC6818/]#uname-aLinuxGEC68183.4.39-gec#4SMPPREEMPTTueOct2421:09:31CST2017armv7lGNU/Linux[root@GEC6818/]#insmodled_drv.ko[292.145000]gec6818leddriverinit[root@GEC6818/]#lsmodled_drv7600-Live0xbf000000(O)
[root@GEC6818/]#rmmodled_drv.ko[364.399000]gec6818leddriverexit正大气象厚德载物MinnanUniversityofScienceandTechnology1)简单方法[root@GEC6818/]#cat/proc/sys/kernel/printk
7717[root@GEC6818/]#echo7417>/proc/sys/kernel/printk
将echo7417>/proc/sys/kernel/printk写入:/etc/profile2)printk加优先级printk(KERN_WARNING"gec6818leddriverinit\n");printk("<4>""gec6818leddriverexit\n");3)配置linux内核,修改优先级--->一劳永逸(1)使用默认的配置文件bobey@ubuntu:~/6818GEC/kernel$cparch/arm/configs/GEC6818_defconfig.config(2)makemenuconfig-->配置内核sudoapt-getupdatesudoapt-getinstalllibncurses5-dev#makemenuconfigKernelhacking--->(4)Defaultmessageloglevel(1-7)(3)保存退出(4)复制配置文件cp.configarch/arm/configs/GEC6818_defconfig(5)编译内核./mk-k/home/bobey/6818GEC/out/release/boot.img--->烧写到emmc正大气象厚德载物MinnanUniversityofScienceandTechnology设置printk的优先级驱动程序有入口和出口,但是应用程序只有入口--main()五、驱动程序和应用程序的区别编译方法应用程序:gcc驱动程序:使用内核源码包提供的头文件、使用内核源码的编译工具:Makefile驱动程序是一个个独立的模块。各个驱动程序之间,一般是没有关系设计驱动程序时,只能使用内核源码提供的头文件,不能使用标准的C库:stdio.h,printf()正大气象厚德载物MinnanUniversityofScienceandTechnology03PARTTHERE字符设备驱动正大气象厚德载物MinnanUniversityofScienceandTechnology正大气象厚德载物MinnanUniversityofScienceandTechnology一、字符设备驱动的设计流程-------定义并初始化一个字符设备---------1、定义一个字符设备--->structcdev2、定义并初始化字符设备的文件操作集--->structfile_operations3、给字符设备申请一个设备号--->设备号=主设备号<<20+次设备号4、初始化字符设备5、将字符设备加入内核-------自动生成设备文件---------6、创建class7、创建device,其中device是属于class的-------得到物理地址对应的虚拟地址-------8、申请物理内存区,申请SFR的地址区。SFR---SpecialFunctionRegister:GPIOEOUT9、内存的动态映射,得到物理地址对应的虚拟地址10、访问虚拟地址正大气象厚德载物MinnanUniversityofScienceandTechnology二、编写LED驱动程序1、描述字符设备的结构体--cdev#include<linux/cdev.h>structcdev{ structkobjectkobj; --->内核管理驱动的时候,使用的一个object structmodule*owner; --->cdev是属于哪个module,一般写成THIS_MODULE conststructfile_operations*ops; --->cdev的文件操作集 structlist_headlist; --->内核管理cdev的链表 dev_tdev; --->设备号 unsignedintcount; --->次设备的数量};在linux内核中,使用cdev来描述一个字符设备,每个字符设备都有一个自己的cdev。设计字符设备首先定义一个cdev。例:staticstructcdevgec6818_led_cdev;正大气象厚德载物MinnanUniversityofScienceandTechnology二、编写LED驱动程序2、定义并初始化一个文件操作集(1)文件操作集#include<linux/fs.h>structfile_operations{ structmodule*owner; ............................... ssize_t(*read)(structfile*,char__user*,size_t,loff_t*); ssize_t(*write)(structfile*,constchar__user*,size_t,loff_t*); int(*mmap)(structfile*,structvm_area_struct*); int(*open)(structinode*,structfile*); int(*release)(structinode*,structfile*); long(*unlocked_ioctl)(structfile*,unsignedint,unsignedlong); ..............................}正大气象厚德载物MinnanUniversityofScienceandTechnology二、编写LED驱动程序2、定义并初始化一个文件操作集(2)文件操作集的作用每个cdev都有一个文件操作集,文件操作集是驱动程序给应用程序提供的接口。应用程序open()会找到驱动程序的open(),驱动程序的open()可以用来访问硬件。(3)例intgec6818_led_open(structinode*inode,structfile*filp){ return0;}ssize_tgec6818_led_read(structfile*filp,char__user*user_buf,size_tsize,loff_t*off){}ssize_tgec6818_led_write(structfile*filp,constchar__user*user_buf,size_tsize,loff_t*off){
}正大气象厚德载物MinnanUniversityofScienceandTechnology二、编写LED驱动程序2、定义并初始化一个文件操作集intgec6818_led_release(structinode*inode,structfile*filp){
return0;}staticconststructfile_operationsgec6818_led_fops={ .owner=THIS_MODULE,//此处是逗号 .open=gec6818_led_open, .read=gec6818_led_read, .write=gec6818_led_write, .release=gec6818_led_release,};正大气象厚德载物MinnanUniversityofScienceandTechnology二、编写LED驱动程序3、给字符设备申请一个设备号---dev_tdev(1)什么是设备号每个设备文件(字符设备or块设备)都有一个设备号,相当于设备文件ID。设备号是一个32bits的无符号整型值,设备号有主设备号(高12位)和次设备号(低20位)组成的。 typedef__u32__kernel_dev_t; typedef__kernel_dev_t
dev_t;(2)设备号运算的函数 1)由主设备号和次设备号生成设备号 #defineMKDEV(ma,mi) (((ma)<<MINORBITS)|(mi))//MINORBITS=20 2)由设备号得到主设备号和次设备号 #defineMAJOR(dev) ((unsignedint)((dev)>>MINORBITS)) #defineMINOR(dev) ((unsignedint)((dev)&MINORMASK))正大气象厚德载物MinnanUniversityofScienceandTechnology二、编写LED驱动程序3、给字符设备申请一个设备号---dev_tdev(3)主设备号和次设备号的作用
例:cd/dev---ls-l crw-rw----1rootroot204,64Jan11970ttySAC0串口0 crw-rw----1rootroot204,65Jan11970ttySAC1 crw-rw----1rootroot204,66Jan11970ttySAC2 crw-rw----1rootroot204,67Jan11970ttySAC3串口3主设备号描述一个硬件设备的类型:如uart、IIC、摄像头、...次设备号描述这种硬件类型下的具体某个硬件/dev/sys/class/主设备号一样,说明使用同一个类。正大气象厚德载物MinnanUniversityofScienceandTechnology二、编写LED驱动程序3、给字符设备申请一个设备号---dev_tdev(4)如何申请设备号
1)静态注册--->指定设备号,注册到内核中。如果内核已经使用该设备号,注册就不成功。intregister_chrdev_region(dev_tfrom,unsignedcount,constchar*name)参数说明: dev_tfrom--->注册的设备号;如果一次注册多个设备号,from就是注册设备号的开始值 unsignedcount--->次设备的数量 constchar*name---->设备名称,但不是设备文件的名字。#cat/proc/devices返回值:
成功返回0,失败返回复数错误码。例:crw-rw----1rootroot204,64Jan11970ttySAC0串口0crw-rw----1rootroot204,65Jan11970ttySAC1crw-rw----1rootroot204,66Jan11970ttySAC2crw-rw----1rootroot204,67Jan11970ttySAC3串口3register_chrdev_region(MKDEV(204,64),4,"ttySAC")//ttySAC--->设备名称
///dev/ttySAC0--->设备文件正大气象厚德载物MinnanUniversityofScienceandTechnology二、编写LED驱动程序3、给字符设备申请一个设备号---dev_tdev(4)如何申请设备号
2)动态分配--->内核自动分配空闲的设备号intalloc_chrdev_region(dev_t*dev,unsignedbaseminor,unsignedcount,
constchar*name)参数说明: dev_t*dev --->分配后的设备号 unsignedbaseminor --->次设备号的开始值 unsignedcount --->次设备的数量 constchar*name ---->设备名称,但不是设备文件的名字。#cat/proc/devices返回值:
成功返回0,失败返回复数错误码。
3)设备号的注销voidunregister_chrdev_region(dev_tfrom,unsignedcount)参数说明: dev_tfrom --->注册的设备号;如果一次注册多个设备号,from就是注册设备号的开始值 unsignedcount --->次设备的数量正大气象厚德载物MinnanUniversityofScienceandTechnology二、编写LED驱动程序4、初始化字符设备voidcdev_init(structcdev*cdev,conststructfile_operations*fops)思考:staticstructcdevgec6818_led_cdev;//有内存cdev_init(&gec6818_led_cdev,conststructfile_operations*fops);或:staticstructcdev*gec6818_led_cdev;//没有内存cdev_init(gec6818_led_cdev,conststructfile_operations*fops);//segmentfaultok:staticstructcdev*gec6818_led_cdev;gec6818_led_cdev=(structcdev*)kmalloc(sizeof(structcdev),GFP_KERNEL)if(gec6818_led_cdev==NULL){
}cdev_init(gec6818_led_cdev,conststructfile_operations*fops);//segmentfault正大气象厚德载物MinnanUniversityofScienceandTechnology二、编写LED驱动程序5、将字符设备加入内核(1)字符设备加入到内核intcdev_add(structcdev*p,dev_tdev,unsignedcount)参数: structcdev*p--->定义初始化好的字符设备 dev_tdev--->设备号 unsignedcount--->次设备的数量返回值:
错误返回错误码(2)
从内核中移除字符设备voidcdev_del(structcdev*p)正大气象厚德载物MinnanUniversityofScienceandTechnology二、编写LED驱动程序6、创建class
创建class和device的目的是在安装的驱动的时候,可以自动生成设备文件,在卸载驱动的时候,可以自动的删除设备文件。
如果不自动生成设备文件:也可以手动创建:#mkmodc/dev/led_drv主设备号
次设备号
创建的class生成在:/sys/class/#include<linux/device.h>(1)创建classstructclass*class_create(structmodule*owner,constchar*name)参数说明: structmodule*owner--->创建的class属于哪个module,一般为THIS_MODULE。 constchar*name--->自定义的class的名字返回值:
得到的class(2)class的删除voidclass_destroy(structclass*cls);正大气象厚德载物MinnanUniversityofScienceandTechnology二、编写LED驱动程序7、创建devicedevice是输于class的,当驱动程序有了class和device以后,内核使用mdev这个工具,根据class和device创建该驱动的设备文件。创建的device怎么查看:/sys/class/***/#include<linux/device.h>(1)创建devicestructdevice*device_create(structclass*class,structdevice*parent,dev_tdevt,void*drvdata,constchar*fmt,...)参数说明: structclass*class --->device属于哪个class structdevice*parent --->device的父设备,一般为NULL dev_tdevt --->设备号 void*drvdata --->驱动的data,一般为NULL constchar*fmt --->设备文件的名字返回值: structdevice* --->创建好的device(2)删除devicevoiddevice_destroy(structclass*class,dev_tdevt)正大气象厚德载物MinnanUniversityofScienceandTechnology二、编写LED驱动程序8、申请物理内存区回忆:裸机控制硬件的流程:
分析原理图-->找到控制硬件的GPIO-->找GPIO的寄存器--->分析寄存器--->理解寄存器的控制顺序--->通过寄存器的地址来访问该寄存器注意:裸机使用的是物理地址,所以直接使用CPU手册查到的地址可以编程。linux驱动使用的虚拟地址,不能直接使用物理地址。想办法,如果通过CPU手册查到的物理地址找到其对应虚拟地址???一般分成两个过程:
申请物理地址区作为一个资源----->将物理内存区做内存的动态映射,得到虚拟地址。注意:
资源---有限的,一旦一个物理内存区已经申请了,后面就不能再次申请。正大气象厚德载物MinnanUniversityofScienceandTechnology二、编写LED驱动程序8、申请物理内存区(1)申请物理内存区作为资源structresource*request_mem_region(resource_size_tstart,resource_size_tn, constchar*name)参数说明: resource_size_tstart --->物理内存区的开始地址 resource_size_tn --->物理内存区的大小 constchar*name --->自定义的物理内存区的名字返回值: structresource* --->物理内存区作为了资源思考:LED驱动,申请哪个物理内存区??? D8-->GPIOC17,D9-->GPIOC8,D10-->GPIOC7,D11-->GPIOC12 startaddress --->0xC001C000 addresssize --->结束地址:0xC001CFFF,大小:0x1000 name --->"GPIOC_MEM"(2)释放申请的物理内存区voidrelease_mem_region(resource_size_tstart,resource_size_tn)正大气象厚德载物MinnanUniversityofScienceandTechnology二、编写LED驱动程序9、io内存动态映射,得到虚拟地址#include<linux/io.h>(1)IO内存动态映射
将一段物理地址内存区映射成一段虚拟地址内存区void__iomem*ioremap(phys_addr_toffset,unsignedlongsize)参数说明: phys_addr_toffset --->要映射的物理内存区开始地址 unsignedlongsize --->物理内存区的大小返回值: void__iomem* --->映射后,虚拟地址内存区的首地址(2)解除IO内存动态映射voidiounmap(void__iomem*addr)正大气象厚德载物MinnanUniversityofScienceandTechnology二、编写LED驱动程序10、使用虚拟地址(1)得到虚拟地址 gpioc_base_va=ioremap(phys_addr_toffset,unsignedlongsize) if(gpioc_base_va==NULL){ printk("ioremaperror\n"); release_mem_region(0xC001C000,0x1000); device_destroy(leds_class,led_num); class_destroy(leds_class); cdev_del(&gec6818_led_cdev); unregister_chrdev_region(led_num,1); return-EBUSY; } //得到每个寄存器的虚拟地址 gpiocout_va=gpioc_base_va+0x00; gpiocoutenb_va=gpioc_base_va+0x04; gpiocaltfn0_va=gpioc_base_va+0x20; gpiocaltfn1_va=gpioc_base_va+0x24; gpiocpad_va=gpioc_base_va+0x18;正大气象厚德载物MinnanUniversityofScienceandTechnology二、编写LED驱动程序10、使用虚拟地址(2)虚拟地址的类型:void__iomem*(3)访问虚拟地址的方法:与访问物理地址的方法一样 //10.访问虚拟地址 //10.1GPIOC7,8.12,17--->function1,作为普通的GPIO
*(unsignedint*)gpiocaltfn0_va&=~((3<<14)|(3<<16)|(3<<24)); *(unsignedint*)gpiocaltfn1_va&=~(3<<2); *(unsignedint*)gpiocaltfn0_va|=((1<<14)|(1<<16)|(1<<24)); *(unsignedint*)gpiocaltfn1_va|=(1<<2); //10.2GPIOC7,8.12,17--->设置为输出
*(unsignedint*)gpiocoutenb_va|=((1<<7)|(1<<8)|(1<<12)|(1<<17)); //10.3GPIOC7,8.12,17--->设置为输出高电平,D8~D11off
*(unsignedint*)gpiocout_va|=((1<<7)|(1<<8)|(1<<12)|(1<<17));(4)虚拟地址的访问方法:使用内核提供的函数u32readl(constvolatilevoid__iomem*addr)voidwritel(u32b,volatilevoid__iomem*addr)或者:void__raw_writel(u32b,volatilevoid__iomem*addr)u32__raw_readl(constvolatilevoid__iomem*addr)正大气象厚德载物MinnanUniversityofScienceandTechnology三、常见错误码#include<linux/errno.h>#define EPERM 1 /*Operationnotpermitted*/#define ENOENT
2 /*Nosuchfileordirectory*/#define ESRCH 3 /*Nosuchprocess*/#define EINTR 4 /*Interruptedsystemcall*/#define EIO 5 /*I/Oerror*/#define ENXIO 6 /*Nosuchdeviceoraddress*/#define E2BIG 7 /*Argumentlisttoolong*/#define ENOEXEC 8 /*Execformaterror*/#define EBADF 9 /*Badfilenumber*/#define ECHILD 10 /*Nochildprocesses*/#define EAGAIN 11 /*Tryagain*/#define ENOMEM 12 /*Outofmemory*/#define EACCES 13 /*Permissiondenied*/#define EFAULT 14 /*Badaddress*/#define ENOTBLK 15 /*Blockdevicerequired*/#define EBUSY 16 /*Deviceorresourcebusy*/#define EEXIST 17 /*Fileexists*/正大气象厚德载物MinnanUniversityofScienceandTechnology三、常见错误码#define EXDEV 18 /*Cross-devicelink*/#define ENODEV 19 /*Nosuchdevice*/#define ENOTDIR 20 /*Notadirectory*/#define EISDIR 21 /*Isadirectory*/#define EINVAL 22 /*Invalidargument*/#define ENFILE 23 /*Filetableoverflow*/#define EMFILE 24 /*Toomanyopenfiles*/#define ENOTTY 25 /*Notatypewriter*/#define ETXTBSY 26 /*Textfilebusy*/#define EFBIG 27 /*Filetoolarge*/#define ENOSPC 28 /*Nospaceleftondevice*/#define ESPIPE 29 /*Illegalseek*/#define EROFS 30 /*Read-onlyfilesystem*/#define EMLINK 31 /*Toomanylinks*/#define EPIPE 32 /*Brokenpipe*/#define EDOM 33 /*Mathargumentoutofdomainoffunc*/#define ERANGE 34 /*Mathresultnotrepresentable*/四、用户空间和内核空间交互数据正大气象厚德载物MinnanUniversityofScienceandTechnology#include<linux/uaccess.h>(1)从用户空间获取数据unsignedlong__must_checkcopy_from_user(void*to,constvoid__user*from,unsignedlongn)放在驱动程序的write().(2)将数据拷贝给用户unsignedlong__must_checkcopy_to_user(void__user*to,constvoid*from,unsignedlongn)放在驱动程序的read()(3)完善write和read函数的编写五、驱动程序的调试与安装正大气象厚德载物MinnanUniversityofScienceandTechnology驱动程序的调试1、应用程序(编写测试程序test.c)---使用系统IO的函数
$arm-linux-gcc-otesttest.c $filetesttest:ELF32-bitLSBexecutable,ARM,EABI5version1(SYSV),dynamicallylinked,interpreter/lib/ld-linux.so.3,forGNU/Linux3.2.0,notstripped2、驱动程序---使用字符设备驱动模型1)查看主设备号和设备名称 root@GEC6818/test]#cat/proc/devices Characterdevices: 100led_device2)查看设备文件 [root@GEC6818/test]#ls/dev/led_drv-l crw-rw----1rootroot100,0Jan100:04/dev/led_drv3)查看申请的内存 [root@GEC6818/test]#cat/proc/iomem c001c000-c001cfff:GPIOC_MEM4)查看class和device [root@GEC6818/test]#ls/sys/class/gec210_leds/ led_drv五、驱动程序的调试与安装正大气象厚德载物MinnanUniversityofScienceandTechnology安装驱动1)将led_drv.ko和应用程序test下载到目标板中2)insmodled_drv.ko
如果没有打印出虚拟地址,则
vi/etc/profile
加入
echo7417>/proc/sys/kernel/printk
source/etc/profilermmodled_drv.koinsmodled_drv.ko3)执行应用程序./test五、驱动程序的调试与安装正大气象厚德载物MinnanUniversityofScienceandTechnology安装驱动1)将led_drv.ko和应用程序test下载到目标板中2)insmodled_drv.ko
如果没有打印出虚拟地址,则
vi/etc/profile
加入
echo7417>/proc/sys/kernel/printk
source/etc/profilermmodled_drv.koinsmodled_drv.ko3)执行应用程序./test正大气象厚德载物MinnanUniversityofScienceandTechnology2、直流电机驱动直流电机驱动电路如图所示。
通过查看原理图发现控制直流电机的I/O引脚为GPIOC24和GPIOC25。
如果让直流电机正转GPIOC24输出高电平,GPIOC25输出低电平;直流电机反转GPIOC24输出低电平,GPIOC25输出高电平,直流电机停止GPIOC24输出低电平,GPIOC25输出低电平。驱动程序见源码正大气象厚德载物MinnanUniversityofScienceandTechnology3、PWM驱动驱动程序见源码蜂鸣器电路连接图如图所示。PWM2的管脚为GPIOC14PWM相关的寄存器如图所示。嵌入式系统原理与应用第七章Linux系统移植正大气象厚德载物MinnanUniversityofScienceandTechnology目录CONTENTS01.U-Boot编译与移植02.Linux编译与移植03.Linux文件系统制作正大气象厚德载物MinnanUniversityofScienceandTechnology01PARTONE嵌入式系统简介正大气象厚德载物MinnanUniversityofScienceandTechnology正大气象厚德载物MinnanUniversityofScienceandTechnology一、BootLoader介绍二、S5p6818启动方式三、Uboot移植四、Uboot命令U-Boot编译与移植
S5p6818启动正大气象厚德载物MinnanUniversityofScienceandTechnology一、BootLoader介绍BootLoader系统启动引导程序,主要作用:搬移内核(系统)到内存中执行。分类标准说明针对不同CPU架构1、针对X86架构的有LIL0、GRUB、ntldr等针对不同2、针对ARM架构的有vivi、armboot等CPU架构3、针对PPC架构的有ppcboot等4、可以支持多种架构的u-boot等针对不同操作系统1、专门用来启动Linux系统的vivi2、专门用来启动WinCE系统的eboot3、基于eCos系统的引导程序redboot4、可以启动多种操作系统的u-boot等正大气象厚德载物MinnanUniversityofScienceandTechnology一、BootLoader介绍BootLoader简单对比BooloaderMonitor描述X86ARMLILO否Linux磁盘引导程序是否GRUB否GNU的LILO替代程序是否ntldr否x86上引导windowsNT系列是否armboot是专门为arm架构设计的boot否是ppcboot是引导ppc架构操作系统否是vivi是韩国Mizi公司针对三星ARM架构CPU设计引导程序否是redboot是基于eCos的引导程序是是u-boot是通用引导程序,支持多种CPU架构、多种操作系统是是正大气象厚德载物MinnanUniversityofScienceandTechnologyS5P6818systemboot的两种方式(芯片手册第3章systemBootP93):1、外部静态内存启动:2、内部ROM启动:NANDbootSD/MMC/SDFSbootSPISerialEEPROMbootUARTbootUSBboot二、S5p6818启动方式二、S5p6818启动方式--- 确定启动方式为:SDHC启动BootMCU_SD0:1MCU_SD1:0MCU_SD2:1采用的是SD/MMC启动方式SD/MMC接口有3个通道,SD0卡槽、SD1卡槽和EMMC。默认是从SD0卡槽的中SD卡启动,如果SD0卡槽没有SD卡,是从EMMC启动。MCU_SD3:0,选用的是CH1二、S5p6818启动方式--- SDHC启动方式介绍iROM(0x34000000)20KBiRAM(0xffff0000)64KB1、上电执行固化在iROM中的指令,此代码出厂就有,主要功能初始化SD,识别SD接口等;2、从SD/MMC/eMMC拷贝用户的启动代码(约56KB)到iRAM;3、跳转到iRAM地址中,执行用户的启动代码;注:用户启动代码约等于56Kb。二、S5p6818启动过程S5P6818启动过程BL0阶段:芯片选择启动iROM、iROM选择启动下一阶段引导程序所在设备(P95图iROM启动Uboot第一阶段BL1Uboot第一阶段启动Uboot第二阶段BL2Uboot第二阶段启动内核综上所述,我们的userbootcode是从SD卡等外部设备上加载的,这样iROM就会先找到能够启动的外部设备SD卡,并从核心板上的EMMC上搬运userbootcode,而搬运的这段代码就是我们常说的Bootloader。ubootpak.bin主要就是一个包含了2ndboot和uboot.bin的完整Bootloader。二、S5p6818启动过程二、S5p6818启动过程二、S5p6818启动过程二、S5p6818启动过程三、Uboot移植---简介1、简介:Uboot最初是由PPCBoot发展而来,目前已成为Armboot和PPCboot的替代品2、特点:
支持操作系统有Linux、NetBSD、VxWorks、QNX、RTEMS、ARTOS、LynxOS等。
支持的处理器架构有PowerPC、MIPS、X86、ARM、NIOS、Xscale3、Uboot最新版本:http://git.denx.de/?p=u-boot.git;a=summary三、Uboot移植---源码目录三、Uboot移植---源码目录三、Uboot移植---源码目录三、Uboot移植---编译配置u-boot的配置编译需要经过以下步骤:①在u-boot的根目录下执行:#makeGEC6818_config//对应开发板配置Makefile会构建编译结构,如:架构、cpu、开发板、厂商、芯片、目录等,为下一步真正编译链接做准备。②修改include/configs/x6818.h配置文件③在u-boot根目录下执行:makeARM=ARCHCROSS_COMPILE=../prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-其中ARM=ARCHCROSS_COMPILE=../prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-,可以根据实际情况指定编译器路径,或可将本部分添加到顶层Makefile文件中,则输入编译命令可只输入:make。(注:选择的编译器需支持编译U-boot)三、Uboot移植---编译结果如下:GECuboot.bin三、Uboot移植---编译配置连接文件u-boot.ldsmake命令执行的是Makefile文件的第一个目标即->
->
->
->
->三、Uboot移植---编译配置连接文件u-boot.ldsnsih.txt和2ndboot是厂商提供的,二进制文件。将u-boot.bin、nsih.txt和2ndboot使用tools/mk6818工具生成ubootpak.bin根据以上步骤产生编译和链接所需文件的信息,最终make完成,在根目录下将生成:ubootpak.binu-boot.binu-boot.map三个文件。三、Uboot移植---编译配置1、Uboot源码中README:2、确定配置方法为:makeGEC6818_config3、在终端输入:makehelp4、打开Makefile文件,查找_config5、打开Uboot根目录中的mkconfig,
是一个shell脚本进行配置。三、Uboot移植---编译过程1、打开mkconfigUboot源码提供了配置脚本,完成CPU架构和平台信息选择配置:从boards.cfg文件中匹配到当前平台信息,将该信息重定向到/include/config.h中。信息如下:四、Uboot命令常用命令1、print得到所有命令列表2、help:helptest,列出test功能的使用说明3、ping:测试与其他设备网络是否连通4、setenv:设置环境变量,例:setenvserverip5、saveenv:设置好环境变量以后,保存变量值6、tftp:tftp32000000vmlinux,把server(IP=环境变量中设置的serverip)中/tftpdroot/下的vmlinux通过TFTP读入到物理内存32000000处。7、bootm:起动UBOOTTOOLS制作的压缩LINUX内核,bootm32000008、md:修改RAM中的内容,md32000000(内存的起始地址)四、Uboot命令---U-Boot命令制作内核的启动,通过U-Boot命令来实现的。U-Boot中每个命令都通过U_BOOT_CMD宏来定义,格式如下:U_BOOT_CMD(_name,_maxargs,_rep,_cmd,_usage,_help)各项参数的意义如下:
_name:命令的名字,它不是一个字符串。
_maxargs:最大的参数。
_rep:命令是否可重复,可重复是指运行一个命令后,下次敲回即可再次运行。
_cmd:对应的函数指针,类型为(*cmd)(structcmd_tbl_s*,int,int,char*[])。
_usage:简单的使用说明,这是个字符串。
_help:较详细的使用说明,这是个字符串。四、Uboot命令---U-Boot命令制作例:在U-boot中增加一条test命令,命令至少支持接收3个参数。并且根据输入参数做求和,打印求和的值。1)进入common目录下新增一个cmd_test.c文件,并且复制一份模板。2)打开cmd_test.c按要求修改。制作命令代码框架如下:#include<common.h>#include<command.h>
staticintdo_help(cmd_tbl_t*cmdtp,intflag,intargc,char*constargv[]){……}
U_BOOT_CMD(……);四、Uboot命令---U-Boot命令制作例:在U-boot中增加一条test命令,命令至少支持接收3个参数。并且根据输入参数做求和,打印求和的值。3)修改后如下:4)保存,并修改本级Makefile文件,添加编译语句。ifndefCONFIG_SPL_BUILDobj-y+=main.oobj-y+=command.oobj-y+=exports.oobj-y+=hash.oobj-y+=cmd_test.o5)编译与下载了解awk工具02PARTTWOLinux内核编译与移植正大气象厚德载物MinnanUniversityofScienceandTechnology一、Linux内核版本及获得二、Linux内核结构三、Linux内核启动引导过程四、Linux内核的配置和编译五、Linux3.4.39内核移植Linux内核编译与移植-S5P6818一、Linux内核版本变迁及获得BootLoader系统启动引导程序,主要作用:搬移内核(系统)到内存中执行。一、Linux内核版本变迁及其获得登录Linux内核的官方网站/,可以看到如图Linux内核的版本号可以从源代码的顶层目录下的Makefile中看到,比如下面几行它们构成了Linux的版本号:3.4.39。VERSION=3PATCHLEVEL=6SUBLEVEL=39二、Linux内核结构内核源码结构下载源码后解压进入源码顶层目录如下图,其中首先要分析的三个重要文件为:Makefile、Kconfig、.config。.config为隐藏文件需输入ls-a可查看,是编译后自动生成文件保存相关配置项,Kconfig是生成配置菜单的重要文件。1、Makefile1)打开顶层Makefile:init-y、drivers-y、net-y、libs-y和c
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年现代车辆工程师考试试卷及答案
- 2025年体育教育与训练专业技能测试试题及答案
- Isopaucifloral-F-racemic-Isopaucifloral-F-生命科学试剂-MCE
- Gaboxadol-hydrochloride-Standard-Lu-02-030-hydrochloride-Standard-生命科学试剂-MCE
- 2025年汽车电子技术专业考试试题及答案
- 2025年电子商务师考试理论知识试卷及答案
- 零售商店管理系统开发协议
- 《小说的叙事技巧:高二语文文学鉴赏教学教案》
- 遥感技术应用于农业生产经营的合作协议
- 六年级状物作文海棠花500字(13篇)
- 2024-2030年中国内河水运行业市场现状调查及发展趋向研判报告
- 广东省深圳市福田区福田小学小学语文六年级小升初期末试题(含答案)
- 数智时代的商业变革智慧树知到期末考试答案章节答案2024年山东大学(威海)
- 2024年福建省宁德市中考一模《物理》试题(解析版)
- 水平三体操大单元18课时教案
- 2024届新疆石河子小升初易错点语文检测卷含答案
- 土木工程专业毕业答辩常问问题
- 供水管网抢修管理课件
- 多学科疼痛护理
- 24春国家开放大学《统计学原理》形成性考核1-3参考答案
- 环卫保洁整体服务方案
评论
0/150
提交评论