Практического применения этого проекта я не вижу (не мегафон же). Но, для меня это был довольно хороший опыт работы со звуком на ESP32-WROOM. Скетч разрабатывался в среде Arduino IDE 2.3.5. Заменил на Arduino IDE 2.3.6, скетч компилируется, загружается и работает.
Насчет железа. Дополнил предыдущий проект “ESP32 — проигрывание mp3 файлов с SD через декодер PCM5102A” (там и о распайке перемычек на PCM5102A)
https://conntest.ru/program/esp32-proigryvanie-mp3-fajlov-s-sd-cherez-dekoder-pcm5102a
модулем микрофона INMP441 и еще одной кнопкой, которая управляет изменением коэффициента усиления выходного сигнала от 0.5 до 3.0 через 0.5, по кругу. Еще добавил светодиод, который степенью яркости отражает величину этого коэффициента. Показания также выводятся в Serial Port после изменения (нажатия кнопки). Звук довольно чистый.
Подключение кнопки управления коэффициентом усиления: один контакт на GND, другой на P4. Светодиод индикации коэффициента подключен плюсом к 3,3 V через резистор 180 Ом, минусом к P2.
Таблица подключения модулей к ESP32-WROOM (обозначения контактов ESP32 относятся к переходной плате).
Микрофон INMP441 с интерфейсом I2S – моно (контакт L / R подключен к GND, наверное, можно подключить этот контакт к ESP32 и обрабатывать стерео), а декодер интерфейса I2S PCM5102A – стерео. В принципе, преобразование возможно, но я остановился на моно, работает только одна колонка.
Таблица подключения на https://conntest.ru/program/peredacha-zvuka-s-inmp441-na-dekoder-pcm5102a-s-pomoshhyu-esp32
Скетч:
#include <driver/i2s.h>
#include <driver/ledc.h>
// === Пины подключения INMP441 ===
#define I2S_WS 14
#define I2S_SD 33
#define I2S_SCK 32
// === Пины подключения PCM5102A ===
#define I2S_LRCK 25
#define I2S_DIN 22
#define I2S_BCK 26
#define I2S_MIC_PORT (I2S_NUM_0)
#define I2S_DAC_PORT (I2S_NUM_1)
#define bufferLen 128
int32_t sBuffer[bufferLen];
// === Кнопка ===
#define BUTTON_PIN 4
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 50;
bool lastButtonState = HIGH;
bool buttonPressed = false;
// === Усиление ===
float gainLevels[] = {0.5, 1.0, 1.5, 2.0, 2.5, 3.0};
int gainIndex = 0;
// === Светодиод (PWM) ===
#define LED_PIN 2
#define LEDC_CHANNEL LEDC_CHANNEL_0
#define LEDC_TIMER LEDC_TIMER_0
void setup_pwm() {
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.duty_resolution = LEDC_TIMER_8_BIT,
.timer_num = LEDC_TIMER,
.freq_hz = 5000,
.clk_cfg = LEDC_AUTO_CLK
};
ledc_timer_config(&ledc_timer);
ledc_channel_config_t ledc_channel = {
.gpio_num = LED_PIN,
.speed_mode = LEDC_LOW_SPEED_MODE,
.channel = LEDC_CHANNEL,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = LEDC_TIMER,
.duty = 0,
.hpoint = 0
};
ledc_channel_config(&ledc_channel);
}
void set_pwm_brightness(int brightness) {
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL, brightness);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL);
}
// === Усиление сигнала ===
void applyGain(int32_t* buffer, int samples, float gain) {
for (int i = 0; i < samples; ++i) {
float amplified = buffer[i] * gain;
if (amplified > INT32_MAX) amplified = INT32_MAX;
if (amplified < INT32_MIN) amplified = INT32_MIN;
buffer[i] = (int32_t)amplified;
}
}
// === I2S: вход ===
void i2s_install_in() {
const i2s_config_t i2s_config_in = {
.mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX),
.sample_rate = 48000,
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = 0,
.dma_buf_count = 16,
.dma_buf_len = bufferLen,
.use_apll = false
};
i2s_driver_install(I2S_MIC_PORT, &i2s_config_in, 0, NULL);
}
void i2s_setpin_in() {
const i2s_pin_config_t pin_config_in = {
.mck_io_num = -1,
.bck_io_num = I2S_SCK,
.ws_io_num = I2S_WS,
.data_out_num = -1,
.data_in_num = I2S_SD,
};
i2s_set_pin(I2S_MIC_PORT, &pin_config_in);
}
// === I2S: выход ===
void i2s_install_out() {
const i2s_config_t i2s_config_out = {
.mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_TX),
.sample_rate = 48000,
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = 0,
.dma_buf_count = 16,
.dma_buf_len = bufferLen,
.use_apll = false
};
i2s_driver_install(I2S_DAC_PORT, &i2s_config_out, 0, NULL);
}
void i2s_setpin_out() {
const i2s_pin_config_t pin_config_out = {
.mck_io_num = -1,
.bck_io_num = I2S_BCK,
.ws_io_num = I2S_LRCK,
.data_out_num = I2S_DIN,
.data_in_num = -1,
};
i2s_set_pin(I2S_DAC_PORT, &pin_config_out);
}
// === Проверка кнопки ===
void checkButton() {
static bool lastStableState = HIGH;
static bool lastReadState = HIGH;
static unsigned long lastChangeTime = 0;
bool currentRead = digitalRead(BUTTON_PIN);
if (currentRead != lastReadState) {
lastChangeTime = millis();
}
if ((millis() - lastChangeTime) > debounceDelay) {
if (currentRead != lastStableState) {
lastStableState = currentRead;
if (lastStableState == LOW) {
buttonPressed = true;
}
}
}
lastReadState = currentRead;
}
void setup() {
Serial.begin(115200);
Serial.println("Старт...");
pinMode(BUTTON_PIN, INPUT_PULLUP);
i2s_install_in();
i2s_setpin_in();
i2s_start(I2S_MIC_PORT);
i2s_install_out();
i2s_setpin_out();
i2s_start(I2S_DAC_PORT);
setup_pwm();
set_pwm_brightness(map(gainIndex, 0, 5, 255, 0));
delay(500);
}
void loop() {
checkButton();
if (buttonPressed) {
gainIndex = (gainIndex + 1) % (sizeof(gainLevels) / sizeof(gainLevels[0]));
int brightness = map(gainIndex, 0, 5, 255, 0);
set_pwm_brightness(brightness);
Serial.print("Нажата кнопка! Новое усиление: ");
Serial.println(gainLevels[gainIndex]);
buttonPressed = false;
}
size_t bytesIn;
esp_err_t result = i2s_read(I2S_MIC_PORT, &sBuffer, sizeof(sBuffer), &bytesIn, portMAX_DELAY);
if (result == ESP_OK && bytesIn > 0) {
int samples = bytesIn / sizeof(int32_t);
float gain = gainLevels[gainIndex];
applyGain(sBuffer, samples, gain);
size_t bytesOut;
esp_err_t res = i2s_write(I2S_DAC_PORT, sBuffer, bytesIn, &bytesOut, portMAX_DELAY);
if (res != ESP_OK || bytesOut != bytesIn) {
Serial.println("Ошибка записи в I2S DAC");
}
} else {
Serial.println("Ошибка чтения из I2S микрофона");
}
}