Microphone prints not working for ESP32?

Hey. I'm trying to test my INMP441 microphone (datasheet) on my Lolin D32 (ESP32) board. I've been going through a lot of different codes on forums, GitHub repos and whatnot but I can't seem to get any of them to work.

I was hoping if anyone could share on insight into this and if I might be doing something wrong? My knowledge level in understanding the microphone and its programming are pretty much in the basics.

Two examples I've been trying to get to work:

Visual Studio Code sketch that prints "�H�!jHH1!)9MJ!)1I�8�␞�)!��!�WH�␌)" (forum post)

/*
 * app_main.c
 *
 *  Created on: 30.03.2017
 *      Author: michaelboeckling
 */

#include <stdlib.h>
#include <stddef.h>
#include <inttypes.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <sys/time.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_log.h"
#include "driver/i2s.h"

#define TAG "main"

static void init_i2s()
{
	const int sample_rate = 44100;

	/* TX: I2S_NUM_0 */
    i2s_config_t i2s_config_tx = {
	.mode = I2S_MODE_MASTER | I2S_MODE_TX,
	.sample_rate = sample_rate,
	.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
	.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,   // 2-channels
	.communication_format = I2S_COMM_FORMAT_I2S_MSB,
	.dma_buf_count = 32,                            // number of buffers, 128 max.
	.dma_buf_len = 32 * 2,                          // size of each buffer
	.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1        // Interrupt level 1
    };

    i2s_pin_config_t pin_config_tx = {
			.bck_io_num = GPIO_NUM_26,
			.ws_io_num = GPIO_NUM_25,
			.data_out_num = GPIO_NUM_22,
			.data_in_num = GPIO_NUM_23
	};
    i2s_driver_install(I2S_NUM_0, &i2s_config_tx, 0, NULL);
    i2s_set_pin(I2S_NUM_0, &pin_config_tx);


    /* RX: I2S_NUM_1 */
    i2s_config_t i2s_config_rx = {
	.mode = I2S_MODE_MASTER | I2S_MODE_RX, // Only TX
	.sample_rate = sample_rate,
	.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,    // Only 8-bit DAC support
	.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,   // 2-channels
	.communication_format = I2S_COMM_FORMAT_I2S_MSB,
	.dma_buf_count = 32,                            // number of buffers, 128 max.
	.dma_buf_len = 32 * 2,                          // size of each buffer
	.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1        // Interrupt level 1
	};

	i2s_pin_config_t pin_config_rx = {
		.bck_io_num = GPIO_NUM_2,
		.ws_io_num = GPIO_NUM_15,
		.data_out_num = I2S_PIN_NO_CHANGE,
		.data_in_num = GPIO_NUM_13
	};

	i2s_driver_install(I2S_NUM_1, &i2s_config_rx, 0, NULL);
	i2s_set_pin(I2S_NUM_1, &pin_config_rx);

}


