我们如何在STM32上测试麦克风系统:Yandex设备开发人员的经验



嗨,我是Yandex硬件解决方案团队的Gennady“ Crail” Kruglov。

为麦克风矩阵选择麦克风是我们工作中一个复杂而有趣的部分:我们测试具有各种参数的模型,尝试各种矩阵配置,并改进声音处理算法。

开发回声和降噪算法的开发人员不仅可以处理以前从实验室设备中获取的原始数据,还可以通过将新的麦克风矩阵连接到笔记本电脑来与之交互,例如与新的麦克风矩阵进行实时交互。

乍看之下似乎很简单。在本文中,我将解释如何解决将声音从具有PDM接口的七个麦克风通​​过USB传输到计算机的问题,我们遇到了什么硬件和软件上的细微差别以及如何克服它们(扰流器:这种方法可以适用于麦克风数量≤8的矩阵)在文章的末尾,我将分享到该流的链接,在此我将展示STM32微控制器的开发过程,并讨论下一个系列。

问题的提法


一点背景:为第一个Yandex.Station创建一个可控的灵敏度光束,为Mini版本选择了带有七个麦克风(模拟)的电路-带有四个(已经数字化)的麦克风。对于其他产品,考虑了各种配置,但对于我们来说,七麦克风矩阵仍然是基本的,经典的。

因此,给定:七个数字麦克风,需要对其进行测试。发现:实施起来不太困难,并且与他们互动的方式也很灵活。将任务分为两部分是合乎逻辑的:

1.从麦克风获取数据。

2.将它们发送到计算机。

在完成的设备中,当用户联系Alice时,来自数字麦克风的信号会直接发送到中央处理器(将其称为SoC-片上系统更为正确,但“处理器”更加熟悉和方便),它具有足够的功能来处理它们。但是对于调试算法,将这些数据直接发送到开发人员的计算机要方便得多。最简单的方法是通过USB连接:因此,开发板必须具有带有适当单元的微控制器。我们喜欢STM32控制器,但是不可能将来自麦克风的声音流直接发送到它:没有PDM信号接收单元(脉冲密度调制)-数字麦克风的输出接口。

另一个选择是将麦克风板连接到所用SoC制造商的调试板。但是,此决定与Linux alsamixer息息相关,其参数强烈影响将PDM转换为PCM的结果。这些模块不仅可能针对不同制造商的处理器而有所不同,甚至对于同一厂商的两种型号也可能有所不同。我提醒您,我们需要一个简单,透明且可预测的解决方案。

硬件解决方案


接受STM32无法接受多通道PDM的情况。一个人可以使用SPI模块接收PDM信号,但是只有一个麦克风可以连接到一根SPI总线。我们使用STM32L476RC控制器,其中只有3条这样的总线。额外的复杂性:PDM信号的频率很高,有必要对其进行抽取,平均,处理和滤波-对于七个麦克风,此任务非常复杂。

由于我们在谈论的是调试板,而不是大规模生产的原型,因此我们将专注于专用芯片TSDP18xx。它完成了所有必要的工作:它为PDM生成必要的频率和信号,对PDM信号进行平均和处理,然后将其全部转换为I2S信号。更确切地说,TDM(时分多路复用)是因为I2S总线采用两个通道,并且如果您通过相同的导线进行更多驱动,则将其称为I2S不再是正确的。

这种方法的优点是,所有准备和平均化工作都由TSDP承担。减号-所有算法都紧密地连接在该微电路内部,无法更改。特别是,您无法通过修改平均参数来调节音量。但是对于调试而言,这并不重要。

注意双手:微电路上有七个麦克风,八个通道。一个未被使用的输出仍然存在,因此在将来为简单起见,我将讨论八通道音频流。

因此,我们将八通道TDM提升到STM32,我们得到了八通道音频流。数据如何移动:



SAI-用于I2S / TDM的STM32硬件单元。它非常灵活,允许您实现许多协议选项。但是正因为如此,很容易对频率要求感到困惑。

时钟树值得仔细研究。一个12 MHz石英谐振器连接到微控制器。在应用到PLL块之前,我们将该频率除以3,得到4 MHz。然后它是这样的:

1.最好提高核心频率以跟上所有工作:例如,该控制器的最大频率为80 MHz。我们使用第一个PLL模块:将4 MHz乘以40,再除以2。2

. USB需要48 MHz。为此,请使用第二个PLL模块:将4 MHz乘以24,再除以2。3

.关于麦克风。我们的测试板使用的采样频率为Fs = 16 kHz,这是语音识别领域采用的标准。从4 MHz的初始频率开始,您需要获得一些可以转换为16 kHz TDM总线帧频率的信号(aka LRCK,aka FCK,aka FrameSync)。在这种情况下:

[位同步频率(BCLK,BitClk,Sync,SCK)] = Fs∙[通道数]∙[每通道的位数],

即:SCK = 16 kHz∙8∙16 = 2048 kHz。

