
通过 HAT+ 规范标准 其中 EEPROM 作为 树莓派 HAT 标准的识别机制中的 ID EEPROM 按照标准存储下面这些板卡信息:

树莓派通过 VCore 的 bootloader(树莓派的一大逻辑黑盒)在启动过程中通过 I2C0 读取 ID EEPROM 内容进一步加载 dts overlay,kernel 会按照正常的 驱动模块去根据 compatible 结合 kernel 配置项 /usr/lib/modules/7.0.0-1010-raspi/modules.alias 去初始化 buildin 和 buildout 的驱动模块。
因此我特地找了下 sense hat 的 eeproom 内容 (没看到 dts overlay 的名字,所以说 bootloader 里面黑盒子逻辑让开发者膈应(双标))

在 rpi-sense-v2 overlay 中描述了 sensehat/display/joystick/lsm9ds1-magn/lps25h-press/hts221-humid/lsm9ds1-accel 这些设备信息, 里面重载了 i2c1 总线,包含上述设备的 i2c 地址。
下图是最新 树莓派 kernel 的 rpi-sense-v2.dts 内容:

通过这套 HAT 机制,通过插入 Sense HAT 开机,树莓派内核即可自动加载合适的驱动,做到即插即用以及多个 不同功能的 HAT 外设可以共同工作的效果。
通过 DTS 我们可以看到 除了 I2C 总线设备外, 额外有一个 rpi-sense-fb 和 sensehat-joystick 的设备,通过 kernel 源码可以找到对应驱动,这两个驱动其实是抽象了 TINY88 的 i2c 通讯后挂载的两个设备。
sensehat-joystick 驱动,它额外把 与 TINY88 连接的GPIO23 注册为按键中断,当中断到来时通过 与 TINY88 通讯获得按键键值后通过标准 input 设备上报按键。

rpi-sense-fb 驱动,通过注册 framebuffer 设备,提供 RGB LED matrix 的更新功能,当有数据要刷入时,通过与 TINY88 通讯批量写入buffer 数据。

这个 framebuffer 设备还额外提供了 三套 gamma (LUT)参数用于颜色矫正(RGB 分别5bit).

