在使用STM32的數字麥克風I2S接口時,計算采樣率讓人頭疼,芯片手冊上沒有明確的說法,而手冊上的計算方法經過測試卻和實驗不符。借助搜索引擎,大部分資料都是來自於開發板賣家或開發板論壇,主要是咪頭采集然后配置WM89系列解碼芯片,然后配合FatFS、MP3解碼等模式,主要是講解I2S錄音、存儲、放音等。外文資料得到的也寥寥無幾,也沒有找到講解STM32數字麥克風配置、計算的文檔。加上網上資料轉載、抄襲、淺嘗輒止的筆記教程,這些更是讓檢索大海撈針,過程艱辛一言難盡,有些網文三言兩語抑或作者都沒有搞清楚隨手一寫,有些是作者搞清楚了但藏着掖着最關鍵的點沒說,有些是跟着別人現成的教程做了一邊又寫了一篇筆記卻沒有增加任何新東西,種種緣由搞得技術圈文章氛圍差到極點讓人惱火。
我的需求是音頻特征點檢測,所以把聲音錄制然后傳輸到PC上是首要任務,經過多次摸索,終於了解一二,現在分享出來方便后來者,恐水平有限有未發現的錯誤而誤導他人,在文尾附上STM32 I2S和PDM采集相關的原廠資料以作參考。
盡管內容龐雜,但爭取化繁為簡講清楚數字麥克風單聲道模式的PDM信號采集,PDM到PCM解碼,以及上位機驗證分析如python/matlab腳本讀取錄音文件和播放,頻譜分析等。
1、 STM32 I2S接口標准和數據格式
這些內容參考STM32芯片編程手冊,基本上就是4個模式,以及16位32位數據格式,若使用SPI/I2S接口通信還要有MSB、LSB配置。
2、 STM32 I2S采樣率的配置
STM32的時鍾配置和數據格式決定了音頻信號的采樣率,如下計算。在使用了ST CUBE MX后,下面的計算過程也省略了,直接配置傳感器的數據格式、接口標准、采樣率就可以了。
上面是STM32芯片手冊給出的信息,在做音頻采集時候,發現這和實測效果相差較遠,原來這組公式並不適合PDM信號的數字麥克風。PDM麥克風只是利用了STM32的I2S信號時鍾和數據線,它的采樣只是按照bit采樣,每一個sample為1bit,要轉換為類似於AD/DA的采樣值,還需要進行PDM2PCM轉換,ST給出了一個驅動包,可以進行類似轉換,可以參考AM3998和UM2372手冊。
下面的公式才是PDM麥克風與STM32 I2S接口配合時使用的采樣率計算方法,其中FS是PDM bit sample的采樣率,DIV是PDM到PCM的抽樣因子,經過抽樣,把bit sample變為類似於模擬采樣的sample。這里的Fs都是指采樣sample的速率,雖然PDM輸出是以u16或u32方式呈現的,但其采樣率是按照bit計算的,一個sample只有1個bit。
例如下面的配置,PDM采樣率為32khz,單聲道應用,那么PDM2PCM使用64抽取比,則真實的音頻采樣率為16*2*32khz/64 = 16khz。
/* I2S2 init function */ void MX_I2S2_Init(void) { hi2s2.Instance = SPI2; hi2s2.Init.Mode = I2S_MODE_MASTER_RX; hi2s2.Init.Standard = I2S_STANDARD_MSB; hi2s2.Init.DataFormat = I2S_DATAFORMAT_16B; hi2s2.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE; hi2s2.Init.AudioFreq = I2S_AUDIOFREQ_32K; hi2s2.Init.CPOL = I2S_CPOL_LOW; hi2s2.Init.ClockSource = I2S_CLOCK_PLL; hi2s2.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_DISABLE; if (HAL_I2S_Init(&hi2s2) != HAL_OK) { Error_Handler(); } }
此時PDM的時鍾頻率為32khz*16*2=1024khz,測量結果如下驗證了該分析結論。
STM32F407的I2S IP核是按照左右聲道來處理音頻信號的,所以其SW腳信號頻率為32khz。
3、PDM和PCM信號
PDM調制器將緩沖模擬信號轉換為串行脈沖密度調制信號,時鍾輸入( CLK)用於控制PDM調制器。PDM信號無法直接驅動DA進行聲音播放,PDM信號要變為聲音信號還需要進行下采樣,經過一次低通濾波和抽樣,然后成為PCM信號。
PDM是一種調制形式,用於表示數字域中的模擬信號。它是1位數字采樣的高頻數據流。在PDM信號中,脈沖的相對密度對應於模擬信號的幅度。大量的1s對應於高(正)幅度值,而大量的0s對應於低(負)幅度值,交替的1s和0s對應於幅度值0。
PDM轉為PCM信號,需要進行濾波和抽取。PDM信號采樣率就是I2S的clk時鍾頻率,可見這是一個高頻采樣,按bit采樣的信號。PCM信號是目標音頻的采樣率,比如高保真44khz,PDM2PCM的抽樣因子M,則M=PDM頻率/音頻采樣率。
ST 提過了PDM2PCM的軟件包,可以完成上面的工作。
軟件包源碼沒有開源,使用手冊也簡潔的讓人抓狂,我覺得可能是因為ST更高級的MCU直接帶了硬解碼,所以對中低端MCU I2S接口的軟解碼關注度也不夠。幸好之前做過信號處理工作,一些概念和內在邏輯能猜個八九不離十,使用起來沒有任何難度就上手了,這個軟件包使用時需要配置下面幾個參數。
1)初始化PDMFilter,包括采樣率,低通高通濾波器截止頻率,通道個數。
typedef struct { uint16_t Fs; float LP_HZ; float HP_HZ; uint16_t Out_MicChannels; char InternalFilter[34]; } PDMFilter_InitStruct;
2)完成參數初始化后調用濾波器初始化函數。
Void PDM_Filter_Init (PDMFilter_InitStruct * Filter)
3)最后調用下面函數完成PDM2PCM的抽取。
PDM_Filter_XX_XX(uint8_t* data, uint16_t* dataOut, uint16_t MicGain, PDMFilter_InitStruct * Filter)
ST提供了多種PDM2PCM的抽取方法。
int32_t PDM_Filter_64_MSB(uint8_t* data, uint16_t* dataOut, uint16_t MicGain, PDMFilter_InitStruct * Filter); int32_t PDM_Filter_80_MSB(uint8_t* data, uint16_t* dataOut, uint16_t MicGain, PDMFilter_InitStruct * Filter); int32_t PDM_Filter_64_LSB(uint8_t* data, uint16_t* dataOut, uint16_t MicGain, PDMFilter_InitStruct * Filter); int32_t PDM_Filter_80_LSB(uint8_t* data, uint16_t* dataOut, uint16_t MicGain, PDMFilter_InitStruct * Filter);
參考文檔:
1、如何將PDM數字麥克風連接到STM32單片機
AN5027 使用STM32 32位Arm® Cortex® MCU連接PDM數字麥克風
2、 PDM audio software decoding on STM32 microcontrollers
3、 UM2372_用於STM32F4_F7_H7的PDM2PCM軟件包介紹
STM32Cube PDM2PCM software library for the STM32F4/F7/H7 Series
4、 基於 STM32 I2S 的音頻應用開發介紹
數字麥克風PDM信號采集與STM32 I2S接口應用--筆記目錄:
數字麥克風PDM信號采集與STM32 I2S接口應用(一)
https://www.cnblogs.com/pingwen/p/11298675.html
數字麥克風PDM信號采集與STM32 I2S接口應用(二)
https://www.cnblogs.com/pingwen/p/11301935.html
數字麥克風PDM信號采集與STM32 I2S接口應用(三)
https://www.cnblogs.com/pingwen/p/11794081.html
數字麥克風PDM轉PCM與STM32 I2S接口應用----重要文檔列表
https://www.cnblogs.com/pingwen/p/11302452.html
數字麥克風PDM信號采集與STM32 I2S接口應用(四)--單片機源碼
https://www.cnblogs.com/pingwen/p/13371144.html
尊重原創技術文章,轉載請注明。