STM32F4 Discovery 麥克風USB錄音

952 views
Skip to first unread message

Lin

unread,
Apr 13, 2014, 2:48:10 PM4/13/14
to stm...@googlegroups.com
目前專題研究STM32的麥克風錄音存至USB隨身碟,使用STM32F4 Discovery開發版,使用Audio_playback_and_record範例做修改,由於範例錄出來的音檔取樣率只有8kHz,不符合需求,欲提升至16kHz或更快。

現在可以做到I2S驅動開發板上的MP45DT麥克風,透過SPI中斷接收PDM資料,等待64筆後,由PDM_Filter_64_LSB函數轉成PCM音訊,整體麥克風驅動、中斷方式與Audio_playback_and_record範例一樣,主要差異在於後端資料儲存,已有先測試將轉換好的PCM資料存放在STM32F4的內部RAM,累積32000筆後再透過USART3傳到LabVIEW驗證聲音,結果取樣率16kHz無誤,頻譜分析也能到8kHz,聲音正常,代表麥克風驅動至PDM轉PCM這部分是正確的(參考附件wave1.png)。

後端資料儲存測試過將PDM_Filter_64_LSB函數轉換出PCM資料即時寫入隨身碟,但將結果顯示至聲波圖會發現充滿音爆現象(參考附件wave2.png),可能原因為STM32寫入隨身碟速度不夠;另外也測試過即時將轉換出PCM資料透過USART(921600bps)發送到LabVIEW端接收,其結果也充滿音爆。是否請大家幫忙指點問題或建議呢? 目前主要撰寫8bit MCU,32bit MCU第一次接觸,萬分感謝。


wave2.png
wave1.png

Bee

unread,
Apr 14, 2014, 1:18:33 AM4/14/14
to stm...@googlegroups.com
看起來數值是沒有問題。
不過音爆圖看來不像是有雜訊。因為皆以256的數值為其偏差量。
也就是在將16位元資料以8位元存入時,符號位元錯誤。
建議取樣使用unsigned short為單位。存入USB時則是unsigned char為單位。
使用無號數才不會有數值轉換問題。
另外PC側也相同,解讀時也以unsigned為主。

Lin

unread,
Apr 14, 2014, 7:54:51 AM4/14/14
to stm...@googlegroups.com
Bee您好


附件wave1.png的結果是先將轉換好的PCM音訊儲存於STM32F4的內部RAM,32000筆,待累積完畢後再轉存至USB隨身碟的結果,抱歉這部分沒有於上面描述清楚。

f_write (&file, (uint16_t *)PCM_DATA, 32000*2 , (void *)&bytesWritten);


有先驗證過fatfs的f_write函數,寫入時是從低位元開始寫入,
如寫入0xAB CD, 寫入完畢從LabVIEW驗證資料則為0xCD AB,這部分在LabVIEW已有將位元順序調整回來0x AB CD,可以參考附件wave3.png,這張圖是沒有將位元順序調整回來,直接轉換成聲波圖,結果是很雜亂;將位元順序還原後就如上面附件wave1.png所示,聲音正常,取樣率正確,無爆音。

即時寫入:f_write (&file, (uint16_t *)PCM_DATA_BUF, 16*2 , (void *)&bytesWritten);




Bee於 2014年4月14日星期一UTC+8下午1時18分33秒寫道:
wave3.png

Bee

unread,
Apr 14, 2014, 9:48:59 PM4/14/14
to stm...@googlegroups.com
看來即時寫入這件事是造成音爆主因。
我看了一下原始碼,主程式沒有什麼內容。也就是大部分工作在中斷程式內。
您若是在中斷程式中發動寫入,因為USB傳輸並不是在固定時間內可以確定完成。
結果可能會影響其他工作,包括取I2S相關的工作,進而造成資料錯誤。

我是用ADC做音頻相關,取樣率在100KHz,RAM的速度可以負擔。
儲存則是用SDIO上的SD卡,因為是確定STM32為主控,所以不會有其他不確定因素。
存下來的資料由SD卡到PC側無問題。
但我中斷少用,內容也只有一點,減少中斷程式內執行時間。大量資料傳輸則是用DMA。
因為驅動SD卡也是用到Fatfs,我認為有點慢,在大量資料傳送時,直接使用SDIO寫入。其他非大量資料動作時,則用Fatfs工作。

