├── Readme.md └── examples ├── InputSerialPlotter └── InputSerialPlotter.ino ├── NoiseLevel └── NoiseLevel.ino └── VUMeterDemo └── VUMeterDemo.ino /Readme.md: -------------------------------------------------------------------------------- 1 | #ESP32 I2S MEMS Microphone Arduino IDE Example 2 | This repository holds some samples for connecting a I2S MEMS microphone to an ESP32 board. 3 | 4 | At first I thought hooking up an I2S microphone would be straight forward, but it seems that I2S is a somewhat new or neglected interface. The examples distributed by adafruit only apply for Feather M0; the generic I2S example from the ESP32 examples is not directly applicable. Hence this repository. 5 | 6 | ## Components used in this example 7 | I am using these components: 8 | * [adafruit-huzzah32-esp32-feather](https://www.adafruit.com/product/3405) 9 | * [adafruit-i2s-mems-microphone-breakout](https://www.adafruit.com/product/3421) 10 | 11 | ## How to connect the components? 12 | There are no dedicated I2S pins on the ESP32. Instead, you will have to configure/enable the pins in your code. 13 | Eventually, I connected I2S-MEMS pins to the following ESP32 pins: 14 | * SEL is unconnected, i.e. only one channel, apparently left 15 | * LRCL to #15 16 | * DOUT to #32 17 | * BCKL to #14 18 | * GND to GND 19 | * 3V to 3V 20 | 21 | Don't try to connect them to the similar sounding SCL/SCA/SCK, they're for the incompatible I2C interface. 22 | 23 | ## How to use the examples? 24 | You can open each of the examples as a sketch in the Arduino IDE. I've commonly used a baudrate of `115200`, you will need to configure this in your serial monitor, otherwise it'll display rubbish. 25 | 26 | ## Noteworthy 27 | * Either the `SEL` config is wrong, or the ESP32 I2S channel handling. 28 | * I had to use `I2S_CHANNEL_FMT_ONLY_RIGHT` whenever `SEL` pin was unconnected/ground, and `I2S_CHANNEL_FMT_ONLY_RIGHT` when `SEL` is high. 29 | * I could only get it to work with 32 bit sampling. 30 | * I don't know if this is a limitation of either hardware, or a configuration mistake on my side. 31 | * Although the setup seems to react nicely to noise. 32 | * I do not know if the recorded data is actually a valid sound. 33 | * There might be some bit-juggling still to be done. 34 | 35 | ## Credits 36 | Credits go to Adafruit for the easy-to-use hardware and the nice guide (even if it is not fully applicable here, it's still a great place for starters) and the [espressif examples](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/i2s). -------------------------------------------------------------------------------- /examples/InputSerialPlotter/InputSerialPlotter.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * ESP32 I2S Serial Plotter Example. 3 | * 4 | * This example is based on the espressif-idf example and Public Domain. 5 | * @author maspetsberger 6 | */ 7 | 8 | #include 9 | 10 | const i2s_port_t I2S_PORT = I2S_NUM_0; 11 | 12 | void setup() { 13 | Serial.begin(115200); 14 | Serial.println("Configuring I2S..."); 15 | esp_err_t err; 16 | 17 | // The I2S config as per the example 18 | const i2s_config_t i2s_config = { 19 | .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX), // Receive, not transfer 20 | .sample_rate = 16000, // 16KHz 21 | .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, // could only get it to work with 32bits 22 | .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT, // although the SEL config should be left, it seems to transmit on right 23 | .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), 24 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // Interrupt level 1 25 | .dma_buf_count = 4, // number of buffers 26 | .dma_buf_len = 8 // 8 samples per buffer (minimum) 27 | }; 28 | 29 | // The pin config as per the setup 30 | const i2s_pin_config_t pin_config = { 31 | .bck_io_num = 14, // BCKL 32 | .ws_io_num = 15, // LRCL 33 | .data_out_num = -1, // not used (only for speakers) 34 | .data_in_num = 32 // DOUT 35 | }; 36 | 37 | // Configuring the I2S driver and pins. 38 | // This function must be called before any I2S driver read/write operations. 39 | err = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL); 40 | if (err != ESP_OK) { 41 | Serial.printf("Failed installing driver: %d\n", err); 42 | while (true); 43 | } 44 | err = i2s_set_pin(I2S_PORT, &pin_config); 45 | if (err != ESP_OK) { 46 | Serial.printf("Failed setting pin: %d\n", err); 47 | while (true); 48 | } 49 | Serial.println("I2S driver installed."); 50 | } 51 | 52 | void loop() { 53 | 54 | // Read a single sample and log it for the Serial Plotter. 55 | int32_t sample = 0; 56 | int bytes_read = i2s_pop_sample(I2S_PORT, (char *)&sample, portMAX_DELAY); // no timeout 57 | if (bytes_read > 0) { 58 | Serial.println(sample); 59 | } 60 | 61 | } 62 | 63 | // actually we would need to call `i2s_driver_uninstall(I2S_PORT)` upon exit. 64 | -------------------------------------------------------------------------------- /examples/NoiseLevel/NoiseLevel.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * ESP32 I2S Noise Level Example. 3 | * 4 | * This example calculates a mean noise level. 5 | * This example is Public Domain. 6 | * 7 | * @author maspetsberger 8 | */ 9 | 10 | #include 11 | 12 | const i2s_port_t I2S_PORT = I2S_NUM_0; 13 | const int BLOCK_SIZE = 1024; 14 | 15 | void setup() { 16 | Serial.begin(115200); 17 | Serial.println("Configuring I2S..."); 18 | esp_err_t err; 19 | 20 | // The I2S config as per the example 21 | const i2s_config_t i2s_config = { 22 | .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX), // Receive, not transfer 23 | .sample_rate = 16000, // 16KHz 24 | .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, // could only get it to work with 32bits 25 | .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT, // although the SEL config should be left, it seems to transmit on right 26 | .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), 27 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // Interrupt level 1 28 | .dma_buf_count = 8, // number of buffers 29 | .dma_buf_len = BLOCK_SIZE // samples per buffer 30 | }; 31 | 32 | // The pin config as per the setup 33 | const i2s_pin_config_t pin_config = { 34 | .bck_io_num = 14, // BCKL 35 | .ws_io_num = 15, // LRCL 36 | .data_out_num = -1, // not used (only for speakers) 37 | .data_in_num = 32 // DOUT 38 | }; 39 | 40 | // Configuring the I2S driver and pins. 41 | // This function must be called before any I2S driver read/write operations. 42 | err = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL); 43 | if (err != ESP_OK) { 44 | Serial.printf("Failed installing driver: %d\n", err); 45 | while (true); 46 | } 47 | err = i2s_set_pin(I2S_PORT, &pin_config); 48 | if (err != ESP_OK) { 49 | Serial.printf("Failed setting pin: %d\n", err); 50 | while (true); 51 | } 52 | Serial.println("I2S driver installed."); 53 | } 54 | 55 | void loop() { 56 | 57 | // Read multiple samples at once and calculate the sound pressure 58 | int32_t samples[BLOCK_SIZE]; 59 | int num_bytes_read = i2s_read_bytes(I2S_PORT, 60 | (char *)samples, 61 | BLOCK_SIZE, // the doc says bytes, but its elements. 62 | portMAX_DELAY); // no timeout 63 | 64 | int samples_read = num_bytes_read / 8; 65 | if (samples_read > 0) { 66 | 67 | float mean = 0; 68 | for (int i = 0; i < samples_read; ++i) { 69 | mean += samples[i]; 70 | } 71 | Serial.println(mean); 72 | } 73 | } 74 | 75 | // actually we would need to call `i2s_driver_uninstall(I2S_PORT)` upon exit. 76 | -------------------------------------------------------------------------------- /examples/VUMeterDemo/VUMeterDemo.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * ESP32 I2S VUMeter Example. 3 | * 4 | * This example is based on the "Sound Pressure Meter" Example in the 5 | * Adafruit I2S MEMS Breakout board. 6 | * All beyond that is Public Domain. 7 | * 8 | * @author maspetsberger 9 | */ 10 | 11 | #include 12 | 13 | const i2s_port_t I2S_PORT = I2S_NUM_0; 14 | const int BLOCK_SIZE = 128; 15 | 16 | void setup() { 17 | Serial.begin(115200); 18 | Serial.println("Configuring I2S..."); 19 | esp_err_t err; 20 | 21 | // The I2S config as per the example 22 | const i2s_config_t i2s_config = { 23 | .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX), // Receive, not transfer 24 | .sample_rate = 16000, // 16KHz 25 | .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, // could only get it to work with 32bits 26 | .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT, // although the SEL config should be left, it seems to transmit on right 27 | .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), 28 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // Interrupt level 1 29 | .dma_buf_count = 4, // number of buffers 30 | .dma_buf_len = BLOCK_SIZE // samples per buffer 31 | }; 32 | 33 | // The pin config as per the setup 34 | const i2s_pin_config_t pin_config = { 35 | .bck_io_num = 14, // BCKL 36 | .ws_io_num = 15, // LRCL 37 | .data_out_num = -1, // not used (only for speakers) 38 | .data_in_num = 32 // DOUT 39 | }; 40 | 41 | // Configuring the I2S driver and pins. 42 | // This function must be called before any I2S driver read/write operations. 43 | err = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL); 44 | if (err != ESP_OK) { 45 | Serial.printf("Failed installing driver: %d\n", err); 46 | while (true); 47 | } 48 | err = i2s_set_pin(I2S_PORT, &pin_config); 49 | if (err != ESP_OK) { 50 | Serial.printf("Failed setting pin: %d\n", err); 51 | while (true); 52 | } 53 | Serial.println("I2S driver installed."); 54 | } 55 | 56 | void loop() { 57 | 58 | // Read multiple samples at once and calculate the sound pressure 59 | int32_t samples[BLOCK_SIZE]; 60 | int num_bytes_read = i2s_read_bytes(I2S_PORT, 61 | (char *)samples, 62 | BLOCK_SIZE, // the doc says bytes, but its elements. 63 | portMAX_DELAY); // no timeout 64 | 65 | int samples_read = num_bytes_read / 8; 66 | if (samples_read > 0) { 67 | 68 | float mean = 0; 69 | for (int i = 0; i < samples_read; ++i) { 70 | mean += (samples[i] >> 14); 71 | } 72 | mean /= samples_read; 73 | 74 | float maxsample = -1e8, minsample = 1e8; 75 | for (int i = 0; i < samples_read; ++i) { 76 | minsample = min(minsample, samples[i] - mean); 77 | maxsample = max(maxsample, samples[i] - mean); 78 | } 79 | Serial.println(maxsample - minsample); 80 | } 81 | } 82 | 83 | // actually we would need to call `i2s_driver_uninstall(I2S_PORT)` upon exit. 84 | --------------------------------------------------------------------------------