インターフォンの製作(その6)

今回からマイクの接続になります。前回でアンプから音が出せる様になっています。今、ESP32が2台有るので、一方でサイン波を出してもう一方のESP32のマイクでそれを拾い、IDEのシリアルプロッタを使用して画面に波形を出力します。

アンプ同様マイクも、i2s_config_tとi2s_pin_config_tの設定から初めます。アンプの設定と比較して説明して行きます。


#include <driver/i2s.h>
 
#define I2S_NUM_MIC                    I2S_NUM_1
#define I2S_PIN_CLK_MIC             27
#define I2S_PIN_WS_MIC              25
#define I2S_PIN_DOUT_MIC         I2S_PIN_NO_CHANGE
#define I2S_PIN_DIN_MIC             26
 
 
#define I2S_SAMPLE_RATE             32000
#define I2S_BUFFER_COUNT         4
#define I2S_BUFFER_SIZE               512
 
uint8_t recBuffer[I2S_BUFFER_SIZE]; 
 
void setup() {
  Serial.begin(115200);
  
  i2s_config_t i2s_config_MIC = {
    .mode                     = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
    .sample_rate              = I2S_SAMPLE_RATE,
    .bits_per_sample          = I2S_BITS_PER_SAMPLE_32BIT,
    .channel_format           = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format     = I2S_COMM_FORMAT_I2S,
    .intr_alloc_flags         = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count            = I2S_BUFFER_COUNT,
    .dma_buf_len              = I2S_BUFFER_SIZE,
    .use_apll                 = false,
    .tx_desc_auto_clear       = false,
    .fixed_mclk               = 0
  };
  i2s_pin_config_t pin_config_MIC = {
    .bck_io_num                   = I2S_PIN_CLK_MIC,
    .ws_io_num                    = I2S_PIN_WS_MIC,
    .data_out_num                 = I2S_PIN_DOUT_MIC,
    .data_in_num                  = I2S_PIN_DIN_MIC,
  };
 
  i2s_driver_install(I2S_NUM_MIC, &i2s_config_MIC, 0, NULL);
  i2s_set_pin(I2S_NUM_MIC, &pin_config_MIC);
}
 
void loop() 
{
  int a;
  size_t transBytes;
  int32_t* val;

    i2s_read(I2S_NUM_MIC, (char*)recBuffer, I2S_BUFFER_SIZE, &transBytes, portMAX_DELAY);

    for(a=0; a< I2S_BUFFER_SIZE; a += 4)
    {
      val = (int32_t*)&recBuffer[a];
      Serial.println(*val);
    }
}
  • 3行:define I2S_NUM_MIC  I2S_NUM_1
    • 使用するI2Sの番号を宣言している箇所です。
    • アンプ時は、I2S_NUM_0を使用しました。
    • 今回は、I2S_NUM_1を使用します。
  • 4から7行:使用するピンの定義です。回路は、ここを参照下さい。
    • アンプの時は、DOUTを使用していましたが、今回はマイクなのでDINのみ使用となります。
  • 11、12行
    • 以前はっきりと分かっていないバッファーの数と長さですが、取り敢えずアンプと同じ値を使う事にしました。
  • 14行: uint8_t  recBuffer[I2S_BUFFER_SIZE];
    • マイクから読み込んだデータ保管用バッファー。
    • 符号無し8ビットで512バイト確保。
    • これも幾つが適切かよく分かっていません。
  • 19から31行: i2s_config_tの設定。
    • 20行:.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
      • I2Sのモードを設定する箇所。
      • マイクなので、I2S_MODE_RXを指定。(アンプの時は、I2S_MODE_TX)
    • それ以外は、アンプの時と同じ値を使用。
  • 32から37行: i2s_pin_config_tの設定
  • 39,40行: I2Sドライバーのインストールとピン設定。
  • 49行:i2s_read(I2S_NUM_MIC, (char*)recBuffer, I2S_BUFFER_SIZE, &transBytes, portMAX_DELAY);
    • マイクからデータを読み込むの関数。
    • 第一引数: I2Sの番号。今回は、I2S_NUM_1(1番)
    • 第二引数: 保存するバッファーのポインター
    • 第三引数: バッファーのサイズ
    • 第四引数: 読み込まれたデータの数。
    • 第五引数: タイムアウト指定。portMAX_DELAY指定でタイムアウト無し。
  • 51から55行: 読み込んだデータを32ビットに変換。
    • 読み込んだデータが8ビット形式なので32ビットに変換
    • 54行で値を表示

一方のESP32に音を出力するプログラムを実行して、もう一方のESP32でこのスケッチを実行して下さい。シリアルプロッタにこんな波形が出ると思います。波形からサイン波が録音出来ている事が分かります。

サンプリングとデータの数から音の周波数は500Hzでは無いかと予想しています。この波形は500Hzなのでしょうか。ちなみに横軸の単位は何なんでしょうか。プロットしている部分のスケッチを確認すると


    for(a=0; a< I2S_BUFFER_SIZE; a += 4)
    {
      val = (int32_t*)&recBuffer[a];
      Serial.println(*val);
    }

測定した8ビットのデータを32ビットへの変換し、変換が終わったらプロットしなさいって事です。波形はサイン波になると思いますが500Hzには成らない。

横軸はプロットされた数と仮定する。今回は1波長128個。プロットされた波形は1波長約80個(目分量)。少なくとも128ではない。横軸は何なんだろう。

