Can't seem to get clean audio out of a INMP441, anyone see any obvious issues with this?

RyanDe
Posts: 3
Joined: Fri Jan 24, 2025 6:45 pm

Can't seem to get clean audio out of a INMP441, anyone see any obvious issues with this?

Postby RyanDe » Fri Jan 24, 2025 6:49 pm

I've walked through all the other threads on this but for some reason I can't make it work. :-/

I have a python script that I run and this dumps the data out to but when I open it in audacity it's just static (maybe I can make out something but it could be my immagination)

I've tried three different mics. I setup another esp32 as a fake slave to make sure the data was flowing and it is. I can see the data if I print it but it's just a bunch of numbers. Any thoughts?

Code: Select all


#include <stdio.h>
#include <string.h>
#include "driver/i2s_std.h"
#include "esp_log.h"
#include "freertos/FreeRTOSConfig.h"
#include "freertos/FreeRTOS.h"
#include <inttypes.h>    // Include this at the top of your file if not already included
#include "driver/gpio.h" // Include GPIO driver for button

#define BUFFER_SIZE 1024
#define RX_SAMPLE_SIZE (I2S_DATA_BIT_WIDTH_32BIT * BUFFER_SIZE)
#define MY_LOG_TAG "I2S_MIC"
#define BUTTON_GPIO 1 // Define GPIO1 as the button pin

i2s_chan_handle_t rx_handle;
int32_t i2s_rx_buff[RX_SAMPLE_SIZE];
size_t bytes_read;

// Storage
// int1_t mic_data[BUFFER_SIZE * 30]; // Array to store mic data
int16_t buffer16[BUFFER_SIZE * 30] = {0};
int data_index = 0; // Index to store data

// Initialize the button GPIO
void init_button()
{
  gpio_config_t io_conf = {
      .pin_bit_mask = (1ULL << BUTTON_GPIO), // Set GPIO1 as the button pin
      .mode = GPIO_MODE_INPUT,               // Set pin as input
      .pull_up_en = GPIO_PULLDOWN_ENABLE,    // No pull-up resistor
      .pull_down_en = GPIO_PULLDOWN_DISABLE, // Enable pull-down resistor
      .intr_type = GPIO_INTR_DISABLE,        // No interrupt for the button
  };
  gpio_config(&io_conf);
}

// This is our INMP441 mems microphone
void init_rx_i2s_chan()
{
  i2s_chan_config_t rx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
  i2s_new_channel(&rx_chan_cfg, NULL, &rx_handle);
  i2s_std_config_t std_rx_cfg = {
      .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(16000),
      .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_MONO),
      .gpio_cfg = {
          .mclk = I2S_GPIO_UNUSED,
          .bclk = GPIO_NUM_2,
          .ws = GPIO_NUM_4,
          .dout = I2S_GPIO_UNUSED,
          .din = GPIO_NUM_3,
          .invert_flags = {
              .mclk_inv = false,
              .bclk_inv = false,
              .ws_inv = false,
          },
      },
  };
  ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle, &std_rx_cfg));
  ESP_ERROR_CHECK(i2s_channel_enable(rx_handle));
}

void app_main(void)
{
  init_rx_i2s_chan();
  init_button();

  bool is_recording = false; // Track if recording is active

  while (true)
  {
    // Check if button is pressed (GPIO1 is LOW)
    if (gpio_get_level(BUTTON_GPIO) == 0)
    {
      if (!is_recording) // If not already recording, start recording
      {
        // ESP_LOGI(MY_LOG_TAG, "Button pressed - Start recording");
        is_recording = true; // Set the recording flag
        data_index = 0;      // Reset the data index for the new recording
      }
    }
    else
    {
      if (is_recording) // If recording and button is released, dump data
      {
        // ESP_LOGI(MY_LOG_TAG, "Button released - Dumping recorded data: %d", data_index);
        for (int i = 0; i < data_index; i++)
        {
           printf("%c", buffer16[i] & 0xFF);        // Print lower byte of 16-bit data
           printf("%c", (buffer16[i] >> 8) & 0xFF); // Print higher byte of 16-bit data
        }
        
        // For humans
        // for (int i = 0; i < data_index; i++)
        // {
        //   printf("%hd\n", buffer16[i]); // Print the data (adjust format as needed)
        // }
        // ESP_LOGI(MY_LOG_TAG, "Button released - Dumping recorded data: %d", data_index);
        is_recording = false; // Stop recording
      }
    }

    vTaskDelay(pdMS_TO_TICKS(10));

    if (i2s_channel_read(rx_handle, i2s_rx_buff, RX_SAMPLE_SIZE, &bytes_read, 100) == ESP_OK)
    {
      // ESP_LOGI(MY_LOG_TAG, "Bytes read: %zu", bytes_read);
      size_t samplesRead = bytes_read / sizeof(int32_t);
      for (int i = 0; i < samplesRead; i++)
      {
        int32_t sample = i2s_rx_buff[i];
        if (sample == 0)
        {
          // Right channel
          continue;
        }

        // Only get the middle bytes
        int16_t raw = (sample >> 8) & 0xFFFF;
        if (is_recording)
        {
          if (data_index < (BUFFER_SIZE * 30))
          {
            buffer16[data_index++] = raw;
          }
          else
          {
            ESP_LOGI(MY_LOG_TAG, "Buffer full");
            is_recording = false;
          }
        }
      }
    }
    else
    {
      ESP_LOGI(MY_LOG_TAG, "Read Failed!");
    }
  }
}

RyanDe
Posts: 3
Joined: Fri Jan 24, 2025 6:45 pm

Re: Can't seem to get clean audio out of a INMP441, anyone see any obvious issues with this?

Postby RyanDe » Sun Jan 26, 2025 5:06 pm

Update so if someone finds this searching. For this issue it seems just trying to get the data via serial was most of the problem and as soon as I hooked up an SD card and wrote to that things go better and I could make out sound. From there some more tweaks and the basic data collection looks like this now.

Code: Select all

if (i2s_channel_read(rx_handle, i2s_rx_buff, RX_SAMPLE_SIZE, &bytes_read, 1000) == ESP_OK)
    {
      // ESP_LOGI(MY_LOG_TAG, "Bytes read: %zu", bytes_read);
      if (is_recording)
      {
        size_t samples = bytes_read / sizeof(int32_t);
        for (size_t i = 0; i < samples; i += 2)
        {
          int32_t sample = i2s_rx_buff[i];

          // Convert 32-bit sample to 16-bit
          // int16_t sample16 = (int16_t)(sample >> 16);
          int16_t sample16 = (sample >> 16) & 0xFFFF;
          uint8_t bytes[2] = {(uint8_t)(sample16 & 0xFF), (uint8_t)((sample16 >> 8) & 0xFF)};
          wavFile.write(bytes, 2);
        }
      }
    }
    
Part of the problem I was having was I was ignoring samples that were zero to try and get rid of the right channel but in some cases it wasn't zero (noise) so it was included making it odd kinds of weird. Notice in my loop now I'm just skipping two samples at a time so this is skipping over the right channel and I don't have to worry about it.
Shifting over 16 bits seems to be fine, I get rid of the padding and the least signifiant bits, good enough for my use case.

Who is online

Users browsing this forum: No registered users and 62 guests