ESP32 with INM441 I2S microphone.
ESP32 with INM441 I2S microphone.
Hi,
how do I get data from INMP441 I2S microphone, every tutorial I have seen are using getting only 16 bit whereas the microphone is 24 bit and also most of the codes available online seem to calculate the average of received data. I dont understand it, can someone throw some light on this ? thanks.
how do I get data from INMP441 I2S microphone, every tutorial I have seen are using getting only 16 bit whereas the microphone is 24 bit and also most of the codes available online seem to calculate the average of received data. I dont understand it, can someone throw some light on this ? thanks.
Re: ESP32 with INM441 I2S microphone.
The INMP441 I2S interface delivers 24 bits of data in the high order bits of a 32 bit word. This is fixed and cannot be configured otherwise. You need to shift the 32 bit word right by 8 bits, then you will have your 32 bit sample.
Note this is a signed integer.
Code below is converting the sample to 16 bits.
char audio_buffer[samples * bytesPerInputSample];
int32_t *input_buffer;
input_buffer = (int32_t *)&audio_buffer;
uint16_t *output_buffer; // the output buffer, uint16_t required by file write
output_buffer = (uint16_t *)&audio_buffer;
for (int i = 0; i < samples; i++) {
int32_t val32 = input_buffer >> 8; // shift out the empty byte - this is a signed int, the shift will preserve the sign
int16_t val16 = (int16_t)val32; // convert 32 bit signed to 16 bit signed
output_buffer = (uint16_t)val16; // output buffer is unsigned
}
Note this is a signed integer.
Code below is converting the sample to 16 bits.
char audio_buffer[samples * bytesPerInputSample];
int32_t *input_buffer;
input_buffer = (int32_t *)&audio_buffer;
uint16_t *output_buffer; // the output buffer, uint16_t required by file write
output_buffer = (uint16_t *)&audio_buffer;
for (int i = 0; i < samples; i++) {
int32_t val32 = input_buffer >> 8; // shift out the empty byte - this is a signed int, the shift will preserve the sign
int16_t val16 = (int16_t)val32; // convert 32 bit signed to 16 bit signed
output_buffer = (uint16_t)val16; // output buffer is unsigned
}
Re: ESP32 with INM441 I2S microphone.
Just having the same problem.
yes, right-shift by 8 gives the proper 24bit.
just leaving it as is, gives amplification by 256.
however, inspecting the data, i do see, that the low-byte is not always 00, but sometimes C0 , so some artifacts going on.
hmm?? that is strange.
Also one should note that the I2S interface cannot really work in "mono".
left and right lane are always transmitted.
i2s_channel_read() will also always read both lanes from the I2S modul.
"mono" would mean, place only one audio signal on the left or the right channel of the I2S device and leave the other one connected to GND = 0.
We would like it the other way, that mono mode results in reading only the one active mono channel, thus halfing the datarate to the correct value of a mono channel.
suggestion to improve !?
yes, right-shift by 8 gives the proper 24bit.
just leaving it as is, gives amplification by 256.
however, inspecting the data, i do see, that the low-byte is not always 00, but sometimes C0 , so some artifacts going on.
hmm?? that is strange.
Also one should note that the I2S interface cannot really work in "mono".
left and right lane are always transmitted.
i2s_channel_read() will also always read both lanes from the I2S modul.
"mono" would mean, place only one audio signal on the left or the right channel of the I2S device and leave the other one connected to GND = 0.
We would like it the other way, that mono mode results in reading only the one active mono channel, thus halfing the datarate to the correct value of a mono channel.
suggestion to improve !?
Re: ESP32 with INM441 I2S microphone.
Why do you say that? Shifting the 24 bit value doesn't change it. Agreed, the signal is quite loud, my code has the ability to attenuate the value if necessary (configurable):just leaving it as is, gives amplification by 256.
Code: Select all
// first, shift out the lower empty byte
int32_t val32 = input_buffer[i] >> 8; // shift out the empty byte - this is a signed int, the shift will preserve the sign
// we now need to reduce this to a 16 bit integer value, ensuring values are between -32,768 and 32,767
// but if we just reduce the high values we'll be clipping the sound, better to attenuate it (by experience)
// apply an attenuation factor if it sounds too high
val32 = val32 / ATTENUATION_FACTOR; // reduce the overall signal strength if requested
If the low order byte is unused, I don't see what it contains is unimportant. It could just be random data.however, inspecting the data, i do see, that the low-byte is not always 00, but sometimes C0 , so some artifacts going on.
Surely if configured as mono, it only samples from the configured microphone.We would like it the other way, that mono mode results in reading only the one active mono channel, thus halfing the datarate to the correct value of a mono channel.
Code: Select all
i2s_std_config_t std_cfg = {
... .slot_cfg = {
.data_bit_width = I2S_DATA_BIT_WIDTH_32BIT, // INMP441 provides 24 bits of data, we have to use 32 bit and discard a byte
.slot_mode = I2S_SLOT_MODE_MONO,
.slot_mask = I2S_STD_SLOT_LEFT, // L/R pin is connected to GND
etc
-
MicroController
- Posts: 2661
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: ESP32 with INM441 I2S microphone.
Because a left-aligned 24-bit value in a 32-bit integer is numerically 'too big' by a factor of 2^8. Right-shifting by 8 bits scales it back into the correct 24-bit range. (Depends on how you look at the values though. You could say they're 32-bit values without data in the lowest bits, or that they're 24-bit values left-shifted by 8.)Why do you say that?just leaving it as is, gives amplification by 256.
To get the 16-bit signed value you want, you can either do
Code: Select all
int32_t sample32 = *(const int32_t*)&audiodata;
int16_t sample16 = sample32 >> 16;
Code: Select all
const int16_t* const samples16 = (const int16_t*)&audiodata;
for(unsigned i = 0; i < samplecnt; ++i) {
int16_t sample16 = samples16[2*i + 1]; // ignore even indices, only consider the odd ones
...
}
Re: ESP32 with INM441 I2S microphone.
But it's not a 32 bit integer, yet. The original value is 24 bit, and the shift is just moving it into the correct position and making it a 32 bit value. It's not an arithmetic shift because the low order byte doesn't form part of the value.Because a left-aligned 24-bit value in a 32-bit integer is numerically 'too big' by a factor of 2^8.
Consider this: let's say the 24 bit value is 1, and we want to end up with this value as 32 bit integer also of 1. Shifting it >> 8 does this. Your mistake is viewing the low order byte as part of the sample value, which it isn't, so you're seeing the original value as 256.
-
MicroController
- Posts: 2661
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: ESP32 with INM441 I2S microphone.
It most definitely is. You may want to reconsider the equivalence between bit-shifting and multiplication/division.But it's not a 32 bit integer, yet.Because a left-aligned 24-bit value in a 32-bit integer is numerically 'too big' by a factor of 2^8.
(Btw, "arithmetic shift" is the term normally used for a sign-preserving right shift, as opposed to a "logical shift".)
More importantly, your original proposal
Code: Select all
int32_t val32 = input_buffer[i] >> 8; // shift out the empty byte - this is a signed int, the shift will preserve the sign
int16_t val16 = (int16_t)val32; // convert 32 bit signed to 16 bit signed
Re: ESP32 with INM441 I2S microphone.
We'll just have to agree to disagree about this.
In the actual code, I do check that the value will fit into a int16_t:
That's partly what the attenuation factor is for (note the equivalence between bit-shifting and multiplication/division). If overflow occurs a warning is logged so that the attenuation can be increased if it becomes excessive, but the occasional overflow is acceptable if caused by a transient noise spike.
In the actual code, I do check that the value will fit into a int16_t:
Code: Select all
// check for int16_t overflow
signal_overflow = signal_overflow || val32 < SHRT_MIN || val32 > SHRT_MAX;
signalMax = max(val32, signalMax);
signalMin = min(val32, signalMin);
-
MicroController
- Posts: 2661
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: ESP32 with INM441 I2S microphone.
https://docs.espressif.com/projects/esp ... ndard-modehowever, inspecting the data, i do see, that the low-byte is not always 00, but sometimes C0 , so some artifacts going on.
Check for "Phillips" vs. "MSB" format. The mic seems to use "Phillips" format, and if you read in "MSB" format the data will appear right-shifted by one bit.
Re: ESP32 with INM441 I2S microphone.
Code: Select all
int32_t val32 = input_buffer[i] >> 8; // shift out the empty byte - this is a signed int, the shift will preserve the sign
int16_t val16 = (int16_t)val32; // convert 32 bit signed to 16 bit signed
int16_t val16 = (int16_t)val32; // convert 32 bit signed to 16 bit signed...this will take the low-16bits of val32 to be put into val16!!
I am using Philips format, still observe 0xdb in the lowbyte in times. but yeah..just zero it out.Check for "Phillips" vs. "MSB" format. The mic seems to use "Phillips" format, and if you read in "MSB" format the data will appear right-shifted by one bit.
My other concern is that the volume of the mics data is extremely low. So need to amplify.
Who is online
Users browsing this forum: Baidu [Spider] and 12 guests