數字麥克風PDM訊號採集與STM32 I2S介面應用(二)

  • 2019 年 10 月 3 日
  • 筆記

      在使用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

AN3998在STM32微控制器上的PDM軟體音頻解碼

3、  UM2372_用於STM32F4_F7_H7的PDM2PCM軟體包介紹

STM32Cube PDM2PCM software library for the STM32F4/F7/H7 Series

4、  基於 STM32 I2S 的音頻應用開發介紹

基於 STM32 I2S 的音頻應用開發介紹

 

尊重原創技術文章,轉載請註明。

https://www.cnblogs.com/pingwen/p/11301935.html