1
\$\begingroup\$

I am attempting to connect a DMM-4026-B-I2S-EB-R to an ESP32-S2-DevKitC.

I am writing this code in the Arduino IDE. It is based on the code from this article.

I believe my code works; I included it anyway.

/*
  ESP32 I2S Microphone Sample
  esp32-i2s-mic-sample.ino
  Sample sound from I2S microphone, display on Serial Plotter
  Requires INMP441 I2S microphone

  DroneBot Workshop 2022
  https://dronebotworkshop.com
*/

// Include I2S driver
#include <driver/i2s.h>

#define I2S_WS 4
#define I2S_SD 5
#define I2S_SCK 18

// Use I2S Processor 0
#define I2S_PORT I2S_NUM_0

// Define input buffer length
#define bufferLen 64
int16_t sBuffer[bufferLen];

void i2s_install() {
  // Set up I2S Processor configuration
  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_16BIT,
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format = I2S_COMM_FORMAT_STAND_I2S,
    .intr_alloc_flags = 0,
    .dma_buf_count = 8,
    .dma_buf_len = bufferLen,
    .use_apll = false
  };

  esp_err_t debug1 = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
  Serial.print("Driver is: ");
  Serial.println(debug1);
}

void i2s_setpin() {
  // Set I2S pin configuration
  const i2s_pin_config_t pin_config = {
    .bck_io_num = I2S_SCK,
    .ws_io_num = I2S_WS,
    .data_out_num = I2S_PIN_NO_CHANGE,
    .data_in_num = I2S_SD
  };

  esp_err_t debug2 = i2s_set_pin(I2S_PORT, &pin_config);
  Serial.print("RESULT OF SET PIN:");
  Serial.println(debug2);
}

void setup() {

  // Set up Serial Monitor
  Serial.begin(115200);
  Serial.println(" ");

  delay(1000);

  // Set up I2S
  i2s_install();
  i2s_setpin();
  i2s_start(I2S_PORT);
  i2s_set_clk(I2S_PORT, 22050,  I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO);

  delay(500);
}

void loop() {

  // False print statements to "lock range" on serial plotter display
  // Change rangelimit value to adjust "sensitivity"
  
  

  // Get I2S data and place in data buffer
  size_t bytesIn = 0;
  esp_err_t result = i2s_read(I2S_PORT, &sBuffer, bufferLen, &bytesIn, portMAX_DELAY);

  if (result == ESP_OK) {
    Serial.print("READ IS: ");
    Serial.println(result);
    // Read I2S data buffer
    int16_t samples_read = bytesIn / 8;
    if (samples_read > 0) {
      float mean = 0;
      for (int16_t i = 0; i < samples_read; ++i) {
        mean += (sBuffer[i]);
      }

      // Average the data reading
      mean /= samples_read;

      // Print to serial plotter
      Serial.println(mean);
    }
  }
  else
  {
    Serial.println(result);
  }
}

The microphone worked exactly once. Now, the microphone outputs random, but seemingly periodic values.

Serial Plotter, showing graph of random output

Note the output here is all negative. The one time it worked, the output created an almost sine-wave-like graph, ranging from positive to negative.

This output continues even if ground is disconnected from the dev board or 3V3 is disconnected from the dev board, but not both.

Here is the output from the Serial Monitor:

-20479.50
READ IS: 0
-24575.00
READ IS: 0
-16384.00
READ IS: 0
-24576.00
READ IS: 0
-24576.00
READ IS: 0
-32768.00
READ IS: 0
-12287.00
READ IS: 0
-20480.00
READ IS: 0
-16384.00
READ IS: 0
-16384.00
READ IS: 0
-4096.00
READ IS: 0
-12288.00
READ IS: 0
-8191.00
READ IS: 0
-16383.00
READ IS: 0
-4096.00
READ IS: 0
-12288.00
READ IS: 0
-16384.00
READ IS: 0
-12287.00
READ IS: 0
-12287.00
READ IS: 0
-8191.00
READ IS: 0
-4095.00
READ IS: 0
-28671.00