关键提示:git grep "Raspberry Pi Sense HAT" 以及 dts 中的 comptible 字段, 可以更快的找到驱动代码。
对此我也很好奇 TINY88 的源码, 于是找了下在(https://github.com/raspberrypi/rpi-sense), TINY88 使用汇编来完成 按键 和 LED 的刷新。
设备上确认了下, 状态的确一致:
与这块 hal 直接匹配的驱动模块有这些:
1. simple-mfd-i2c (Tiny88 MCU 对应的 i2c 设备,joystick 和 framebuffer 的父设备)
2. sensehat-joystick 以及 rpisense-fb
3. st_magn_i2c \ st_lsm6dsx_i2c 磁力计和加速度计
4. st_pressure_i2c 大气压计
5. hts221_i2c 湿度传感器
6. 通过额外的检索 我找到 颜色传感器的 驱动:tcs3472
驱动负责的是 初始化设备,中断,以及必要的资源(比如内存),提供 i2c 设备的抽象功能(比如i2c的info 以及子通讯节点的创建),提供 sysfs 相关debug 节点。
综上这完全体现的官方的 HAT 的优待,用户不用做额外的代码和配置修改, 只要用树莓派的 kernel 即可自动加载驱动,用户只要使用对应的上层工具或者 api 即可正常访问 HAT功能,很好的体现 dts 帮助内核灵活加载模块的优势。
设备初探
接下来我们来看下 i2c 设备获取各种传感器的数据:
下面是 i2c_tools 工具获得的 I2C 通道信息。

核对 dts 可以知道 I2C1 总线上各个传感器使用的地址 (我们不知道颜色传感器的地址)
Tiny88 =》0x46
9ds1的加速度传感器/陀螺仪 =》 0x6A
9ds1的磁力 =》 0x1C
压力传感器 =》 0x5C
湿度传感器 =》 0x5F
颜色传感器的地址是 =》0x39 (核对实际设备的地址, 可以知道 )
对于匹配到驱动的传感器设备,相关设备会上报的udev event事件:
通过命令触发:udevadm monitor 2>&1 |grep -i "3f804000.i2c"&;sudo udevadm trigger 2>&1

LED 矩阵和摇杆按键的使用
树莓派的内核驱动抽象出来 framebuffer , 通过 /dev/fb 用于更新 LED 矩阵,因此只要当作正常的 buffer 访问这块 内存即可更新显示数据。通常使用 fbset 工具去设置分辨率属性。这是我获取到的分辨率信息.
代表 这块 framebuffer 的宽高都是8,虚拟分辨率也是8x8 没有双缓冲, 16bit rgb 色彩。

摇杆按键因为时使用 标准的 input 来上报事件, 所以使用 libinput 自动的 libinput-debug-events(老版本是getevent) 可以实时打印按键上报状态。(可以留意到 keycenter 不是标准键值)。 
传感器的使用
我们已经知道了以上传感器都有各自在 linux 下的驱动,只是已有的 dts 中不包含颜色传感器 而湿度传感器默认是 disable,其次加速度传感器的 compatible 和 st_lsm6dsx_i2c 驱动不匹配,到没有对应的 iio 设备。
如果要使用官方的驱动,需要额外增加颜色传感器的 i2c 配置以及 enable 湿度计;
如果需要完全靠 用户态去做 I2C 通讯获得传感器数据则需要把相关驱动移除。
让我们看看内核中的驱动做了什么功能:
磁力计驱动(st_magn_i2c)和 气压计/温度计驱动(st_pressure_i2c)驱动以及 陀螺仪和加速度计驱动(st_lsm6dsx_i2c)和 颜色传感器驱动(hts221_i2c)与 颜色传感器驱动(tcs3472)都是使用I2C总线的 iio (Industrial I/O) 设备,因此可以通过 /sys/bus/iio/devices/iio:deviceX 和 /dev/iio:deviceX 来访问数据输出:
磁场传感器数据: /sys/devices/platform/soc/3f804000.i2c/i2c-1/1-001c/iio:device1/in*
压力传感器数据: /sys/devices/platform/soc/3f804000.i2c/i2c-1/1-005c/iio:device0/in*
或者通过 安装 libiio-utils 可以获得 iio_info 工具, 这个工具可以获取所有 iio 设备的信息。驱动文档参考,用户层编程库。iio 有个好处就是进一步抽象传感器,提供统一的数据和设置通道,同时可以通过 iiod 把本地的 iio 传感设备通过网络共享出去使用,也可以使用网络共享的 iio 设备。
由于 iio 设备占用了 i2c client,因此 会造成 i2c 设备在用户空间无法直接通讯。如果不想使用 iio 驱动转而使用 i2c 通讯,需要移除对应驱动:sudo rmmod st_magn_i2c st_pressure_i2c
注意: 通过开箱贴我们可以知道 sense-hat 的 python 库其实时直接使用 i2c 与设备通讯,而不是使用驱动提供的 sysfs,因此要想用户空间 通过 i2c 形式获取数据, 需要移除对应模块。
总结
总体而言,由于没有使用 树莓派 OS, 相关 dts overlay 比较老旧,虽然主线 kernel 已经包含所有传感器的 iio 驱动,但是无法直接用起来, 还需要更新 dts。而使用 iio 驱动 依旧需要 应用层去实现传感器数据的标定,特别是六轴传感器要用好,需要掌握惯性导航相关专业领域知识,以及线性代数相关空间矩阵逆解算能力(这都是我暂时不具备的)。
因此比较合适的方案是 移除当前匹配到的 iio 设备驱动,继续使用 sense-hat 最新版本提供的 python 接口来完成功能。
参考
官方 kernel 编译教程: https://www.raspberrypi.com/documentation/computers/linux_kernel.html#building
tiny88 控制LED 和 按键读取的源码:https://github.com/raspberrypi/rpi-sense.git
sense hat 里面 eeprom 数据以及 mcu 的源码:https://github.com/raspberrypi/rpi-sense
我要赚赏金
