树莓派 4B 添加多个 SPI 设备

根据 BCM2711 引脚图[1][2]的设置,树莓派 4B 默认引出的 40Pin 可以添加多组 SPI 总线控制器:SPI3、SPI4、SPI0、SPI5 和 SPI1。默认情况下, SPI4 的 SCLK 和 SPI1 的 CE1_N 存在冲突。如果要启用多个 SPI,需要在内核启动时,加载对应的 Device Tree Overlay,仿照默认的 spi0-cs-overlay.dts[3],我们可以设置对应的多个 SPI 控制器。

我们首先修改默认的 SPI0,使得其只保留一条片选线,并用 dtc 命令编译:

/dts-v1/;
/plugin/;


/ {
        compatible = "brcm,bcm2835";

        fragment@0 {
                target = <&amp;spi0_cs_pins>;
                frag0: __overlay__ {
                        brcm,pins = <8>;
                };
        };

        fragment@1 {
                target = <&amp;spi0>;
                frag1: __overlay__ {
                        cs-gpios = <&amp;gpio 8 1>;
                        status = "okay";
                };
        };

        __overrides__ {
                cs0_pin  = <&amp;frag0>,"brcm,pins:0",
                           <&amp;frag1>,"cs-gpios:4";
        };
};
# compile
dtc -I dts -O dtb -o spi0-1cs.dtbo spi0-1cs.dts
# copy to boot partition
sudo cp spi0-1cs.dtbo /boot/overlays

树莓派的官方镜像已经提供了 SPI3,SPI4,SPI5 和 SPI1,我们只需修改 /boot/config.txt,注意,我们要取消注释默认的 spi=on

#dtparam=spi=on
dtoverlay=spi0-1cs
dtoverlay=spi3-1cs
dtoverlay=spi4-1cs
dtoverlay=spi1-1cs

同样,我们可以参考树莓派的默认 dts 编译多个 SPI 从设备描述,比如我根据位于 spi0.0 的 MCP2515 [4] 编译了 spi3.0spi4.0spi1.0 的 3个 CAN控制器,并同样修改 /boot/config.txt

dtoverlay=mcp2515-can0,oscillator=8000000,interrupt=24
dtoverlay=mcp2515-can3,oscillator=8000000,interrupt=25
dtoverlay=mcp2515-can4,oscillator=8000000,interrupt=26
dtoverlay=mcp2515-can1,oscillator=8000000,interrupt=27

查看 dmesg 日志,可以看到 4 个 MCP2515 控制器已经正常工作:

pi@raspberrypi:~$ dmesg | grep spi
[    4.387592] spi-bcm2835 fe204600.spi: no tx-dma configuration found - not using dma mode
[    4.391881] spi-bcm2835 fe204600.spi: chipselect 0 already in use
[    4.391898] spi_master spi3: spi_device register error /soc/spi@7e204600/spidev@0
[    4.391915] spi_master spi3: Failed to create SPI device for /soc/spi@7e204600/spidev@0
[    4.392332] spi-bcm2835 fe204800.spi: no tx-dma configuration found - not using dma mode
[    4.394967] spi-bcm2835 fe204800.spi: chipselect 0 already in use
[    4.394982] spi_master spi4: spi_device register error /soc/spi@7e204800/spidev@0
[    4.394999] spi_master spi4: Failed to create SPI device for /soc/spi@7e204800/spidev@0
[    4.419969] spi-bcm2835aux fe215080.spi: chipselect 0 already in use
[    4.419986] spi_master spi1: spi_device register error /soc/spi@7e215080/spidev@0
[    4.420005] spi_master spi1: Failed to create SPI device for /soc/spi@7e215080/spidev@0
[    5.351820] mcp251x spi0.0 can0: MCP2515 successfully initialized.
[    5.368085] mcp251x spi3.0 can1: MCP2515 successfully initialized.
[    5.379651] mcp251x spi4.0 can2: MCP2515 successfully initialized.
[    5.390782] mcp251x spi1.0 can3: MCP2515 successfully initialized.

[1] https://elinux.org/RPi_BCM2711_GPIOs
[2] https://www.raspberrypi.org/documentation/usage/gpio/
[3] https://github.com/raspberrypi/linux/blob/rpi-5.4.y/arch/arm/boot/dts/overlays/spi0-cs-overlay.dts
[4] https://github.com/raspberrypi/linux/blob/rpi-5.4.y/arch/arm/boot/dts/overlays/mcp2515-can0-overlay.dts

小米路由器4A千兆版 OpenWrt 19.07.2 稳定版固件

