前回は、M5Stack AtomS3RのESP32-S3が持つハードウェアのPDM-to-PCM変換を利用して、PDMマイクの音を録音した( M5Stack AtomS3RでPDMマイクの音をハードウェアでPDM-to-PCM 変換して録音 )。
今回はその続きとして、I2Sからraw PDMデータを受け取り、ESP32-S3上のソフトウェアでPCMへ変換した。録音部分はESPHomeの外部コンポーネントとし、外付けBME280とAtomS3R内蔵のBMI270/BMM150の値をHome Assistantへ送り、LCDにも表示する。
ESP32-S3 の ハードウェアデシメーション(Hardware decimation) ではサンプリング周波数は実質的に48kHzまでしか対応できない。ソフトウェアデシメーション(Software decimation)を利用してサンプリング周波数192kHzで録音ができる。ソフトウェアデシメーションを用いることで超音波の録音が可能になる。ただし、192kHz録音ではデシメーション比が24であり、音響特性は応用によっては不十分と考えられる。
本記事で使用するのは、8 MB PSRAMを搭載したM5Stack AtomS3Rである。外観がよく似たAtomS3は対象ではない。
OpenAI Codex を使って、コードの修正およびこの記事の原稿作成を行った。
作ったもの
PDMマイクの信号を3.072 MHzで受信し、CICフィルターとFIRフィルターを使って48 kHz、16 bit、monoのPCMへ変換する。PCMはAtomS3RのPSRAMへ一時保存し、録音完了後にWAV/BWFファイルとしてブラウザーから取得する。
| 項目 | 内容 |
|---|---|
| 本体 | M5Stack AtomS3R(ESP32-S3) |
| PDMマイク | Knowles SPH0641LU4H-1 |
| PDMクロック | 3.072 MHz |
| PCM | 48 kHz、mono、signed 16 bit |
| デシメーション | CIC3 / 16、127-tap FIR / 4 |
| 録音バッファ | AtomS3RのPSRAM |
| 録音操作 | HTTP port 8088 |
| センサー | BME280、BMI270、BMM150 |
| 連携 | ESPHome API / Home Assistant |
| 検証環境 | ESPHome 2026.7.2 / ESP-IDF 5.5.5 |
raw PDMを受信し、CIC3とFIRで48 kHz PCMへ変換する流れ
ハードウェア変換版との違い
前回はESP32-S3のハードウェアPDM-to-PCM変換機能からPCMを受け取っていた。今回はI2S PDM RXをraw PDM形式に設定し、PDMの1 bitデータをソフトウェアの外部コンポーネント内でPCMへ変換する。
hardware decimation:
PDM microphone -> ESP32-S3 PDM-to-PCM -> PCM
software decimation:
PDM microphone -> raw PDM RX -> CIC3 -> FIR -> PCM
ソフトウェア版では変換処理を確認、変更しやすい反面、ESP32-S3のCPU時間を使う。このため、ESPHomeのコンパイル最適化は性能優先とした。
ハードウェア
使用したもの
- M5Stack AtomS3R
- SPH0641LU4H-1を搭載したPDMマイク基板
- BME280温湿度・気圧センサー
PDMマイクの配線
| SPH0641LU4H-1 | AtomS3R |
|---|---|
| CLK | GPIO5 |
| DATA | GPIO6 |
| VDD | 3.3 V |
| GND | GND |
BME280の配線
| BME280 | AtomS3R |
|---|---|
| VCC | 3.3 V |
| GND | GND |
| SDA | GPIO38 |
| SCL | GPIO39 |
設定ファイルではBME280のI2Cアドレスを0x76としている。0x77になっている基板を使う場合はYAMLのaddressを変更する。
セットアップ
1. リポジトリ
リポジトリは、次の場所である。