4.数据表表明,主时钟与采样率Fs之比如下:MasterClock = 16 kHz∙分频器MCLK∙256。此处256为常数,可在寄存器中设置除数。让我们检查一下方案-对于必要的功能,有一些系数可以将PLL频率除以7或17:



总结问题:您需要选择这样一组PLL和SAI因子以及分频器,以获得16 kHz的采样频率和128倍的比特频率。由于该集合的强制除数为7(或17),因此无法准确获得所需的结果。我必须建立一个乘法器和除法器表才能获得24.571 MHz。最后,将这个频率除以6(MCLK分频器),然后除以256(恒定),我们得到的数字足够接近16 kHz。现在,我将解释为什么这是如此重要。

USB操作


USB使用同步类型的传输来处理多媒体数据:在这种情况下,USB总线上可以保证一定的带宽和延迟值。不能保证数据传输:如果数据包到达失败,则将其视为丢失。这是由于严格的时间限制:没有办法再次询问。

通过USB FullSpeed速度的同步类型(12 Mbit / s; STM32 USB模块可以在此速度下工作),计算机每毫秒就会向设备发送数据:在这段时间之后,它必须收集累积的数据。让我提醒您一些介绍性的内容:采样频率是16 kHz,8个通道,每个通道需要两个字节,因为声音是16位的。总计16000∙2∙8/1000 = 256字节每毫秒。同步传输的一个数据包的大小可以达到1023字节,因此在这一点上没有问题。

因此,数据包大小为256个字节。看起来一切都很好。 16次在TDM上接收到数据,放入缓冲区,USB传入,我们给它一个数据包,然后重复……但这只是在理想世界中发生。问题在于,一方面,我们的16 kHz频率不够完美(略微不足),结果数据每毫秒传输的数据少于一次。另一方面,由于忙碌,计算机的毫秒数也浮动:如果可能,它就会来了。也就是说,麦克风采样频率不同于16 kHz(但始终相同),USB毫秒的长度也不同(这种差异很可能会浮动:结果多了一点,然后又比理想毫秒少了一点)。

为什么这是个问题?您可能会丢失包裹。可能没有必要解释完整的数据对于正确调试算法是必需的。数据包如何丢失:它们累积了256个字节的结果,将其放入缓冲区中,然后继续进行测量。一台计算机来了,拿走了前256个,我们仍然继续进行测量。计算机再次出现,但测量尚未完成-计算机留有空包装。然后,我们完成缓冲区的填充,并开始填充下一个缓冲区,直到计算机再次到达为止。计算机仅接收最后一个数据包;结果,一个数据包丢失了。



实际上,这个问题是已知的。有三种处理方法:

  • . USB. — . «» — . USB . , , ( , 16 ), . , .
  • . .
  • 异步是完成此任务的最佳选择。该设备具有稳定的频率发生器。无需参考USB即可保持完全相同的采样率。在这种情况下,您需要将数据传输到设备,以便没有明显的差异。

对于通过具有数模编码器的设备从计算机播放到扬声器的情况,互联网上已多次讨论了所有这些内容,该设备作为反馈告诉您自从收到最后一个数据包以来已经经过了多少个采样周期。



但是我们的任务恰恰相反,调试需要从麦克风接收数据到计算机,并且充其量只是提到从麦克风向计算机记录信号的问题。为什么不一样:引入来自计算机的反馈?有一个更简单的选择。

他在那


我们使用频繁添加的样本和两个缓冲区来存储要发送的数据。每毫秒16次,我们将下一个样本添加到选定的缓冲区中。在某个时间点会发生中断:USB接收了先前的数据包。如果1号缓冲区已满,它将切换到2号缓冲区。当USB到达下一个数据包时,它已经准备好了。发送2号缓冲区,然后切换回1号缓冲区。



USB在不同的时间点提供数据,包装中包含不同数量的样本。结果可能会超过16个,因此有机会超过256个字节的数据包,最好留出空间进行操作。假设它为384 = 256 + 128:这将提供半毫秒的余量,也就是说,它将USB信号的游泳阶段宽容50%-这样的余量应该绰绰有余。总计:有时会发送大约256个字节,但绝不会发送空数据包,从而避免了数据丢失。也就是说,通过增加封装来解决不均匀的问题,其代价是增加了分配给我们设备的部分总线带宽,而减少了为其他设备分配的部分带宽。

至此,向计算机的数据传输结束了。可以调试开发人员,如果某种数据包不足以完全理解,则可以在注释中提出问题。

我的讯息串和下一集


最近,我从家里的焊接实验室流了两次。起初,我只是展示了焊接过程,并告诉了我使用哪种设备。第二系列只是致力于STM32的开发。

流继续。这个星期五的19:00,我的硬件解决方案开发团队的同事Andrey Laptev将安排对Yandex.Stations Mini的在线分析-展示内部情况并分享生产历史。为了获得更多乐趣,安德烈(Andrey)将电池拧到色谱柱上-并非完全一样,可以通过电线工作。在最后,您将收到一份指南,该指南将使您自己重复这种经历或提出更有趣的设计。

注册观看流。您将收到一封带有日历文件的信件,并在播音日提醒您。感谢您的阅读!

All Articles