マイクで拾ってアンプに出力

マイクの出力をプロッタに出せる様になったので、今度はアンプに繋ぎます。スケッチは、アンプとマイクの設定を行えば良いので、こんな感じになります。


#include <driver/i2s.h>

// AMP Port 
#define I2S_NUM_AMP                 I2S_NUM_0
#define I2S_PIN_WS_AMP              4
#define I2S_PIN_CLK_AMP             16
#define I2S_PIN_DOUT_AMP            17
#define I2S_PIN_DIN_AMP             I2S_PIN_NO_CHANGE

// MIC Port 
#define I2S_NUM_MIC                 I2S_NUM_1
#define I2S_PIN_CLK_MIC             27
#define I2S_PIN_WS_MIC              25
#define I2S_PIN_DOUT_MIC            I2S_PIN_NO_CHANGE
#define I2S_PIN_DIN_MIC             26
 
#define I2S_SAMPLE_RATE             32000
#define I2S_BUFFER_COUNT            2
#define I2S_BUFFER_SIZE             512
 
//DMA Buffer
uint8_t recBuffer[I2S_BUFFER_SIZE];

// Initiate AMP
void i2s_AMP_Init() 
{
  i2s_config_t i2s_config_AMP = {
    .mode                     = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
    .sample_rate              = I2S_SAMPLE_RATE,
    .bits_per_sample          = I2S_BITS_PER_SAMPLE_32BIT,
    .channel_format           = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format     = I2S_COMM_FORMAT_I2S,
    .intr_alloc_flags         = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count            = I2S_BUFFER_COUNT,
    .dma_buf_len              = I2S_BUFFER_SIZE,
    .use_apll                 = false,
    .tx_desc_auto_clear       = false,
    .fixed_mclk               = 0
  };
  
  i2s_pin_config_t pin_config_AMP = {
    .bck_io_num                   = I2S_PIN_CLK_AMP,
    .ws_io_num                    = I2S_PIN_WS_AMP,
    .data_out_num                 = I2S_PIN_DOUT_AMP,
    .data_in_num                  = I2S_PIN_DIN_AMP,
  };
 
  i2s_driver_install(I2S_NUM_AMP, &i2s_config_AMP, 0, NULL);
  i2s_set_pin(I2S_NUM_AMP, &pin_config_AMP);
}

// Initiate MIC
void i2s_MIC_Init() 
{
  i2s_config_t i2s_config_MIC = {
    .mode                     = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
    .sample_rate              = I2S_SAMPLE_RATE,
    .bits_per_sample          = I2S_BITS_PER_SAMPLE_32BIT,
    .channel_format           = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format     = I2S_COMM_FORMAT_I2S,
    .intr_alloc_flags         = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count            = I2S_BUFFER_COUNT,
    .dma_buf_len              = I2S_BUFFER_SIZE,
    .use_apll                 = false,
    .tx_desc_auto_clear       = false,
    .fixed_mclk               = 0
  };
  
  i2s_pin_config_t pin_config_MIC = {
    .bck_io_num                   = I2S_PIN_CLK_MIC,
    .ws_io_num                    = I2S_PIN_WS_MIC,
    .data_out_num                 = I2S_PIN_DOUT_MIC,
    .data_in_num                  = I2S_PIN_DIN_MIC,
  };
 
  i2s_driver_install(I2S_NUM_MIC, &i2s_config_MIC, 0, NULL);
  i2s_set_pin(I2S_NUM_MIC, &pin_config_MIC);
}

void setup() 
{
  Serial.begin(115200);
  i2s_MIC_Init();
  i2s_AMP_Init();
}
 
void loop() 
{
  int32_t buf[128];
  int a,b;
  size_t transBytes;
  int32_t* val;
 
    i2s_read(I2S_NUM_MIC, (char*)recBuffer, I2S_BUFFER_SIZE, &transBytes, portMAX_DELAY);

    b=0;
    for(a=0; a< I2S_BUFFER_SIZE; a += 4)
    {
      val = (int32_t*)&recBuffer[a];
      buf[b]= *val;
      b ++;
    }

    i2s_write_bytes(I2S_NUM_AMP, buf, sizeof(buf), portMAX_DELAY);

}
  • アンプの設定を、i2s_AMP_Init()で。マイクの設定を、void i2s_MIC_Init()で行っています。
  • アンプ側のI2Sの番号を、I2S_NUM_0(0番)。マイク側を、I2S_NUM_1(1番)としています。
  • 94行:i2s_read(I2S_NUM_MIC, (char*)recBuffer, I2S_BUFFER_SIZE, &transBytes, portMAX_DELAY);
    • ここで、マイクの音を読み込み
  • 104行:i2s_write_bytes(I2S_NUM_AMP, buf, sizeof(buf), portMAX_DELAY);
    • ここで、マイクのデータをアンプに送っています

コンパイル後実行して下さい。サイン波を出しているESP32と同じ音がもう一方のESP32(このスケッチを実行しているESP32)のスピーカーから聞こえたと思います。これでアンプとマイクが動作しました。

前回理解出来なかった、”dma_buf_count/dma_buf_len”ですが、アンプと同じ値を使用して取り敢えず動いている様です。今回新たに保存用のバッファーが出てきました。疑問が深まりますが、次回はこの音声データをUDPで送信してみたいと思います。