secrets.example.yamlをsecrets.yamlへコピーし、Wi-Fi、ESPHome API暗号鍵、OTAパスワード、Fallback APパスワードを変更する。
2. 設定を検証する
esphome config atoms3r_software_decimation_pdm_recorder.yaml
3. コンパイルしてAtomS3Rへ書き込む
esphome compile atoms3r_software_decimation_pdm_recorder.yaml
esphome run atoms3r_software_decimation_pdm_recorder.yaml
software decimationの設定
主な設定は次の部分である。
esp32:
framework:
type: esp-idf
advanced:
compiler_optimization: PERF
pdm_recorder:
id: pdm_recorder_id
pdm_clk_pin: GPIO5
pdm_din_pin: GPIO6
capture_mode: software_pcm
pdm_clock: 3072000Hz
raw_pdm_msb_first: true
sample_rate: 48000Hz
data_bit_width: 16bit
saving_bits_per_frame: 16bit
capture_mode: software_pcmによってraw PDM受信とソフトウェア変換を選択する。PDMクロック3.072 MHzをPCMサンプルレート48 kHzで割ると、全体のデシメーション比は64となる。
最大192 kHzのソフトウェアデシメーション
公開YAMLの標準設定は48 kHzであるが、ソフトウェアデシメーション実装は最大192 kHzに対応する。PDMクロック4.608 MHz、デシメーション比24、signed 16 bit、monoの設定で192 kHz録音をAtomS3R実機で確認済みである。
pdm_recorder:
id: pdm_recorder_id
pdm_clk_pin: GPIO5
pdm_din_pin: GPIO6
capture_mode: software_pcm
pdm_clock: 4608000Hz
raw_pdm_msb_first: true
sample_rate: 192000Hz
192 kHzでは、100 msで19,200フレーム、1秒で192,000フレーム、5秒で960,000フレームを取得した。5秒録音の実測時間は5,005 msであり、WAVヘッダーとデータ長は正常、I2S read errorおよびクリッピングは発生しなかった。96 kHzと192 kHzの両方で、HTTP録音要求、録音後のWi-Fi再接続、WAVダウンロードも確認している。
CICとFIRによる変換
最初に3段のCICフィルターで16分の1に間引く。CICは乗算を使わずに大きな間引きを行えるので、PDMのような高いサンプルレートの処理に向いている。
続いて127-tapの固定小数点FIRフィルターを通し、さらに4分の1に間引く。CICとFIRを合わせて64分の1となり、3.072 MHzのPDMから48 kHzのPCMを生成する。
ESP-IDFのraw PDM RXが返す16 bit wordについて、時間順にPDMビットを処理する必要がある。今回のマイクと設定ではraw_pdm_msb_first: trueを使用した。
録音してみる
AtomS3RのLCDまたはルーターでIPアドレスを確認し、同じLANのブラウザーから次を開く。
http://<AtomS3RのIPアドレス>:8088/
録音時間と48 kHzを指定して録音を開始する。録音中はI2S処理を優先するためWi-Fiを一時停止し、録音完了後に再接続する。完了するとWAV/BWFファイルをダウンロードできる。
センサー値とLCD表示
外付けBME280から温度、湿度、気圧を取得する。AtomS3R内部のBMI270/BMM150からは加速度、角速度、地磁気、IMU温度を取得する。
LCDにはIPアドレス、BME280の温湿度、加速度、地磁気を表示する。
Home Assistantとの連携
ESPHome APIを有効にしているので、Home Assistantへデバイスを追加すると、BME280、BMI270、BMM150の値をエンティティとして利用できる。API暗号鍵はsecrets.yamlで管理する。
実機で確認したこと
ESPHome 2026.7.2とESP-IDF 5.5.5でビルドし、AtomS3Rへ書き込んで確認した。
- devcontainerを使わないクリーンビルドとUSB書き込み
- BME280、BMI270、BMM150の全13センサー値を暗号化ESPHome APIで取得
- LAN経由のOTA更新と、再起動後のAPI・HTTP録音の復帰
- HTTP録音画面と、LAN内限定・未認証のNVS設定画面
- 48 kHz、16 bit、monoで500 ms(24,000 frames)と5秒(240,000 frames)を録音
- RIFF/WAVEヘッダー、sample width、sample rate、frame数の整合
- 5秒録音でI2S read errorなし、clipped sample 0
- 発展設定として96 kHzおよび192 kHzの実機録音、192 kHz・5秒で960,000 framesを確認
5秒録音はmin -1566、max 1544、RMS 369.86であった。ここでは録音経路の動作確認だけを目的とし、SNR、THD+N、周波数特性などの音響性能は評価していない。
LCDドライバーの初期化と表示更新経路にはエラーがなかった。画面にIPアドレスとセンサー値が正しく描画されることは、実機画面を見ながら最終確認する必要がある。
ハマりどころ
AtomS3とAtomS3Rを取り違えない
本構成は録音バッファとしてPSRAMを使う。対象は8 MB PSRAMを搭載したAtomS3Rであり、AtomS3では動作しない。
raw PDMには新しいESP-IDFが必要
software decimationでは、I2S PDM RXから変換前のraw PDMを取得する必要がある。今回の検証環境はESPHome 2026.7.2とESP-IDF 5.5.5である。古いESP-IDFのハードウェア変換済みPCMをraw PDMとして扱わないよう、外部コンポーネント側でもバージョンを確認する。
録音中はWeb画面が止まる
録音中はWi-Fiを一時停止するため、ブラウザーは応答待ちのように見える。録音終了後にWi-Fiへ再接続して応答を返す。
HTTP画面に認証はない
録音画面と/settingsには認証がない。信頼できるLAN内だけで使用し、ルーターでポート転送するなどしてインターネットへ直接公開しないようにする。
NVSの設定がYAMLより優先される場合がある
/settingsで保存したネットワーク設定はNVSに残る。YAMLを変更しても設定が変わらない場合は、NVS設定を確認または削除して再起動する。
LCDドライバーの非推奨警告
ESPHome 2026.7.2ではst7789vに非推奨警告が出る。今回は前回の実機確認済み設定との比較を優先し、そのまま使用している。
まとめ
ESP32-S3のI2Sからraw PDMを受け取り、CIC3とFIRを使って48 kHz PCMへ変換する構成をESPHomeの外部コンポーネントとしてまとめた。ハードウェア変換版と同様に、PSRAMへの録音、WAV/BWF取得、センサー表示、Home Assistant連携を一つのAtomS3Rで扱える。


コメント