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

今回は、マイクとアンプを接続します。接続は、サーバー側をAP接続。クライアント側をIPアドレス固定で行います。先ずはサーバー側のスケッチ


#include "WiFi.h"
#include <WiFiUdp.h>
#include <driver/i2s.h>

const char * ssid = "ESP32UDP";         // SSID
const char * password = "12345678";     // password

WiFiUDP wifiUdp;
 
static const int RmoteUdpPort = 9000;  
static const int LocalPort = 9000;     

// 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            4
#define I2S_BUFFER_SIZE             512

//DMA Buffer
#define DMA_BUFFER_SIZE             1024
uint8_t recBuffer[DMA_BUFFER_SIZE];

IPAddress ip(192, 168, 4, 2);           // for fixed IP Address
IPAddress gateway(192,168, 4, 1);       //
IPAddress subnet(255, 255, 255, 0);     //

// 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);
    
  WiFi.mode(WIFI_STA);
  WiFi.config(ip, gateway, subnet);
  WiFi.begin(ssid, password);

  // Try forever
  while (WiFi.status() != WL_CONNECTED) 
  {
    Serial.println("...Connecting to WiFi");
    delay(1000);
  }
  Serial.println("Connected");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  wifiUdp.begin(LocalPort);
  Serial.println("Client OK");
    
  i2s_MIC_Init();
  i2s_AMP_Init();

  Serial.println("Send Server");
    wifiUdp.beginPacket("192.168.4.1", RmoteUdpPort);
    wifiUdp.write((uint8_t *)"OK",2);
    wifiUdp.endPacket();  
  Serial.println("I2S OK");
}

void loop()
{
  uint8_t rv_buf[DMA_BUFFER_SIZE];
  int a,b;
  size_t transBytes;

  Serial.println("Write");
  i2s_read(I2S_NUM_MIC, (char*)recBuffer, DMA_BUFFER_SIZE, &transBytes, portMAX_DELAY);
  wifiUdp.beginPacket("192.168.4.1", RmoteUdpPort);
  wifiUdp.write(recBuffer,DMA_BUFFER_SIZE);
  wifiUdp.endPacket(); 

  if (wifiUdp.parsePacket() > 0)
  {
    Serial.println("Recieve");
    wifiUdp.read(rv_buf , DMA_BUFFER_SIZE);
    i2s_write_bytes(I2S_NUM_AMP, rv_buf, sizeof(rv_buf), portMAX_DELAY);
    wifiUdp.flush();
  }
}
  • 12から16行: I2S アンプ側のパラメータ
  • 19から23行: I2S マイク側のパラメータ
  • 25から27行: サンプリング周波数とDMAバッファーの設定
  • 35から60行: アンプの初期設定関数
  • 63から88行: マイクの初期設定関数
  • 94行: APモードで接続。(IPアドレスは192.168.4.1になる)
  • 103,103行: I2Sマイクとアンプ開始。
  • 107から108行: クライアントの接続待ち
    • この部分無しにLoop()に入ると、クライアントの接続が出来ませんでした。
    • クライアントからの送信待ち
  • 121から127行: クライアントから受信したデータをアンプへ出力
  • 129から132行: マイクのデータをクライアントに送信

次は、クライアント側


#include "WiFi.h"
#include <WiFiUdp.h>
#include <driver/i2s.h>

const char * ssid = "ESP32UDP";         // SSID
const char * password = "12345678";     // password

WiFiUDP wifiUdp;
 
static const int RmoteUdpPort = 9000;  
static const int LocalPort = 9000;     

// 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            4
#define I2S_BUFFER_SIZE             512

//DMA Buffer
#define DMA_BUFFER_SIZE             1024
uint8_t recBuffer[DMA_BUFFER_SIZE];

IPAddress ip(192, 168, 4, 2);           // for fixed IP Address
IPAddress gateway(192,168, 4, 1);       //
IPAddress subnet(255, 255, 255, 0);     //

// 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);
    
  WiFi.mode(WIFI_STA);
  WiFi.config(ip, gateway, subnet);
  WiFi.begin(ssid, password);

  // Try forever
  while (WiFi.status() != WL_CONNECTED) 
  {
    Serial.println("...Connecting to WiFi");
    delay(1000);
  }
  Serial.println("Connected");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  wifiUdp.begin(LocalPort);
  Serial.println("Client OK");
    
  i2s_MIC_Init();
  i2s_AMP_Init();

  Serial.println("Send Server");
    wifiUdp.beginPacket("192.168.4.1", RmoteUdpPort);
    wifiUdp.write((uint8_t *)"OK",2);
    wifiUdp.endPacket();  
  Serial.println("I2S OK");
}

