作者的话
SigmaDSP,ADI的音频DSP,以ADAU开头的基本都是。最近有很多兄弟问到同样一个问题,说我现在搞DSP一点问题都没有了,因为ADI弄的这个图形化编程实在是太简单了。但是继续往下走,要做自己的产品,调个音量,真实世界里我是需要用一个物理旋钮去调,设置EQ,我想用自己的上位机,甚至手机APP来操作!在真实的用户世界里,我不可能扛着台电脑,板子插着个USBi仿真器,来调节参数。那怎么去搞离线的物理控制?怎么去搞上位机来离线控制DSP调音呢?
这不是个新鲜的问题,也不是一个未解决的专业壁垒,很早以前就有成熟的套路和底层实现逻辑,那我就用这篇文章来简单的说一说吧。
硬件准备
我用ADAU1701来讲吧,先说怎么用MCU离线控制DSP,需要的硬件如下:
ADAU1701EVB-A2B开发板 一块
USBi 调试器 一个
MCU扩展卡 一个
配件线缆若干条
ADAU1701 开发板:https://item.taobao.com/item.htm?spm=a1z10.5-c.w4002-5192690539.15.2a4544c9h33DPa&id=38231117844
USBi 仿真器:https://item.taobao.com/item.htm?spm=2013.1.0.0.531c2344DuIT5w&id=38242936768
MCU扩展板:https://item.taobao.com/item.htm?spm=a1z10.5-c.w4002-5192690539.12.133a629cQsJvmm&id=590935455994
软件准备
SigmaStudio 4.7
System Workbench for STM32
STM32 ST-LINK Utility v4.1.0
有同学说你的STM32开发软件咋跟别人的不一样?每个人习惯不同,我因为长期做SHARC DSP,对Eclipse的环境比较熟悉,所以业余搞STM32的时候,就找了个Eclipse内核的软件,操作起来更舒服一些,开发软件这东西,兄弟们哪个用的舒服就用哪个。
离线控制原理
回顾一下ADAU系列DSP的开发流程,用过 ADI SigmaDSP 的用户都知道,SigmaDSP 的开发都是图形化编程,将程序框架做好后,下载 boot 实现音效处理的功能。但是有个很重要的问题就是,你在 SigmaStudio 软件中调试的各种参数是什么样的状态,下载到外部 EEPROM 中实现脱机后,就是什么样的状态,单凭 DSP 是很难实现实时调整 EEPROM 里的程序参数的。这个时候我如果想做个静音?调个音量?调 EQ 参数怎么办?
这个时候,单片机控制 DSP 就能很完美的解决,从原理上讲就是,单片机模拟 USBi,通过单片机来发送 USBi 一样的指令,来控制 EEPROM 里的 SigmaStudio 程序框架,从而实现调音量、静音等功能。
说通俗一点就是,图形化模块数据变化的采集,以及USBi的特殊读写函数,换成MCU来搞,让DSP认为仍然是USBi在以数据的变化来弄他。
简单举例(很重要,提前有一个控制的概念)
我们看一个简单的例子:
这个 SigmaStudio 里的程序,模拟音源从 0/1 输入,经过一个调音量的模块,通过两个实时电平监控,分到 0/1 和 2/3 模拟输出,输出之前可以对每个声道进行调音和静音。这是一个很简单的ADAU1701 的例程,如果把这个例程下载到 EEPROM,那么程序就固定死了,每个音量的大小无法调节,也不能对静音模块进行静音处理。但是有了单片机控制板之后,我们就可以用单片机来模拟 USBi 的指令,让 EEPROM 中的 SigmaStudio 程序认为是 USBi 正在操作它,从而实现脱机状态下得调音量和给每个通道静音。
这些 USBi 的指令从哪里找呢?当你用 USBi 在线调试的时候,都会有具体的显示:
只要我们用单片机,用到相关的函数、程序去模拟 USBi 的这些操作,就能实现啦。
科普完毕,下面进入正题。
ADAU1701 的工程开发
我们先设计一个 ADAU1701 的工程,并基于这个工程进行 MCU 启动与控制的操作。
先做这样一个程序,这个程序我也有提供现成的。再次罗嗦一下吧,在 DSP 板上,通路上来讲,模拟音源从 0/1 入口进,通过一个 ADC 电位器调音模块,分出左右声道,通过两个电平实时检测模块后,分到 0/1 和 2/3 口输出。在每个输出通道前面都做了音量调节和静音模块。
下面的 IO 控制则是实现按键控制 DSP 开发板上的 LED 灯。
特备注意:用 SigmaStudio 软件、USBi、ADAU1701 开发板先自行验证一下这个程序的正确性哈,SS 的程序如果都不正确,那 MCU 那边控制起来就没有任何意义啦,切记要先做好DSP 的开发!
MCU 板计划做的事情
- MCU 板上的四个旋钮分别对应 DSP 程序中的四个调音模块,通过旋钮对 DSP 程序中的这几个模块进行音量调节,根据我们当前提供的 STM32 工程例子,MCU 板上的旋钮、按键对应的 SS 工程的关系如下,这个对应关系是可以通过程序变动的。
单片机硬件板上的 RW1 对应 SS 工程里的 Single1;
单片机硬件板上的 RW2 对应 SS 工程里的 Single2;
单片机硬件板上的 RW3 对应 SS 工程里的 Single3;
单片机硬件板上的 RW4 对应 SS 工程里的 Single4;
- MCU 开发板上的四个静音按键分别对应 DSP 程序中的四个通道静音模块,单片机通过静音按钮控制这四个静音模块实现静音。
单片机硬件板上的 K1 对应 SS 工程里的 Mute1;
单片机硬件板上的 K2 对应 SS 工程里的 Mute2;
单片机硬件板上的 K3 对应 SS 工程里的 Mute3;
单片机硬件板上的 K4 对应 SS 工程里的 Mute4;
- MCU 板上的按键控制自身板上的 LED 灯,以及 DSP 板上的 LED 灯
SS 工程中的程序,MCU 通过控制软件里的 Swith1 和 Switch2 控制 D6 和 D5;MCU 直接控制MCU 开发板上的 LED2 和 LED3
- PC 通过串口输入命令,控制 DSP 工程里的算法模块实现调音
通过串口链接 PC,在串口调试工具中输入相关的命令,实现以上 123 项的全部功能!
- 全部 MCU 功能实现后,将包括 DSP 工程在内的所有程序均写入 STM32 中,实现单片机启动整个系统,避免程序暴露在外部 EERPOM 中。
开关说明
-
DSP 板上的开关,我们把控制 DSP 自启动的 SW1 拨到 OFF,不让 DSP 自启动,把 DSP 板上的 MCU 启动开关 SW2 也拨到 IIC,不用 DSP 开发板上的 STM32 进行启动。自此,DSP 开发板上的 MCU 彻底退休。
-
MCU 板上的开关,我们把 SW12 拨到 BOOT0=0,BOOT1=1。(此开关是控制单片机板自身启动方式)
硬件链接
正式开工,先检查一下硬件是否正常,我们按下图链接:
正常链接后,单片机板的 D1 Power灯亮,DSP 板的 D3 Power 灯亮,D2 USB 5V 灯亮,D7 MCU BOOT STATE 黄色灯闪烁。
特别注意 1:如果供电不足,则 DSP 板上的 D1 RESET 灯会亮起并偶尔闪烁,这个时候检查供电!
特别注意 2:MCU 板上的 USB 接口如果接到 PC 上供电,则 PC 会弹出未识别设备,这个是正常的不影响供电!因为我们还没有 STM32 的 USB 驱动,后期如果有需要我们会慢慢添加上去。
-
一切正常后,按下 MCU 板上的 KEY1 和 KEY2,MCU 板上的 D3 和 DSP 板上的 D6 亮起,实现计划章节中的第三项:单片机控制 LED 灯。
-
输入接 0/1,输出接 2/3,当按下 MCU 开发板的 K3 和 K4,板上对应的黄灯亮起,而 DSP板的输出 2 和 3 开始发出声音播放音乐。(单片机程序写的是静音按键按下去,开始播放音乐,按起来,通道被静音)
-
输入接 0/1,输出接 0/1,当按下 MCU 开发板的 K1 和 K2,板上对应的黄灯亮起,而 DSP 板的输出 0 和 1 开始发出声音播放音乐。(单片机程序写的是静音按键按下去,开始播放音乐,按起来,通道被静音)
实现计划章节中的第二项:单片机控制静音。
- 将 4 个静音按键全部按下,让每个通道都正常直通,分别调节 4 个旋钮,可以通过每个通道的音量的变化,来验证 MCU 控制旋钮调 DSP 工程中的每个通道音量。
实现计划章节中的第一项:单片机控制调音量。
上位机通过串口调试工具控制 DSP 板
这个我要单独拿一个大章节来详细说一下,有点点小复杂。
其他的链接跟开关设置与上面完全一样,不需要改动,串口这我接了一个串口转 USB 线接PC。
串口调试工具
软件我用的是 2.4.1 版的 SerialPortUtility,提供的资料里有。
串口控制协议
使用串口控制需要打开串口控制开关(这一章看不明白没关系,供查询用即可,下一章有详细注解)
开始码 : 0xdd
类型码 : 0x02 静音控制
0x03 音量控制
0x04 Switch 控制
…
数据: Value1 控件编号
Value2 控件参数
静音控制对照表(dd02+ Value1+Value2)
音量控制对照表(dd03+ Value1+Value2)
Switch 控制对照表(dd04+ Value1+Value2)
上位机通过串口控制 SS 程序中 Swich 开关点灯
通过 MCU 的串口控制这个 Swith1 和 Swich2,来实现 DSP 和 MCU 板上对应的 LED 灯点亮和熄灭。
按上图来设置软件,串口选择你自己电脑上显示的串口即可。通过上一章得串口协议可知:
- MCU 通过串口控制 SS 工程中得 Switch1,控制 MCU 板子上的 D3 和 DSP 板上的 D6。
在输入栏输入:DD 04 00 00 MCU 板上 D3 亮起,DSP 板上 D6 亮起;
在输入栏输入:DD 04 00 01 MCU 板上 D3 熄灭,DSP 板上 D6 熄灭。
再详细说一说这个 DD 04 XX XX 吧,DD 是开始,04 是 SW 控制,只要控制 SW,这俩就不变;然后第一个 XX 是表示 SS 工程里的 SW 编号,比如这个例子里我们是控制 Swith1,那么这个XX 就是 00;第二个 XX 是表示点亮和熄灭的,所以 00 是点亮,01 是熄灭。
所以说个题外话,第一个 XX,硬件开关受硬件限制,只能控制 ss 的四个 SW 开关,但是串口可以控制很多,FF 就是 SW256 了!
- MCU 通过串口控制 SS 工程中得 Switch2,控制 MCU 板子上的 D2 和 DSP 板上的 D5
在输入栏输入:DD 04 01 00 MCU 板上 D2 亮起,DSP 板上 D5 亮起;
在输入栏输入:DD 04 01 01 MCU 板上 D2 熄灭,DSP 板上 D5 熄灭。
上位机通过串口控制 SS 程序中静音开关给通道静音
首先让我们看看串口协议:
详细说一下,DD 02 00 00,DD 是开启,02 是类型码,在我的程序里设置的,静音控制都是02,第一个 00 是表示 Mute 编号,Mute1 是 00,Mute2 就是 01 了,依次类推。第二个 00就是状态显示,00 是静音,01 是恢复。
- 串口控制 Mute2
在输入栏输入:DD 02 01 00 输出 1 通道静音
在输入栏输入:DD 02 01 01 输出 1 通道恢复
- 串口控制 Mute3
在输入栏输入:DD 02 02 00 输出 2 通道静音
在输入栏输入:DD 02 02 01 输出 2 通道恢复
- 串口控制 Mute4
在输入栏输入:DD 02 03 00 输出 3 通道静音
在输入栏输入:DD 02 03 01 输出 3 通道恢复
上位机通过串口控制调音量
首先我们看看串口协议怎么说。
- 串口调通道 0 的调音模块
在输入栏输入:DD 03 00 55 将输出通道 0 的音量设置成 0x55(85)
在输入栏输入:DD 03 00 10 很明显音量降低
在输入栏输入:DD 03 00 35 很明显音量升高
详细说明一下,DD 03 00 55,DD 是开启,03 是类型码,在我的程序里设置的,音量模块都是 03,00 表示第一个:Single 1,假设 01 就表示的第二个:Single 2,55 表示音量大小。注意,音量在 0~100(十进制)随意设置,我这里随便设置的 0x55、0x10、0x35,大家可以随意测试。
- 串口调通道 1 的调音模块
在输入栏输入:DD 03 01 55 将输出通道 1 的音量设置成 0x55(85)
在输入栏输入:DD 03 01 10 很明显音量降低
在输入栏输入:DD 03 01 35 很明显音量升高
- 串口调通道 2 的调音模块
在输入栏输入:DD 03 02 55 将输出通道 2 的音量设置成 0x55(85)
在输入栏输入:DD 03 02 10 很明显音量降低
在输入栏输入:DD 03 02 35 很明显音量升高
- 串口调通道 3 的调音模块
在输入栏输入:DD 03 03 55 将输出通道 1 的音量设置成 0x55(85)
在输入栏输入:DD 03 03 10 很明显音量降低
在输入栏输入:DD 03 03 35 很明显音量升高
MCU 启动 DSP 的原理
先说一说原理:
- 在设计好 SigmaStudio 的工程后,下载验证无误后,编译后点击 export System files 按钮,就可以生成导出工程文件,导出的配置文件。如下图所示
-
在上图所生成的配置文件中,我们一般的 MCU 工程用到的有四个文件:“define.h”,“adau701_IC_1.h”,“adau701_IC_1_PARAM.h”,“adau701_IC_1_REG.h”。
-
DSP 需要配置相关的参数才能启动,而这些所有与 DSP 启动相关的参数由“Demo_IC_1.h”中的 default_download_IC_1() 函数完成,只要在 MCU 主程序中执行一次default_download_IC_1() 函数即可启动, 其中SIGMA_WRITE_REGISTER_BLOCK( )是要 STM32处理器来写. 在 STM32 工程的 adau1701_IC_1.h 文件中:
-
default_download_IC_1( ) 中的子函数SIGMA_WRITE_REGISTER_BLOCK( ) 由 I2C/SPI 接口完成数据传送,需要传送的参数有:int devAddress,int address,int length,ADI_REG_TYPE
*pData,四个,分别代表的是:I2C/SPI 设备地址,寄存器地址,数据长度,数据。这四个数据在 Sigmastudio 导出配置的时候已经定义在“Demo_IC_1.h",“Demo_IC_1_REG.h” 中。 -
所以 MCU 启动 DSP 时序是: 1)上电,2)延时等待约 100ms,3)执行一次default_download_IC_1( ) 函数,4)DSP 程序启动,接下来可以通过 MCU 控制调音了。
MCU 控制 DSP 的原理
控制程序源码都提供了,大家直接看就可以。但是我觉得还是要简单说一下 MCU 控制 DSP的原理,让大家能更快的理解。
之前我也反复讲到,从大原理上讲,是 MCU 模拟 USBi 的指令来控制 SS 软件里的模块,但是具体怎么做的呢?
- 控制 SigmaDSP 需要用到 SIGMA_WRITE_REGISTER_BLOCK( )和SIGMA_SAFELOAD_WRITE_REGISTER( )两个接口函数。SIGMA_WRITE_REGISTER_BLOCK( ) 函数与启动 DSP 的接口函数是一样的,SIGMA_SAFELOAD_WRITE_REGISTER( )接口需要先写到 DSP 里面的 Buffer,然后再触发,参考示意图:
- 编译好 SigmaStudio 工程文件后,用鼠标在 SigmaStudio 界面调节一些参数,然后在下面的Capture window 中可以看到会有如下图的信息,每个鼠标动作都会在 Capture window 出现相应的一行/几行动作。Mode 列中显示的即是控制方式,有 Block Write 和 Safeload Write。
- Block Write 使用 SIGMA_WRITE_REGISTER_BLOCK( ) 函数,这个函数就是普通的 IIC 写操作函数,只要把参数跟底层的参数对应上就可以了。
- Safeload Write 控制方式用 SIGMA_SAFELOAD_WRITE_REGISTER( )函数实现。安全加载方式步骤参考 ADI 相关文档,安全加载地址可以通过数据手册中查找
5.写好 SIGMA_WRITE_REGISTER_BLOCK( )和 SIGMA_SAFELOAD_WRITE_REGISTER( )两个函数之后就要知道单片机程序程序如何关联 SS 的控件以及参数控制,首先单片机程序中要建立 SS控件列表,根据 SS 图中的控件数量来建立这个列表,控件列表在 MCU 工程中的 audio.c 中,如下图代表建立了四个调音量模块、四个静音开关、两个 SWITCH。
关联好之后就可以开始写 STM32 对 DSP 的具体控制了。
- 为什么一定要用 Safeload?因为 Safeload 机制可以避免更新 DSP 内核参数时产生噪声。
MCU 启动 DSP 的操作步骤
开发板提供了上述单片机的源代码,用户可以通过编译该单片机例程得到 BIN 程序,并使用单片机烧写器烧写到单片机中,实现单片机启动 DSP,并控制 DSP 板调音的功能,下面我们来看看这个操作应该怎么做。
SS 代码编译导出
首先,我们需要把 SigmaStudio 里的工程导出来。
特别注意:
第一,硬件设计时,先拖出 USBi,再拖出 ADAU1701,再拖出 E2PROM,要确保 ADAU1701是 IC1,E2Prom 是 IC2!因为后面的导出设置中,必须是 ADAU1701 的文件是 IC1。
第二:你必须使用 USBi 把你的 SS 里的工程下载到板子上之后,才可以导出 SS 里的代码。于是我们先把 USBi 和 ADAU1701 开发板链接好,打开 SS,把工程做好,并下载工程,下载完之后:
将导出的文件指定到单片机工程的 MCU 文件夹内。(注意,请取名 adau1701)
下图是我的单片机工程中,MCU 文件夹的位置:
自此,SigmaStudio 和 DSP 的工作已经完成。
STM32 工程编译
- 打开安装好的单片机开发软件,第一次打开,他会让你选择你得程序文件夹,如下:
用纯英文路径,我把这个文件夹拷贝到了 F 盘目录下。
- 点击 OK,进入软件开发界面,直接点击这个“ 010”的图标进行编译,编译完成后,会获得一个 bin 文件,这个就是我们需要烧写的文件。
这个文件会出现在我们的单片机工程文件夹的 debug 文件夹内:
- 使用单片机烧写工具来烧写 bin。
打开软件:
点击下图中 connect to target 按钮,紧接着按一下板子的 RESET 键(注意:不按复位键会连接不上的)
链接成功后如图
- 擦除单片机 flash
擦出完成
- 加载 bin 文件(通过 STM32 软件编译而成)
加载完成:
- 烧写文件
选择默认的就可以了。
- 烧写完成
- 拔掉 MCU 烧写器,断电重新链接硬件外设,上电,实现脱机运行单片机控制 DSP 板的功能。
结束语
基本上MCU控制ADAU系列DSP,都是这个套路,有兄弟说你整篇也没讲上位机呀,确实没讲,但是你看,我把上位机用串口发命令,通过MCU去离线控制DSP的整个逻辑都讲了,你就照这个来呀,自己做上位机,再给你的MCU串口发命令,控制DSP,不就行啦。具体怎么开发上位机,我是嵌入式底层工程师,就不班门弄斧了。