3、LoRa基站软件架构:Linux系统裁剪、SPI驱动移植、LoRa网关协议栈

好,咱们进入第三讲。这一讲,说白了就是要把一个“能跑Linux的开发板”,变成一台“能收发LoRa数据的基站”。

我个人习惯把基站软件分成三层来看:底层系统硬件驱动上层协议。这三层缺一不可。你想想看,系统没裁剪好,跑起来卡顿;SPI驱动没移植对,SX130x芯片不干活;协议栈没配好,数据发不到云端。嗯,每一步都是坑。

3.1 Linux系统裁剪:给基站“瘦身”

为什么需要裁剪?因为商用基站不是开发板。开发板上跑个Ubuntu桌面版,2GB内存都不够用。但基站呢?256MB内存,甚至128MB,就得上线跑一年。

我建议用Buildroot或者Yocto来做系统裁剪。我个人更偏向Buildroot,原因很简单——配置直观,编译快,适合小团队快速迭代。

核心裁剪原则:

  • 只保留必要服务:sshd、ntp、lora-gateway-bridge、packet-forwarder。其他的一律砍掉。
  • 内核模块最小化:SPI驱动、GPIO驱动、网络驱动、USB驱动(如果需要)。别把整个内核的驱动都编进去。
  • 文件系统精简:去掉man手册、locale、不必要的库文件。我见过有人把整个gcc工具链都打包进固件,那简直是灾难。

我的经验: 我在项目中遇到过,第一次裁剪后系统启动只要8秒,但第二次加了几个调试工具后,启动时间飙到了30秒。后来我养成了习惯——每次添加一个包,就测一次启动时间和内存占用。

具体操作上,以Buildroot为例,你需要在make menuconfig里做几件事:

Target options  →  Target Architecture  →  ARM (little endian)
Toolchain  →  Enable C++ support  (如果网关程序是C++写的)
System configuration  →  Root filesystem overlay directory  →  /path/to/your/overlay
Kernel  →  Linux Kernel  →  Defconfig name  →  bcm2709_defconfig (以树莓派3为例)
Target packages  →  Networking applications  →  [*] openssh
Target packages  →  Hardware handling  →  [*] lora-gateway (如果Buildroot有现成包)

嗯,这里要注意:文件系统overlay目录是个好东西。你可以把编译好的网关程序、配置文件都放在这个目录里,Buildroot会自动打包进固件。这样你就不用每次手动拷贝了。

3.2 SPI驱动移植:让CPU和SX130x“对话”

LoRa基站的核心芯片——SX130x系列,是通过SPI接口和主控CPU通信的。所以,SPI驱动移植是重中之重。

为什么会这样?因为SX130x的数据吞吐量不小。8个通道同时接收,每个通道的IQ数据都要通过SPI传输。如果SPI驱动没配好,丢包、错包是家常便饭。

警告: 我曾经在项目中遇到过,SPI时钟频率设得太高(比如32MHz),结果SX130x返回的数据全是乱码。后来降到16MHz,一切正常。所以,不要盲目追求高速,稳定第一。

SPI驱动移植,主要分三步:

  1. 确认硬件连接:SPI的MISO、MOSI、SCLK、CS引脚,必须和SX130x的对应引脚一一对应。别搞反了,我见过有人把MISO和MOSI接反,折腾了两天。
  2. 配置设备树:在Linux设备树(dts文件)中,添加SPI控制器节点和SX130x子节点。
  3. 编译并测试:用spidev_test工具,发送已知数据,验证回读是否正确。

设备树配置示例(以树莓派3为例):

&spi0 {
    status = "okay";
    cs-gpios = <&gpio 8 1>;  // CS引脚,GPIO8

    sx130x: sx130x@0 {
        compatible = "semtech,sx130x";
        reg = <0>;
        spi-max-frequency = <16000000>;  // 16MHz,稳定
        reset-gpios = <&gpio 17 0>;     // 复位引脚
    };
};

编译好内核后,启动系统,用ls /dev/spidev*检查设备节点是否存在。如果能看到/dev/spidev0.0,说明驱动加载成功了。

