Firefly开源社区

标题: golang实现GPIO控制 [打印本页]

作者: tjCFeng    时间: 2015-4-22 22:09
标题: golang实现GPIO控制
本帖最后由 tjCFeng 于 2015-4-23 17:33 编辑

    Go是Google开发的一种编译型,可平行化,并具有垃圾回收功能的编程语言。

    Go是有表达力、简洁、清晰和有效率的。它的并行机制使其很容易编写多核和网络应用,而新的类型系统 允许构建有性的模块化程序。Go编译到机器码非常快 速,同时具有便利的垃圾回收和强大的运行时反射。

   GO快速的、静态类型编译语言,但是感觉上是动态 类型的,解释型语言,易于编写。而且它的特点和C、pascal一样,可以编译为本地原生代码,生成的可直行文件可以直接拷贝到其他同种系统中运行,开发和运行效率都很高,甚至可以达到C语言的80%。


    在大概熟悉了go的语法后,打算在arm平台上尝试一下直接操作底层寄存器的开发,大体思路应该是一样的,但是go已经封装了很多功能,不能直接调用系统的API函数,如果调用的话需要通过嵌入C来实现。从网上找了几个例子看了下也是这样的。不过我还是不死心,进过两天的摸索,查看了相关的例子之后终于初步实现了寄存器的操作,可以算做是学习go的第一步吧。


    本次开发的环境是在Firefly-RK3288开发板的Lubuntu下进行的,直接编译为本地可执行文件。go的开发环境就不详细说明了,从github上下载源代码后直行all.bash可以自动完成安装。目前是1.4.2版本,修复了许多bug。

    以前用pascal封装过Allwinner A20的寄存器类库,估计go大同小异,都是先找到地址,映射到内存,再根据寄存器来赋值完成功能。

    不过一上来就给我难住了,首先是打开/dev/mem文件,返回的应该是个int的文件句柄,而go返回的是个结构体不能直接用。在查看了手册后发现,其中的Fd()是这个句柄,可以拿来使用,第一个问题解决。


    接下来就是映射内存地址了。先看原理图,找到需要用到的IO口


    板子上的WORK_LED是我要控制的,而它对应的是GPIO8_A1这个Pin,并且的高电平是关闭,低电平是点亮。

    这个GPIO8的地址是多少呢?从内核代码里和手册上都能找到



    物理地址是0xFF7F0000。在pascal中是要除以PAGE_SIZE来计算的,而到了go里,不知道是不是因为go把mmap封装了,这样调用不成功,很是奇怪,因为在c和pascal里都是这样的,没道理会改变吧。

    经过多次试验发现,这里是不能除PAGE_SIZE的,估计是跟go的封装有关。映射成功,稀里糊涂第二个问题解决,至少不报错了。


    在go里mmap之后返回的是一个数组,而不是一个指针,并且go的数组指针指向的并不是数组的首地址,所以不能直接对指针赋值来改变寄存器的值,而是直接对数组赋值达到这个效果。映射后的数组是8位的,为了和手一致,需要转换成32位的,经过学习(抄的代码:-)),又用到了unsafe类型,转换后可以打印出数组的内容了,看来第三个问题也解决了。



    赶紧来操作寄存器试一试,GOIO_A0是第0位,那么GPIO_A1理所当然是第1位了。所以直接对这个数组[1]进行赋1和清0,果然那个Work_LED能够控制了。




    大功告成,终于可以控制GPIO了。不过真的对吗?感觉有些地方想不通,手册里标明的第一个寄存器是高低电平,第二个是输入输出,那么我对着数组的[1]赋值算是什么呢?



    经过几次的调试,最后得到确认,数组的[0]才是对应的DR,[1]是DDR,因为数据已经从8位转换为32位了,所以数组[0]中的[1]才是我要控制的GPIO_A1,前面操作的原来是方向寄存器。

    到此才算基本搞清楚了go操作寄存器的方法。第一步至关重要,只要成功了后面的就好办了。



    附上go的全部程序,就是这么一点语句,折腾了两个晚上的时间。



作者: xmetoo    时间: 2015-4-23 08:59
恭喜楼主  底层控制又进一步
作者: tjCFeng    时间: 2015-4-23 12:09
xmetoo 发表于 2015-4-23 08:59
恭喜楼主  底层控制又进一步

没有又进一步,只是用go语言实现了一下,呵呵
作者: biiigfish    时间: 2015-5-14 14:52
弱弱的问一下,runtime是楼主自己做的?
作者: tjCFeng    时间: 2015-5-14 17:13
本帖最后由 tjCFeng 于 2015-5-14 17:14 编辑
biiigfish 发表于 2015-5-14 14:52
弱弱的问一下,runtime是楼主自己做的?

编译后,runtime已经包括在可执行文件中。
golang 是静态编译型的语言,即使从其他的arm linux编译的直接拷过来也能运行,不需要安装其他的东西。
作者: lalazou    时间: 2015-5-24 20:19
rk3288的寄存器手册,能否发我一份呢
2457254539@qq.com
tks
作者: tjCFeng    时间: 2015-5-24 21:03
lalazou 发表于 2015-5-24 20:19
rk3288的寄存器手册,能否发我一份呢

tks

我就是在论坛下的,Firefly已经共享不少了。http://developer.t-firefly.com/thread-686-1-1.html

作者: madman    时间: 2015-5-26 14:21
教程很好{:3_59:}
作者: tjCFeng    时间: 2015-5-27 06:32
madman 发表于 2015-5-26 14:21
教程很好

感谢支持:lol
作者: madman    时间: 2015-5-28 11:48
楼主,我想问下syscall.Mmap里面的4096参数是哪里来的?
作者: tjCFeng    时间: 2015-5-28 12:39
madman 发表于 2015-5-28 11:48
楼主,我想问下syscall.Mmap里面的4096参数是哪里来的?

4096是操作系统的分页大小,一般来说是4096,不过为了保险起见,在go中可以用os.Getpagesize()来获得。
这是个测试程序,我就直接写出来了:lol
作者: madman    时间: 2015-5-28 14:17
tjCFeng 发表于 2015-5-28 12:39
4096是操作系统的分页大小,一般来说是4096,不过为了保险起见,在go中可以用os.Getpagesize()来获得。
...

原来是这样,谢谢楼主:lol
作者: 可能已经注册    时间: 2017-8-23 10:15
楼主,你好,我用kernel4.4的话,使用go无法操作GPIO,但是PWM可以,不妨您试试。
作者: tjCFeng    时间: 2017-8-23 14:51
可能已经注册 发表于 2017-8-23 10:15
楼主,你好,我用kernel4.4的话,使用go无法操作GPIO,但是PWM可以,不妨您试试。

http://developer.t-firefly.com/f ... =1172&pid=47565
参考这个
作者: 可能已经注册    时间: 2017-8-23 16:38
tjCFeng 发表于 2017-8-23 14:51
http://developer.t-firefly.com/forum.php?mod=redirect&goto=findpost&ptid=1172&pid=47565
参考这个

那个帖子我回复过这个问题,GRF.go我已经配置过了,烧写kernel3.14就可以实现操作,但是烧写kernel4.4仍然不行。
作者: tjCFeng    时间: 2017-8-23 20:13
可能已经注册 发表于 2017-8-23 16:38
那个帖子我回复过这个问题,GRF.go我已经配置过了,烧写kernel3.14就可以实现操作,但是烧写kernel4.4仍 ...

跟内核没有关系,因为这个是直接操作寄存器的,没有通过驱动。




欢迎光临 Firefly开源社区 (https://dev.t-firefly.com/) Powered by Discuz! X3.1