本帖最后由 3guoyangyang7 于 2016-4-4 00:08 编辑
这段时间真的很忙很忙,在调试的间隔,抽空把这篇文章发出来,其实这篇文章是在年后写的,一直都没有时间分享,今天觉得,不能再拖了就抽点空把它分享,希望能帮助更多人。支持的朋友点个赞,给个回复,也是小狂继续写下去的动力,这篇文章完事之后不知道什么时候能写下一篇,反正项目也快完事了,小狂会加快进度的,nanopi系列完事之后,小狂会分享最近项目使用的CC3200,会按照我的实现方式,一篇一篇的分享给大家,希望支持。谢谢各位。
哈哈,亲爱的朋友们,想死你们啦,过年好,小狂在这里祝大家新的一年里,学习进步,工作顺利,然后万事大吉,多玩板子,都变成大牛。 关于这篇帖子的内容其实年前就已经做好啦,由于要回家过年,加上到家后家里就一直忙所以就耽搁下了,今天特补上长贴一篇,希望大家看的开心,哈哈,当然看的爽了就给小狂点个赞,给点回复,让小狂在新的一年里更加有动力,去写更多的优秀贴,哈哈,在这先谢过各位看官的支持啦。 这篇贴子其实要说的东西很多,在这先做一下总结,其实说白了就是在进程中映射物理地址,所以首先要把物理地址映射到虚拟文件地址中去,映射完成后,按照s5p4418的UM写关于gpio的库函数,我是按照STM32的库样式来写的,本人比较喜欢那个样式所以就按照那个来了。所以这篇帖子将从三个方面细细道来,按照这篇帖子的内容来,我感觉下边其他的配置都是一样的。
一、物理内存重映射 1、基本概念 首先说说映射物理地址,其实就是mmap内存映射,我这里讲些概念性的东西然后分析分析代码,想了解的更详细可以去自行谷歌或者百度,有的是资料
Mmap内存映射,其实就是将物理内存映射到进程的虚拟地址空间中去,进程对文件的访问就相当于对内存的直接访问啦。先说几个基本的概念,①物理地址,就是你的nanopi2的实际的存储地址,比如RAM,ROM,FLASH这些存储设备的地址,②内核虚拟地址,这个是内核直接访问的地址,它与物理地址只有一个偏移量,③进程虚拟地址,这个是我们要用到的,这个地址位于用户空间,mmap的作用就是将物理地址映射到进程虚拟地址上,不是映射到内核地址上,而ioremap是将物理地址映射到内核虚拟地址上。 2、映射步骤 ①先用open系统调用打开文件,并返回文件描述符fd。 ②使用mmap建立内存映射,并返回映射首地址指针start。 ③对映射进行各种操作,在这里其实就是对nanopi2的寄存器进行操作 ④用mumap关闭内存映射 ⑤用close系统调用关闭文件fd。 3、调用函数的具体含义 头文件包含#include ①void *mmap(void *start, size_t length, intprot, int flags, int fd, off_t offset); 这个就是mmap的定义,现在把各个参数的含义列举如下 start : 映射区的开始地址。(一般建议为null,让内核帮我们自动寻找一个合适的地址) length : 映射区的长度。 prot:期望的内存保护标志,不能与文件的打开模式冲突。是以下的某个值,可以通过or运算合理的组合在一起:
PROT_EXEC //页内容可以被执行
PROT_READ //页内容可以被读取
PROT_WRITE //页可以被写入
PROT_NONE //页不可访问 flags:指定映射对象的类型,映射选项和映射页是否可以共享。它的值可以是一个或者多个以下位的组合体。 MAP_SHARED //与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。直到msync()或者munmap()被调用,文件实际上不会被更新。
MAP_PRIVATE //建立一个写入时拷贝的私有映射。内存区域的写入不会影响到原文件。这个标志和以上标志是互斥的,只能使用其中一个。(剩下的一些参数就不具体列出可以参考网上) fd:有效的文件描述词。 offset:被映射对象内容的起点。 return : 返回所映射的虚拟内存首地址。 ②int munmap(void *start, size_t length); 这个函数时内存释放函数,映射完成后应该及时释放内存。这些参数的具体含义同mmap的参数,这个释放函数还有一些返回值的含义,具体出现了可以百度,就不浪费篇幅写这个了,一般情况下是不会出问题的,当然出问题根据返回值查问题是一个好手段。 4、代码分析 下面我们就按照2中的步骤来映射地址 话说一个好的工程目录是一个工程的根本,所以先上一个工程目录的图片
Core 用来存放4418的核心,比如寄存器定义啊,地址映射啊,数据类型再定义啊啊 Lib用来存放各种库文件,现在加入的有gpio的,以后还会逐步添加 先分析物理地址映射的代码 首先头文件要包含
第一个是mmap所需头文件,然后打开文件指令第三个,得到页大小的函数在第二个里边,所以,头文件不能少,一定要包含 ①打开文件函数
打开正确返回文件符fd,打开错误提示打开错误,/dev/mem是物理地址的描述文件。 ②进行物理地址映射
输入为需要映射的物理地址,和相应的文件描述符 如果文件描述符为0返回-1,否则使用mmap进行机制映射,返回映射的虚拟地址。 NULL:起始地址为空,由系统自行分配 getpagesize():获取一页的大小,然后定义映射的页大小 PROT_READ......:可读可写可共享 Fd:打开的文件描述符 Baseaddr:需要映射的物理地址 ③释放内存
为了使用方便就把地址以上步骤定义到了一个函数中
这个是systermcore.c的全部内容,下边贴上systermcere.h的内容,供参考
Volatile的作用感兴趣的可以查一查我简单的说上一嘴,其实就是在操作寄存器的时候编译器起到一个保护的作用。一般寄存器的读写都要加上 这个就是内存映射的全部内容啦,下边一节讲4418的gpio的um怎么看 二、4418 gpio分析 玩硬件的最重要的是要学会看UM,就是用手手册,芯片寄存器的各个含义全在um里,所有的功能也都在里,无论是单片机,还是各种嵌入式,DSP,FPGA,这个都比较重要。所以希望让刚入门的打算走驱动开发的小伙伴们引起注意。下边我就简单分析一下4418GPIO的UM,我就大概说一下,具体的参考4418的um。 4418给出的功能有①输入操作②输出操作③io的复用功能 这是我用viso画的一个导图,所以可以很明白看到io的配置,包括输入输出啊,这些东西。 1、输入操作 使用输入操作,需要设置相应的GPIO替代函数选择寄存器,除此之外还需要设置gpio的输出使能寄存器GPIOXOUTENB。
可以选择输入的类型,通过使用GPIOXEVENTDETECTMODE寄存器,分别为高电平,低电平,上升沿,下降沿,GPIO EVENT DETECT MODE及窜起包含两个,具体的请看UM
上边是所有需要配置的寄存器,这个图很清楚的说明了问题,希望对小白有帮助吧。
2、输出操作
输出操作比较简单其实也不简单,这个是最基本的输出配置图,还有一些附加的配置比如
配置io的速度
配置io的驱动能力
配置GPIO的上拉电阻的选择。 4418的开漏输出是在特定的引脚上所以,具体配置可以参考UM 3、交替函数 说白了这个的功能就是引脚的复用,怎么说呢4418的引脚就那么多,但是想要实现更多的功能就要使用引脚复用,这个是芯片厂商惯用的伎俩,所以,不要被迷惑,举个例子说明
AC15的交替函数0的功能就是gpio,1的动能是i2s,同理可以看出各个引脚的功能,使用的时候根据自己的需求选择合适的交替函数就行。 整个的4418的GPIO的功能就这些,不明白的可以仔细阅读一下UM当然我个人感觉三星的UM不好,有些东西说的不详细。 三、库函数的编写 1、定义寄存器 编写库函数的第一步,我们是要先定义一下寄存器的地址
我们可以很清楚的看到,每个GPIO的基础地址
这是各个寄存器的偏移地址,所以我们只需要定义一个结构体就可以把所有的寄存器全部定义。看程序
这个定义的是没组GPIO的基础地址
这个是定义所有的寄存器,寄存器的定义是参考UM的寄存器的位数和种类定义的,因为结构体的变量的地址可以依次增加所以特别方便。
2、GPIO库的编写 编写库之前必须非常熟悉GPIO的功能,建议是一个功能一个功能的实现,不要一次性实现太多的功能,这样会导致错乱的风格是按照意法半导体STM32的风格编写的,直接看程序
定义所有的IO引脚
定义IO引脚的一些设置. GPIO_Pin:引脚号 GPIO_Speed:速度设置 GPIO_Alternate:交替函数设置 GPIO_DRV0:驱动力0设置 GPIO_DRV1:驱动力1设置
速度种类设置
IO功能设置
交替函数设置
驱动力设置 GPIO的初始化函数设置这一块比较多,详细的不做说明啦,不懂的可以回帖问,有问必答,直接贴代码啦
这个是gpio初始化的函数
GPIO设置高低电平的函数。当然啦我这里没有写输入,中断的gpio库,由于最近时间太紧张所以只能先实现gpio的输出功能啦,等以后有时间了会一一补上,如果有兴趣的小伙伴也可以自己写的,当然能够补全为人类做贡献那也是极好的,哈哈。 四、程序检验
先初始化GPIOB26引脚,然后拉高拉低,当然大家看到了我屏蔽了很多代码,为了测试函数的通用性,我测试了很多IO,这个是必须要有的,当然我一个人的能力有限,不能保证现在所有的代码没有一点问题,所以希望小伙伴们可以大胆尝试,错误都是试出来的。BUG都是改出来的。 编译没有错误后,利用scp把程序下载到开发板上然后连接逻辑分析仪测试是否正确,我们需要先看一下GPIOB26在是哪一个引脚
可以看到第12个引脚,我们接上
然后打开逻辑分析仪的软件 执行指令我的是这个
直接执行,一定要给root权限,因为要访问根目录下的设备节点,所以没有的话是访问不了的。
输入密码就会发现如下
证明我们的程序已经成功运行啦,至此,这篇帖子的内容已经全部完成啦,写到这很累,相信大家的眼睛也很累啦,写的好请给个支持,赞一下就行,写的不好请多多指教,有任何问题都可以以回帖的方式提问,我有时间的话肯定回答,谢谢各位看官的支持,要求不高只求回帖支持,您的支持是我写下去的最大东西。谢谢,下一帖写项目规划。再次感谢陪我一起成长的论坛。
小狂nanopi2系列其他帖子请见下面导航帖 https://bbs.elecfans.com/forum.php?mod=viewthread&tid=541781&page=1&extra=#pid4116358
|