作者:爪爪熊
链接:https://www.jianshu.com/p/0495c0554a63
來源:简书
之前将go语言的运行环境给搭建起来了,但是没有开始真正的试试Go 语言操作树莓派硬件的效果。
一、树莓派3B硬件介绍
树莓派3B采用了博通的BCM2837方案,而树莓派2采用的是博通的BCM2836方案,这两个方案 树莓派2采用32bit的 ARMv7指令集的 ARM Cortex-A7 内核,树莓派3B采用了 64bit的 ARMV8指令集的 AR Cortex-A53内核,看起来BCM2837似乎略胜一筹,毕竟升级到了64位处理器。一下是树莓派3B的样图:
树莓派3B.png
网上查阅了一圈资料,发现BCM2837的资料都没放出来,在官网上找到了一则说明:
This is the Broadcom chip used in the Raspberry Pi 3, and in later models of the Raspberry Pi 2. The underlying architecture of the BCM2837 is identical to the BCM2836. The only significant difference is the replacement of the ARMv7 quad core cluster with a quad-core ARM Cortex A53 (ARMv8) cluster.
The ARM cores run at 1.2GHz, making the device about 50% faster than the Raspberry Pi 2. The VideocoreIV runs at 400Mhz.
Also see the Raspberry Pi 2's chip BCM2836 and the Raspberry Pi 1's chip BCM2835
看样子官网说外设没差别,就核心换了一下,那大致可以认为外设包括I2C、GPIO、SPI、timer这些基本的东西都没有怎么变化才对。不过为了保险起见,还是查阅了相关文档。以下是树莓派3B GPIO引脚图。
树莓派3B 接口.png
对比一下树莓派2的相关引脚图:
树莓派2 接口.png
仔细查阅了下,这上面常用的GPIO,SPI,I2C,UART都提供了。这还算好,发现常用的PWM不见了,这可有点麻烦了,后面再继续研究PWM。
二、点亮LED灯
我们尝试下所有开发板的第一个例程,点亮LED灯。这里找寻了一会暂时觉得可以使用下 nathan-osman 大神的 go-rpigpio 库。
1
安装好了敲入以下代码:
1
保存并编译:
1
这时候我们在 GPIO2 和 GND 之间串上一个 LED 灯 和一个 1K的电阻,发现 LED灯已经开始以飞快的频率闪烁了。
前一小节通过了调用github上某位同道中人写好的库,实现了对GPIO的操作,这里从原理上分析如何操作 树莓派3B 的寄存器,也是从最简单的例子开始,点亮第二个LED灯。
所以我们现在的任务:通过操作寄存器的方式点亮第二个LED灯(板子上的第10脚,对应BCM.GPIO15,也是之前图中的RXD)。
BCM.GPIO15.png
三、分析下树莓派硬件寄存器
BCM2835数据手册
这里因为之前查阅了官网的说明,BCM2837 和 BCM2835 在外设这一块是没有变化的,所以我们可以直接参考 BCM2835 的数据手册。我们直接翻阅到 89 页左右,这里就是我们的目标了,GPIO 主要在第六章,这里找到下面这个表格:(图片部分截取)
寄存器地址.png
可以看到在芯片地址中 GPIO 主要分布在 0x7E200000 这个地址往后走的一部分,最大的地址是 0x7E200B0。我们接着查阅芯片手册中关于每个寄存器作用。最后确认下来,如果我们要点亮那个LED灯,需要将 BCM.GPIO15设置为输出,且输出一个高电平就可以了。通过找寻寄存器对应的区域,判断到需要将下面图2中15位设置为1(BCM.GPIO15设置为输出模式)。
GPIOAFSR1.png
进一步设置中需要对输出寄存器相关位进行赋值,可以将 BCM.GPIO15 设置为高,也就是下图3中寄存器相关位。
GPSET0.png
当时设置了输出位为高电平可以点亮LED灯,同时也需要输出位为低电平以关闭LED灯,也就是下面图4这个寄存器。
GPCLR0.png
了解清楚我们要操作的寄存器后,我们需要进一步确定这个地址到底是多少,通过手册第5页 图5 我们可以看出实际上ARM的MMU把上面的 0x7E200000 这种实际地址映射到了0x20000000 到 0x40000000 这个地址上去,但是具体地址是多少也不是很清楚,这里就去找到了文档 bcm2835 的c语言程序找寻蛛丝马迹。后来发现了可以通过读取 /proc/device-tree/soc/ranges 找到具体的外设地址和范围,按照实际的偏移进行映射就可以使用了。
地址映射图.png
四、实战
经过了上面一圈的查资料、分析,发现思路越来越明朗了,这里就开始这几实战了。Go 语言对于指针操作会比C语言要求更为严格一点,也没有宏定义可以使用,这里就直接定义到const中。
1
本文源码地址参见 github
版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢。
Golang语言社区
ID:Golangweb
www.bytedancing.com
游戏服务器架构丨分布式技术丨大数据丨游戏算法学习