16KHz和我設計的系統比起來應不算是問題。
你去確認工作筆數,將干涉到的程式找出來才能解開你的問題。

Bee

unread,
Apr 14, 2014, 10:03:35 PM4/14/14
to stm...@googlegroups.com
先做錄音,再做存檔。沒有問題再弄即時。

Lin

unread,
Apr 17, 2014, 8:37:35 AM4/17/14
to stm...@googlegroups.com
你好


我的方式是I2S中斷裡的PDM_Filter_64_LSB()轉換完啟動flag,讓主程式判斷該flag再寫入USB隨身碟,整個流程裡只有I2S中斷。

目前已捨棄USB隨身碟寫入,將資料先寫入STM32F407內崁1MByte的Flash,這部分確定已經可以,可存放30秒的16KHz,16Bit聲音。

最近會測試讓DMA先接收I2S資料,因為PDM_Filter_64_LSB()函數要64筆才能轉換成PCM,可以不必每次讓MCU都處理I2S中斷,等待64筆後DMA通知處理,應該可以再解省MCU時間,這是目前的想法,還不曉得可否執行。


File:waverecorder.c
void AUDIO_REC_SPI_IRQHANDLER(void)
{
  uint16_t app;
  /* Check if data are available in SPI Data register */
  if (SPI_GetITStatus(SPI2, SPI_I2S_IT_RXNE) != RESET)
  {
    app = SPI_I2S_ReceiveData(SPI2);
    InternalBuffer[InternalBufferSize++] = HTONS(app);
    /* Check to prevent overflow condition */
    if (InternalBufferSize >= INTERNAL_BUFF_SIZE)
    {
      PDM_Filter_64_LSB((uint8_t *)InternalBuffer, PCM_BUF, 64 , (PDMFilter_InitStruct *)&Filter);
      PCM_FLAG = 1;
      WaveCounter += 16;
      InternalBufferSize = 0;
      if( WaveCounter > 480000)
      {
        REC_FLAG = 0;
      }
    }
  }
}

File:main.c
while( REC_FLAG )
{
if(PCM_FLAG)
{
for( PCM_i = 0; PCM_i < 16; PCM_i ++)
{
FLASH_ProgramHalfWord (Address, PCM_BUF[PCM_i]);
                                Address = Address + 2;
// if (FLASH_ProgramHalfWord (Address, PCM_BUF[PCM_i]) == FLASH_COMPLETE)
// Address = Address + 2;
// else
// {
// while(1)
// GPIO_SetBits (GPIOD, GPIO_Pin_13);
// }
}
PCM_FLAG=0;
}
}




Bee於 2014年4月15日星期二UTC+8上午9時48分59秒寫道:

Bee

unread,
Apr 18, 2014, 2:42:20 AM4/18/14
to stm...@googlegroups.com
追了USB程式碼,追了很久。大概知道問題了。
因為USB所有函式都在中斷中執行,包括讀取及寫入。所以變成其他工作無法有效的進行。
難怪錄音取樣率低。
而我則因為沒有USB,所以才能即時將資料寫入SD卡。
不過USB要能即時使用,看來結構要改。
這個也是很頭痛的項目。對於沒有遇過USB程式的我來說,要動不難,要所有的裝置可以即時動作就有些難度了。

儲存在Flash也行,不過容量仍是不大,可用性低了些。
還是寫在SD卡好太多了。目前已經實驗寫入16MB以上,都沒有問題。
可以在PC上使用SD卡讀錄到的資料,直接寫簡單的C語言讀檔測試,測試成功再移回STM32內。開發速度會快許多。
Message has been deleted

ma41...@stust.edu.tw

unread,
Sep 13, 2016, 7:53:27 AM9/13/16
to STM32TW
你好 請問一下STM32F407 如何接收3.5MM的麥克風訊號呢??
能指導一下嗎?
Reply all
Reply to author
Forward
0 new messages