My question is: What is the most likely cause of this microphone breakout board not working?

My thinking is that, based on this info, the microphone breakout board did not start up properly. Furthermore, since it did work once, this would tell me the board did not start up properly due to a connection issue. However, I am unsure how to determine which connection is bad, or if that is the problem at all.

  • I have checked the Espressif API reference for the S2
  • I have checked connections, but only with an analog multimeter, perhaps there could still be an issue with a connection due to my poor soldering.

Here is a picture of the circuit:

Image of circuit

The config pin has a 10 kΩ pull down resistor. The L/R pin is connected to ground.

The only tools I have available are a soldering iron and an analog multimeter.

Related questions:

\$\endgroup\$
2
  • \$\begingroup\$ When doing embedded work be VERY VERY suspicious of values == 2^n or 2^n - 1, these are saturation values and can indicate that you're not deserializing data correctly. I am suspecting that you are getting the endien incorrect with the received data. Also since you're not printing the actual data but only the mean, calculate a min and a max while you're at it - it may yield some insight. \$\endgroup\$
    – Bryan
    Commented Aug 24, 2022 at 20:56
  • \$\begingroup\$ @Bryan What do you mean by endien? Do you mean the endian? \$\endgroup\$
    – SunriZe225
    Commented Aug 26, 2022 at 0:43

1 Answer 1

1
\$\begingroup\$

I think the first thing to rethink is what i2s_read will return to you.

If we take a peek in the GitHub of Espressif and go to the i2s part, you can see for the new master version: (i2s_channel_read is the new name of the function i2s_read, but practically the same)

esp_err_t i2s_channel_read(i2s_chan_handle_t handle, void *dest, size_t size, size_t *bytes_read, uint32_t timeout_ms)
{
    I2S_NULL_POINTER_CHECK(TAG, handle);
    ESP_RETURN_ON_FALSE(handle->dir == I2S_DIR_RX, ESP_ERR_INVALID_ARG, TAG, "this channel is not rx channel");

    esp_err_t ret = ESP_OK;
    uint8_t *data_ptr;
    uint8_t *dest_byte;
    int bytes_can_read;
    *bytes_read = 0;
    dest_byte = (uint8_t *)dest;
    /* The binary semaphore can only be taken when the channel has been enabled and no other reading operation in progress */
    ESP_RETURN_ON_FALSE(xSemaphoreTake(handle->binary, pdMS_TO_TICKS(timeout_ms)) == pdTRUE, ESP_ERR_INVALID_STATE, TAG, "The channel is not enabled");
    while (size > 0 && handle->state == I2S_CHAN_STATE_RUNNING) {
        if (handle->dma.rw_pos == handle->dma.buf_size || handle->dma.curr_ptr == NULL) {
            if (xQueueReceive(handle->msg_queue, &(handle->dma.curr_ptr), pdMS_TO_TICKS(timeout_ms)) == pdFALSE) {
                ret = ESP_ERR_TIMEOUT;
                break;
            }
            handle->dma.rw_pos = 0;
        }
        data_ptr = (uint8_t *)handle->dma.curr_ptr;
        data_ptr += handle->dma.rw_pos;
        bytes_can_read = handle->dma.buf_size - handle->dma.rw_pos;
        if (bytes_can_read > (int)size) {
            bytes_can_read = size;
        }
        memcpy(dest_byte, data_ptr, bytes_can_read);
        size -= bytes_can_read;
        dest_byte += bytes_can_read;
        handle->dma.rw_pos += bytes_can_read;
        (*bytes_read) += bytes_can_read;
    }
    xSemaphoreGive(handle->binary);

    return ret;
}

You see the buffer is cast to uint8_t, so just bytes.

Now comes the tricky part; changing two uint8_t to a uint16_t is simple. Like:

uint8_t msb,lsb;
uint16_t result;

result = msb << 8 | lsb;

But an uint16_t is not an int16_t.

I’m not chewing everything for you now, try to find that answer as well here. You will find a very extensive answer. But it’s super informative to learn by yourself!

Oh. And reading the buffer: lsb is first. Msb second. And so on.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.