Openwifi 开源项目解读(一)
1. Openwifi 项目概述与核心价值
1.1 Openwifi 到底是什么
Openwifi 是一个完全开源的 Wi-Fi 芯片实现项目,核心代码托管在 GitHub 的 open-sdr/openwifi 仓库里。它不依赖高通、博通、MTK 那类商用 Wi-Fi 芯片,而是用 FPGA 可编程逻辑加软件无线电的方式,从物理层到 MAC 层完整实现了 802.11a/g/n 协议栈。换句话说,别人用芯片实现的功能,Openwifi 把它写成 Verilog 和 C 代码,让你能自己编译、烧录、修改、观察每一个协议细节。
我第一次看到这个项目时,第一反应是不太相信——Wi-Fi 协议栈复杂程度业界公认,OFDM 调制解调、信道估计、加解密、ACK 时序、退避算法,任何一个环节都够折腾一阵子。但 Openwifi 确实做到了,而且不是停留在仿真层面,它可以在真实的 Zynq 开发板上跑起来,让手机、电脑通过它上网,也能作为终端去连接普通路由器。就冲这一点,它就配得上“硬核开源项目”这个评价。
1.2 为什么说它是“硬核”开源项目
很多人理解的“开源 Wi-Fi”其实是 Linux 下的开源驱动,比如 ath9k、iwlwifi 这些,它们只是把芯片的寄存器控制逻辑开源了,芯片内部的基带处理和 RF 收发仍然是一颗不透明的硬件。Openwifi 的不同之处在于,它把决定 Wi-Fi 性能的物理层信号处理也开源了,用 FPGA 逻辑实现,这是一条完全不同的技术路线。
具体来说,Openwifi 的工程分两大部分:FPGA 里面的设计负责 OFDM 收发、同步、信道估计、调制解调这类实时性极强的物理层功能,还有对时序要求极其苛刻的低层 MAC 功能;而运行在 ARM 处理器上的 Linux 系统则负责高层 MAC、协议管理、配置管理等不那么“硬实时”的任务。软硬件各管一摊,划分清晰。
这个项目的价值在于,它第一次让普通人可以用低成本的方式看到 Wi-Fi 通信的“内脏”。做无线通信研究的人,以前想拿一个信道的原始 CSI(信道状态信息)数据,得买专门的测试仪器,用 Openwifi 可以直接从 FPGA 侧把信道估计结果导出来,想做自定义 MAC 协议也可以直接改 Verilog,这种自由度是任何商用芯片都提供不了的。
1.3 适合哪些人关注和深入学习
如果你属于下面几类人,Openwifi 值得花时间折腾:
- 无线通信专业的研究生或高年级本科生,做物理层算法、MAC 协议、信号处理相关课题,需要一个开放的实验平台,而不是整天用 MATLAB 仿真自嗨。
- FPGA 工程师,想找一个真实、复杂、有完整协议约束的数字信号处理工程来练手,Openwifi 的工程规模、时序要求都远超市面上那些流水灯和简易 UART 例程。
- 软件无线电(SDR)爱好者,平时玩过 GNU Radio、USRP,想更进一步,挑战一个真正能和商用设备互通 OFDM 系统。
- Wi-Fi 协议栈开发者或测试工程师,需要摸清协议行为、做异常流量注入、验证兼容性。
当然,Openwifi 的学习曲线不低,需要同时具备 FPGA、Linux 驱动、无线通信三方面基础。但反过来讲,能把这三样串起来的人,在市场上相当稀缺。这篇文章先将整体框架讲清楚,后续再分模块深入。
2. 核心架构拆解:软硬件怎么分工
2.1 硬件选型的逻辑:Zynq 加 AD9361
Openwifi 最常用的硬件平台是 Xilinx Zynq-7000 系列 SoC 搭配 ADI(亚德诺)的 AD9361 射频收发芯片。Zynq 的特点是芯片里同时包含 ARM 处理器(PS 端)和可编程逻辑(PL 端),这正好匹配 Openwifi 的软硬件分工需求。ARM 端跑 Linux 和协议栈,FPGA 端跑物理层算法,两端之间通过 AXI 总线高速交互。
AD9361 是一个集成度很高的射频收发器,频率范围覆盖 70MHz 到 6GHz,带宽可以配置,正好覆盖 2.4GHz 和 5GHz 两个 Wi-Fi 频段。它集成了 ADC、DAC、混频器、滤波器,相当于把“天线之后到基带之前”这一大坨模拟电路全部封装进一颗芯片。AD9361 通过 LVDS 接口和 FPGA 交换数字 IQ 数据,速率非常高,一般的 SPI 接口根本扛不住。
我当时选平台时纠结过是买 ZedBoard 还是 ZC706。ZedBoard 便宜,但资源相对紧张;ZC706 性能强但价格贵。如果你是自己学习,ZedBoard 级别基本够用;如果实验室有预算,选择更高端的 Zynq UltraScale+ 平台会更从容。需要注意,不同板卡的工程配置不同,Openwifi 仓库里的 boards 目录针对多种板卡提供了现成脚本,选板卡时尽量选官方支持列表里的型号,否则移植工作量不小。
2.2 FPGA 里跑的是 PHY 和 low MAC
Wi-Fi 物理层的工作核心是 OFDM 调制解调,包括加扰、编码、交织、星座映射、IFFT、加循环前缀等一系列操作。接收端更复杂,需要做分组检测、频率偏移估计与补偿、符号同步、信道估计、均衡、解映射、Viterbi 译码等。这些信号处理任务对延迟和吞吐有硬性要求,必须用硬件流水线实现,这也是 Openwifi 选择 FPGA 做物理层的原因。
除了 PHY,FPGA 里还实现了一部分被称为 low MAC 的功能。为什么要把 MAC 层拆开?因为 Wi-Fi 协议里有些操作是微秒级时延要求,比如收到数据帧后要在 SIFS(短帧间间隔,16 微秒)时间内回复 ACK,这个时延如果经过 ARM 处理器和 Linux 调度,几乎不可能满足。所以 Openwifi 把这些“时间关键”的 MAC 功能放进 FPGA,例如 ACK 自动回复、退避计数器的硬件加速、帧校验和地址过滤等。
这种“low MAC 在硬件、high MAC 在软件”的划分,和许多商用 Wi-Fi 芯片的设计思路是一致的。商用芯片之所以把部分 MAC 做进硬件,也是因为软件处理无法满足时序要求。区别在于,商用芯片你改不了里面的逻辑,而 Openwifi 的 Verilog 代码就摆在那里,你可以改 ACK 回复策略,可以自定义退避参数,甚至实现一个完全非标的协议。
2.3 ARM Linux 上跑的是上层协议栈
ARM 端跑的是一套完整的 Linux 系统,Openwifi 在 Linux 里实现了一个标准网络设备驱动。从上层看,它就是一个普通的无线网卡,支持标准的 nl80211 接口。也就是说,Linux 自带的 hostapd 可以拿它开热点,wpa_supplicant 可以拿它连接 Wi-Fi 网络,上层应用完全不需要感知底层是商用芯片还是 Openwifi。
这里有个很妙的设计:Openwifi 的驱动注册给内核的是 mac80211 框架,mac80211 是 Linux 内核里的软件 MAC 层实现。一般情况下,mac80211 下面是芯片厂商提供的硬件驱动,负责和芯片固件通信;在 Openwifi 里,硬件驱动变成了一个“软硬结合”的驱动,它把 mac80211 要发的帧通过 DMA 送到 FPGA,同时从 FPGA 接收帧再送回 mac80211。对于上层协议栈,这一切是透明的。
这种架构带来的好处是,你不需要自己实现 802.11 的管理帧处理、关联认证流程、电源管理等复杂协议逻辑,Linux 内核已经把这些都做好了。你可以把精力专注在物理层算法、MAC 增强机制、CSI 采集等更有价值的事情上。这就是 Openwifi“巨人的肩膀”策略——协议栈复用内核,底层重写。
2.4 这套分工带来什么好处
一句话总结:性能和灵活性兼得。如果全用软件实现,像 GNU Radio 配合通用 SDR 硬件也能发送和接收 Wi-Fi 信号,但实时性和吞吐率很难保证,往往只能在离线场景下处理;如果全用硬件实现,像商用芯片那样,灵活性又大打折扣。Openwifi 的软硬件协同设计,恰好取了两者的优点。
从调试角度看,FPGA 内部有大量可观测的信号,你可以用 Xilinx 的 ILA(集成逻辑分析仪)抓取 PHY 内部任意节点的波形,这在真实通信场景中是极其宝贵的调试手段。我调试同步算法时,就曾经用 ILA 抓过接收端的相关峰值信号,直接看分组检测是否在正确的时间点上触发,这种“透视芯片内部”的能力是商用 Wi-Fi 平台完全不具备的。
当然,没有完美的方案。这套架构的代价是开发门槛高,FPGA 综合布局布线动辄几个小时,修改一次 PHY 算法从改代码到上板验证可能要半天。你需要适应这种“慢节奏”的开发模式。
3. 代码仓库结构与关键模块
3.1 仓库整体怎么看
Openwifi 的代码仓库结构第一次看会有点懵,目录很多,文件命名也比较随意。摸清规律之后其实很好找重点。主要的核心目录就几个:
- boards/:板级配置文件,针对不同开发板的引脚约束、时钟配置、FPGA 工程脚本都在这里。
- fpga/:FPGA 工程的全部 Verilog 源码,包括 PHY、low MAC、接口逻辑等。
- host/:Linux 端软件,包括内核驱动、用户态工具、配置脚本等。
- openwifi/:整个工程的顶层目录,汇总了各子模块的构建脚本和文档。
个人建议学习的顺序是先从 README 和文档入手,把项目背景和架构看懂,再进入 host 目录看驱动流程,最后才深入 fpga 目录看 Verilog。千万别一上来就钻进某个 .v 文件里,很容易被大量信号定义淹没。
3.2 FPGA 工程里的重点文件
FPGA 设计里有一个核心模块叫 openwifi_top,它是整个逻辑的顶层,负责把 PHY、MAC、射频接口、DMA、寄存器管理等子模块组织起来。从这个顶层模块出发,可以梳理出完整的数据通路。
物理层相关模块里,值得重点看的是 ofdm 相关模块,它们实现了 OFDM 调制解调的核心。发送方向包括加扰、FEC 编码、交织、QAM 映射、导频插入、IFFT、加 CP;接收方向则相应有分组检测、载波频偏估计、定时同步、信道估计、均衡、软解调、Viterbi 译码。这些模块用硬件描述语言实现时,大量使用流水线结构和定点数运算,和教科书里的浮点仿真实现有很大差别。
low MAC 部分最值得关注的是 ACK 生成逻辑和退避状态机。ACK 逻辑要求在收到正确数据帧后精确计时回复,硬件实现中用的是计数器驱动;退避状态机则是典型的有限状态机设计。如果你对“用 RTL 实现通信协议”感兴趣,这两个模块是绝佳学习材料。
值得特别注意的是,Openwifi 里还包含一个称为 side channel 的辅助通道,用于传输 CSI、信道质量等观测数据。这个侧通道的设计非常巧妙,它不干扰正常的用户数据通路,而是把物理层内部的信息以并行数据流的方式导出,供上层分析和可视化。这也是 Openwifi 能做 Wi-Fi 感知应用的基础。
3.3 host 目录里的软件栈
host 目录下的驱动程序是 Openwifi 和内核之间的桥梁。驱动需要完成几个关键任务:初始化 FPGA 的寄存器配置、分配 DMA 缓冲区、处理 mac80211 的回调函数、上报接收帧和统计信息。如果你熟悉 Linux 无线子系统,看这份驱动的实现会很有收获。
除了驱动,Openwifi 还提供了一些实用工具,比如可以查看无线状态的小工具、配置射频参数的命令行程序、以及从 FPGA 导出 CSI 数据到文件的程序。这些工具虽然代码量不大,但在调试和实验中特别有用。我建议你拿到源码后,先把这些工具用起来,再自己动手改代码。
4. 从零搭建 Openwifi 开发环境
4.1 硬件准备清单
想真正跑起来 Openwifi,你需要准备一套完整的硬件链路。首先是 Zynq 开发板,我用的是一块 ZedBoard,ARM 频率、FPGA 资源和接口都够用;其次是 AD9361 射频子板,通常可以选 ADI 官方的 FMComms2/3/4 系列评估板,通过 FMC 接口连接在 Zynq 板卡上。
天线方面,需要准备工作在 2.4GHz 或 5GHz 频段的天线,普通 Wi-Fi 用的 2.4G 天线就可以,注意接口要和 AD9361 子板匹配。此外还需要一张 MicroSD 卡装 Linux 系统、一个 JTAG 下载器(用于调试 FPGA)、以及若干杜邦线和串口线用于调试。整套硬件成本在几千到上万元,具体取决于板卡档次,对实验室来说是可以接受的投入。
4.2 编译环境与工具链
软件开发环境建议使用 Linux 系统,Ubuntu 18.04 或 20.04 都是不错的选择。需要安装 Xilinx Vivado 用于 FPGA 综合和布局布线,版本最好和 Openwifi README 建议的保持一致,避免版本差异导致 IP 核不兼容的问题。我这个项目当时用的 Vivado 2020.1 左右的版本,整体构建没有遇到大坑。
交叉编译环境也非常重要。因为目标平台的 ARM 处理器和你的 x86 开发机架构不同,Linux 内核、驱动、应用工具都需要用交叉编译器编译。Openwifi 文档中给出了详细的工具链安装步骤,核心是安装 arm-linux-gnueabihf 交叉编译器,并确保 PATH 环境变量正确。PetaLinux 工具也会用到,它用来生成能够在 Zynq 上启动的 Linux 镜像,不过如果你只是学习,有些基础镜像可以直接用现成的。
磁盘空间至少准备 100GB 以上,Vivado 安装加工程构建会占用大量空间。内存建议 16GB 起步,综合 FPGA 工程时如果内存不够,会出现卡死或直接失败的情况。
4.3 获取源码并构建 FPGA 工程
获取源码很简单:
git clone https://github.com/open-sdr/openwifi.git cd openwifi进入仓库后,先阅读 README 了解构建流程。构建 FPGA 工程的命令通常是一条 make 命令指向具体的板卡配置,例如:
make design BOARD=zedboard这条命令会调用 Vivado 以批处理模式运行脚本,完成从源码综合到生成 bitstream 的全过程。这个过程非常耗时,在普通电脑上可能需要一两个小时甚至更久,建议在性能较好的机器上运行,并且确保这期间电脑不要休眠。Vivado 综合时的 CPU 占用率会非常高,散热要做好。
构建完成后,会在输出目录生成 .bit 格式的 bitstream 文件,这就是 FPGA 的配置文件。之后还需要把它跟 ARM 端的可执行程序组合成一个完整的 BOOT.bin,用于开发板启动。具体步骤在文档里写得很详细,跟着做即可。
4.4 烧录与启动 Linux
将生成的 BOOT.bin、uImage(Linux 内核镜像)、devicetree、rootfs 等文件拷入 SD 卡的正确分区,设置开发板从 SD 卡启动。上电后通过串口连接开发板,可以看到 U-Boot 和 Linux 的启动日志。
启动成功后,需要确认 FPGA 是否加载了 Openwifi 的 bitstream。如果是通过 SD 卡启动时自动加载的,dmesg 应该能看到相关初始化信息;如果不是,可以通过 JTAG 或 /dev/xdevcfg 设备节点手动加载。这个环节容易出现各种启动异常,最常见的问题是设备树配置和实际硬件不匹配,导致外设无法识别。
Linux 起来之后,还要交叉编译 Openwifi 的内核驱动和用户态工具,并将它们部署到开发板的文件系统。Openwifi 文档中有专门章节介绍驱动编译,我用下来感觉最需要注意的是内核头文件版本必须和实际运行的 Linux 内核一致,否则驱动加载时会出现版本不匹配错误。
4.5 第一次运行 Openwifi
一切准备就绪后,可以先尝试最简单的功能——启动一个 AP 热点。通过 hostapd 配置一个开放网络,然后手机搜索这个热点并连接。这一步能通,就说明 Openwifi 的 PHY 和 MAC 已经正常工作了。
我至今记得第一次用 Openwifi 的 AP 让手机联网时的场景。手机显示连接成功的那一刻,还是有种“不可思议”的感觉——因为你知道,这背后从射频信号到 FPGA 处理到 Linux 协议栈再到 hostapd,整条链路都是你自己搭起来的。那一刻我觉得之前几天的折腾都值了。
如果想做更深入的实验,可以配置成 monitor 模式,用 Wireshark 抓取空口报文。由于 Openwifi 的 PHY 是开放的,抓到的报文甚至可以包含标准的 Wi-Fi 头之外的信息,这对分析协议行为很有价值。另外,CSI 导出功能也值得试试,把信道状态数据导出来用 Python 画频谱图,视觉效果很直观。
5. 常见问题与排查技巧
5.1 编译阶段典型报错
构建 FPGA 工程时最常遇到的问题是 Vivado 版本不符。老版本 Vivado 打不开新版本的 IP 核,反之亦然。遇到这类报错,最直接的办法是安装 README 里指定的版本,或者自己手动替换 IP 核配置。我不建议硬着头皮在一个版本上死磕,版本问题越早解决越省时间。
另一个高频报错是综合过程中内存不足,Vivado 直接崩溃或报“fail to synthesize”这类信息。解决办法是关闭其他大型程序,增大交换分区,或者换一台内存更大的机器。还有一个容易忽略的坑是路径问题——Vivado 对工程路径中的空格和中文很敏感,确保仓库路径完全由英文字符组成。
5.2 上板启动与驱动加载问题
启动阶段最常见的现象是 Linux 起来了但网络设备不存在。排查时先确认 FPGA 是否已经加载成功,检查电源是否给 AD9361 供电正确。可以用 iio 相关的工具查看 AD9361 的状态,如果设备节点不存在,往往是 SPI 通信失败,需要检查设备树配置。
驱动加载失败时,用 dmesg 查看内核日志。我看到过不少次是 DMA 缓冲区分配失败或者中断号冲突导致的。这类问题通常和内核配置有关,建议严格按照 Openwifi 文档中的内核裁剪选项来编译内核,缺少任何一个相关配置都可能导致驱动工作不正常。
MAC 地址问题也值得注意。如果多个 Openwifi 设备同时工作,默认 MAC 可能相同,需要手动为每个设备分配不同的 MAC 地址。这个原因导致的“网络不通”非常隐蔽,我第一次排查了很久才发现是 MAC 冲突。
5.3 无线链路与性能问题
如果你能连上 AP 但信号很差,先检查天线是否正确连接。AD9361 子板通常有两个射频通道,必须在天线接口连接天线或假负载,空载状态可能导致接收灵敏度下降甚至损坏前端。
吞吐率上不去的时候,可以从几个方向排查:确认是在 802.11n 模式还是 802.11g 模式,确认信道带宽配置是 20MHz 还是 40MHz,检查发射功率设置。Openwifi 作为一个开源实现,吞吐率本来就无法和商用芯片拼极限性能,但如果性能比预期差很多,多半还是配置问题。
CSI 数据抓取失败时,要确认是否启用了侧通道导出功能,以及主机端的接收程序是否正确运行。这项功能对时序要求敏感,建议先在短距离、弱干扰环境下验证。
5.4 问题排查速查表
| 现象 | 可能原因 | 排查手段 |
|---|---|---|
| Vivado 综合报错 | 版本不匹配、路径含中文 | 换版本、改路径 |
| 综合时崩溃 | 内存不足 | 增大内存或交换分区 |
| Linux 启动后无网络设备 | FPGA 未加载/设备树错误 | 检查 bitstream、设备树 |
| 驱动加载失败 | 内核配置缺失 | 用 dmesg 定位,检查内核选项 |
| AD9361 无法初始化 | SPI 通信失败 | 检查接线、电压、时钟 |
| 能连 AP 但互ping不通 | MAC 地址冲突/防火墙 | 手动设置 MAC,关闭防火墙 |
| CSI 无法导出 | 侧通道未开启 | 检查驱动选项和工具参数 |
| 吞吐率低 | 带宽/模式配置不当 | 检查信道宽度、速率配置 |
6. 我能拿 Openwifi 做什么
6.1 用于教学与科研的实验平台
Openwifi 最适合的场景就是大学实验室。无线通信课程如果只讲理论和仿真,学生很难建立直观概念;用 Openwifi 做实验,可以直接看到 OFDM 信号的频谱、星座图、信道估计结果,这是课本和 MATLAB 给不了的真实体验。
科研方面,Openwifi 在很多方向都有应用潜力。基于 CSI 的 Wi-Fi 感知是一个热门方向,通过分析信道状态信息的变化,可以做人体活动识别、呼吸检测、室内定位等应用。拿 Openwifi 采集 CSI 数据的质量和灵活性,明显优于那些被锁死的商用芯片方案。另外,如果你研究 MAC 层优化,比如新型退避算法、同步机制、低时延传输,也可以直接修改 FPGA 里的状态机进行验证。
6.2 基于 Openwifi 的二次开发方向
在 Openwifi 基础上做二次开发,有几个比较可行的方向。一个是物理层实验平台,你可以修改调制编码方式,甚至实现一个非标准的波形,然后观察它对吞吐和误码率的影响;另一个是抗干扰方向,通过自定义的频域滤波或干扰检测逻辑,研究 Wi-Fi 在复杂电磁环境下的表现。
还有一类有意思的应用是把 Openwifi 用在无人机或机器人的通信系统里。由于它支持灵活的定制能力,可以为地面站和无人机之间设计专用通信协议,实现测控和数传一体化。当然,这需要比较强的软硬件综合能力,适合进阶玩家挑战。
6.3 给新手的建议与后续学习路线
如果你刚接触 Openwifi,我的建议是分三步走:第一步,先不要改代码,按照文档把现有工程完整跑起来,确保 AP 模式、STA 模式、monitor 模式都能正常工作;第二步,通过学习 host 目录的代码,理解 openwifi 设备和普通无线网卡驱动的关系,学会用标准 Linux 命令控制和诊断设备;第三步,再进入 FPGA 工程,从替换一个参数开始,逐步修改和验证,建立软硬件联调的经验。
我个人在实际操作中的一个体会是:遇到问题不要急着在群里问,先自己看 dmesg、看 Vivado 日志、用 ILA 抓信号。这个“自己死磕”的过程虽然痛苦,但收获最大。Openwifi 这种项目没有太多现成的保姆级教程,大部分知识都要靠读代码和实验获得,而这恰恰也是它最大的价值所在。
下篇文章我打算深入解读 Openwifi 的 FPGA 物理层实现,重点讲 OFDM 同步模块的硬件设计思路,以及如何用 ILA 调试时序问题。想继续深挖这个项目的话,欢迎持续关注。