使用STM32的DFSDM外设来驱动PDM麦克风进行音频采集

0、前言

最近需要使用STM32L4系列来完成音频采集的工作,前前后后一共尝试了三种方案,最终在各种测试条件以及功耗等原因下,选择了目前这个方案。

主控使用的是STM32L475RCT6(无需一致,只要有DFSDM即可),MEMS麦克风使用的是ST的MP45DT02TR-M(某宝4.5一片)。

先说一下最终的效果,最终实现在8KHz采样率下,系统能正常工作,整体功耗大约为8mW。

1、之前的两种方案

最开始所使用的是INMP441麦克风,这款MEMS传感器使用I2S总线来驱动,使用单片机SAI外设给传感器相应的脉冲,其能输出1bit的PDM数据,然而对于本人实际使用来说,需将PDM数据流转化为PCM数据流才行。这里借鉴了ST官方Discover开发板的例程,使用ST官方提供的已加密的PDMtoPCM软件包,调用相应的滤波器来对PDM数据流进行过采样,最终输出PCM数据流。不过在调试过程中,噪音较大,自己目前尚不能对多余得到噪音进行消除,于是开始考虑第二种方案。

第二种方案是借鉴正点原子的潘多拉开发板,使用驻体麦克风方案。需要一个音频芯片ES8388,还需要一个咪头,以及比较复杂的外围电路,原理图如下图所示,

在这里插入图片描述
还有一点,ES8388是QFN封装,如果焊接不到位很容易导致虚焊(本人因为虚焊导致IIC一直无法应答,一度怀疑自己的IIC驱动是否有问题,从硬件IIC换到软件IIC还是不能解决,把芯片吹掉重新焊才解决问题)。这个方案需要使用IIC来进行音频芯片的控制字写入,然后使用STM32的SAI外设来进行数据采集。芯片内部集成了降噪等功能,单片机所采集的数据就是PCM格式的,这样直接将采集到的的数据发送计科,很是方便。不过也有不好的地方,在本人的实际测试过程中,其无法防震,震动会印象麦克风的收音效果,很容易失真(也可能是本人的处理不到位,不过在测试过程中确实存在这个影响)。如下图所示

在这里插入图片描述
还有一点就是使用本方案,PCB的尺寸较大,由于被外设所要求的频率限制,无法将主频进一步降低,为了低功耗,还需要将ES8388的DAC功能关闭,本人所调试的功耗极限值是8KHz采样率下30mW左右。

最终是参考了ST官方的NUCLEO开发板的例程,使用DFSDM来对PDM数据流进行抽样,来获得PCM数据流。

2、PDM?PCM?

什么是PDM?这里转载别人的一段话,解释的很明白。请参见https://www.cnblogs.com/pingwen/p/11301935.html

PDM调制器将缓冲模拟信号转换为串行脉冲密度调制信号,时钟输入( CLK)用于控制PDM调制器。

PDM信号无法直接驱动DA进行声音播放,PDM信号要变为声音信号还需要进行下采样,经过一次低通滤波和抽样,然后成为PCM信号。

PDM是一种调制形式,用于表示数字域中的模拟信号。它是1位数字采样的高频数据流。在PDM信号中,脉冲的相对密度对应于模拟信号的幅度。大量的1s对应于高(正)幅度值,而大量的0s对应于低(负)幅度值,交替的1s和0s对应于幅度值0。

PDM转为PCM信号,需要进行滤波和抽取。

在这里插入图片描述

3、DFSDM?

什么是DFSDM?

PDM转为PCM信号,需要进行滤波和抽取。

根据音频应用领域的标准化规定,PDM调制(脉冲密度调制)是数字麦克风的常见输出格式。PDM信号相当于∑∆调制信号,因此,DFSDM支持PDM信号。

数字麦克风是使用半导体技术制造的MEMS器件(微机电系统)。此类麦克风的有源致动器包括一张膜和一对微电极, 其中一个电极是固定的,另一个电极结合在膜内。当空气压力(声音)施加到膜上时,移动电极远离其默认位置,两个电极之间产生电容变化。感应信号由内置电子处理,作为PDM调制信号输出(脉冲密度调制)。

数字麦克风需要外部时钟信号(麦克风CLK输入信号),数据作为PDM调制信号,通过DATA输出线发送。时钟速度的范围通常介于1至3.2 MHz之间。DFSDM_CKOUT输出信号提供时钟信号,后者将麦克风输出数据速率定义至DFSDM。

