简介openwifi 是一套基于 SDR 软件定义无线电、兼容 Linux mac80211 的全栈 IEEE 802.11/Wi-Fi 开源设计面向从事 FPGA 基带开发、无线通信协议研究及软件无线电实验的工程师与高年级学生帮助在 Zynq 平台上搭建可运行的 Wi-Fi 收发链路。资源包共 140 个文件约 8.7MB以 C 源码与头文件承载 Linux 驱动及 mac80211 接口Verilog 与 HLS 相关文件实现 FPGA 侧低 MAC 与基带处理另含设备树 dts/dtb、Makefile、shell 脚本、内核配置及少量 Python 辅助脚本覆盖从驱动编译到硬件描述的多层结构。设计支持 802.11a/g/n、20MHz 带宽与 70MHz 至 6GHz 频段在 FPGA 中实现 DCFCSMA/CA低 MAC 层并达到 10us SIFS同时提供 CSI 信道状态信息与 IQ 实时捕获能力通道访问优先级参数如 RTS/CTS、SIFS/DIFS、CW 等均可配置。目前已有 3418 人学习下载适合作为理解开源 Wi-Fi 基带与软硬件协同设计的实践参考。1. openwifi 到底在做什么把 Wi-Fi 基带塞进一块 FPGA 里如果你手里有一块 Zynq 开发板想从 PHY 层开始自己掌控 Wi-Fi 的每一个比特而不是被商用芯片的固件黑匣子挡在外面openwifi 就是目前少数能让你从 FPGA 寄存器一路看到空口帧的开源方案。它把 IEEE 802.11 的基带处理——OFDM 调制解调、前导码检测、信道估计、MAC 层时序——全部用 FPGA 逻辑实现跑在 Zynq 的 PL 端ARM 端跑 Linux 驱动和上层协议栈。换句话说你拿到的不是一块“配置好的 Wi-Fi 芯片”而是一套可以改、可以抓、可以注入的 SDR 基带参考设计。这套东西适合谁三类人一是做无线通信教学和科研的需要让学生看到真实空口波形和 MAC 帧交互二是做自定义无线协议的想在 802.11 帧格式基础上改字段、改时序、做私有控制帧三是做无线安全的需要在物理层和 MAC 层之间做帧注入和嗅探。不适合谁想拿它当家用路由器网卡用的趁早换方案——它的吞吐和稳定性跟商用芯片不在一个量级驱动成熟度也差得远。2. 从空口到寄存器openwifi 的收发链路怎么搭起来2.1 射频前端与基带的边界在哪里openwifi 的硬件架构里射频前端通常是一块 AD9361 或类似的 RFIC负责把 2.4 GHz 或 5 GHz 的模拟信号搬移到基带 I/Q 采样。FPGA 侧通过 LVDS 或 CMOS 接口拿到采样流采样率一般设在 20 MSPS 或 40 MSPS对应 20 MHz 或 40 MHz 信道带宽。这个边界很关键RFIC 的增益、本振频率、采样率一旦配错后面所有基带算法都白搭。我一般会先确认三件事RFIC 的参考时钟是不是锁在 FPGA 提供的时钟上I/Q 两路的直流偏置有没有校准采样率跟 802.11 的符号率是不是整数倍关系。20 MSPS 对应 20 MHz 信道一个 OFDM 符号 4 微秒短训练序列 8 微秒这些时序在 FPGA 里是用计数器硬连出来的改采样率就得同步改计数器分频比。2.2 FPGA 里跑的是哪些模块收发链路在 FPGA 里大致分四段发射侧是 MAC 帧组装 → 扰码 → 卷积编码 → 交织 → 映射 → IFFT → 加循环前缀 → 数字上变频接收侧反过来数字下变频 → 前导码检测 → 粗频偏估计 → 精频偏估计 → 信道估计 → 均衡 → 解映射 → 解交织 → Viterbi 译码 → 解扰 → MAC 帧解析。这些模块在 openwifi 里不是全部自己写的它复用了不少开源 IP比如 Xilinx 的 FFT IP 做 OFDM 调制解调自己写的主要是前导码检测状态机、信道估计器和 MAC 时序控制器。前导码检测是接收链路里最玄学的部分短训练序列做自相关长训练序列做互相关两个峰值的间隔和幅度比决定了一个帧是不是真的来了。阈值设高了漏帧设低了虚警这个参数得根据实际信道环境调。2.3 最小可跑通的步骤假设你手里有一块 Zynq-7000 系列开发板加 AD9361 射频子板想先把收发链路跑通大致步骤是第一步确认 FPGA 工程能综合出比特流。openwifi 的 FPGA 工程通常基于 Vivado打开工程后先看约束文件里的引脚分配是不是跟你的板子对得上。不对的话改 XDC 文件把 RFIC 的 SPI、LVDS、时钟引脚映射到实际管脚。第二步编译 Linux 驱动和用户态工具。ARM 端跑的是 PetaLinux 或类似发行版驱动模块负责把 FPGA 的寄存器映射到字符设备用户态工具通过 ioctl 或 sysfs 配置信道、增益、MAC 地址。# 在 ARM Linux 侧加载驱动模块 insmod openwifi_drv.ko # 确认设备节点出现 ls /dev/openwifi0 # 用用户态工具设置信道和带宽 ./wifi_tool -i openwifi0 -c 6 -b 20这里的-c 6是信道号对应 2.437 GHz 中心频率-b 20是 20 MHz 带宽。驱动收到命令后写 FPGA 的寄存器RFIC 的本振和采样率跟着变。第三步抓一个空口帧看看。用另一块商用网卡发一个 beacon 帧openwifi 侧开接收看能不能在用户态工具里打印出帧长度和 RSSI。# 开启接收模式打印收到的帧信息 ./wifi_tool -i openwifi0 -r -v # 预期输出类似 # RX frame: len128, rssi-45, rate6M如果一直没输出先查前导码检测的阈值寄存器再查 RFIC 的增益是不是太低。RSSI 在 -80 dBm 以下基本解不出来。2.4 参数怎么设几个必调的寄存器参数典型值作用调错后果采样率20 MSPS决定基带带宽跟信道带宽不匹配解调全错前导码检测阈值0.6~0.8自相关峰值门限高了漏帧低了虚警频偏估计范围±50 kHz粗频偏校正范围不够长训练序列对不齐发射增益根据 RFIC 定空口功率太高失真太低对方收不到MAC 重传次数3~7丢帧重传太小丢包太大延迟高这些值不是拍脑袋定的前导码阈值我一般从 0.7 开始试虚警多就往上加 0.05漏帧多就往下减。频偏估计范围跟 RFIC 的晶振精度有关普通晶振 ±20 ppm 在 2.4 GHz 上就是 ±48 kHz所以 ±50 kHz 是底线。3. 把 openwifi 跑起来从比特流到第一个管理帧3.1 硬件准备和引脚约束先确认板子和射频子板的组合。常见的是 Zynq-7000 系列加 AD9361但不同厂商的板子引脚定义不一样。拿到工程后第一件事是看 XDC 文件里set_property PACKAGE_PIN的管脚号跟原理图对不对。不对的话RFIC 的 SPI 配不通本振不工作后面全白搭。我一般会先用一个简单的 SPI 回环测试确认 FPGA 能跟 RFIC 通信往 RFIC 的某个只读寄存器写一个已知值再读回来对比。这个测试在 Vivado 的 ILA 里抓波形最直观。3.2 编译和烧录的完整命令# 在 Vivado 里综合、实现、生成比特流 vivado -mode batch -source build_bitstream.tcl # 生成的文件在 project.runs/impl_1/ 下通常是 system_wrapper.bit # 把比特流和 FSBL 打包成 BOOT.bin petalinux-package --boot --fsbl zynq_fsbl.elf --fpga system_wrapper.bit --u-boot # 烧到 SD 卡上电启动启动后串口会打印 Linux 内核日志看到openwifi_drv: probe success就说明驱动加载了。如果卡在Waiting for root device多半是 SD 卡分区或文件系统有问题。3.3 第一个管理帧的收发验证管理帧是 802.11 里最简单的帧类型beacon、probe request、probe response 都属于这一类。验证收发链路是否正常我一般先让 openwifi 发一个 probe request用商用网卡抓包看能不能收到。# openwifi 侧发送 probe request ./wifi_tool -i openwifi0 -t mgmt -s probe_req -d ff:ff:ff:ff:ff:ff # 商用网卡侧用抓包工具过滤 # 预期看到源 MAC 是 openwifi 的 MAC目的 MAC 是广播如果商用网卡抓不到先查发射增益是不是太低再查信道是不是跟抓包网卡一致。2.4 GHz 信道 1、6、11 是互不重叠的设成其他信道容易跟周围 AP 干扰。3.4 接收侧的解调验证接收比发射难调因为要处理真实信道里的多径和频偏。我一般会先用电缆直连两块板子把发射端和接收端用衰减器连起来排除空口干扰。这时候如果解不出帧问题就在基带算法本身不在射频。# 接收侧开调试模式打印每个阶段的统计 ./wifi_tool -i openwifi0 -r -d 3 # 输出会显示前导码检测次数、频偏估计值、信道估计 SNR、译码成功帧数如果前导码检测次数很多但译码成功帧数为零多半是信道估计或均衡出了问题。检查长训练序列的互相关峰值是不是够尖锐信道估计的导频插值是不是跟实际信道匹配。4. 避坑openwifi 调试里最容易翻车的五个地方4.1 前导码检测阈值设错帧全丢现象接收端统计里前导码检测次数为零或者偶尔有一两次但译码全失败。原因自相关峰值门限设得太高弱信号帧根本触发不了。或者短训练序列的延迟线长度跟采样率不匹配自相关峰位置偏移。解决把阈值从 0.7 降到 0.5 试同时用 ILA 抓自相关器的输出波形看峰值是不是在预期位置。采样率 20 MSPS 时短训练序列的周期是 0.8 微秒对应 16 个采样点延迟线长度得设成 16。4.2 频偏估计范围不够长训练序列对不齐现象前导码检测到了但信道估计的 SNR 很低均衡后星座图散成一团。原因RFIC 的晶振精度不够实际频偏超过估计范围长训练序列的两个重复符号相位差太大互相关峰分裂。解决先测 RFIC 的实际频偏用频谱仪看发射信号的中心频率跟标称值差多少。如果超过 ±50 kHz要么换晶振要么扩大频偏估计范围。扩大范围会增加计算量FPGA 资源不够的话得权衡。4.3 MAC 时序冲突收发撞在一起现象发射的时候接收链路也在工作两边抢 FPGA 的寄存器总线导致发射帧不完整或接收丢帧。原因openwifi 的 MAC 层是半双工时分复用的发射和接收不能同时开。如果驱动里没做好互斥或者用户态工具同时下了收发命令就会撞。解决在驱动里加互斥锁确保同一时间只有一个方向在工作。用户态工具加状态检查发射没完成之前不接受接收命令。4.4 信道估计导频插值跟实际信道不匹配现象低速率的帧能解高速率的帧全失败。原因802.11 的导频子载波间隔是固定的但信道变化快的时候简单的线性插值跟不上高频段衰减大的子载波估计误差大。高速率调制对信道估计精度要求更高所以先崩。解决把导频插值从线性改成二阶或基于 DFT 的插值代价是 FPGA 资源增加。或者降低发射速率先用 6 Mbps 跑通再往上加。4.5 驱动和 FPGA 寄存器版本不匹配现象驱动加载成功但一发命令就报Invalid argument或直接内核 panic。原因FPGA 比特流和驱动是分开编译的寄存器地址映射可能对不上。改了 FPGA 逻辑但没同步改驱动的头文件地址偏移就错了。解决把寄存器映射定义放在一个共享的头文件里FPGA 和驱动都引用同一个文件。每次改 FPGA 逻辑后重新生成头文件驱动跟着重编译。5. 进阶用 openwifi 做自定义帧注入和空口嗅探5.1 自定义帧注入的寄存器级操作openwifi 最值钱的地方是你能在 MAC 层和 PHY 层之间注入自己造的帧。标准 802.11 帧的 MAC 头是 24 字节但你可以改帧控制字段里的类型和子类型造出标准里没有的控制帧。具体做法是绕过驱动的帧组装逻辑直接往 FPGA 的发射 FIFO 里写原始字节。# 用调试工具直接写发射 FIFO ./wifi_tool -i openwifi0 --inject-raw --hex 08010000ffffffffffff001122334455 # 这串 hex 是帧控制字段持续时间目的MAC源MACBSSID # 注入的帧会跳过驱动的正常封装直接进基带发射链路注入的帧能不能被商用网卡识别取决于帧控制字段的合法性。类型和子类型设成保留值商用网卡会直接丢弃。想让它被处理得用标准里定义的类型但可以改里面的信息元素。5.2 空口嗅探的过滤和统计接收侧开嗅探模式FPGA 会把所有前导码检测成功的帧都往上传包括不是发给你的帧。这时候驱动的过滤逻辑很关键不然 ARM 端会被海量帧淹没。# 开嗅探模式只统计管理帧 ./wifi_tool -i openwifi0 -r --sniffer --filter mgmt # 输出会按帧子类型分类计数 # beacon: 120, probe_req: 45, probe_resp: 38, assoc_req: 3这个统计在排查干扰源的时候特别有用。如果某个信道的 beacon 数量异常多说明周围 AP 密集换信道比调参数更有效。5.3 验证方法用已知帧做回环测试改完基带逻辑后怎么确认没改坏我一般会做一个数字回环把发射链路的输出直接接到接收链路的输入绕过射频。发一个已知内容的帧看接收端解出来的字节是不是跟发的一样。# 开数字回环模式 ./wifi_tool -i openwifi0 --loopback digital # 发一个已知帧 ./wifi_tool -i openwifi0 -t mgmt -s probe_req -d aa:bb:cc:dd:ee:ff # 接收端打印解出的帧内容跟发送内容逐字节对比这个测试能排除射频和信道的影响直接验证基带算法的正确性。如果回环都解不对空口肯定更不行。5.4 一个我踩过的坑最早调接收链路的时候前导码检测一直虚警周围没有 802.11 信号也在报帧。查了两天才发现是自相关器的阈值寄存器位宽设错了实际写入的值比预期大了一个数量级。FPGA 里寄存器位宽和驱动里的数据类型对不上这种坑在软硬件协同设计里太常见了。后来我养成了一个习惯每个寄存器在驱动里定义的时候旁边必须注释位宽和复位值改 FPGA 逻辑的时候先看这个注释。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?