ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

hi3516cv610移植AIC8800D80 USB WiFi驱动实战

hi3516cv610移植AIC8800D80 USB WiFi驱动实战 1. 项目背景与整体设计思路1.1 为什么要在hi3516cv610上折腾AIC8800D80hi3516cv610这颗SoC在视频编解码和边缘视觉设备里出场率很高低功耗、ISP能力够用、外围接口也齐全很多做智能门禁、网络摄像头、工业视觉模组的团队都拿它当主力平台。但原厂SDK默认的无线方案往往只覆盖了少数几款芯片一旦项目需要双频WiFi或者对吞吐、并发有更高要求就得自己动手换模组。AIC8800D80是近几年在嵌入式圈子里被讨论得比较多的一款USB WiFi蓝牙二合一芯片支持2.4G/5G双频USB2.0接口Linux驱动开源程度相对友好成本也压得住所以把它移植到hi3516cv610上就成了一件很实际的事。这个项目的核心目标很明确让hi3516cv610的Linux系统能够识别AIC8800D80这个USB设备加载正确的驱动完成固件下载最终把wlan0和蓝牙设备节点都拉起来能正常扫描、连接、跑通数据通路。听起来就是“插上去、装驱动、能上网”三步但真正做过USB无线驱动移植的人都知道这里面涉及内核配置、USB枚举、固件路径、电源管理、时钟同步等一堆细节任何一个环节对不上设备就是认不到或者认到了也起不来。适合看这篇内容的人应该是已经有一定嵌入式Linux基础、能独立编译内核和根文件系统、手里有hi3516cv610开发板和AIC8800D80模组的工程师。如果你刚接触这块建议先把内核配置和USB子系统的基本概念过一遍不然下面有些操作你会知其然不知其所以然。1.2 整体方案选型与设计考量移植USB WiFi驱动摆在面前的路其实有几条。第一条是直接用芯片原厂提供的驱动包通常是一个独立的ko文件加一堆配置脚本编译进内核或者做成模块加载。第二条是走内核自带的mac80211框架把芯片驱动适配到标准cfg80211接口上。第三条是找社区已经移植好的版本改改就能用。AIC8800D80的情况比较特殊它的官方驱动是基于mac80211框架写的但同时又依赖一个独立的USB传输层和固件加载机制。所以实际做法是把官方驱动源码拿到手针对hi3516cv610的内核版本做适配编译生成aic8800_fdrv.ko和aic8800_bsp.ko两个模块再配合固件文件放到指定目录最后通过insmod顺序加载。这个方案的好处是改动量可控不需要动内核核心代码出问题也容易回退。为什么不用内核自带的驱动因为hi3516cv610的SDK内核版本通常是4.9或者5.10这个版本段的内核里根本没有AIC8800D80的驱动社区补丁也不完整。自己从官方驱动适配是最稳妥的路。另一个考量是USB接口的兼容性hi3516cv610的USB控制器是DWC2或者类似IP对USB2.0全速和高速设备支持没问题但枚举过程中的一些时序细节需要确认否则会出现设备反复插拔或者枚举失败的情况。整体设计上我把工作拆成四块内核配置与编译环境准备、驱动源码适配与编译、固件部署与加载脚本、上电验证与问题排查。这四块是递进关系前面没做对后面一定出问题所以每一步都要验证到位再往下走。2. 内核配置与编译环境准备2.1 确认内核版本与USB子系统配置动手之前第一件事是确认你手上的hi3516cv610 SDK内核版本。进到内核源码根目录执行make ARCHarm CROSS_COMPILEarm-himix200-linux- kernelversion或者直接看Makefile开头的VERSION和PATCHLEVEL。这个信息决定了你后面拿哪个版本的AIC8800D80驱动来适配。官方驱动一般会标注支持的内核范围比如4.9到5.15跨大版本适配的工作量差别很大。确认版本后进入内核配置界面make ARCHarm CROSS_COMPILEarm-himix200-linux- menuconfig需要重点检查的配置项有这么几个。USB支持是基础CONFIG_USB_SUPPORTy必须开。主机控制器驱动里CONFIG_USB_DWC2y或者对应的平台USB控制器要选上hi3516cv610一般用的是DWC2。USB设备文件系统CONFIG_USB_DEVICEFS可以不开但CONFIG_USB_GADGET如果不用OTG功能也可以关掉减少干扰。网络协议栈这边CONFIG_NETy、CONFIG_WIRELESSy、CONFIG_CFG80211y、CONFIG_MAC80211y这几个是必须的。AIC8800D80驱动依赖mac80211框架如果这个没开编译驱动时会报一堆符号找不到的错误。另外CONFIG_CFG80211_WEXTy建议打开方便用iwconfig这类老工具调试。固件加载机制也要确认CONFIG_FW_LOADERy和CONFIG_FW_LOADER_USER_HELPERy最好都开这样驱动可以通过request_firmware接口从用户空间加载固件文件。有些SDK默认只开了前者导致固件加载失败但又不报明显错误排查起来很费时间。注意修改内核配置后一定要保存到defconfig或者你当前使用的配置文件名否则下次编译又回到默认状态。建议用make savedefconfig生成精简配置再对比。2.2 编译工具链与内核模块编译选项hi3516cv610的官方工具链一般是arm-himix200-linux-系列交叉编译器路径要加到环境变量里export PATH$PATH:/opt/hisi-linux/x86-arm/arm-himix200-linux/bin export CROSS_COMPILEarm-himix200-linux- export ARCHarm验证工具链能用arm-himix200-linux-gcc -v能看到gcc版本信息就对了。这里有个坑不同版本的SDK可能用不同的工具链比如有的用arm-himix100有的用arm-himix200混用会导致编译出来的ko文件在板子上加载时报“invalid module format”。所以一定要用SDK自带的工具链不要图省事用系统自带的gcc。内核模块编译选项方面CONFIG_MODULESy必须开否则没法编译ko文件。CONFIG_MODULE_UNLOADy建议开方便调试时卸载重载。CONFIG_MODVERSIONS如果开了驱动编译时也要对应处理否则会出现版本魔术字不匹配的问题。实际项目中我一般把这个关掉减少不必要的麻烦。编译内核模块前先确保内核已经编译过一次因为驱动编译需要内核的Module.symvers和头文件。执行make ARCHarm CROSS_COMPILEarm-himix200-linux- uImage -j8 make ARCHarm CROSS_COMPILEarm-himix200-linux- modules -j8编译完成后内核源码目录下会有Module.symvers文件这个文件在编译外部驱动时会被引用用来做符号校验。2.3 USB控制器与电源管理相关配置hi3516cv610的USB控制器在设备树里的配置直接影响AIC8800D80能不能被识别。需要确认设备树中USB节点的status是“okay”dr_mode是“host”或者“otg”。如果是otg模式还要确认ID引脚的电平检测是否正常否则可能默认进不了host模式。电源管理这块CONFIG_PMy和CONFIG_PM_SLEEP如果开了USB设备的运行时电源管理可能会在空闲时把设备挂起导致WiFi断流。调试阶段建议先关掉CONFIG_USB_SUSPEND等驱动稳定后再按需开启。另外CONFIG_USB_ANNOUNCE_NEW_DEVICESy可以打开这样插入USB设备时内核日志会打印设备描述符信息方便确认枚举是否成功。还有一个容易被忽略的点是USB PHY的配置。hi3516cv610的USB PHY可能需要额外的时钟或者复位控制这些通常在设备树或者uboot里已经配好了但如果你用的是自制板就要仔细核对原理图和设备树是否一致。我遇到过因为PHY复位引脚没拉对导致USB设备时认时不认的情况最后查了两天才发现是硬件上拉电阻的问题。3. AIC8800D80驱动源码适配与编译3.1 驱动源码获取与目录结构梳理AIC8800D80的驱动源码一般从模组厂商或者芯片原厂获取拿到手通常是一个压缩包解压后目录结构大致如下aic8800/ ├── drivers/ │ ├── aic8800_fdrv/ # 主驱动实现mac80211接口 │ ├── aic8800_bsp/ # 板级支持负责USB传输和固件加载 │ └── aic8800_btlpm/ # 蓝牙低功耗相关 ├── firmware/ │ ├── aic8800D80/ # 固件文件 │ └── ... ├── include/ └── Makefile核心是aic8800_fdrv和aic8800_bsp两个目录。fdrv是功能驱动注册到mac80211框架处理扫描、连接、数据收发。bsp是总线驱动负责USB设备的枚举、端点配置、固件下载。两者通过导出符号互相调用所以加载顺序不能错必须先加载bsp再加载fdrv。固件目录里一般有多个文件比如fmacfw.bin、fmacfw_rf.bin、fw_patch_table.bin等不同版本的文件名可能略有差异。这些文件最终要放到板子的/lib/firmware/aic8800D80/目录下驱动启动时会通过request_firmware去加载。3.2 针对hi3516cv610的内核适配修改官方驱动通常是在x86或者较新的ARM内核上开发的直接拿到hi3516cv610的4.9或5.10内核上编译大概率会报错。常见的适配点有这几类第一类是内核API差异。比如cfg80211_scan_done的回调参数在不同内核版本里不一样4.9内核里是struct cfg80211_scan_info更早的版本可能是直接传aborted标志。这种要对着内核头文件改。第二类是USB接口API变化。usb_control_msg的参数顺序、usb_bulk_msg的超时单位、usb_submit_urb的GFP标志等在不同版本间有细微差别。编译报错时根据提示逐个改就行。第三类是并发和锁机制。新内核里mutex和spinlock的用法更严格有些驱动里用了init_MUTEX这种老接口需要改成mutex_init。第四类是设备树匹配。如果驱动里写死了USB的vendor id和product id要确认和实际模组一致。AIC8800D80的VID/PID常见的是0x368B/0x8D80但不同批次可能不同用lsusb或者内核日志确认。我一般会先直接编译一遍把报错信息收集起来按类型批量改。改完后用make -C /path/to/kernel M$PWD modules编译确认生成aic8800_bsp.ko和aic8800_fdrv.ko。提示适配过程中建议用git管理源码每改一类问题提交一次方便回退和对比。驱动源码动辄几千行改乱了很难恢复。3.3 编译参数与Makefile调整驱动的Makefile里通常有KERNELDIR变量指向内核源码路径编译前要改成你实际的路径KERNELDIR ? /home/user/hi3516cv610/sdk/linux-4.9.y PWD : $(shell pwd) CROSS_COMPILE ? arm-himix200-linux- ARCH ? arm编译命令make -C $(KERNELDIR) M$(PWD) ARCHarm CROSS_COMPILEarm-himix200-linux- modules如果驱动分多个目录顶层Makefile里会有obj-m aic8800_bsp/这样的写法确保两个模块都被编译到。编译过程中常见的警告可以忽略但错误必须解决。有一类错误是“unknown symbol”说明依赖的内核符号没有导出需要在驱动里用EXPORT_SYMBOL导出或者调整加载顺序。另一类是“section mismatch”通常是函数定义和引用不在同一个段里改一下__init和__exit标注就行。编译成功后用modinfo检查ko文件arm-himix200-linux-objdump -h aic8800_bsp.ko确认有.text、.data、.bss等段并且没有“no symbols”的警告。4. 固件部署与驱动加载脚本4.1 固件文件放置与权限设置固件文件要放到板子根文件系统的/lib/firmware/aic8800D80/目录下。这个路径是驱动里写死的或者通过模块参数指定。如果根文件系统是只读的要提前在制作镜像时就把固件打包进去。文件权限一般是644属主root。如果驱动以非root用户加载要确保该用户对固件文件有读权限。实际项目中我遇到过因为固件文件权限不对驱动加载时报“firmware request failed”但又不提示具体原因的情况后来用strace跟踪才发现是权限问题。固件文件列表要核对清楚缺一个都可能导致驱动初始化失败。常见的文件有文件名作用fmacfw.bin主固件fmacfw_rf.bin射频校准固件fw_patch_table.bin补丁表aic8800D80_bt_fw.bin蓝牙固件不同版本的驱动可能要求不同的文件名以驱动源码里的request_firmware调用为准。4.2 模块加载顺序与依赖处理加载顺序必须是先bsp后fdrvinsmod /lib/modules/aic8800_bsp.ko insmod /lib/modules/aic8800_fdrv.ko如果fdrv依赖bsp导出的符号顺序反了会报“unknown symbol”错误。可以用modprobe配合depmod自动处理依赖但嵌入式环境里depmod不一定有手动insmod更直接。加载bsp后用dmesg看日志应该能看到USB设备枚举成功、固件下载完成的提示。如果看到“aic8800_bsp: probe success”之类的信息说明bsp这一层通了。然后再加载fdrv看是否注册出wlan0接口。可以用lsmod确认模块加载状态用ifconfig -a或者ip link看有没有wlan0。如果wlan0没出来先检查fdrv的加载日志常见原因是固件没加载成功或者mac80211注册失败。4.3 上电自动加载与稳定性优化调试阶段手动insmod没问题后可以做成开机自动加载。在/etc/init.d/rcS或者systemd的service文件里加insmod /lib/modules/aic8800_bsp.ko sleep 1 insmod /lib/modules/aic8800_fdrv.ko中间加个sleep是为了等bsp完成固件下载和USB端点配置不加的话fdrv可能在bsp还没准备好时就加载导致初始化失败。这个延时根据实际硬件情况调整一般1秒够了慢的板子可能要2秒。稳定性优化方面可以在驱动加载参数里关掉一些调试日志减少串口输出压力。另外如果板子USB供电不稳可以在硬件上加个电容或者在软件里调整USB PHY的驱动能力。我遇到过WiFi跑大流量时USB断连的情况最后发现是电源纹波太大加了个100uF电容就稳了。5. 常见问题与排查技巧实录5.1 USB设备识别不到怎么办这是最常见的问题现象是插入模组后dmesg没有任何USB枚举日志。排查思路从硬件到软件逐层往下先确认模组供电正常用万用表量USB接口的5V和3.3V。然后确认USB差分线没有接反D和D-对调是低级错误但确实有人犯。再看设备树里USB控制器的status是不是“okay”dr_mode是不是“host”。软件层面用lsusb看能不能列出设备。如果lsusb能看到但驱动不认说明VID/PID不匹配要在驱动里加对应的id_table。如果lsusb也看不到检查内核里USB主机控制器驱动有没有加载ls /sys/bus/usb/devices/看有没有设备节点。还有一种情况是USB设备被识别到了但反复断开重连这通常是供电不足或者信号完整性差。可以试着降低USB速度到全速模式在设备树里把maximum-speed改成“full-speed”试试。5.2 固件加载失败排查固件加载失败的表现是bsp加载后dmesg报“firmware request failed”或者“load firmware timeout”。先确认固件文件路径和文件名对不对用ls -l /lib/firmware/aic8800D80/看文件在不在、权限对不对。如果文件没问题检查内核的CONFIG_FW_LOADER有没有开以及/sys/class/firmware/目录是否存在。有些精简根文件系统里没有这个目录需要手动创建。还有一种情况是固件文件本身损坏比如传输过程中被截断。用md5sum对比一下源文件和板子上的文件。我遇到过因为用ftp传输时没设二进制模式固件文件被转成了文本模式大小变了驱动加载当然失败。5.3 WiFi能识别但连不上或断流wlan0出来了但扫描不到AP或者连上就断这类问题通常和射频校准、电源管理、天线有关。先确认射频固件fmacfw_rf.bin加载成功没有这个文件射频参数不对信号会很差或者根本发不出去。电源管理方面关掉USB的autosuspendecho -1 /sys/module/usbcore/parameters/autosuspend或者在驱动加载参数里加power_save0。另外检查iw dev wlan0 get power_save如果是on就关掉。天线匹配也很关键AIC8800D80一般有主天线和辅天线如果只接了一根要在驱动里配置成单天线模式否则MIMO校准会失败。这个在驱动源码的板级配置里有对应参数。5.4 常见问题速查表现象可能原因排查方法dmesg无USB枚举日志供电不足、D/D-接反、设备树未使能量电压、查原理图、看设备树statuslsusb能看到但无wlan0VID/PID不匹配、驱动未加载对比id_table、lsmod确认模块固件加载失败路径错误、权限不对、文件损坏检查/lib/firmware、md5sum对比wlan0存在但扫描不到AP射频固件未加载、天线未接确认rf固件、检查天线连接连上后频繁断流电源管理、USB供电不稳关autosuspend、加滤波电容加载fdrv报unknown symbol加载顺序错、bsp未导出符号先insmod bsp、检查EXPORT_SYMBOL5.5 实操心得与避坑建议第一个心得是每次改完驱动或者配置一定要冷启动板子再测试不要用reboot。USB控制器的状态在热重启时可能没有完全复位导致枚举异常冷启动能排除这类干扰。第二个是保留一份能工作的最小系统镜像驱动移植过程中如果把系统搞挂了可以快速回退。我一般会在SD卡上做两个分区一个放稳定版一个放调试版通过uboot切换。第三个是善用内核的动态调试功能。在驱动里加pr_debug或者dev_dbg然后通过echo -n module aic8800_bsp p /sys/kernel/debug/dynamic_debug/control打开调试日志比直接改printk灵活得多。第四个是关于固件版本匹配。AIC8800D80的固件和驱动版本要对应用错版本可能出现各种奇怪问题比如能扫描但连不上、连上后吞吐极低等。拿到新驱动时先确认配套固件版本不要混用。最后说一个我踩过的坑hi3516cv610的USB控制器在同时接多个USB设备时带宽分配可能出问题。如果板子上还接了USB摄像头或者4G模组WiFi性能会受影响。解决办法是把WiFi模组单独挂到一个USB控制器上或者调整USB的周期性传输预算。这个在设备树里可以通过tx-fifo-resize之类的参数微调具体要看控制器IP的文档。
返回列表