Запись звука с INMP441 на SD карту с помощью ESP32

Записываем звук в формате WAV с микрофона I2S INMP441 на SD карту с помощью ESP32-WROOM. Скетч разрабатывался в среде Arduino IDE 2.3.5. Заменил на Arduino IDE 2.3.6, скетч компилируется, загружается и работает.

Скачать Arduino IDE 2.3.6

arduino-ide_2.3.6_Windows_64bit.exe (11 Загрузок)

Насчет железа. Дополнил проект “ESP32 — проигрывание mp3 файлов с SD через декодер PCM5102A”

https://conntest.ru/program/esp32-proigryvanie-mp3-fajlov-s-sd-cherez-dekoder-pcm5102a

модулем микрофона INMP441 и еще одной кнопкой, которая “начинает запись/останавливает запись”.

Общий вид средств работы со звуком, на текущий момент.

Подключение кнопки управления записью: один контакт на GND, другой на P4.

Таблица подключения модулей к ESP32-WROOM (обозначения контактов ESP32 относятся к переходной плате). Расширенный вариант, PCM5102A к данному скетчу не относится.

Таблицу соединений можно легко посмотреть здесь:
https://conntest.ru/program/peredacha-zvuka-s-inmp441-na-dekoder-pcm5102a-s-pomoshhyu-esp32

Микрофон INMP441 с интерфейсом I2S – моно (контакт L/ R подключен к GND). Ввел режим автоусиления, в котором не совсем уверен.

Алгоритм такой:

  1. после сброса определяется наличие карты и ожидается нажатия кнопки;

  2. после нажатия начинается чтение с микрофона;

  3. после следующего нажатия чтение останавливается и происходит запись на карту. Функция generateFilename выбирает первое свободное имя по шаблону «/record_%03d.wav».

Процесс работы выводится в Монитор порта Arduino IDE.

Для начала хватит. Не учитывал возможность длительной записи. Поэкспериментирую с этим вариантом на практике.

Скетч:

#include <SD.h>
#include <SPI.h>

// INMP441 микрофон
#define I2S_WS     14
#define I2S_SD     33
#define I2S_SCK    32

#define I2S_PORT I2S_NUM_0

#define SD_CS     5      // Пин CS SD-карты (настраиваем по своей схеме)

#define BUFFER_LEN 512
int32_t i2sBuffer[BUFFER_LEN];     // 32-бит (с 24-битами звука)
int16_t wavBuffer[BUFFER_LEN];     // Конвертированный 16-битный WAV

File audioFile;
bool isRecording = false;
int bytesWrittenTotal = 0;
char filename[20];  // Буфер для имени файла

// === WAV-заголовок ===
void writeWavHeader(File file, int sampleRate, int bitsPerSample, int channels, int dataSize) {
  file.seek(0);
  file.write((const uint8_t *)"RIFF", 4);
  uint32_t chunkSize = 36 + dataSize;
  file.write((byte *)&chunkSize, 4);
  file.write((const uint8_t *)"WAVE", 4);

  file.write((const uint8_t *)"fmt ", 4);
  uint32_t subchunk1Size = 16;
  uint16_t audioFormat = 1;
  file.write((byte *)&subchunk1Size, 4);
  file.write((byte *)&audioFormat, 2);
  file.write((byte *)&channels, 2);
  file.write((byte *)&sampleRate, 4);
  uint32_t byteRate = sampleRate * channels * bitsPerSample / 8;
  uint16_t blockAlign = channels * bitsPerSample / 8;
  file.write((byte *)&byteRate, 4);
  file.write((byte *)&blockAlign, 2);
  file.write((byte *)&bitsPerSample, 2);

  file.write((const uint8_t *)"data", 4);
  file.write((byte *)&dataSize, 4);
}

// === I2S ===
void i2s_install() {
  const i2s_config_t i2s_config = {
    .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX),
    .sample_rate = 16000,
    .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format = I2S_COMM_FORMAT_I2S_MSB,
    .intr_alloc_flags = 0,
    .dma_buf_count = 8,
    .dma_buf_len = BUFFER_LEN,
    .use_apll = false,
    .tx_desc_auto_clear = false,
    .fixed_mclk = 0
  };
  i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
}

void i2s_setpin() {
  const i2s_pin_config_t pin_config = {
    .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_PORT, &pin_config);
}

// Генерация уникального имени файла
void generateFilename() {
  for (int i = 0; i < 1000; i++) {
    sprintf(filename, "/record_%03d.wav", i);
    if (!SD.exists(filename)) {
      Serial.print("Создан файл для записи: ");
      Serial.println(filename);
      return;
    }
  }
  Serial.println("Не удалось найти свободное имя файла!");
  while (true); // Стоп, если всё занято
}

float gain = 2.0;                      // Начальное усиление
const float targetLevel = 12000.0;     // Целевая амплитуда
const float maxGain = 10.0;
const float minGain = 0.1;
const float adaptRate = 0.005;         // Скорость адаптации