void loop()
{
  uint8_t rv_buf[DMA_BUFFER_SIZE];
  int a,b;
  size_t transBytes;

  Serial.println("Write");
  i2s_read(I2S_NUM_MIC, (char*)recBuffer, DMA_BUFFER_SIZE, &transBytes, portMAX_DELAY);
  wifiUdp.beginPacket("192.168.4.1", RmoteUdpPort);
  wifiUdp.write(recBuffer,DMA_BUFFER_SIZE);
  wifiUdp.endPacket(); 

  if (wifiUdp.parsePacket() > 0)
  {
    Serial.println("Recieve");
    wifiUdp.read(rv_buf , DMA_BUFFER_SIZE);
    i2s_write_bytes(I2S_NUM_AMP, rv_buf, sizeof(rv_buf), portMAX_DELAY);
    wifiUdp.flush();
  }
}
  • 基本はサーバー側と同じ。
  • 35から37行: 固定IPアドレスの指定
  • 99行: クライアント側はSTAモードで接続。
  • 100行: IPアドレスを固定。
  • 121から123行: サーバーにダミーデータを送信
    • サーバーにクライアントがレディになった事を知らせる
  • 134から137行: マイクのデータをサーバーに送信
  • 135行: beginPacket()の第一引数にサーバーのIPアドレスを直接指定
  • 139から144行: サーバーからのデータをアンプに出力。

この2つのスケッチを実行すれば、サーバーからクライアント、クライアントからサーバーに音声データを送信出来ます。簡易インターフォンとなります。コンパイル実行して下さい。

AP接続について

今回は2つあるESP32の一方をサーバーとしましたが、もう一つESP32を用意しそれをサーバー専用にしその他の2つをIPアドレス固定でサーバーに接続した場合、お互いに通信出来るのか確認してみました。つまり以前ルータを介して接続した時のルータの変わりにAP接続のESP32を使用する接続です。

サーバ側のスケッチ


#include "WiFi.h"

const char * ssid = "ESP32UDP";             // SSID
const char * password = "12345678";         // password

void setup()
{
  Serial.begin(115200);

  WiFi.softAP(ssid, password); 
  delay(1000);

  Serial.print("AP IP address: ");            //    192.168.4.1
  Serial.println(WiFi.softAPIP());
  
  Serial.println("Server OK");
}

void loop()
{
}
  • このESP32はただ単に、AP接続のサーバを立ち上げているだけです。

クライアント側


#include "WiFi.h"
#include <WiFiUdp.h>
#include <driver/i2s.h>

const char * ssid = "ESP32UDP";         // SSID
const char * password = "12345678";     // password

WiFiUDP wifiUdp;
 
static const int RmoteUdpPort = 9000;  
static const int LocalPort = 9000;     

// 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            4
#define I2S_BUFFER_SIZE             512

//DMA Buffer
#define DMA_BUFFER_SIZE             1024
uint8_t recBuffer[DMA_BUFFER_SIZE];

IPAddress ip(192, 168, 4, 2);           // for fixed IP Address
IPAddress gateway(192,168, 4, 1);       //
IPAddress subnet(255, 255, 255, 0);     //

// 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);
    
  WiFi.mode(WIFI_STA);
  WiFi.config(ip, gateway, subnet);
  WiFi.begin(ssid, password);

  // Try forever
  while (WiFi.status() != WL_CONNECTED) 
  {
    Serial.println("...Connecting to WiFi");
    delay(1000);
  }
  Serial.println("Connected");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  wifiUdp.begin(LocalPort);
  Serial.println("Client OK");
    
  i2s_MIC_Init();
  i2s_AMP_Init();

  Serial.println("I2S OK");
}

void loop()
{
  uint8_t rv_buf[DMA_BUFFER_SIZE];
  int a,b;
  size_t transBytes;

  Serial.println("Write");
  i2s_read(I2S_NUM_MIC, (char*)recBuffer, DMA_BUFFER_SIZE, &transBytes, portMAX_DELAY);
  wifiUdp.beginPacket("192.168.4.3", RmoteUdpPort);
  wifiUdp.write(recBuffer,DMA_BUFFER_SIZE);
  wifiUdp.endPacket(); 

  if (wifiUdp.parsePacket() > 0)
  {
    Serial.println("Recieve");
    wifiUdp.read(rv_buf , DMA_BUFFER_SIZE);
    i2s_write_bytes(I2S_NUM_AMP, rv_buf, sizeof(rv_buf), portMAX_DELAY);
    wifiUdp.flush();
  }
}
  • 先程のクライアント用のスケッチです。
  • 131行: ここで、相手側にIPアドレスを、”192.168.4.3”と指定しています。

もう一つのクライアントは上記のスケッチ、

  • 35行: IPアドレスの指定を、”192.168.4.3” に変更
  • 131行: 相手先のIPアドレスを、”192.168.4.2”に変更

して下さい。これで、”192.168.4.2”と”192.168.4.3”の間でUDP通信する事になります。また、今回はサーバー用にESP32を1台使用しているので、クライアントの認識が問題無く出来る様なので、認識用のダミーデータの送信は削除しています。3つのスケッチをコンパイル実行して下さい。インターフォンとして動作しました。

これを応用すれば、

  • 現在は1対1の通信で相手が固定だが、相手を変更する事が可能
  • 複数接続しその中の1つまたは複数、または全員と繋ぐ事が可能

が考えられます。各部屋にこの機器を置いて、部屋同士または一斉に話す事が可能になるのでしょうか。