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

インターフォンの製作(その2)でUDP通信の説明をしています。今回はこのスケッチにマイク、アンプを追加する事になります。でもその前にちょっとまとまったデータを送信してみたいと思います。アンプの検証に使ったサイン波のデータをUDPで送って見ます。

クライアント側スケッチ


#include "WiFi.h"
#include <WiFiUdp.h>
#include <ESPmDNS.h>

const char * ssid = "XXXXXX";
const char * password = "YYYYYY";

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

#define DMA_BUFFER_SIZE             1024
uint8_t recBuffer[DMA_BUFFER_SIZE];

#define VOLUME ( (1UL << 27) - 1)
#define BUFSIZE 256

void setup()
{
  Serial.begin(115200);
    
  WiFi.mode(WIFI_STA);
  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());
    
  if (MDNS.begin("U_Client")) 
    Serial.println("MDNS responder started");
      
  wifiUdp.begin(LocalPort);
  Serial.println("Client OK");
    
int i,a,b,c;
  c=0;
  for(int i=0; i<BUFSIZE; i++)
  {
    a = sin( (2*PI / (BUFSIZE) ) * i) * VOLUME;
    for(b=0; b<4; b ++)
    {
      recBuffer[c]=(a >> b*8) & 0xff;
      c ++;
    }
  }  
}

void loop()
{
  Serial.println("wifiUdp.write");
  wifiUdp.beginPacket(MDNS.queryHost("U_Server"), RmoteUdpPort);
  wifiUdp.write(recBuffer,DMA_BUFFER_SIZE);
  wifiUdp.endPacket();  
}
  • 37行まで
    • 自宅のルータを介し、DNSを使用してドメイン名を”U_Client”と指定しています。
  • 39行: ここでUDPを開始。
  • 42から52行
    • ここでサイン波を計算しています。
    • サイン波は32ビットなのですが、UDPで送れるデータは8ビットなので32ビットを8ビットに変換しています。
    • UDPで一度に送るデータ数を1024としています。
    • よって32ビットのサイン波データ数は256となります。(256 x 4 = 1028)
  • 58行:wifiUdp.beginPacket(MDNS.queryHost(“U_Server”), RmoteUdpPort);
    • MDNS.queryHost(“U_Server”)でサーバーのドメイン名からIPアドレスを取得
  • 59行:wifiUdp.write(recBuffer,DMA_BUFFER_SIZE);
    • 8ビットに変換したサイン波データの送信
  • loop()関数によりサイン波データをサーバーに送り続けます。

サーバー側スケッチ


#include <WiFiUdp.h>
#include <ESPmDNS.h>
#include "WiFi.h"

const char * ssid = "XXXXXX";
const char * password = "YYYYYY";

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

WiFiUDP UDP;

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

  WiFi.mode(WIFI_STA);
  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());
    
  if (MDNS.begin("U_Server")) 
    Serial.println("MDNS responder started");

  UDP.begin(LocalPort);
  Serial.println("Server OK");
}

//DMA Buffer
#define DMA_BUFFER_SIZE             1024

void loop()
{
  int32_t buf[DMA_BUFFER_SIZE / 4];
  uint8_t rv_buf[DMA_BUFFER_SIZE];
  int a,b;
  int32_t* val;
     
  if (UDP.parsePacket() > 0)
  {

    Serial.println("Recieve");
    UDP.read(rv_buf , DMA_BUFFER_SIZE);
    b=0;
    for(a=0; a< DMA_BUFFER_SIZE; a += 4)
    {
      val = (int32_t*)&rv_buf[a];
      buf[b]= *val;
      b ++;
    }
    UDP.flush();
    
    for(a=0; a< DMA_BUFFER_SIZE / 4; a ++) 
      Serial.println(buf[a]);
  }

}
  • DNSを使用して、”U_Server”とドメインを指定
  • 48行: データ受信待ち
  • 52行: 受信データ読み込み
  • 53から60行: 読み込んだデータを32ビットに変換
  • 62,63行: データの表示

クライアント、サーバー両者を実行すれば、サーバー側のシリアルプロッタにサイン波が表示されるはずです。