避坑指南: 我曾经在调试SPI时,发现数据总是多一个字节。后来发现是CS片选信号的时序问题——SX130x要求CS在传输结束后保持高电平,但驱动默认是低电平。解决办法是在设备树里加上spi-cs-high属性。

3.3 LoRa网关协议栈:Packet Forwarder + Lora Gateway Bridge

好了,系统跑起来了,SPI也能通信了。接下来就是让基站“联网”了。这里有两个关键组件:

  • Packet Forwarder:负责和SX130x芯片直接通信,把收到的LoRa数据包转发到网络服务器。
  • Lora Gateway Bridge:负责把Packet Forwarder的数据格式转换成MQTT或HTTP,方便云端处理。

说白了,Packet Forwarder是“搬运工”,Lora Gateway Bridge是“翻译官”。

3.3.1 Packet Forwarder配置

Packet Forwarder的配置文件是global_conf.json。核心参数如下:

{
    "SX130x_conf": {
        "lorawan_public": true,
        "clksrc": 1,          // 时钟源,1表示使用内部TCXO
        "antenna_gain": 0,    // 天线增益,单位dBi
        "spi_dev_path": "/dev/spidev0.0",
        "spi_speed": 16000000
    },
    "gateway_conf": {
        "gateway_ID": "AA:BB:CC:DD:EE:FF:00:01",  // 唯一标识,建议用MAC地址
        "server_address": "127.0.0.1",             // 本地运行Lora Gateway Bridge
        "serv_port_up": 1680,
        "serv_port_down": 1681
    }
}

嗯,这里要注意:gateway_ID必须唯一。我见过有人把两个基站的ID设成一样,结果云端数据全乱了。建议用网卡的MAC地址来生成。

3.3.2 Lora Gateway Bridge配置

Lora Gateway Bridge的作用,是把Packet Forwarder的UDP数据,转换成MQTT消息,发送到云端(比如TTN、ChirpStack)。

配置文件lora-gateway-bridge.toml示例:

[integration.mqtt]
  server = "tcp://localhost:1883"
  username = ""
  password = ""
  qos = 1

[backend]
  type = "semtech_udp"
  udp_bind = "0.0.0.0:1700"  // 监听Packet Forwarder的UDP数据

[filter]
  gateway_ids = [
    "AA:BB:CC:DD:EE:FF:00:01"
  ]

关键点: 我建议把Packet Forwarder和Lora Gateway Bridge部署在同一台设备上。这样UDP通信延迟最低,而且不会因为网络问题导致数据丢失。如果非要分开部署,记得用有线网络,别用Wi-Fi——Wi-Fi的抖动太大,LoRa基站受不了。

3.4 实战:从零启动一个LoRa基站

好了,理论讲完了。咱们来走一遍实战流程:

  1. 编译系统:用Buildroot编译出带SPI驱动和网络功能的Linux系统。
  2. 烧录固件:把编译好的sdcard.img烧录到SD卡。
  3. 启动系统:插入SD卡,上电。用串口或SSH登录。
  4. 测试SPI:运行spidev_test -D /dev/spidev0.0 -s 16000000 -H,发送0xAA,看回读是否正常。
  5. 启动Packet Forwarder./packet-forwarder -c global_conf.json
  6. 启动Lora Gateway Bridge./lora-gateway-bridge -c lora-gateway-bridge.toml
  7. 验证:在云端查看基站是否在线,是否能收到上行数据。

注意: 我第一次部署时,Packet Forwarder启动后一直报SPI read error。查了半天,发现是SX130x的复位引脚没拉高。解决办法是在启动Packet Forwarder之前,先通过GPIO把复位引脚拉高,延时100ms再启动。

嗯,这一讲的内容就到这里。说白了,LoRa基站的软件架构并不复杂,但每一步都有细节。系统裁剪要“瘦”而不“弱”,SPI驱动要“稳”而不“快”,协议栈要“通”而不“乱”。

下一讲,咱们聊聊天线选型与射频调试——这可是决定基站覆盖范围的关键。到时候见。