2017年9月17日日曜日

ESP32のPDMでクリアーなサウンドを(希望)

ESP32のPDM出力、波形がもの凄く崩れてます。ローパスフィルタ通して音を聞くともの凄くツブれた音になります。

Facebookでトランジスタ1個で波形整形すると良い、とアドバイスをいただいたのですが、アナログスキルがないので、部品頼みで整形しました(手元のオペアンプは遅すぎてコンパレータとして働いてくれませんでした)。

昔懐かしいシュミットトリガSN74HC14を使います。私が子供の頃TTLのSN74N/Aシリーズは5v専用だったんですが現在のHCシリーズはCMOSなので電源電圧範囲が広く、それにあわせてスレッショルドが変わるので便利です。

接続はESP32から3.3vとGndとGPIO25,26をつなぎます。SN74HC14の使っていないピンは全部GNDに落として置きます(基本のお約束)。HC14はインバータなので2段にしています(あんまり意味ないんですが)。HC14の遅延は最大でも20nS程度なので、今回の用途では問題ありません(と断言したら怒られるかな)。


ESP32SN74HC14Amplifier
GPIO251
2-3
4R-IN
GPIO2613
11-12
10L-IN
3.3V14
GND1,7,9

出てきた波形はこちらです。黄色がGPIO出力、水色がシュミットで整形後です(プローブx10)。


上の表では省略していますが、SN74HC14の出力にはフィルタを通してからアンプに入れます。フィルタは基本的なCR型で、HC14の4ピン→220Ω→アンプ入力(6ピン→220Ω→アンプ入力)、アンプ入力とGNDの間に0.1μFのコンデンサを入れます。これで約8khzのローパスフィルタになります。

結果として、内蔵DACよりもかなり良い感じの音になります。

でも、無音時のホワイトノイズが消えてくれません。あと一歩です。

うーん、アナログはわからない……。ソースコードはこんな感じです。


//
// Sound
//
#include "driver/i2s.h"
#include "driver/gpio.h"
#include "ching.h"
#include "clap.h"
#include "cymbal.h"
#include "voice.h"
const i2s_port_t I2S_NUM = (i2s_port_t)0;
const i2s_bits_per_sample_t BITS_PER_SAMPLE = (i2s_bits_per_sample_t)16;
// PDM
void set_16k_16() {
i2s_set_pin(I2S_NUM, NULL);
i2s_config_t i2s_config;
i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_PDM); // Only TX
i2s_config.sample_rate = 16000;
i2s_config.bits_per_sample = BITS_PER_SAMPLE;
i2s_config.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT; //right channels
// i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT; //right left
i2s_config.communication_format = I2S_COMM_FORMAT_PCM;
i2s_config.dma_buf_count = 4;
i2s_config.dma_buf_len = 1024;
i2s_config.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1; //Interrupt level 1
i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
}
void setup()
{
Serial.begin(115200);
set_16k_16();
Serial.println("setup end");
}
int iSound = 0;
void loop()
{
Serial.println("ching");
i2s_write_bytes(I2S_NUM, (const char *)ching, sizeof(ching), portMAX_DELAY);
delay(500);
Serial.println("clap");
i2s_write_bytes(I2S_NUM, (const char *)clap, sizeof(clap), portMAX_DELAY);
delay(500);
Serial.println("cymbal");
i2s_write_bytes(I2S_NUM, (const char *)cymbal, sizeof(cymbal), portMAX_DELAY);
delay(500);
Serial.println("voice");
i2s_write_bytes(I2S_NUM, (const char *)voice, sizeof(voice), portMAX_DELAY);
delay(500);
}

0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。