unsigned long lastButtonPress = 0;
bool buttonState = HIGH;
bool lastButtonState = HIGH;

void handleButton() {
  bool currentState = digitalRead(4);
  if (currentState != lastButtonState) {
    lastButtonState = currentState;
    if (currentState == LOW && millis() - lastButtonPress > 300) {
      lastButtonPress = millis();
      
      if (!isRecording) {
        // Начинаем запись
        generateFilename();
        audioFile = SD.open(filename, FILE_WRITE);
        if (audioFile) {
          writeWavHeader(audioFile, 16000, 16, 1, 0);
          isRecording = true;
          bytesWrittenTotal = 0;
          Serial.println("Запись начата");
        } else {
          Serial.println("Ошибка создания файла");
        }
      } else {
        // Останавливаем запись
        isRecording = false;
        writeWavHeader(audioFile, 16000, 16, 1, bytesWrittenTotal);
        audioFile.flush();
        audioFile.close();
        Serial.println("Запись остановлена. Файл сохранен.");
      }
    }
  }
}

// === SETUP ===
void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("Инициализация...");

  // Инициализация I2S
  i2s_install();
  i2s_setpin();
  i2s_start(I2S_PORT);

  // Инициализация SD-карты
  if (!SD.begin(SD_CS)) {
    Serial.println("SD-карта не найдена");
    while (true);
  }
  Serial.println("SD-карта подключена.");

  // Настройка кнопки
  pinMode(4, INPUT_PULLUP);
  
  Serial.println("Готов к работе. Нажмите кнопку для начала записи.");
}

// === LOOP ===
void loop() {
  handleButton();
  
  if (!isRecording) return;

  size_t bytesRead = 0;
  i2s_read(I2S_PORT, (void *)i2sBuffer, sizeof(i2sBuffer), &bytesRead, portMAX_DELAY);
  int samples = bytesRead / sizeof(int32_t);

  float peak = 0;

  for (int i = 0; i < samples; i++) {
    int32_t sample24 = i2sBuffer[i] >> 9;
    float amplified = sample24 * gain;

    if (amplified > 32767.0f) amplified = 32767.0f;
    if (amplified < -32768.0f) amplified = -32768.0f;

    wavBuffer[i] = (int16_t)amplified;

    if (fabs(sample24) > peak) peak = fabs(sample24);
  }

  // Автоусиление
  if (peak > 0) {
    float targetGain = targetLevel / peak;
    gain += (targetGain - gain) * adaptRate;

    if (gain > maxGain) gain = maxGain;
    if (gain < minGain) gain = minGain;
  }

  audioFile.write((byte *)wavBuffer, samples * sizeof(int16_t));
  bytesWrittenTotal += samples * sizeof(int16_t);
}```

Слушайте, не в состоянии жирный текст от обычного отличить?

НЕКОТОРЫЕ НЕ ЗНАЮТ О СУЩЕСТВОВАНИИ КАПСЛОКА ДАЖЕ. ЖИРНЫЙ ТЕКСТ ПРОСТО МЕЛОЧЬ))) Как-то так.
(странно, если все буквы заглавные, сообщение не публикуется)

Спойлер

CopyPast, aesthetes.

проекты тоже все цельнотянутые с чужих сайтов?

А ты найди. Мой сайт: https://conntest.ru/

Найди на других сайтах.

Правда, такое возможно, но маловероятно. Это - при условии, что мой код кому-то очень понравился и он включил его без ссылки на автора. Время имеет значение, даже, не по Эйнштейну.

Коду - два дня. Потрещим?

Проверен временем. Самое то - выкладывать для повторения.

2 лайка

Т.е. вам плевать - вывалили, а там хоть потоп?

1 лайк

:smile:

Ну ты дал «жару», спасибо!

Промахнулся, бывает ))

1 лайк

Код реально работает, а там, хоть потом.

https://aliexpress.ru/item/1005008515666889.html есть еще такая железка, но я толком не работал с ней, в основном пытался получить доступ к sd карте который она не дает… но записывать и воспроизводить может вроде звук, и проигрывать mp3… может будет полезно… не знаю что вы конкретно хотели сделать…

О такой железяке я ничего не знаю и, пока, знать не хочу.

С кем поспорить, кто первый предоставит код (естественно, рабочий) записи звука с микрофона I2S INMP441 на SD карту в формате mp3 с помощью ESP32? Включайте ИИ и собственный.

ахахахаххах мне показалось, или он что то подозревает тоже на счет некоторых бывалых этого форума ? https://ok.ru/group/55270256017418/topic/151392325667594

как то не совсем честно получается, вы значит wav, а вам надо mp3…

Ну что, вызов принят?

напишите рабочий код записи на sd карту через телефон, пример я вам уже скинул, и я подумаю над тем что бы принять ваш вызов, люблю не просто сотрясать воздух, а поупражняться в коде)))