DFSDM可通过一条线路并联2个麦克风(立体声配置:左右声道)。两个麦克风共用数据和时钟信号。时钟信号从DFSDM_CKOUT引脚分配到左右麦克风。来自两个麦克风的输出数据信号在同一条线路上复用:左侧麦克风在时钟上升沿提供数据,右侧麦克风在时钟下降沿提供数据(参见 图 27 )。左声道或右声道麦克风的配置通常是通过在麦克风上配置引脚来实现的(L/R选择引脚)。
在这里插入图片描述

DFSDM将DATA线上的两个麦克风信号进行分离。可以重定向DFSDM声道x的输入,以便将此声道 (x+1) 作为输入。接下来,将声道x配置为在上升沿进行数据采样,将声道(x+1)配置为在下降沿进行数据采样。两个声道的时钟信号相同,且内部连接至DFSDM_CKOUT信号。通过此配置,声道x从左侧麦克风接收数据,而声道(x+1)从右侧麦克风接收数据。两个声道向各自的数字滤波器馈送数据,最终为左右麦克风声道输出两个独立的并联数据流。参见图 28,了解使用DFSDM的立体声麦克风应用的完整图形。

在这里插入图片描述
DFSDM可以通过DFSDM_CKOUT引脚提供的时钟信号,为外部∑∆调制器提供时钟。此引脚的时钟频率决定了输入采样频率,后者也取决于输出数据速率频率。可以选择以下一种时钟源,用于驱动DFSDM_CKOUT:

• DFSDM 时钟:
– APB 时钟
– 系统时钟(独立于APB时钟分频器)
• PLL时钟(用于I2S的音频PLL)

将所选时钟源的频率除以2-256范围内的因数(根据DFSDM_CHyCFGR1寄存器中的CKOUTDIV字段设置的预分频比),得到DFSDM_CKOUT频率。

4、使用DFSDM驱动PDM麦克风分辨率

DFSDM 具有 24 位数据寄存器,可通过配置实现不同分辨率的支持,有效数据最高支持到 24 位。同时,新的HAL 库支持全硬件获取 16 位采样数据,不增加 CPU 负载。DFSDM 分辨率由过采样率,滤波器类型和右移位器决定。在这里插入图片描述
在这里插入图片描述
在此处增加关于分辨率的解释。

参见积分器最大数据表。

Filter 过采样率(FOSR)积分器率 过采样率(IOSR)Sinc^1Sinc^2FastSincSinc^3Sinc^4Sinc^5
xy± x ▪ y± x^2 ▪ y± 2x^2 ▪ y± x^3 ▪ y± x^4 ▪ y± x^5 ▪ y

在本次实验中,FOSR使用的是128,IOSR为1,采用Sinc^4滤波,所以输出的数值范围在±268,435,456,也就是精度可达到29bit。

5、CubeMX中DFSDM的配置

在本次演示中,使用STM32L475RCT6(只要具有DFSDM外设即可)。在我的测试样板中,MEMS的CLK管脚连接在PC2,MEMS传感器的DATA数据输出管脚接在PB12上。

本次演示,使用STM32L475RCT6的DFSDM外设来驱动MP45DT02TR-M麦克风,进行8KHz的音频采集。

5.1 DFSDM通道选择

在DFSDM外设中,选中通道1,并且勾选CKOUT
在这里插入图片描述
之后在右侧的预览图会发现PC2和PB12已经被占用
在这里插入图片描述

5.2 通道配置

在“Configuration” 标签页,点击“Channel1”打开 DFSDM通道 配置界面。

在这里插入图片描述

Type:配置数据读取时刻。SPI with rising edge 在时钟的上升沿读取数据;SPI with falling edge 在时钟下降沿读取数据。
**Spi clock:**总线时钟源。Internal SPI clock 利用内部时钟,对应为 CKOUT 时钟。
**Offset:**数据偏移量补偿。
Right Bit Shift : 右移位。右移位的确定,涉及到获取有效数据的位数,需要结合滤波器和积分器配置及分辨率需求进行确定。本文中,经过滤波器和积分器处理后输出数据分辨率为29-bit,所以将右移位设置为 5,从而 在 24位数据寄存器中获得有效的 24-bit 数据。
Analog watchdog parameters : DFSDM中模拟看门狗参数设置。应用例中没涉及到此功能,参数保持默认。

5.3 滤波器配置

选中Filter1,进行滤波器配置
在这里插入图片描述

Regular channel selection: 数据来源。选择与外部麦克风连接的通道。
Continuous mode:转换模式。选择连续转换模式。 Trigger to start regular conversion: 启动转换的触发源。
Fast mode: 快速模式。在连续转换数据源来自于同一个通道时可启用,能够提高转换速度。
DMA mode : DMA 模式。完成通道选择之后即可以进行DMA配置。
selection: 注入通道选择。应用例中没涉及到此功能,参数保持默认。
Sinc Order: 滤波类型。
Fosr: 滤波器过采样率。
Iosr: 积分器过采样率。