这个路由器用的 MT7621 的解决方案,性价比很高,然而它的 OpenWrt 正式版固件要到下一个正式版才有。虽然 snapshot 开发版也可以使用,然而笔者下载烧录并启动时不幸遇雷[1],想来想去还是 backport 一个正式版会比较好。

经过一番折腾,现把 patch[2] 和编译好带 luci 界面的 factory.bin[3] 分享于此。

小米很令人失望的锁了 U-Boot,必须使用编程器烧写,参考 [4],笔者用 CH341A 编程器读取出了整个 SPI 接口 Nor-Flash 内的内容,务必多次读取并校验这些文件均一致,做好备份,以防不测。接着修改读取出的文件中约 0x19690 处 off(0x6F 0x66 0x66) 为 ..5(0x00 0x00 0x35),并写回 Flash,这样在其启动的时候就能打断 U-Boot 并烧写上文编译好的固件了。

更新:出了一个 root 破解工具 [5],进入拿到 shell 之后可以直接 mtd 命令烧录 OpenWRT 固件。

使用 CH341A 读取路由器中的 Flash

[1] https://git.openwrt.org/?p=openwrt/openwrt.git;a=commit;h=fdfca33350150644481096f1c7a80db2b670cdec
[2] https://sharing-1252192454.cos.ap-shanghai.myqcloud.com/openwrt/mir4a-gigabyte/backport%20to%2019.07.2.diff
[3] https://sharing-1252192454.cos.ap-shanghai.myqcloud.com/openwrt/mir4a-gigabyte/openwrt-ramips-mt7621-xiaomi_mir3g-v2-squashfs-factory.bin
[4] https://forum.openwrt.org/t/xiaomi-mi-router-4a-gigabit-edition-r4ag-r4a-gigabit-fully-supported-but-requires-overwriting-spi-flash-with-programmer/36685
[5] https://github.com/acecilia/OpenWRTInvasion

USB-CAN 开发笔记

最近在接触 CAN 总线的开发,找了一圈 CAN 总线的适配器,某宝上全是各类坐地起价的分析仪。这类分析仪有个特点是在系统中呈现的形式为一个 USB 串口设备,其通信方式为厂家私有并不公开,集成开发的时候必须带上厂家的 .dll 或者 .so 文件。

经过一翻搜索之后,发现了一个以 Geschwister Schneider 制造的 USB/CAN 设备(VendorId: 0x1d50, ProductId: 0x606f)的 USB 通信协议为蓝本的开源方案。在 Linux 下以标准 SocketCAN 设备 [5] 呈现,驱动已经进入主线[1],在 Windows 下以 WCID 设备 [6] 呈现,开源 API 见 [2]。开源的硬件方案 [3],对应的固件 [4]。

在其基础上分叉出来的方案还有 [7],[8] 和 [9]。另外 SocketCAN 还有一个开源的 Golang 包 [10]。

[1] https://github.com/torvalds/linux/blob/master/drivers/net/can/usb/gs_usb.c
[2] https://github.com/HubertD/cangaroo/tree/master/src/driver/CandleApiDriver/api
[3] https://github.com/HubertD/candleLight
[4] https://github.com/HubertD/candleLight_fw
[5] https://www.kernel.org/doc/Documentation/networking/can.txt
[6] https://github.com/pbatard/libwdi/wiki/WCID-Devices
[7] https://store.linklayer.com/collections/frontpage/products/cantact-v1-0
[8] https://canable.io/
[9] https://github.com/codenocold/microbus
[10] https://github.com/linklayer/go-socketcan

腾讯云 EIP 直通设置

EIP 直通意思就是说虚拟机直接绑定公网 IP,启用的先决条件有两个:

(1)虚拟机在虚拟网络

(2)发工单申请 EIP 直通功能

在启用直通功能后,需要运行腾讯云提供的脚本 eip_linux.sh,然而有一个简单粗暴的方法。

(1)在 /etc/network/interfaces 直接设置静态 IP,address 跟 EIP,10.0.0.0/24 替换为所在子网

iface eth0 inet static
# replace with your EIP
address XXX.XXX.XXX.XXX
netmask 255.255.255.255
up ip route add 10.0.0.0/24 dev eth0
up ip route add default via 10.0.0.1 dev eth0
down ip route del default via 10.0.0.1 dev eth0
down ip route del 10.0.0.0/24 dev eth0

(2)设置 /etc/resolve.conf,比如上海联通的一组 DNS

nameserver 210.22.70.3
nameserver 210.22.84.3