NOTE该项目主要是26年嵌赛海思赛题的作品,本博客直接使用了项目报告的诸多部分。相比于报告,博客没有存放相关照片展示。省二。
总的来说,无线连接部分确实是有难度的!尤其是在网络方式上,该音响使用的是dlna协议,而海思至少公开的版本中各种连接方式给出的官方库文件远没有类似乐鑫丰富,基本上只是确保了可以连接上。再加之我当时确实没有什么基础,对mcu的认识都很不全面,更不需要提网络了,很多地方借助了ai帮助。本文主要描述软件实现。
项目说明
背景
生活品质提高的大环境下,无线音箱逐渐成为常见的消费电子品类,然而,实际体验下来我们发现现有的不少无线音响方案在多个维度存在明显短板。
首先是音频传输质量。传统蓝牙音频受限于传输带宽,高码率场景下依赖有损压缩,延迟表现不尽理想。星闪作为新一代短距通信标准,在速率和时延上实现了全面超越。本作品基于海思 WS63 SoC,利用其集成的星闪协议栈,实现了 48 kHz / 16 bit 双声道 PCM 无压缩传输,从根本上解决了蓝牙音频在音质与延迟上的固有矛盾。
其次,在连接协议方面,当前市面音箱普遍只支持单一连接方式——蓝牙直连或单一的wifi方式,两者各有适用场景但难以兼顾。本作品在 WS63 平台上尝试并实现了 SLE 与 DLNA 双模融合,用户可根据不同需求灵活切换。
此外,本作品也关注了音响通用性问题。我们发现,主流平台售卖的音响功能单一,仅面向特定场景,无法满足用户的不同需求。本作品将音响模块化,使用不同的喇叭模组来适配如桌面,室外等不同的需要。
环境与材料说明
现在说明一下软件环境和使用材料的说明:
1.软件上使用vsc的hispark_studio插件编写ws63,截至目前版本是26.6.1,支持最高cpp17_gun编译,本项目完全在cpp17版本下编译完成。
2.列出代码调试主要用到的硬件模块:
- 小熊派H3863(自己画的板子使用的是ws63e裸片)
- pcm2706模块
- pcm5102模块
- ttp229模块(主流模块需要自己完成硬件配置,拉低P1,2,3)
- sk9822是硬件直接画出的
功能概述
功能与特性
- SLE无线音频: 基于WS63星闪协议实现了48k16bit双声道音频的PCM无压缩传输,相较于传统蓝牙,本作品在无线音箱上实现了更流畅更稳定的音质效果。
- DLNA网络音响: 使用WS63强大的网络功能实现了简易DLNA服务,可以对接QQ音乐等支持DLNA协议的主流音乐平台。
- 断电配置保存: 使用WS63自带的NV存储模块存储音响核心配置,断电不易失。
流程图
软件实现说明
软件整体介绍
本音响软件方面主要包含微信小程序和ws63音响主体程序两大部分。
微信小程序部分主要用于实现音响的远程控制和网络连接相关选项,使用可视化面板实现音响音量,亮度,模式等核心部分的控制,同时提供了预设音色选择等小程序额外控制选项。在网络连接方面,小程序是音响配网流程的重要一环,小程序可以改写音响内部的联网配置,比如要连接的网络名称和密码等。
音响主体部分由星闪发送端,播放端和音响控制端三个部分组成。星闪发送端实现获得音频数据后再由星闪协议发送给播放端。播放端在星闪模式下接收发送端的数据并播放,在dlna模式下接收dlna获得资源经过minimp3解码后播放,此外,播放端同时也是联网端,与小程序保持连接与通讯。控制端用于音响基础控制和语音模块信息接收,将控制内容同步至播放端,同时同步控制端小程序配置的信息并接收实时播放状态用于灯效信号输出。
NOTE软件部分使用cpp语言,因此使用了类封装。下面的说明建立在类封装基础上
软件各部分实现说明
LiteOS任务处理
首先,简单说明LiteOS层面的初始化流程。
发送端只包含IIS读取和SLE发送两个任务的创建,上电后首先初始化SLE任务,随后,等待8s延时,启动IIS读取任务。
控制端控制创建sk9822,ttp229,双板通讯,nv存储和语音模块的任务。
播放端创建双板通讯,网络,nv存储还有模式控制的任务,模式控制会根据当前模式选择创建星闪或DLNA任务。但是IIS实例会在模式选择任务创建时被创建。
星闪连接
星闪是本音响重要无线连接模式,支持48mhz16bit双声道的无压缩音频传输。
IMPORTANT实际测试下发现,要实现星闪的高速功能需要调整nv发射功率(7)和mcs发射速率(12),本音响音频传输带宽比较极限,如果再尝试调小传输间隔或者增大mtu将会出现周期性杂音。同时注意,实测下星闪发送端将间隔减小不会导致启动失败,但是接收端会,当前使用的间隔是官方最小值0x14,使用的mtu为800,理论最大值我记得是1500,但是实际是达不到的,发送1500实际接收小于1500.
NOTE星闪部分也算是比较成功的库实现了,独立的比较好(毕竟逻辑是线性的很流畅啊~),但是没有处理消息回调。
首先说明发送端逻辑,发送端为连接发起端,SLE_Server,在sle创建的同时,构造函数内注册回调函数,构造函数最后调用使能星闪。若星闪使能成功,调用使能成功的回调函数,回调函数内部调整nv发射功率为最大值7,设置本机地址后开始seek扫描。seek寻找到结果后调用seekfind回调,回调内判断是否为目标地址类型,如果是,关闭seek,seek关闭回调内连接对应设备,调用连接状态改变函数,切换更高的连接速率并开启PHY4M以实现高速传输,phy设置成功的回调中配置mcs为12,注册从机,协商MTU为800,SSAP查找服务和属性,确认设备后开始音频传输。
下面是sle_server的流程图
接下来说明播放端的星闪,接收端为SLE_Client,即广播端,接收server发送来的数据,播放端星闪只在音响被处理为星闪模式的时候才会被创建实例。当实例被创建时,注册回调并使能星闪,随后注册本机地址,设置ssap服务和特征,设置mtu,最后开启广播,与接收端建立联系后保持连接。
下面是sle_client的流程图
DLNA连接
DLNA是音响的第二种连接方式,主要建立在和QQ音乐的通讯尝试上。
IMPORTANT网络占用内存极大,注意使用静态数组(static修饰),防止动态变量不断创建导致问题,特别是udp这种部分,收到大量消息时容易溢出,还有一个地方要注意的是minimp3_ex内部的函数实现也大量依赖新变量创建,注意改为静态版本,否则极易溢出。 同时说明一下QQ音乐有时会发送https格式的地址,https实现和http不同,此音响没有实现https处理,而是在DLNA声明中表明需要http的mp3文件。 还有一点,QQ设置里那个音响是连不上非QPlay设备的,需要在播放页点设备投放。 我们在使用裸片进行连接dlna时发现了本地地址会改变的情况(小熊派不会),需要软件设置一下mac地址来固定。
NOTE十分混乱,我曾经尝试过分离,现在库里面还保留着我尝试分离的组件,但是结果很不理想,分开就不能跑了,也不知道为什么,只要合并一部分就能跑通一部分,最后没有办法,只能保留ai改来改去的一大坨了。会有一天能理解这个神秘的网络吧?
DLNA相关任务只有在处于DLNA模式和网络已连接状态下才会被创建,DLNA有两个任务,分别负责处理连接(dlna_task)和处理音频(minimp3_task)。
dlna任务启动后,会等待分发本地地址,随后启动简易dlna服务,这个任务中同时接收udp和tcp数据,首先,udp用于实现ssdp广播,使得QQ音乐可以识别该音响,TCP用于实际DLNA协议,使用select()函数(sdk自带)实现一个任务同时处理两种服务消息。
以下是dlna_task的主要流程
除此之外,尝试与QQ音乐建立连接,需要满足QQ音乐对音响判断的最小要求。简单来说,QQ音乐会按照DLNA协议向音响发送申请,询问音响具体实现了什么功能,这里声明的部分会影响音响后续的功能,如果声明了但是没有具体实现会在后续QQ音乐尝试通讯时没有任何回应或是错误回应从而导致连接断开。
这些描述用于声明本音响的功能,有些功能是必须的,比如QQ音乐要求定时检查连接状态,这需要音响至少在音乐播放上与QQ音乐保持同步。程序中dlna会处理资源链接,开始,暂停还有跳转功能。QQ音乐还会定期同步播放进度,ws63内部播放时长的计算是通过系统时钟确定的,计时会在关键控制时刻进行相应处理。
QQ会根据协议发送命令
dlna_task只能保证音响和QQ音乐保持连接,但是具体的播放需要minimp3_task实现。将播放任务独立出去是因为DLNA要求在播放中也能够即使交流,再处理播放任务除了及时性问题外也会使得一个任务过于臃肿。由于QQ音乐提供的url下载得到的音频资源是MP3格式的,而需要的是PCM格式,所以需要一个合适的解码过程。minimp3开源库提供了解码支持,在其提供的minimp3_ex文件中提供了完整的MP3解码为PCM的实现。
在接收到Play等命令后,minimp3任务会进行状态标记,while循环中不断判断当前状态,如果当前为播放状态,minimp3将持续从url中下载音频,同时,为了防止音频流下载过快,minimp3会动态判断当前是否需要下载新内容。
下面是minimp3_task的主要流程
IMPORTANT需要作出说明的是,流程图中连接url的部分实际上需要判断是否为新歌,如果不是新歌,那么说明刚刚不是切歌而是暂停或者跳转逻辑,那么应该在连接url携带已接收的字节数,从中断位置或者目标位置开始重新下载。
音频数据处理
WS63 在发送端配置 IIS RX 通路,从 PCM2706 获取 PCM 数据;在播放端配置 IIS TX 通路,将 PCM 数据输出至 PCM5102 DAC 模块。即音频流为
IMPORTANTws63的sdk库文件中的iis在计算上存在问题,会导致时钟错误。
NOTE本文中考虑了cache一致性(海思cache默认为32,可以在Kconfig中配置)的问题,本意是为了解决当时遇到的杂音问题,但实际杂音并非cache导致,所以其实我不确定这个cache是否真的造成了影响。 本项目的IIS均配置为主动时钟产生,根据实际作出选择,之前的杂音问题就来自于时钟模式问题!
发送端使用pcm2706作为模拟声卡采集设备声音,pcm2706会自动将电脑声音转换为44.1khz/48khz的音频数据并通过IIS方式输出,配置ws63的IIS为接收模式搭配DMA_LLI以接收pcm2706发送的PCM数据。IIS接收数据后将数据保存在缓存中,通过标志位告诉星闪任务现在有新的一帧数据可以发送了。被星闪发送的缓冲区会被清空,星闪发送波动造成的数据滞留帧会被舍弃。
下面是发送端数据传输的主要链路
播放端的IIS相比于接收端,需要进行更多的缓冲区处理。首先,不是有数据就发送,而是使缓冲区有一定积攒后再开启DMA传输,如果未发送缓冲区过少,将硬性增加数据以易于数据积累,若缓冲区告急则直接停止传输以等待重新达到阈值,这里的稳定性处理是独立于DLNA任务中的网络下载任务的。PCM数据也并非直接发送给PCM5102,而是经过音响配置选项处理,配置选项包括了音量,低音增强,和预设音效,夜间模式下最大音量降低。PCM数据会被处理并被用于控制端SK9822的灯效控制。同时,由于SLE和DLNA下音频频率一般不同,所以IIS在需要时更改频率。
IIS和DMA的激活流程几乎与发送端一致,以下是播放端的音频数据处理
接收端防用于防抖动的缓冲区处理如下
NV存储模块
为支持音响配置和网络连接等参数可修改且断电不丢失,系统使用海思 WS63 内置 NV 存储进行数据保存。
NV 存储在播放端和控制端均已启用:
- 播放端:主要保存网络相关配置,如预设 Wi-Fi 名称、密码及设备广播名称等。
- 控制端:主要保存音响参数配置,如音量、灯珠亮度等。 设备每次开机时会检查 NV 中是否存在已保存配置;若存在,则读取并覆盖软件默认初始值。
当接收到小程序或语音控制模块的控制命令后,系统会立即将相关配置写入 NV。对于 TTP229 触摸模块产生的操作,为减少频繁擦写对 Flash 寿命的影响,系统会在停止操作 5 秒后再统一保存配置。
NOTE似乎正常的保存逻辑应该是在断电时保存的,但是本音响没有断电检测的部分。
两板通讯与同步
本音响使用了两个WS63主控,即播放端和控制端。控制端主要处理SK9822灯效和TTP229触控模块。控制端没有使能SLE,也不进行网络连接,所以小程序控制是小程序与播放端之间通讯的实现,但是相关基础配置如音量等实际使用NV存储保存在控制端,同时,音频信号在播放端被处理,但SK9822属于控制端控制的模块,需要两板间有有效通讯方式来同步这些数据。
IMPORTANT本音响原来使用spi进行两版间通讯的实现,但实际情况是,海思sdk的spi部分似乎有bug,这个我没法确定,具体来说就是两个spi在同时激活时,模式不同会出现模式覆盖的问题。海思官方文档中似乎也对两个spi有建议说明。我不是很能理解这个问题,因为海思的两个spi实际不是对等的,只有一个spi同时支持主从模式,所以理论上来说不会有覆盖问题,但是问题实际出现了。最终只能放弃激活两个spi了,由于sk9822必须使用spi,所以两板子改用了双线协议。但是保留了原来的spi的名字。
通讯内容包含两个部分,一个是配置部分,包含当前的模式,声音,亮度,是否联网等配置选项,在上电时,控制端会查看是否有NV存储内容,若有,会使用NV存储选项覆盖软件初始配置的选项,并向播放端同步。如果播放端接收到小程序控制选项,通用会同步到控制端,是谁应该覆盖谁,由数据第一帧决定,如果两端同时发送同步命令,则先执行播放端的同步。
下面是配置部分的流程
NOTE我不知道这个音频分析是怎么实现的,这段是AI直接生成的。似乎有地方没有用全,但不清楚具体情况。
第二部分是音频同步部分,将iis播放中计算得到的音频相关参数填入,由播放端和配置打包给控制端,音频参数是单向传递的数据,控制端发送过来的部分只包含配置内容。
下表说明了字节含义
| 字节序号 | 内容 | 说明 |
|---|---|---|
| 0 | 表明是否为同步 | 0:查询;127:同步 |
| 1 | 网络设置 | 前四位为热点后四位为网络,其中3:关闭;7:打开 |
| 2 | 模式选择 | 0:关闭;63:SLE;127:DLNA |
| 3 | 音量 | 0-100有效 |
| 4 | 灯珠亮度 | 0-100有效 |
| 5 | 低音强度 | 0-100有效 |
| 6 | 音效模式 | 0:正常;1:人声;2:低音增强;3:流行;4:摇滚 |
| 7 | 夜间模式 | 0:正常;1:夜间模式 |
| 8-12 | 音频频段 | — |
| 13 | 音频强度 | — |
| 14 | 节拍 | 0:无;1:有 |
| 15 | 无意义 | — |
TTP229触摸模块
TTP229-BSF 模块位于控制端,用于读取触摸按键和滑条输入,并转换为音响控制参数。TTP229 最多支持 16 个按键,本音响使用其中 11 个:8 个用于滑条检测,另外 3 个为五角星形功能按键。
在 16 键模式下,TTP229 只能使用串行通信;BSF 版本仅支持 TTP229 自有的双线协议。本系统中的 TTP229 仅用于基础控制,并加入防误触设计:按键识别基于抬手检测,持续按下只计为一次操作,松手后再次按下才会识别为新的操作。
IMPORTANTttp229的引脚同时代表了配置,注意引脚模式配置。如果极易误触或者很难识别,可能是电容导致的灵敏度问题。
三个五角星形按键按 A、B、C 编号:
- A 键:切换滑条工作模式。
- 处于切换模式时,滑条用于切换控制项;
- 处于配置模式时,滑条用于调整当前配置值。
- B 键:在配置模式下选择当前要控制的配置项。
- C 键:用于开启或关闭热点。 无论当前控制对象是什么,滑条均遵循统一规则:向左滑动为减小,向右滑动为增大。
以下是ttp229的处理逻辑
SK9822灯条设计
SK9822 灯效显示模块位于控制端,主要用于驱动 18 颗 SK9822 RGB 灯珠,并根据当前音响状态和音频分析结果生成动态灯效。模块会从系统配置中获取音量、亮度、工作模式、热点状态和网络状态等参数,同时接收两板通信任务回传的音频能量和节拍检测结果,最终通过 SPI 将灯珠帧数据发送至 SK9822 灯带。部分配置变化也会通过灯效进行反馈,例如音量变化提示。由于 SK9822 数据传输量较大,本模块使用 SPI DMA 方式发送数据,以提高传输效率并降低 CPU 占用。
IMPORTANT这里使用dma是因为有fifo限制,分次发送会有逻辑问题,fifo水位在Kconfig中实际可以更改,但是由于时间有限,所以直接采用了dma。
SK9822 灯效会根据当前状态动态变化。正常空闲时,两排灯珠显示旋转 RGB 灯效;播放音乐时,会在基础 RGB 旋转效果上叠加音频响应,包括亮度变化和颜色叠加,形成随音乐律动的视觉效果。
当音量发生变化时,原有灯效会暂时切换为白色进度条,用于显示当前音量的大致大小。发生模式切换时,会在基础 RGB 效果上叠加由中间向两侧扩散的波浪效果:无模式为白色,星闪模式为绿色,DLNA 模式为红色。热点开启时,会显示从左向右扩散的黄色波纹;热点关闭时,则显示从右向左移动的黄色波纹。除音量进度条外,其余提示效果均叠加在基础 RGB 灯效之上。
SK9822 灯效同时受亮度配置影响;开启夜间模式后,整体最大亮度会降低。
以下是SK9822的主要流程说明
语音模块处理
语音模块是音响的第三种控制逻辑,使用模块实现语音识别。该模块使用IIC从模式连接在控制端,控制端会在内部处理相关命令。语音模块主要包含内部预留的语音模块处理命令和自定义识别命令。
下面列出的是语音预留命令的部分
| 命令 | 回复 | IIC指令 |
|---|---|---|
| 小闪小闪(唤醒词) | 我在 | — |
| 增大播报音量 | 增大播报音量 | — |
| 减小播报音量 | 减小播报音量 | — |
| 最大播报音量 | 最大播报音量 | — |
| 中等播报音量 | 中等播报音量 | — |
| 最小播报音量 | 最小播报音量 | — |
| 开启播报 | 开播报 | — |
| 关闭播报 | 关播报 | — |
下面列出的是会对音响产生控制的命令部分
| 命令 | 回复 | IIC指令 |
|---|---|---|
| 切换星闪模式 | 模式已更改 | 01 |
| 切换网络模式 | 模式已更改 | 02 |
| 打开网络连接 | 网络已打开 | 03 |
| 打开热点连接 | 热点已打开 | 04 |
| 关闭网络连接 | 网络已关闭 | 05 |
| 关闭热点连接 | 热点已关闭 | 06 |
| 增大亮度 | 增大亮度 | 07 |
| 减小亮度 | 减小亮度 | 08 |
| 亮度最大 | 调到最大 | 09 |
| 亮度最小 | 调到最小 | 0A |
| 增大音响音量 | 增大音响音量 | 0B |
| 减小音响音量 | 减小音响音量 | 0C |
| 音响音量最大 | 调到最大 | 0D |
| 音响音量最小 | 调到最小 | 0E |
| 开启夜间模式 | 夜间模式已开启 | 0F |
| 关闭夜间模式 | 夜间模式已关闭 | 10 |
| 增大低音 | 增加低音 | 11 |
| 减小低音 | 减小低音 | 12 |
| 低音最大 | 调到最大 | 13 |
| 低音最小 | 调到最小 | 14 |
| 默认音效 | 默认音效 | 15 |
| 人声 | 人声音效 | 16 |
| 低音增强 | 低音增强音效 | 17 |
| 流行 | 流行音效 | 18 |
| 摇滚 | 摇滚音效 | 19 |
| 介绍自己 | 我是海思多模态音箱 | 1B |
需要说明的是,根据语音模块要求,每个IIC命令实际是AA 55 00 XX FB,上表只说明了XX的部分。
NOTE实际语音模块还支持反向控制即被动模式,但目前还没有实际测试过。
总结
7.10
总的来说,作为第一个比较大型的长时间项目,从中学到了很多,也因为时间问题很多事情没能继续解决。比赛还未结束,即使初审未果这个音响也会作为其他比赛的项目继续下去!
7.26
简单说明吧,首先,不得不承认差距确实存在,别人实现了更多的功能,确实下了功夫,而我们精力过分分散,做得项目很一般也没什么起色。下个学期必须集中一点才行了,不能再把时间分配到其他地方去了!
由于QQ音乐直接下载存在速度问题,所以我们暂时采取的措施是使用服务器进行中转,先把URL上传到服务器,服务器下载完,WS63再去服务器下载。
如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时