実行すると確かにサイン波は表示されます。でもクライアントはサイン波を送り続けているので、サイン波が連続して表示(スクロールする)されるはずですが、時々止まってしまいます。

通信の問題でしょうか。これくらいのデータ送信でも負担なのでしょうか。取り敢えずこのサイン波をアンプに繋いで音にして見ます。

サーバー側のスケッチにアンプを追加しました。


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

const char * ssid = "XXXXXX";
const char * password = "YYYYYY";

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

#define I2S_SAMPLE_RATE             32000
#define I2S_BUFFER_COUNT            4
#define I2S_BUFFER_SIZE             512

// 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

//DMA Buffer
uint8_t recBuffer[I2S_BUFFER_SIZE];

WiFiUDP UDP;

// 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);
}

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

  WiFi.mode(WIFI_STA);
  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());
    
  if (MDNS.begin("U_Server")) 
    Serial.println("MDNS responder started");

  UDP.begin(LocalPort);
  i2s_AMP_Init();
  
  Serial.println("Server OK");
}

//DMA Buffer
#define DMA_BUFFER_SIZE             1024

void loop()
{
  int32_t buf[DMA_BUFFER_SIZE / 4];
  uint8_t rv_buf[DMA_BUFFER_SIZE];
  int a,b;
  int32_t* val;
     
  if (UDP.parsePacket() > 0)
  {

    Serial.println("Recieve");
    UDP.read(rv_buf , DMA_BUFFER_SIZE);
    b=0;
    for(a=0; a< DMA_BUFFER_SIZE; a += 4)
    {
      val = (int32_t*)&rv_buf[a];
      buf[b]= *val;
      b ++;
    }
    UDP.flush();
    
    for(a=0; a< DMA_BUFFER_SIZE / 4; a ++) 
      Serial.println(buf[a]);

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

}
  • 4行: #include <driver/i2s.h>を追加
  • 12から54行: アンプ機能の追加。詳細は、”インターフォンの製作(その4)”を参照下さい。
  • 110行: i2s_write_bytes(I2S_NUM_AMP, buf, sizeof(buf), portMAX_DELAY);
    • これで送られて来たデータをアンプに送信しています。

コンパイル後実行すると音が出るには出るんですが、最初プツプツと何回か音がした後サイン波になります。とにかくサイン波は聞こえるので、クライアント側にマイクを接続して見ます。接続したスケッチは以下の通り。


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

const char * ssid = "XXXXXX";
const char * password = "YYYYYY";

WiFiUDP wifiUdp; 

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

// 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]; 

// 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.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());

  if (MDNS.begin("U_Client")) 
    Serial.println("MDNS responder started");
    
  wifiUdp.begin(LocalPort);
  i2s_MIC_Init();
  Serial.println("Client OK");
    
}

void loop()
{
  size_t transBytes;

  Serial.println("i2s_read");
  i2s_read(I2S_NUM_MIC, (char*)recBuffer, DMA_BUFFER_SIZE, &transBytes, portMAX_DELAY);
 
  wifiUdp.beginPacket(MDNS.queryHost("U_Server"), RmoteUdpPort);
  wifiUdp.write(recBuffer,DMA_BUFFER_SIZE);
  wifiUdp.endPacket();  
}
  • 4行: driver/i2s.hの読み込み
  • 14から19行: MIC用のパラメータ
  • 30から55行: I2S マイク用の初期設定用関数
  • 79行: I2S マイク開始
  • 89行: マイクからのデータ読み込み

これでマイクの音が送信されるはずです。コンパイル実行して下さい。こんな感じになりました

  • 最初またブツブツと音がして(サイン波の時より大きい)、しばらくすると静まりました。
  • クライアント側のマイク音を入力すると、サーバー側のスピーカに音が出るので、マイクもアンプもデータ送信(UDP)も動作している模様。
  • ただマイクに入力した音でスピーカーの音が違う。エコーが掛かっている感じがする。

プツプツは、”インターフォンの製作(その5)”でも有りましたが、今回は若干違う様に思えます。そもそも、シリアルプロットでサイン波が止まるのがおかしいと思います。何が原因かスケッチをいじってみます。