完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
本帖最后由 jackeyt 于 2017-4-6 22:44 编辑 试用目录: 1、【EVB-T335开发板试用体验】+1开箱上电 2、【EVB-T335开发板试用体验】2、开发环境搭建+踩坑纪录 3、【EVB-T335开发板试用体验】3、建立linux内核source insight工程 此贴是【EVB-T335开发板试用体验】的第四篇:Linux驱动篇:点亮一盏LED灯(上) 该系列主要有三篇文章,主要介绍在Linux下如何编写LED(IO)驱动的三种主流方法: 1、使ioremap/unremap实现虚拟地址到物理地址的映射,以实现对芯片物理寄存器的读写操作从而实现IO控制; 2、使用Linux的GPIO库实现对IO的直接操作从而实现LED的亮灭控制; 3、利用平台总线(platform)实现IO操作,该方法易用,移植方法,主推方法。 本篇是该系列的第一篇,主讲如何通过“寄存器”的方法实现Linux对IO的操作实现。 主要包括以下内容: 一、硬件部分 1、硬件原理图分析 2、芯片手册使用说明 二、软件部分 1、Linux 驱动实现原理 2、Linux 驱动框架 3、Linux 驱动API使用 4、手把手教你编写Linux驱动-实现LED操作控制 5、Makefile的编写与使用 6、驱动编译、安装 三、应用层测试程序 1、应用层测试程序实现 2、交叉编译结果与测试 一、硬件部分 在进行嵌入式开发的过程中,第一件事就是确定硬件设备连接原理图,然后根据硬件设备特性以工作原理,操作主控芯片,以实现功能的逻辑。 1、硬件原理图分析 请见EVB-T335x官方自带的板子资料中相关的硬件原理图: 因此,只需要控制该IO口输出高低电平即可实现对LED灯的亮灭控制。 那么,该IO对应于芯片来说,具体的说明情况以及如何控制,我们得来看一下芯片的DataSheet手册。 2、芯片手册使用说明 根据上述说明,我们按下来查看一下,芯片的DataSheet手册:位于linux_evb-t335datasheetCoM-T335CPUam335x-ref.pdf & am3354.pdf 那么,输入:GPIO3_16 进行搜索,即可得到如下图所示的寄存器控制名称。 那么,在am335x-ref.pdf中,我们可以找到mcasp0_axr0的寄存器名称为:conf_mcasp0_axr0,其位于CONTROL_MODULE REGISTERS 下面,且其地址偏移值为:998H 到这里,我们只是找到相应的控制寄存器,因此,我们还需要找到GPIO3的基地址,以及数据输出寄存器即可。如下图所示: 这里,我们可以看到GPIO3的基地址为:0x481AE000 此时,点击如上图所示的GPIO3处,可以进入超链接,到GPIO3的各个详细寄存器的说明。效果如下图: 这里,我们只关心两个寄存器:GPIO_OE以及GPIO_DATAOUT 我们依旧使用超链接点击跳转至相应的说明位置: 由上述两图可知,当向GPIO_OE寄存器里面往第n位写入1,就能使得该位对应地设为输出模式;同理,当向GPIO_DATAOUT寄存器里面往第n位写入1或者0,就能使得该位对应的IO口设为高/低电平。 总结: 1、首先,设置模式控制寄存器:conf_mcasp0_axr0,地址为:0x44E10000(基地址)+ 0x998(偏移地址) 2、其次,设置GPIO3的输出使能寄存器:GPIO_OE,地址为:0x481AE000(基地址)+ 0x134(偏移地址),向第16位写入1,使得GPIO3_16设为输出模式。 3、最后,向GPIO_DATAOUT寄存器,地址为:地址为:0x481AE000(基地址)+ 0x13C(偏移地址)向其里面往第n位写入1或者0,就能使得该位对应的IO口设为高/低电平;从而实现控制LED亮灭操作。 以上,就是硬件原理部分,有基本的硬件原理以及操作逻辑,我们就可以开始来写驱动程序了。下面开始介绍软件部分。 二、软件部分 在进行嵌入式开发的过程中,最常做的事情就是驱动配置硬件设备,然后根据功能需求使用硬件设备,实现功能的逻辑。如下是为其相互之间的关系: 应用程序<===>驱动程序<===>硬件设备 1、驱动程序:主要作为操作和配置硬件设备,使得硬件设备能够正常进行工作。 例如,在写点灯程序时,前提条件是从原理图了解到LED等与CPU/MCU之间的硬件连接(使用了哪一个GPIO口),驱动程序的作用就是初始化配置GPIO口,使得GPIO口能够进行工作,比如现在配置为推完输出模式。GPIO能够正常工作之后,那么就需要进行最基本的操作了,即灯亮和等灭。这就是驱动程序。 2、应用程序:当驱动程序能够时间最基本的灯亮和灯灭,那么是需要实现跑马灯,还是各种花样的灯的显示,这就由应用程序来决定了。 3、硬件设备:能够接受CPU/MCU通过驱动程序进行的操作,或者是能够为CPU/MCU提供有效的数据。 1、Linux 驱动实现原理 对于Linux操作系统而言,因其系统的强大和所支持功能的完善,可支持各种设备在Linux操作系统下运行。所以设备的类型繁多,如:字符设备,块设备,网络接口设备,USB设备,PCI设备,平台设备,混杂设备……而设备类型不同,也意味着其对应的驱动程序模型不同。即每一种类型的设备,都有其相应的驱动模型。 但总体而言,既然都是运行在Linux操作系统下的设备,所以其应当存在相应的驱动架构来进行驱动设备。 2、Linux 驱动框架 Linux下的设备驱动框架总结如下: 1. 加载(初始化)内核驱动:依赖于Linux内核的驱动模型,建立所需要操作的设备驱动并进行相应的操作。如下图: 2. 实现设备操作: 根据硬件设备的型号、功能特性等,实现驱动硬件设备正常工作,能够进行基本的操作,比如读取设备数据或者向设备写数据等。 3. 注销设备驱动: 在Linux系统中,会存在设备热拔插或者用户不想使用相应设备的应用场景,那么可以将相应的设备驱动在内核空间注销,将不能使用相应的设备驱动。 3、Linux 驱动API使用 对于Linux内核驱动而言,任何一种设备驱动模型都会用Linux内核中的一种结构来进行描述。对于字符设备确定而言,在Linux内核中使用struct cdev结构来描述。其结构原型如下: 【unsigned int count】:其表示设备的数目/数量,在同一个系统中,可能存在多个相同的设备,那么不需要每一个设备就为其提供一个驱动,而是统一提供同一个驱动,只需要在驱动中识别出是操作哪一个设备即可。Count结构成员的作用就是记录这一个驱动中存在多少个设备。 【dev_t dev】:表示这个设备的设备号,在Linux操作系统中,通过设备号的方式来进行区分不同是设备。 【const struct file_operations *ops】:设备驱动操作的函数集/方法集。这个方法集为上层应用程序提供相应的接口通道。实现用户空间的操作函数与内核空间的操作实现一一映射关系。 所以我们需要对所使用到的结构成员进行配置,驱动开发所使用到的结构成员分别为: 【unsigned int count】、【dev_t dev】、【const struct file_operations *ops】 (1)、分配设备cdev Cdev变量的定义可以采用静态和动态两种方法进行分配。静态方法直接分配内存,而动态方法随机分配内存。 静态分配cdev: 定义:struct cdev mdev; mdev即代表相应的字符设备空间地址。 动态分配cdev: 定义:struct cdev *pdev = cdev_alloc(); pdev即代表对于的字符设备的空间地址。 (2)、初始化设备cdev Linux内核中,字符设备struct cdev的初始化使用cdev_init。其原型如下: 参数: cdev:待初始化的struct cdev结构 fops:设备对应的操作函数集 由原型所要求的参数可知,需要初始化一个字符设备,必须根据申请一个struct cdev结构的空间,然后对其成员进行配置。即实现设备的操作函数集、为设备申请设备号(包括主设备号和次设备号)、指定此类型的字符设备有多少个相同设备。 (3)、注册设备cdev Linux内核中字符设备的注册使用cdev_add函数来进行完成注册。其原型如下: 其相关参数定义为: p:待添加到内核中的字符设备结构,即为struct cdev。 dev:设备号 count:该类设备的设备数量,各个设备的区别体现为从设备号。 在开发驱动时,当确定了字符设备的结构,主设备号和从设备号、设备的数量,就可以使用cdev_add函数将相应的字符设备添加到Linux内核驱动中进行注册。 (4)、硬件初始化 关于硬件的初始化就简单了。直接根据所需要操作的字符设备,阅读器Datasheet,然后根据Datasheet进行硬件的配置即可。 所以,对于不同的硬件,需要操作的硬件不一样,针对EVB-335x的硬件原理已经在上面讲过啦,各位请看上文。 从上图基本可知,在用户空间的每一种硬件设备操作函数,在内核空间通用有一个映射操作函数实现。 int (*open) (struct inode *, struct file *):打开设备,响应open系统 int (*release) (struct inode *, struct file *):关闭设备,响应close系统调用 loff_t (*llseek) (struct file *, loff_t, int):重定位读写指针,响应lseek系统调用 ssize_t (*read) (struct file *, char __user *, size_t, loff_t *):从设备读取数据,响应read系统调用 ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *):向设备写入数据,响应write系统调用 从以上函数指针操作方法中可以提取出两个重要的参数成员,即为struct file和struct inode。 【struct file】:在Linux系统中,每一个打开的文件,在内核中都会对应的关联一个struct file结构体,它由内核在打开文件时创建,在文件关闭后释放。 其非常重要的成员有: loff_t f_pos /*文件读写指针*/ struct file_operations *f_op /*该文件所对应的操作*/ 【struct inode】:每一个存在于文件系统里面的文件都会关联一个inode 结构,该结构主要用来记录文件物理上的信息。因此, 它和代表打开文件的file结构是不同的。一个文件没有被打开时不会关联file结构,但是却会关联一个inode 结构。 在struct inode结构中,dev_t i_rdev尤其重要,表示设备号。 4、手把手教你编写Linux驱动-实现LED操作控制 OK!经过上述的硬件、软件原理以及linux驱动框架等等的讲解,下面我们就开始动手写我们的第一个驱动程序,以LED为入门实操,实现Linux GPIO的操作实讲,以达到一通百通的目的。 首先,将上述的步骤总结一下: (1)、编写好linux驱动框架:包含相应的头文件;入口、出口函数;模块声明宏定义等; (2)、编写、完善file_operation结构体,包含相应的方法; (3)、完善相应的出入口函数:包括相应的硬件初始化,字符设备注册/销毁,IO口重映射等等。 (4)、完善file_operation结构体下具体方法的实现以提供给应用程序的调用等。 ——按照以上4个步骤,开始来编写我们第一个驱动程序: 第一步:编写好linux驱动框架:
|
|
相关推荐
10 个讨论
|
|
楼主写的真心不错,学习了,感谢楼主分享。
|
|
|
|
|
|
只有小组成员才能发言,加入小组>>
【盈鹏飞RK3399安卓主板 XPC-3399Pro免费试用】+烧写出厂固件
10187 浏览 0 评论
【盈鹏飞EVB-T335开发板试用体验】debian系统烧写
3217 浏览 1 评论
【盈鹏飞I.MX6UL工控开发板试用体验】linux can 测试
3150 浏览 0 评论
174浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-9-29 02:53 , Processed in 0.931302 second(s), Total 95, Slave 75 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号