void task_megaphone(void *pvParams)
{
	uint16_t buf_len = 1024;
	char *buf = calloc(buf_len, sizeof(char));

	struct timeval tv = {0};
	struct timezone *tz = {0};
	gettimeofday(&tv, &tz);
	uint64_t micros = tv.tv_usec + tv.tv_sec * 1000000;
	uint64_t micros_prev = micros;
	uint64_t delta = 0;

	init_i2s();

	int cnt = 0;
	int bytes_written = 0;

	while(1)
	{
		char *buf_ptr_read = buf;
		char *buf_ptr_write = buf;

		// read whole block of samples
		int bytes_read = 0;
		while(bytes_read == 0) {
			bytes_read = i2s_read_bytes(I2S_NUM_1, buf, buf_len, 0);
		}

		uint32_t samples_read = bytes_read / 2 / (I2S_BITS_PER_SAMPLE_32BIT / 8);

		//  convert 2x 32 bit stereo -> 1 x 16 bit mono
		for(int i = 0; i < samples_read; i++) {

			// const char samp32[4] = {ptr_l[0], ptr_l[1], ptr_r[0], ptr_r[1]};

			// left
			buf_ptr_write[0] = buf_ptr_read[2]; // mid
			buf_ptr_write[1] = buf_ptr_read[3]; // high

			// right
			buf_ptr_write[2] = buf_ptr_write[0]; // mid
			buf_ptr_write[3] = buf_ptr_write[1]; // high


			buf_ptr_write += 2 * (I2S_BITS_PER_SAMPLE_16BIT / 8);
			buf_ptr_read += 2 * (I2S_BITS_PER_SAMPLE_32BIT / 8);
		}

		// local echo
		bytes_written = samples_read * 2 * (I2S_BITS_PER_SAMPLE_16BIT / 8);
		i2s_write_bytes(I2S_NUM_0, buf, bytes_written, portMAX_DELAY);

		cnt += samples_read;

		if(cnt >= 44100) {
			gettimeofday(&tv, &tz);
			micros = tv.tv_usec + tv.tv_sec * 1000000;
			delta = micros - micros_prev;
			micros_prev = micros;
			printf("%d samples in %" PRIu64 " usecs\n", cnt, delta);

			cnt = 0;
		}
	}
}

/**
 * entry point
 */
void app_main()
{
    printf("starting app_main()\n");
    xTaskCreatePinnedToCore(&task_megaphone, "task_megaphone", 16384, NULL, 20, NULL, 0);
}

Arduino IDE sketch that prints nothing but 0 (youtube video and GitHub repo):

#include <driver/i2s.h>
#define I2S_WS 15
#define I2S_SD 13
#define I2S_SCK 2

#define I2S_PORT I2S_NUM_0

void setup() {
  Serial.begin(115200);
  Serial.println("Setup I2S ...");

  delay(1000);
  i2s_install();
  i2s_setpin();
  i2s_start(I2S_PORT);
  delay(500);
}

void loop() {
  int32_t sample = 0;
  int bytes = i2s_pop_sample(I2S_PORT, (char*)&sample, portMAX_DELAY);
  if(bytes > 0){
    Serial.println(sample);
  }
}

void i2s_install(){
  const i2s_config_t i2s_config = {
    .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX),
    .sample_rate = 44100,
    .bits_per_sample = i2s_bits_per_sample_t(32),
    .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
    .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
    .intr_alloc_flags = 0, // default interrupt priority
    .dma_buf_count = 8,
    .dma_buf_len = 64,
    .use_apll = false
  };

  i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
}

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

to get answers more easy you should take work from the shoulders of your potential supporters.
you should provide:

  • a datasheet of your microphone-sensor-module
  • looking if the manufacturer of the sensor-module has some testcode
  • a handdrawn schematic how you have connected your microphone-module to your ESP32

that's all work than can be done by you even if you don't know anything about electronics and nothing about programming.

best regards Stefan

That’s a good point. I don’t know how I missed the importance of adding those. Thanks for pointing that out.

I added the Fritzing diagram and datasheet link but I couldn’t find any test code from the manufacturer so I only could use and show the two simplest example codes I managed to get to work (as in I got the program to run).

looking into the datasheet.... Ah!! That is an I2S-microphone. This means the output-signal is a digital stream of bits which is something completely different than the analog output-signal of a standard (or should I say "old-fashioned") microphone.

So googling with keywords **arduino using a I2S microphone ** come up with this
https://www.arduino.cc/reference/en/libraries/adafruit-zero-i2s-library/

www.google.de/search?lr=&newwindow=1&as_qdr=all&ei=l-jlX7OJEcrAlAaKl4ygBg&q=arduino+using+a+I2S+microphone

the microcontroller-world is not superstandardized like USB-devices. You have to take care of much more details than just "does the plug fit into the socket?" and this means "RTDS" read the data-sheet.