为了给CPU减负,建议使用DMA进行数据接收。
在这里插入图片描述

DMA 配置中,选择 Circular 模式,可实现循环向数据 buffer 中填充采样数据。
Data Width 设置为 Half Word,以便实现只获取数据寄存器的高 16 位数据,实现 16-bit 分辨率数据采集。

5.4 时钟配置

这里我选择的是由Audio时钟提供时钟源,此时由SAI1的时钟提供时钟源。也可以选择系统时钟来提供时钟源,具体采样率计算请参见以下公式。

采样率 F s Fs Fs F S = F C K O U T F o s r × I o s r F_{S}=\frac{F_{CKOUT}}{F_{o s r} \times I_{o s r}} FS=Fosr×IosrFCKOUT

其中, F C K O U T F_{CKOUT} FCKOUT 的计算公式为 F C K O U T = F A u d i o d i v i d e r F_{CKOUT}=\frac{F_{Audio}}{ divider} FCKOUT=dividerFAudio

在这里插入图片描述

Selection: CKOUT 时钟源选择。
Divider: 时钟预分频因子。

5.5 时钟树配置

如下配置,使得SAI1的时钟为17.411765MHz,可以得到8KHz的采样率。
在这里插入图片描述

5.6 串口配置

在本次演示中,使用串口1将采集到的数据发送到PC端进行处理。

在单麦克风8KHz采样下,串口波特率设置为256000kbps即可满足要求。

在这里插入图片描述
不要忘记打开串口的DMA

在这里插入图片描述
还要打开串口中断。

在这里插入图片描述
由此,CubeMX的配置就完成。

6、程序设计

在本次演示中,使用半传输中断来接收数据,能保证不间断的PCM数据流。

6.1 原理解释

开启DFSDM接收之后,设定每次接收固定长length’的数据。当接收到length/2个数据之后,便进入半传输中断回调函数,此时DMA传输仍在进行,通过串口将已接收到的前length/2个数据发送走,然后当接收到length个数据之后进入传输完成中断,由于开起了DMA的Circular传输模式,会继续接收,不过会覆盖缓存区,此时使用串口将后length/2个数据发送。由此即可实现不间断的PCM数据流。

6.2 部分源代码

#define SAMPLE_FREQ				8000
#define BYTE_PER_SAMPLE		2
#define MICROPHEN_NUMBER	1
#define FRAME_NUMBER			1
// 16bit sample resolution
#define BUF_LENGTH 				(SAMPLE_FREQ / 1000 * MICROPHEN_NUMBER * FRAME_NUMBER)

int16_t Buf_Mic0[BUF_LENGTH] = {0x12};

int main(void)
{
  	/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  	HAL_Init();
  	/* Configure the system clock */
  	SystemClock_Config();
  	/* Initialize all configured peripherals */
  	MX_GPIO_Init();
  	MX_DMA_Init();
  	MX_USART1_UART_Init();
  	MX_DFSDM1_Init();
  
  	// 读取一下USART_FLAG_TC标志位,防止硬件复位之后发送第一个数据丢失
	__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC);
	
	/* 启动采样,在初始化完成后调用 */	
	if(HAL_DFSDM_FilterRegularMsbStart_DMA(&hdfsdm1_filter0, Buf_Mic0, BUF_LENGTH) == HAL_ERROR)
  	{
		Error_Handler();
  	}
  
  	HAL_Delay(5000);
  	__HAL_DMA_DISABLE(&hdma_dfsdm1_flt0);
  	while (1){}
}

// 半传输回调函数
void HAL_DFSDM_FilterRegConvHalfCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
{
	//半传输完成,可在此添加对采样数据的处理
	HAL_UART_Transmit_DMA(&huart1, (uint8_t *)Buf_Mic0, BUF_LENGTH);
}

// 传输完成回调函数
void HAL_DFSDM_FilterRegConvCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
{
	//传输完成,可在此添加对采样数据的处理
	HAL_UART_Transmit_DMA(&huart1, (uint8_t *)(Buf_Mic0 + BUF_LENGTH / 2), BUF_LENGTH);
}

6.3 实际测试

采集5s的音频,使用Python处理后进行播放,效果还不错

在这里插入图片描述

7、总结

以上就是本人使用STM32L475的DFSDM来开发PDM麦克风的经验,欢迎讨论交流。

  • 25
    点赞
  • 160
    收藏
    觉得还不错? 一键收藏
  • 25
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值