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驱动移植,主要分三步:
- 确认硬件连接:SPI的MISO、MOSI、SCLK、CS引脚,必须和SX130x的对应引脚一一对应。别搞反了,我见过有人把MISO和MOSI接反,折腾了两天。
- 配置设备树:在Linux设备树(dts文件)中,添加SPI控制器节点和SX130x子节点。
- 编译并测试:用
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基站
好了,理论讲完了。咱们来走一遍实战流程:
- 编译系统:用Buildroot编译出带SPI驱动和网络功能的Linux系统。
- 烧录固件:把编译好的
sdcard.img烧录到SD卡。 - 启动系统:插入SD卡,上电。用串口或SSH登录。
- 测试SPI:运行
spidev_test -D /dev/spidev0.0 -s 16000000 -H,发送0xAA,看回读是否正常。 - 启动Packet Forwarder:
./packet-forwarder -c global_conf.json - 启动Lora Gateway Bridge:
./lora-gateway-bridge -c lora-gateway-bridge.toml - 验证:在云端查看基站是否在线,是否能收到上行数据。
注意: 我第一次部署时,Packet Forwarder启动后一直报SPI read error。查了半天,发现是SX130x的复位引脚没拉高。解决办法是在启动Packet Forwarder之前,先通过GPIO把复位引脚拉高,延时100ms再启动。
嗯,这一讲的内容就到这里。说白了,LoRa基站的软件架构并不复杂,但每一步都有细节。系统裁剪要“瘦”而不“弱”,SPI驱动要“稳”而不“快”,协议栈要“通”而不“乱”。
下一讲,咱们聊聊天线选型与射频调试——这可是决定基站覆盖范围的关键。到时候见。