尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

RV1106开发板AIC8800DC蓝牙音频移植实战:从驱动到BlueALSA播放

发布时间:2026/9/25 1:52:17

资讯中心
01
ARTICLE

RV1106开发板AIC8800DC蓝牙音频移植实战:从驱动到BlueALSA播放

RV1106开发板AIC8800DC蓝牙音频移植实战:从驱动到BlueALSA播放
做RV1106这种小板子最烦的不是算力不够而是WiFi和蓝牙这种“外设”没人帮你配好。我这次要处理的是一块AIC8800DC二合一模组一边是WiFi6一边是蓝牙5.0RV1106的Buildroot SDK里其实已经带了驱动源码但真要把它从“能加载”变成“能连手机、能放歌”中间至少隔着一层固件、一层设备树、一层蓝牙协议栈。这篇文章就是我个人完整走完一遍的记录内容包括驱动移植、HCI初始化、bluetoothctl配对、BlueALSA播放音频以及调试A2DP和HFP音频时踩过的那些坑。手头有RV1106开发板、想把AIC8800DC蓝牙用起来做音频播放的朋友可以照着这份流程走能省下不少时间。1. 整体设计思路先摸清RV1106和AIC8800DC的硬件关系1.1 RV1106为什么适合玩AIC8800DC蓝牙RV1106是瑞芯微面向IPC、智能摄像头这类场景推出的视觉处理芯片单核Cortex-A7跑到1.2GHz内置了256MB DDR和0.5TOPS NPU所以很多做边缘视觉产品的朋友手头都有这块板子。但它的定位决定了它不会像手机SoC那样把WiFi、蓝牙都集成进去你需要外挂一颗Combo芯片然后自己在Linux下把驱动、固件、协议栈串起来。AIC8800DC就是一颗主打WiFi6 蓝牙5.0的Combo模组WiFi部分走SDIO接口蓝牙部分走UART接口音频走PCM/I2S接口。在同类芯片里它的优势是瑞芯微的SDK里通常已经放了一版驱动源码而且爱联官方对RV1106这类平台的适配还算积极固件也能从SDK的vendor目录里直接拿到。相比自己从零移植一个蓝牙协议栈这个起点已经好很多了。不过“驱动源码有”和“能出声”是两码事。RV1106的SDK虽然带了一版AIC8800驱动但你在实际板子上要做的事情还不少先确认驱动版本和固件文件对得上再配置设备树指定蓝牙UART和音频PCM引脚然后启动BlueZ协议栈最后还要把音频路由配置明白。整个过程涉及Linux驱动开发、蓝牙协议栈、ALSA音频三块知识缺一样都容易卡住。1.2 引脚接线SDIO、UART、PCM一个都不能漏先看硬件连接。AIC8800DC不是一颗纯蓝牙芯片它内部同时有WiFi和蓝牙两条子系统硬件引脚必须分开接好。以我手头这块模组为例WiFi走SDIO接口需要接CLK、CMD、D0-D3蓝牙HCI走UART接口至少要TXD、RXD、CTS、RTS四根线音频走PCM/I2S接口要接CLK、FS、TX、RX四根线。我整理了一张表方便对照功能模块AIC8800DC引脚RV1106端说明WiFiSDIO_CLK / SDIO_CMD / SDIO_D0-D3SDIO1或SDIO2用于WiFi6数据通信蓝牙HCIBT_UART_TX / BT_UART_RXUART3或UART4用于蓝牙控制与数据蓝牙流控BT_UART_CTS / BT_UART_RTS对应UART的CTS/RTS必须接硬件流控很重要蓝牙音频BT_PCM_CLK / BT_PCM_FS / BT_PCM_TX / BT_PCM_RXI2S0或I2S1用于HFP/SCO语音和部分A2DP音频路由电源VDD_3V3 / VDD_1V8电源轨模组峰值电流不低要留足余量射频RF_ANT / GND天线区天线下方净空不要铺铜这里最容易被忽略的是UART的RTS/CTS两根线。很多人图省事只接TXD/RXD觉得蓝牙控制通道“能通就行”实际上AIC8800DC的HCI通信数据量大一旦跑A2DP音频ACL数据包会很多没有硬件流控时数据会丢包表现就是连上就断、声音断断续续、设备列表刷新异常。我建议从一开始就把四线UART接全不要省。音频PCM引脚也要提前接好尤其是你打算做HFP通话或者把音频桥接到板载Codec的时候。RV1106这边的I2S接口和AIC8800DC的PCM接口命名可能不完全一样但本质是四线同步串口CLK对应位时钟FS对应帧同步TX/RX对应数据线。我在后面讲HFP配置时还会再提一次。1.3 音频链路规划A2DP和HFP走的是两条路很多第一次接触蓝牙音频的朋友会以为“蓝牙芯片就是音频芯片”实际上AIC8800DC内部虽然集成了蓝牙射频但音频数据怎么走取决于你是用A2DP还是HFP/SCO。A2DP用于听音乐数据量比较大HFP用于通话语音数据量小但实时性要求高。A2DP这条路径通俗说就是主控这边的BlueZ协议栈先把PCM音频用SBC或AAC编码变成一个个数据包然后通过HCI UART发给AIC8800DC由它的蓝牙射频把这些包发出去。耳机收到数据后自己解码头、播放声音。所以在这种场景下PCM/I2S接口并不一定参与音频传输关键瓶颈反而是UART的波特率。我实测下来115200波特率跑A2DP几乎不可能流畅后面会专门说。HFP/SCO这条路径则不同。通话时语音数据由蓝牙HCI层直接走PCM/I2S通道AIC8800DC把从射频收到的语音包转成PCM信号输出给主控的Codec由Codec驱动扬声器麦克风采集的语音也通过Codec进PCM接口再由AIC8800DC的射频发出去。这时PCM/I2S的引脚、时钟极性、帧同步配置就直接影响通话质量。明白这两条路就不会在调试时想当然A2DP没声音去改PCM配置肯定没用HFP没声音光调ALSA也没用。先把“当前用的哪个Profile、数据走哪条通道”想清楚再动手能少走很多弯路。2. 内核驱动与固件部署先让系统认识AIC8800DC2.1 检查SDK里的驱动代码从哪拿、放哪RV1106的Buildroot SDK一般会在kernel/drivers/net/wireless/下面放vendor Wi-Fi驱动AIC8800DC的驱动目录通常叫aic8800_fdrv或者类似名字。我建议拿到SDK后先搜一下find . -iname *aic8800* 2/dev/null如果你能找到目录说明驱动源码已经集成了省去网上找源码的麻烦。如果找不到那就要确认你手上的SDK版本是不是太旧或者需要找芯片原厂/开发板厂商要一版支持RV1106的驱动补丁。这里有个小经验AIC8800DC的驱动往往会分成WiFi部分和蓝牙部分。WiFi部分本质是一个网络设备驱动负责SDIO传输、802.11协议帧处理蓝牙部分则通过一个platform driver或者辅助模块把UART上的HCI通道注册给内核的蓝牙子系统。两者经常是同一个驱动包编译出来的两个模块所以排查问题时最好在dmesg里同时看到WiFi和蓝牙两段初始化日志。拿到驱动源码后我的习惯是先编译一遍不直接改任何代码。这样可以先确认SDK的编译链路是通的后续调设备树或内核配置时如果编译报错也知道问题出在哪里。2.2 内核配置与设备树关键选项和dts示例内核配置这一步主要是把蓝牙子系统和AIC8800驱动打开。蓝牙协议栈依赖的选项至少包括CONFIG_BT蓝牙核心支持CONFIG_BT_HCIUART让UART能注册成HCI设备CONFIG_BT_RFCOMM串口仿真部分场景会用到CONFIG_BT_BNEP蓝牙网络共享如果不需要可以不开AIC8800的驱动选项一般在menuconfig的Device Drivers - Network device support - Wireless LAN下面也可能在Vendor目录里具体名字带AIC8800字样。编译内核或模块时确认这些选项不是m而是y或者你明确知道后续会insmod对应模块。设备树部分更关键。要让蓝牙HCI跑在UART上需要在dts里使能对应的UART节点并配置正确的pinctrl。假设你的蓝牙接在UART3那么大概是这样uart3 { status okay; pinctrl-names default; pinctrl-0 uart3_xfer uart3_cts uart3_rts; dma-names tx, rx; dmas dmac 0, dmac 1; };这里注意两点一是pinctrl里一定要包含CTS/RTS这两个引脚的复用配置只配了TXD/RXD硬件流控就没法工作二是如果这个UART在SDK里被默认当成了调试串口需要先在uboot或kernel cmdline里把console对应关系改掉不然HCI初始化时会被调试日志干扰。如果你的方案要把HFP通话音频接到板载Codec还需要使能对应的I2S/PCM节点。AIC8800DC的PCM接口可以工作在PCM或者I2S模式设备树里要保证CLK、FS、TX、RX的引脚复用正确。这块不同的板子差异比较大我不给死配置但建议你先把“蓝牙HCI能注册、A2DP能出声”作为第一优先级HFP音频放在第二步再调。编译内核时RV1106的SDK一般用Buildroot管理编译命令通常类似make rockchip_rv1106_defconfig make编译完后把内核镜像和模块打包进系统镜像烧录到开发板上然后看启动日志。2.3 固件和系统配置firmware路径、rfkill与Bluetooth服务驱动编译好了没有固件照样起不来。AIC8800DC的固件文件一般会放在SDK的某个目录里需要拷贝到板子的/lib/firmware/下面。常见的文件名包括aic8800_fw.binaic8800_btsram.binaic8800_btfw.bin具体文件名以你拿到的驱动包为准。我踩过的一个坑就是只拷贝了WiFi固件没拷贝蓝牙SRAM固件结果WiFi能连上路由器蓝牙却始终扫不到设备。检查逻辑很简单ls -l /lib/firmware/aic8800/ dmesg | grep -i aic如果dmesg里有类似“Failed to load firmware”的日志那基本就是文件路径不对、文件名不匹配或者固件版本和驱动版本不一致。系统侧还有两件事。第一是rfkill有些模组的蓝牙使能引脚是独立GPIO控制的如果SDK默认没有把它拉高或注册成rfkill设备那蓝牙芯片可能一直处于复位状态。你可以用rfkill list看看有没有蓝牙设备如果没有多半是电源/使能引脚没控制好。第二是BlueZ服务Buildroot镜像里可能没有默认启动bluetoothd需要确保/system里的dbus和bluetooth服务正常systemctl status bluetooth如果没有systemd也可以手动启动bluetoothd我在第三部分会给出具体命令。3. 蓝牙协议栈启动与配对让开发板“可见”且能连上3.1 HCI层初始化btattach、波特率与hci0注册蓝牙协议栈的最底层是HCI它一般跑在UART上内核通过一个叫btattach或hciattach的工具把UART设备“挂”成hci0。RV1106上最常用的方式是btattachbtattach -B /dev/ttyS3 -S 1500000 这里的/dev/ttyS3对应你设备树里使能的UART3-S指定HCI初始化后的波特率。第一次调试我建议先用115200验证链路把波特率参数去掉或者设为115200先看hci0能不能注册出来hciconfig -a如果能看到一个hci0说明UART链路和Bluez的基本通道没问题。这时候再测试高波特率因为A2DP音频传输对带宽有硬性需求115200波特率跑无损或高码率音频会出现卡顿。我实测下来AIC8800DC的HCI至少建议跑到1500000才能比较宽松地应付SBC编码的A2DP流。注册成功后执行hciconfig hci0 up如果执行后报错或者hci0状态一直是DOWN优先看内核日志dmesg | grep -i hci dmesg | grep -i bluetooth常见问题有两个一是UART设备节点被复用比如调试串口也占用同一路UART二是蓝牙固件没加载成功HCI复位命令得不到回应。还有一种情况是pinctrl没配好导致UART引脚根本不通。这个阶段别急着去调音频先把hci0稳定在UP状态后面的一切才有基础。3.2 bluetoothctl配对与连接操作hci0起来了下一步就是让手机或蓝牙音箱能连到开发板。先用bluetoothctl交互式操作bluetoothctl进入交互界面后按顺序执行power on scan on pairable on agent on default-agent discoverable onscan on之后应该能看到附近的可发现蓝牙设备。如果想连接手机手机端需要开启蓝牙并处于“可被搜索”状态。在bluetoothctl里找到对应的MAC地址执行pair 12:34:56:78:9A:BC connect 12:34:56:78:9A:BC trust 12:34:56:78:9A:BC如果配对时要求输入PIN码但因为开发板没有屏幕确认成了大问题。这里最好在启动bluetoothd时带上参数或者用agent自动接受。我在调试时一般优先设置一个固定PIN或者使用JustWorks配对方式也就是不需要输PIN的配对模式很多耳机、音箱默认都是这种。配对成功不代表能播放音频。你还需要确认连接后的Profile是否协商成功特别是A2DP。可以用bt-device -l或者继续通过bluetoothctl查看设备信息。如果看到设备已经Trusted但音频Profile没起来就要进到下一步检查和BlueALSA的联动。3.3 用btmon和hciconfig排查链路问题蓝牙调试有个神器叫btmon它能把蓝牙协议栈发出去的HCI命令和事件全部打出来。调试配对失败、链路断开、Profile协商失败时我基本都是靠它定位。比如手机和开发板都显示配对了但过几秒就断开这时在btmon里能看到HCI层反复在发Link Key相关的请求或者有Error Code提示。常用的排查组合是btmon -w /tmp/bt_trace.log hciconfig hci0 piscan bt-adapter --set Powered 1然后打开手机反复尝试连接最后把bt_trace.log拉回PC用Wireshark的蓝牙解析功能看。Wireshark能识别HCI ACL、SDP、A2DP等协议报文比在终端看日志直观很多。我第一次查A2DP Profile起不来的问题时就是靠Wireshark看到SDP过程没有正确响应才定位到BlueZ配置缺了Media服务。如果只是想快速确认芯片能力也可以用hciconfig hci0 features这条命令能看到芯片是否支持BR/EDR、LE、SCO等关键特性。AIC8800DC是双模蓝牙BR/EDR和LE都应该能看到。如果features里连基本的声音Profile能力都没有那就要怀疑是不是固件版本太老。4. 音频播放链路打通与实测4.1 轻量方案优先为什么用BlueALSA而不是PulseAudio嵌入式Linux下播放蓝牙音频主流方案有两套一套是PulseAudio一套是BlueALSA。PulseAudio功能全但它依赖的服务组件多在RV1106这种小内存、低主频的板子上跑起来有点重而且调试音频路由时会多一层抽象不利于快速定位问题。我的建议是优先用BlueALSA它做的事情很纯粹把BlueZ的A2DP和HFP音频桥接给ALSA让aplay、arecord这种标准命令直接读写蓝牙音频设备。安装BlueALSA后启动方式一般是这样bluealsa --profile a2dp-sink --profile a2dp-source 启动后Bluez设备连上时BlueALSA会自动创建一个ALSA设备。用aplay -l可以看到类似bluealsa的设备名。播放音乐时直接用aplay指定设备aplay -D bluealsa:DEV12:34:56:78:9A:BC,PROFILEa2dp test.wav这里DEV参数换成你实际连接的蓝牙设备MAC。如果aplay能正常播放耳机或音箱也出声那A2DP链路就算通了。BlueALSA还有一个好处是它的调试信息很直白。如果A2DP Profile没协商成功启动时会报“device does not support A2DP”或者“Failed to open PCM”之类的提示根据提示去查BlueZ的Profile配置方向就很明确。4.2 A2DP播放实测从aplay到蓝牙耳机我实测的播放命令是分两步走的。先生成一个测试音频文件避免直接拿MP3测试时搞不清是解码问题还是蓝牙链路问题ffmpeg -f lavfi -i sinefrequency440:duration10 -ar 44100 -ac 2 test.wav这是一段10秒的440Hz正弦波如果蓝牙链路通了耳机里会听到清晰的“嗡——”声。再用aplay播放aplay -D bluealsa:DEV12:34:56:78:9A:BC,PROFILEa2dp test.wav如果声音出来了说明从ALSA到BlueALSA再到BlueZ,再到AIC8800DC的HCI UART最后到蓝牙耳机的整条A2DP链路是通的。如果声音卡顿或断续最先怀疑的就是HCI UART波特率。刚才前面提到过115200波特率肯定不够SBC编码的A2DP流通常需要300-400kbps的带宽而UART 115200的理论上限只有约115kbps显然入不敷出。我把波特率提到1500000之后卡顿问题基本消失。还有一个体验技巧A2DP播放时可以同时开一个定时器测量一段音乐的播放时长看它是否稳定。我在测试中发现如果UART有偶发丢包歌曲会播放得“忽快忽慢”时间轴不稳定。这时在dmesg里查UART overrun相关日志基本能确认瓶颈。4.3 通话场景的HFP/SCO音频路由与相关坑点A2DP搞定之后不少人会继续做HFP通话。HFP涉及SCO音频而SCO音频的默认通道很可能是PCM/I2S不是HCI UART。这也是热词里常提到的“蓝牙A2DP切SCO模式”的由来。简单说当手机通过蓝牙HFP连上开发板时系统会从A2DP切到SCO音频数据改走PCM接口。AIC8800DC的BT_PCM引脚接到RV1106的I2S接口然后由RV1106的Codec处理语音。这个链路只要有一处配置不对就会出现“音乐正常一通话就没声音”或者“能听到系统声音但对方听不到我说话”的怪现象。我踩过的一个坑是I2S时钟极性问题。RV1106的I2S和AIC8800DC的PCM时钟极性不一定默认匹配。蓝牙侧通常默认PCM时钟在上升沿采样而I2S可能默认在下降沿采样导致数据错位表现为有沙沙声但听不清人声。解决办法是在设备树里调整I2S的format或者通过ALSA的配置指定同步模式。不同Codec的具体参数不一样这块只能结合你自己的硬件确认。另外HFP还有一种低功耗模式SCO音频可以在HCI上走叫做esco over HCI但这种模式下系统负载会高一些也更容易出现延迟。我自己实际项目里如果产品需要长时间通话我还是建议用PCM/I2S硬路由稳定性和音质都更好。5. 避坑指南实操中最常踩的七个坑5.1 固件加载失败与hci0不出现这个问题出现的频率最高。现象是dmesg里看不到aic8800蓝牙初始化日志或者日志提示firmware loading failed。排查顺序我一般是这样ls /lib/firmware/aic8800/确认固件文件确实存在且文件名和驱动的请求名一致。dmesg | grep aic看驱动是否在探测阶段就报错了。rfkill list确认没有把蓝牙射频kill掉。确认UART的pinctrl配置特别是RTS/CTS是否占用冲突。确认蓝牙对应的UART没被console或其他服务占用。有一次我折腾了一下午最后发现是内核里把同一个UART注册成了两个设备导致HCI设备无法创建。解决办法就是把dts里的aliases和chosen部分检查清楚。5.2 蓝牙连上但没声音先查这三处如果你的蓝牙设备已经连接成功但A2DP播放没有声音按以下顺序查第一确认BlueALSA进程确实在跑而且它监听的是系统当前使用的BlueZ实例。第二执行aplay -L看bluealsa设备是否出现在列表里。第三确认蓝牙耳机/音箱支持的Profile。有些设备只支持HFP不支持A2DP这种情况下你开着music播放它当然不会出声音。另外别忘了看 /etc/bluetooth/main.conf 里的配置。BlueZ 5.x之后A2DP相关功能可能需要在main.conf里显式启用。如果你发现SDP阶段没有回应AudioSource/AudioSink服务多半就是这里的配置问题。[General] EnableSource,Sink,Media DisableHeadset上面这个DisableHeadset很关键如果你只想测试A2DP暂时把HFP关掉能避免很多Profile之间互相抢占的怪问题。5.3 A2DP切SCO导致声音丢失经典坑这是我在实际项目里遇到的最让人抓狂的一个问题。蓝牙耳机连着开发板听歌突然一个系统通知声音触发HFP Profile或者手机打个电话进来A2DP就断了音乐不再播放而通话音频也没有正确路由到Codec结果就是两边都没声音。原因就是BlueZ在同一时刻通常只会让一个音频Profile占用音频通道A2DP和HFP之间需要切换而这个切换过程如果PCM/I2S侧配置不到位就会掉链子。我建议初调阶段先Disable掉HFP专注打通A2DP。真正做产品时再专门设计一个Profile切换状态机在应用层控制音频焦点而不是依赖底层自动切换。如果切换到HFP后没有声音优先检查PCM/I2S的时钟是否正常。用示波器量AIC8800DC的BT_PCM_CLK如果切换后CLK停振基本就是主控侧I2S没有正确进入工作状态。5.4 音频杂音、断音、延迟偏大音频杂音和断音大部分时候不是软件问题而是硬件环境。有一次我觉得SBC编码质量不够好音质发闷后来发现是电源纹波太大。AIC8800DC在WiFi和蓝牙同时工作时瞬时电流可以达到几百毫安如果3.3V供电轨没有足够的储能电容射频发射瞬间电压跌落音频就会爆音。断音则要优先检查HCI UART波特率。我前面反复强调A2DP高音质播放时115200就是不够用别在这个问题上浪费时间直接把波特率拉到1500000以上再试。延迟偏大这个问题A2DP本身就有固定延迟SBC编码加蓝牙射频传输150-250ms很正常。如果你做的是影音同步类产品光在蓝牙协议栈上做文章不够还得考虑视频播放端提前补偿或者选择延迟更低的编解码方案。普通音乐播放场景这个延迟不影响体验。5.5 硬件布局的暗雷天线、流控、电源最后三个硬件坑每一个都能让软件调试白费天线AIC8800DC的RF天线区域下方一定不能铺铜也不能有密集走线。我有一块板子为了节省面积在天线净空区旁边走了一根电源线结果蓝牙灵敏度直线下降手机隔着一堵墙就断开。后来重新搞定布局问题立刻改善。流控再次强调UART的CTS/RTS一定要接。我用过一块转接板偷懒没接CTS/RTS结果hci0能注册但蓝牙搜索设备的列表刷得特别慢连接后经常会断。把流控接上世界清净了。电源AIC8800DC这种Combo芯片的峰值功耗不低尤其是WiFi 6和蓝牙同时打开时电源轨余量不足会导致芯片频繁复位。增加一个100uF左右的储能电容或者换一个输出能力更强的LDO/DCDC能解决很多“莫名重启”“找不到设备”的问题。5.6 避坑汇总速查表问题现象优先排查解决方案hci0不出现无蓝牙设备节点dmesg、firmware路径、UART占用检查驱动加载与固件文件配对失败PIN码无法确认bluetoothd agent配置使用JustWorks或自动agent连上没声音A2DP无输出BlueALSA进程、main.conf启动BlueALSA并确认Profile声音卡顿A2DP断续HCI UART波特率提到1500000以上通话没声音HFP切换后无声I2S/PCM时钟极性调整设备树I2S格式杂音爆音射频发射瞬间爆音电源纹波增加储能电容断连严重距离稍远就断开天线净空区与流控重新布局、接好CTS/RTS这几个坑我基本是按“从软件到硬件”的顺序排的调试时也建议按照这个顺序来先排除固件和配置问题再查电源和射频不然容易被表面现象带偏。最后分享一点我自己的调试习惯每次改动只动一个变量然后回归测试。比如这次我把UART波特率从115200改到1500000就只测音频卡顿这一个指标不要同时去改asound.conf和固件版本。蓝牙音频链路涉及的东西已经够多了变量越多越难定位。先把最慢的链路跑通再去优化音质和延迟这是我一直沿用的思路你也可以试试。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。