So this should get you starting. If any questions arise with using these code-examples
just post them.

best regards Stefan

That was a helpful post for sure, thank you.

However, I tried some Arduino I2S code examples, but these understandably kept saying they're not meant for a Lolin D32 board. So I tried ESP32-specific instead. I came across plenty of code examples I had previously tested but found one that made more sense to me after reading more about this. But I still couldn't get it to work.

I tried these four code examples:

https://esp32.com/viewtopic.php?t=15185#p58341

https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/i2s.html

I tried changing:

  • the channel from right to left (while also connecting and disconnecting L/R-pin to the ground)
  • bits/sample from 36-bit to 24-bits (since datasheet says it's 24-bit)
  • GPIO pins (my wirings match the pin layout on the code, which is also the same as on the #1 post)
  • different I2S configs

but they all had the same result: printing a bunch of 0s. Here's the code I most recently used:

#include "driver/i2s.h"
#include "esp_now.h"

const i2s_port_t I2S_PORT = I2S_NUM_0;

void setup() {
  Serial.begin(115200);
  esp_err_t err;

  // The I2S config as per the example
  i2s_config_t i2s_config = {
    .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
    .sample_rate = 11025, // or 44100 if you like
    .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // Ground the L/R pin on the INMP441.
    .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count = 4,
    .dma_buf_len = ESP_NOW_MAX_DATA_LEN * 4,
    .use_apll = false,
    .tx_desc_auto_clear = false,
    .fixed_mclk = 0,
  };

  // The pin config as per the setup
  const i2s_pin_config_t pin_config = {
    .bck_io_num = 26,   // Serial Clock (SCK)
    .ws_io_num = 25,    // Word Select (WS)
    .data_out_num = I2S_PIN_NO_CHANGE, // not used (only for speakers)
    .data_in_num = 33   // Serial Data (SD)
  };

  // Configuring the I2S driver and pins.
  // This function must be called before any I2S driver read/write operations.
  err = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
  if (err != ESP_OK) {
    Serial.printf("Failed installing driver: %d\n", err);
    while (true);
  }
  err = i2s_set_pin(I2S_PORT, &pin_config);
  if (err != ESP_OK) {
    Serial.printf("Failed setting pin: %d\n", err);
    while (true);
  }
  Serial.println("I2S driver installed.");
}

void loop() {
  int32_t sample = 0;
  int bytes_read = i2s_pop_sample(I2S_PORT, (char *)&sample, portMAX_DELAY); // no timeout
  if (bytes_read > 0) {
    Serial.println(sample);
  }
}

I'm once again at a dead-end and I'm not sure how to proceed. I'm actually starting to worry the microphone board is simply broken.

Anyone have any thoughts?

Do you have a logic analyzer or an oscilloscope?
To see if the microphone does some bitbanging on the I2S-port could be seen with such a device.

a 8 channel logic analyser
like this one for just $10
https://www.ebay.de/sch/i.html?_from=R40&_trksid=p2386202.m570.l1313&_nkw=8+Kanal+USB+Logik+Analyser+24+MHz+Logic+Analyzer&_sacat=0
I bought one recently. It works with the opensource-software pulseview which can be downloaded here
https://sigrok.org/wiki/Windows

pulseView can even analyse the bitbanging of Serial I2C. SPI amd CAN-Bus to show you the bytevalues that have been transmitted

I haven't worked with I2S at all.
Does the procedure of using I2S have a initiliastion which gives back a true for successful and a false for failed?

For I2C there is a scanner software.

I2S differs fundamentally from I2C but maybe something similar is available.

If hardware isn't too expensive I have the habit to buy two or three at once. just in case I brick one or one is defect.

best regards Stefan

Since you're unfamiliar with both programming and the I2S protocol, I'd recommend looking at the Teensy Audio Library. It has proven I2S support and requires little technical knowledge to use. You'll need to switch boards to a T3.2/5/6 or T4.0/1.