arduino-esp32
arduino-esp32 copied to clipboard
INMP441 frequency artifact
Board
ESP32-WROOM-DA
Device Description
Teyleten Robot INMP441 Omnidirectional Microphone Module MEMS High Precision Low Power I2S Interface for ESP32
Hardware Configuration
no
Version
latest master (checkout manually)
IDE Name
2.2.1
Operating System
macOS
Flash frequency
uknown
PSRAM enabled
yes
Upload speed
921600
Description
Recording audio data via INMP441, full audible spectrum, 22 kHz. Spectrogram of the recorded signal, in addition to the original signal, has the same signal inverted and also there's noise notch at 1/3 of the frequency range. Tried different ESP32 boards and INMP441 microphones, result is always the same. In the example below, I played full frequency sweep from base frequency 0 Hz to the upper limit 22 kHz. X-axis time, Y-axis frequency, data in dB.
Sketch
/*
ESP32 I2S Microphone
*/
// Include I2S driver
#include <driver/i2s.h>
#include "soc/i2s_reg.h"
// Connections to INMP441 I2S microphone
#define I2S_WS 25
#define I2S_SD 32
#define I2S_SCK 33
#define I2S_PORT I2S_NUM_0 // Use I2S Processor 0
#define bufferCnt 10
#define bufferLen 1024
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_t(16),
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_I2S),
.intr_alloc_flags = 0,
.dma_buf_count = bufferCnt,
.dma_buf_len = bufferLen,
.use_apll = false
};
i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
}
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 = -1,
.data_in_num = I2S_SD
};
i2s_set_pin(I2S_PORT, &pin_config);
}
void setup() {
// Set up Serial Monitor
Serial.begin(921600);
// Set up I2S
i2s_install();
i2s_setpin();
i2s_start(I2S_PORT);
}
void loop() {
// 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.write((const char*)sBuffer, bytesIn);
}
}
Debug Message
No debug message.
Other Steps to Reproduce
No response
I have checked existing issues, online documentation and the Troubleshooting Guide
- [X] I confirm I have checked existing issues, online documentation and Troubleshooting guide.
@vkfive - It seems that there was some changed in IDF 4.4.5 that have affected I2S. Could you please try the same with Arduino Core 2.0.9 (it uses IDF 4.4.4)? Thanks!
SuGlider, thanks for the recommendation. I've tried it. Noise notch at 1/3 bandwidth is gone, but the inversion is still there.
@vkfive how do you detect the inversion? In other words, how can we replicate this case? When you say inverted, do you mean that the sample values are inverted (and not the sample bits)?
@vkfive Maybe it is about the Byte Order in a 16 bits sample? Swaping the bytes would fix it?
@me-no-dev If you look at the spectrogram, the frequency sweep signal is flipped upside down and overlaid on the original signal. Bandwidth we are using is 22kH. For instance, 1kHz tone, also appears as 22kHz-1kHz = 21kHz signal. I don't have good understanding how bit position, or order, ... can generate such an effect.
SuGlider I'll try it, thanks.
Hi @SuGlider , anyupdate on this? I have similar settings with 16000 Hz sampling rate and 16 bit, and the frequency being recorded is somehow flipped.
Hi Ravi,I've resolved that issue. INMP441 uses 24bit data, and I was reading it as 32bit, or something like that. Check that part, there's some reshuffling of bits you have to do. All best. V
On Wednesday, May 15, 2024 at 11:22:32 PM GMT-4, Ravi Prakash ***@***.***> wrote:
Hi @SuGlider , anyupdate on this? I have similar settings with 16000 Hz sampling rate and 16 bit, and the frequency being recorded is somehow flipped. image.png (view on web)
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>
@vkfive Thanks for the input. I have been trying to read the data as 32 bit and then extract or keep only the 24 bits but have not been successful. Capturing data as 16bit gives me good audio result albeit the frequency issue. Everyone else for some reason seem to be reading the data as 16 bit but not sure if there spectrogram also have this issue. Did you ever end up putting your working code or data reading step as github link that I can refer too? Thanks
Hi Ravi, I've attached one version of the code that worked for me. Obviously you have to have reader that can grab data in interpret it on the serial port side. Good luck!
On Tuesday, May 21, 2024 at 04:45:46 PM GMT-4, Ravi Prakash ***@***.***> wrote:
@vkfive Thanks for the input. I have been trying to read the data as 32 bit and then extract or keep only the 24 bits but have not been successful. Capturing data as 16bit gives me good audio result albeit the frequency issue. Everyone else for some reason seem to be reading the data as 16 bit but not sure if there spectrogram also have this issue. Did you ever end up putting your working code or data reading step as github link that I can refer too? Thanks
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>
Hi @vkfive , awesome. Highly appreciate it. Silly question, did you update the code in the post entry or I should find a file in your last comment? I did not see any file in the comment. Thanks.
I've attached it to my previous email. I'm attaching it again. Please let me know if it went through.Sent from my Verizon, Samsung Galaxy smartphone -------- Original message --------From: Ravi Prakash @.> Date: 5/28/24 12:21 AM (GMT-04:00) To: espressif/arduino-esp32 @.> Cc: vkfive @.>, Mention @.> Subject: Re: [espressif/arduino-esp32] INMP441 frequency artifact (Issue #8614) Hi @vkfive , awesome. Highly appreciate it. Silly question, did you update the code in the post entry or I should find a file in your last comment? I did not see any file in the comment. Thanks.
—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you were mentioned.Message ID: @.***>
Hey @vkfive , I don't think it is going through the email. It may be possible to do it if done through the github comment website as I can see options to attach. Else , if you paste the text in the comment too, I can do the legwork of cleaning and pasting it again for others to use.
How about this, can you see the code?
/* ESP32 I2S Microphone*/ // Include I2S driver#include <driver/i2s.h> // Connections to INMP441 I2S microphone#define I2S_WS 25#define I2S_SD 32#define I2S_SCK 33#define I2S_PORT I2S_NUM_0 // Use I2S Processor 0 // Data size and type parameters#define bufferCnt 10#define bufferLen 1024#define bps 24 // bits per sample#define byte_N 2 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_t(bps), .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_I2S), .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = bufferCnt, .dma_buf_len = bufferLen, .use_apll = false, .tx_desc_auto_clear = false, .fixed_mclk = 0, }; i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);} 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 = -1, .data_in_num = I2S_SD }; i2s_set_pin(I2S_PORT, &pin_config);} void setup() { Serial.begin(921600); // Set up Serial Monitor, 921600 i2s_install(); // Set up I2S i2s_setpin(); i2s_start(I2S_PORT);} void loop() { // Get I2S data and place in data buffer size_t bytesIn = 0; int8_t sBuffer[bufferLen]; esp_err_t result = i2s_read(I2S_PORT, &sBuffer, bufferLen, &bytesIn, portMAX_DELAY); if (result == ESP_OK) { int samplesRead = bytesIn/(bps/8); int bytes_write = samplesRead * (bps/8)/4byte_N;// int bytes_write = samplesRead * (I2S_BITS_PER_SAMPLE_32BIT/8)/4byte_N; int8_t buffer8[bufferLen/(bps/8)byte_N] = {0}; for (int i=0; i<samplesRead; i++) {// buffer8[ibyte_N + 0] = sBuffer[i * 4 + 0]; buffer8[ibyte_N + 0] = sBuffer[i * 4 + 1]; buffer8[ibyte_N + 1] = sBuffer[i * 4 + 2]; } Serial.write((const char*)buffer8, bytes_write); }}
On Wednesday, May 29, 2024 at 04:23:00 PM GMT-4, Ravi Prakash ***@***.***> wrote:
Hey @vkfive , I don't think it is going through the email. It may be possible to do it if done through the github comment website as I can see options to attach. Else , if you paste the text in the comment too, I can do the legwork of cleaning and pasting it again for others to use.
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>
Perfect! Thanks a lot @vkfive .
Did you manage to resolve this? I'm working with a INMP441 too and through my oscilloscope I'm seeing a randomly bit flipped output on a large portion of the frames. I tested with two modules and with a function generator to isolate it. I'm suspecting there might have been a bad batch? (edit: or I damaged both modules in an identical way by soldering too hot?)
I've resolved it, it was in issue with format. INMP441 produces data in 24 bit format, but I was interpreting it as 32 bit. If it doesn't solve it for you, I can send you my code.Sent from my Verizon, Samsung Galaxy smartphone -------- Original message --------From: Jouke Waleson @.> Date: 10/13/24 6:33 PM (GMT+07:00) To: espressif/arduino-esp32 @.> Cc: vkfive @.>, Mention @.> Subject: Re: [espressif/arduino-esp32] INMP441 frequency artifact (Issue #8614) Did you manage to resolve this? I'm working with a INMP441 too and through my oscilloscope I'm seeing a randomly bit flipped output on a large portion of the frames. I tested with two modules and with a function generator to isolate it. I'm suspecting there might have been a bad batch?
—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you were mentioned.Message ID: @.***>
Ok, mine is not a software problem but seems a problem with the actual microphone chip. Thanks for the quick reply!
Commenting in hopes this helps anyone in the future: Ok, I am an idiot, of course it's not a hardware problem. The chance that that happens identically on two mass produced chips is astronomically small. The "flipped bits" were just negative numbers. I was playing around with measuring an analog microphone before I went to bed and when I woke up I realized that it must signed integers because a waveform goes up and down. Solved it in my sleep...
So my actual problem seems similar to the original one in that the microphone bit length and the pcm decoding bit length don't line up. I'll continue the search, no more help needed from people in this thread :)
Hello,
Due to the overwhelming volume of issues currently being addressed, we have decided to close the previously received tickets. If you still require assistance or if the issue persists, please don't hesitate to reopen the ticket.
Thanks.
Esp32-S3 & INMP441 Mic
The audio file is distorted, like a distorted radio, and doesn't contain the natural sounds I recorded.
#include <Arduino.h> #include <driver/i2s.h> #include <SD.h> #include <SPI.h>
#define I2S_WS 4 // LRCK #define I2S_SD 15 // Data #define I2S_SCK 14 // BCLK
#define SD_CS 10 #define SD_MOSI 11 #define SD_MISO 13 #define SD_SCK 12
#define I2S_PORT I2S_NUM_0 #define I2S_SAMPLE_RATE 16000 #define I2S_SAMPLE_BITS 32 #define I2S_CHANNEL_NUM 1 #define RECORD_TIME 20 // seconds #define I2S_READ_LEN 1024
File audioFile; const char* filename = "/recording.wav"; const int headerSize = 44; int totalSamples = I2S_SAMPLE_RATE * RECORD_TIME;
void setup() { Serial.begin(115200); delay(1000);
SPI.begin(SD_SCK, SD_MISO, SD_MOSI, SD_CS); if (!SD.begin(SD_CS)) { Serial.println("SD Card initialization failed!"); while (true); } Serial.println("SD Card initialized.");
i2sInit();
if (SD.exists(filename)) { SD.remove(filename); }
audioFile = SD.open(filename, FILE_WRITE); if (!audioFile) { Serial.println("Failed to open file for writing"); return; }
byte header[headerSize]; wavHeader(header, totalSamples * I2S_CHANNEL_NUM * 2); audioFile.write(header, headerSize);
Serial.println("Recording..."); recordAudio(); Serial.println("Recording done.");
audioFile.seek(0); wavHeader(header, totalSamples * I2S_CHANNEL_NUM * 2); audioFile.write(header, headerSize); audioFile.close();
Serial.println("File saved and closed.");
if (validateWavHeader(filename)) { Serial.println("WAV header valid."); } else { Serial.println("WAV header invalid."); } }
void loop() {}
void i2sInit() { i2s_config_t i2s_config = { .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX), .sample_rate = I2S_SAMPLE_RATE, .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, .communication_format = I2S_COMM_FORMAT_I2S, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = 8, .dma_buf_len = 1024, .use_apll = false, .tx_desc_auto_clear = false, .fixed_mclk = 0 };
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_driver_install(I2S_PORT, &i2s_config, 0, NULL); i2s_set_pin(I2S_PORT, &pin_config); i2s_set_clk(I2S_PORT, I2S_SAMPLE_RATE, I2S_BITS_PER_SAMPLE_32BIT, I2S_CHANNEL_MONO); }
void recordAudio() { size_t bytesRead; int32_t samples[I2S_READ_LEN / 4]; int16_t monoBuffer[I2S_READ_LEN / 4]; int recordedSamples = 0; int lastPercent = -1;
while (recordedSamples < totalSamples) { i2s_read(I2S_PORT, &samples, sizeof(samples), &bytesRead, portMAX_DELAY);
int sampleCount = bytesRead / 4;
int32_t sumAbs = 0;
for (int i = 0; i < sampleCount; i++) {
int32_t sample24 = samples[i] >> 8;
int16_t sample16 = sample24 >> 8;
monoBuffer[i] = sample16;
sumAbs += abs(sample16);
}
for (int i = 0; i < min(sampleCount, 10); i++) {
Serial.printf("Sample[%d] = %d\n", i, monoBuffer[i]);
}
float avgAbs = sumAbs / (float)sampleCount;
Serial.printf("Avg amplitude: %.1f\n", avgAbs);
audioFile.write((uint8_t*)monoBuffer, sampleCount * sizeof(int16_t));
recordedSamples += sampleCount;
int percent = (recordedSamples * 100) / totalSamples;
if (percent != lastPercent) {
Serial.printf("Progress: %d%%\n", percent);
lastPercent = percent;
}
} }
bool validateWavHeader(const char* file) { File f = SD.open(file, FILE_READ); if (!f || f.size() < 44) return false; byte header[44]; f.read(header, 44); f.close(); return (memcmp(header, "RIFF", 4) == 0) && (memcmp(header + 8, "WAVE", 4) == 0); }
void wavHeader(byte* header, int dataSize) { uint32_t fileSize = dataSize + 36; uint32_t byteRate = I2S_SAMPLE_RATE * I2S_CHANNEL_NUM * 2; uint16_t blockAlign = I2S_CHANNEL_NUM * 2;
memcpy(header, "RIFF", 4); header[4] = (fileSize & 0xff); header[5] = (fileSize >> 8) & 0xff; header[6] = (fileSize >> 16) & 0xff; header[7] = (fileSize >> 24) & 0xff; memcpy(header + 8, "WAVEfmt ", 8); header[16] = 16; header[17] = 0; header[18] = 0; header[19] = 0; header[20] = 1; header[21] = 0; header[22] = I2S_CHANNEL_NUM; header[23] = 0; header[24] = I2S_SAMPLE_RATE & 0xff; header[25] = (I2S_SAMPLE_RATE >> 8) & 0xff; header[26] = (I2S_SAMPLE_RATE >> 16) & 0xff; header[27] = (I2S_SAMPLE_RATE >> 24) & 0xff; header[28] = byteRate & 0xff; header[29] = (byteRate >> 8) & 0xff; header[30] = (byteRate >> 16) & 0xff; header[31] = (byteRate >> 24) & 0xff; header[32] = blockAlign; header[33] = 0; header[34] = 16; header[35] = 0; memcpy(header + 36, "data", 4); header[40] = dataSize & 0xff; header[41] = (dataSize >> 8) & 0xff; header[42] = (dataSize >> 16) & 0xff; header[43] = (dataSize >> 24) & 0xff; }