1
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Raspberry Pi でMEMSマイク(PDM出力)を使う

Last updated at Posted at 2021-09-06

やったこと

Raspberry Pi にMEMSマイク(PDM出力)を接続して録音した
ラズパイでPDM入力を使った例が検索しても見つからなかった(2021/09/06)ので書いてみた

書いてる人

エンジニアではありません、ただのオーディオマニアです
Lチカを初めたばかりで簡単なことしかできません
変なところがあれば突っ込みよろしくお願いします

MEMSマイクとは

シリコンマイクとも呼ばれる超小型マイクで急速にエレクトレットコンデンサマイクと置き換わった
iphoneは4からMEMSマイク
小型で熱や衝撃に強く特性も安定している
音質もそこそこ優れたものがある(良くないものもある)
周波数特性はフラットではない(高域に共振によるピークが出る)
アナログ出力のものとデジタル出力(PDM、I2S、SPI)のものがある
今回はMEMSマイクのうちPDM出力のものを使った

PDM(Pulse Density Modulation、パルス密度変調)

アナログ信号をデジタル化する方式で、パルスの密度で振幅を表す
普通のwavやflac、CDはPCM(Pulse Code Modulation)で記録されている
SACDはPDMで記録されている

試した環境

Raspberry Pi 3B ( おそらく2や4でも動くと思うが確認してない )
pi4はクロックが19.2MHzではなくて54MHzなのでこのままでは動きません。試してないのに適当なことを言うのはダメですね。(2021/11/12追記)

OS: Raspberry Pi OS Lite(Release date: May 7th 2021)
C言語(gcc 8.3.0)

Raspberry Pi でPDM入力の使い方

Raspberry Pi のPCMモジュールにPDMモードがあるのでそのまま使う

参考サイト・資料

資料
公式サイトの資料
エラッタ
レジスタのアドレス

参考にしたサイト
楽しくやろう。
このサイトをみながらLチカとか試してみた

設定法

メモリマッピング

  • mmap でアドレスをマッピングする
    これによりGPIO、クロック、PCMの各レジスタにアクセスできるようになる
    ベースアドレスはPi0 Pi2-3 pi4で違うので注意が必要
  • レジスタへのポインタ変数は全て"volatile"をつけて宣言する
  • レジスタは32bitなので uint32_t とする

GPIOの設定

  • GPIO18、GPIO20をALT0に設定する
    GP_FSEL1 レジスタ、GP_FSEL2 レジスタ
    これでGPIO18がPCM_CLK、GPIO20がPCM_DINに設定される

クロック設定

PCMクロック関連レジスタのアドレスは公式のデータシートには載ってない

  • CM_PCMCTL レジスタ
    ENAB = 0にしてクロック無効に
    BUSY = 0を待つ
    SRC = 1(OSC 19.2MHz)、 MASH = 0

MASHは分周を非整数分の1にするときに使う
ジッタと引き換えに正確な周波数が得られる
今回はジッタを嫌ってMASHは使わない

  • CM_PCMDIV レジスタ
    DIVI = 8、DIVF = 0

非整数で分周したい場合には DIVF に 少数部分を4096倍したものを設定する

  • CM_PCMCTL レジスタ
    ENAB = 1(ほかはそのまま)クロック有効に

これで19.2MHzが1/8に分周されてクロックが2.4MHzに設定される
使うMEMSマイクによってクロックの範囲が違うのでMEMSマイクのデータシートを確認すること

PDM設定

  • PCM_CS_A レジスタ
    EN = 0

  • PCM_MODA_A レジスタ
    CLKM = 0, FRXP = 1, PDME = 1, PDMN = 0

CLKM = 0 でクロックがマスターモード
PDME = 1 でPDMモードを有効にする
PDMNはデシメーションフィルタ(4次CIC)の設定
PDMN = 0 で 1/16、 データは 16 bits unsigned に変換される
PDMN = 1 で 1/32、 データは 20 bits unsigned に変換される
クロックが2.4MHz、PDMN=0なら 2.4MHz/16 で サンプリング周波数150kHz、16bitのデータになる
FRXP = 1 にすると16bitデータ2つを32bit fifoに詰め込む
PDWM = 1 で使うと16bitからはみ出たデータは捨てられてしまう

  • PCM_RXC_A レジスタ
    CH1EN = 1, CH2EN = 1

MEMSマイクは設定でクロックの立ち上がりか立ち下がりのどちらかでデータを転送するか選択できる
立ち上がりに設定したマイクと立ち下がりに設定したマイクを接続してCH1ENとCH2ENを両方有効にすれば2chのデータが得られる
FRXP = 1 なら 16bit 2ch分のデータが1つのFIFO(32bit)に入る

  • PCM_CS_A レジスタ
    EN = 1, RXON = 1

これでPCMモジュールがPDMモードで作動し始めて、PCM_FIFO_A レジスタにデーターが送られてくる

データの受信

割り込みやDMAもできるらしいが面倒なのでポーリング
マイクが作動してから1秒くらいは安定しない
MEMSマイクの消費電力は少ないので常に作動させておけば必要なときにすぐ録音が開始できる

  • PCM_FIFO_A レジスタ
    FIFOは64個あるのでデータを64個読み捨てる

  • PCM_CS_A レジスタ
    RXERR フラグを解除

あとはデーターの読み取りを繰り返すだけ

  • RXD = 1 ならPCM_FIFO_Aから読み取る
  • RXERR = 1 ならエラーが起きてる
  • RXD = 0 ならちょっと待つ

RXDを確認してから読み取っているのでアンダーフローはありえない
エラーが起きた場合にはオーバーフロー(読み取りが間に合ってない)
今回作ったソフトはchrtで優先度を上げないとエラーが出る

取り込んだデータの処理

16bit unsigned なので 32768を引いて 16bit signed に変換する
音声ファイルに変換するならSOXを使うのが便利

今回つかったMEMSマイク

  • 秋月電子で買った超音波対応のもの(Knowles社製 SPH0641LU4H-1)
  • 可聴周波数でも使える
  • SN比は64.3dBなのでまあまあ
    MEMSマイクでも70dBを超えるものもあるのでちょっと物足りない
  • 10%THD が 120dB SPL なので大音量には強くない
    したがって大音量楽器の近接での録音なんかには使えない

https://akizukidenshi.com/catalog/g/gK-15577/
https://akizukidenshi.com/download/ds/knowles/SPH0641LU4H-1.PDF
データシートを見るとultrasonic modeにするにはLow-Power Mode か Standard Performance Mode を経由しろとあるので注意

接続

マイクのVDD, GND, CLK, DAT に接続する
VDDは+3.3Vに接続 +5Vと間違わないように
CLK はGPIO18、DATはGPIO20に接続する

作ったソフト

Github に上げてみた
https://github.com/assi-dangomushi/pdm_rec

あとがき

Lチカから始めて意外と簡単にマイクを動作させることができた
基礎知識のないとデータシートを読むのが大変

1
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?