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