RP2040をUSBマイクとして4チャンネルでPCに認識させたいと思っています(サンプリングレート8kHz)。
Arduino IDEでのコード構成や実装手順を分かりやすく教えてください。
RP2040のネイティブUSB機能を制御するために、標準のUSBスタックである「TinyUSB」を使用します。
1. 開発環境の準備(前提条件)
• ボードマネージャーのインストール
• Arduino IDEの「ボードマネージャー」を開きます。
• Earle F. Philhower氏版の「Raspberry Pi Pico/RP2040」
コアを検索してインストールします。(※Arduino公式のMbedコアではなく、こちらの方がTinyUSBのカスタマイズが容易です)
• USBスタックの設定変更• ツールメニューから、ツール > USB Stack > "Adafruit TinyUSB" を選択します。
2. コード構成のポイント
USBマイクとして認識させるには、USB記述子(ディスクリプタ)で「4チャンネル、8kHz、16bit(または16bitPCM)」を正確にPCへ伝える必要があります。
通常、標準のライブラリは1ch(モノラル)や2ch(ステレオ)の44.1kHz/48kHz向けに組まれていることが多いため、 TinyUSBの構成マクロをカスタム定義するか、コールバック関数で4ch分のデータをパッキングして送信する コード構成にします。
• サンプリング周波数 : 8,000 Hz
• チャンネル数 : 4 ch
• 1サンプルあたりのバイト数 : 2バイト (16-bit PCM)
• 1回(1ミリ秒ごと)の送信データ量 :
8本 × 4ch × 2バイト = 64バイト / ミリ秒
3. 実実装コード例
以下は、PCから音声要求(1msごとのUSB IAD IN転送)が来た際に、4ch分のダミー音データ(テストトーンなど)を生成してPCへ送信する基本スケッチです。実際のマイク入力を載せる場合は、readMicHardware() の部分をI2SマイクやADCの読み取り処理に置き換えてください
cpp
#include "Adafruit_TinyUSB.h" // --- USB Audioクラスの設定定数 --- #define SAMPLE_RATE 8000 #define CHANNELS 4 #define BITS_PER_SAMPLE 16 #define BYTE_PER_SAMPLE (BITS_PER_SAMPLE / 8) // 1ミリ秒あたりに必要なサンプル数 (8000Hz / 1000ms = 8サンプル) #define SAMPLES_PER_MS (SAMPLE_RATE / 1000) // 1回のパケットサイズ (8サンプル * 4ch * 2バイト = 64バイト) #define PACKET_SIZE (SAMPLES_PER_MS * CHANNELS * BYTE_PER_SAMPLE) // TinyUSB Audio オブジェクトの生成 Adafruit_USBD_Audio usb_audio; // 送信用バッファ uint8_t audio_buffer[PACKET_SIZE]; void setup() { // 1. USBオーディオの初期化設定 (サンプリングレート, チャンネル数, ビット深度) usb_audio.begin(SAMPLE_RATE, CHANNELS, BITS_PER_SAMPLE); // 2. シリアルデバッグ(必要に応じて) Serial.begin(115200); } void loop() { // PCからデータ要求があり、送信可能な状態かをチェック if (usb_audio.ready()) { // 4チャンネル分のデータを生成・バッキングする int16_t *pcm_pointer = (int16_t *)audio_buffer; for (int s = 0; s < SAMPLES_PER_MS; s++) { // 例として、各チャンネルに異なる単純な波形や値を代入 pcm_pointer[s * CHANNELS + 0] = readMicHardware(0); // CH1マイクデータ pcm_pointer[s * CHANNELS + 1] = readMicHardware(1); // CH2マイクデータ pcm_pointer[s * CHANNELS + 2] = readMicHardware(2); // CH3マイクデータ pcm_pointer[s * CHANNELS + 3] = readMicHardware(3); // CH4マイクデータ } // PCへ1ミリ秒分のデータを書き込み(送信) usb_audio.write(audio_buffer, PACKET_SIZE); } } // 実際のハードウェア(I2SやADC)から音声を読み取る関数(擬似コード) int16_t readMicHardware(uint8_t channel) { // ここにマイクICからのデータ取得処理を記述します。 // テスト用:固定値、またはチャンネル毎に異なる周波数のサイン波など return (int16_t)(sin(millis() * 0.05 * (channel + 1)) * 3000); }
4. 実実装の手順
• スケッチの書き込み :
上記コードをArduino IDEに入力し、RP2040(Raspberry Pi Picoなど)を接続して通常通り書き込みます。
• PCとの接続確認 :
書き込み完了後、一度USBケーブルを抜き差しします。
• PC側のオーディオ設定を確認 :
• Windowsの場合 : 「コントロールパネル」>「サウンド」>「録音」タブを開きます。認識されたデバイス(例: "TinyUSB Audio")のプロパティを開き、「詳細」タブの規定の形式で「 4チャンネル、16ビット、8000Hz (電話の音質) 」と表示されているか確認します。
• Macの場合 : 「オーディオMIDI設定」アプリを開き、対象デバイスが「4入力 / 0出力」かつ「8,000.0 Hz」になっていることを確認します。
• 波形の確認 :
Audacity などの録音ソフトを立ち上げ、録音チャンネル数を「4」に設定して録音ボタンを押すことで、4つの独立したトラックにそれぞれのチャンネルの音が同期して録音されるかテストできます。
⚠️ 注意点:ハードウェアの同期
8kHz・4chという設定自体はUSBの帯域をほとんど消費しないため、TinyUSBの処理としては非常に軽量です。しかし、 実際のマイク(I2Sマイクなど)から4本のデータを取得するタイミング がUSBの「1ミリ秒ごと」の要求と完全に同期していないと、時間経過とともにデータの過不足(バッファオーバーフロー/アンダーフロー)が発生し、プチプチとしたノイズの原因になります。
実用化の際は、RP2040の DMA(Direct Memory Access) 機能や PIO(Programmable I/O) を駆使して、マイクのサンプリング(8kHz周期)とバッファリングをバックグラウンドで厳密に行う実装の追加を推奨します。
次に進むにあたり、以下の詳細をお知らせいただければさらに具体的なコードにブラッシュアップ可能です。
• 使用予定の マイクの型番・種類 (例:I2Sマイクの INMP441、またはアナログマイク+内蔵ADCなど)
• マイクとRP2040の配線予定 (どのピンにどのマイクを繋ぐか)
■TinyUSBについて
TinyUSBを使うと、マイコンをUSB機器(デバイス)にしたりUSB機器を操作する側(ホスト)にしたりすることができます。具体的には、キーボードやマウスのエミュレーション、USBシリアル通信、USBメモリの読み書きなどを簡単に実装できます。
主な機能とできること
• USBデバイス(周辺機器)としての動作
• HIDクラス :自作キーボード、マウス、ゲームパッド
• CDCクラス :仮想COMポート(シリアル通信)
• MSCクラス :USBストレージ(内蔵フラッシュやSDカードの読み書き)
• Audio / MIDIクラス :USBスピーカー、マイク、楽器(MIDI)
• その他 :WebUSB、WinUSB、DFU(ファームウェア書き換え)など [1, 2,
• USBホスト(親機)としての動作
• 接続されたUSBキーボードやマウスからの入力読み取り
• USBメモリ(MSC)からのデータ読み書き
• USBシリアル機器(CDC)との通信