Extracting 24-bit Audio from INMP441: Very Low Amplitude and High Distortion Issue
- March 27, 2025
- 2 replies
- 3594 views
Hello gurus,
I am in desperate need of your help. I am trying to extract audio from an INMP441 microphone using a Nucleo STM32F4RE11 and store it as a WAV file on an SD card. According to the datasheet, the microphone outputs signed PCM 24-bit audio in MSB-first order, wrapped in a 32-bit frame.
To handle this, I have configured the I²S "Data and Frame Format" to "32 Bits Data on 32 Bits Frame", attempting to extract the 24-bit data from the 32-bit frame and convert it to Little Endian format. However, I am facing issues with the extracted audio:
-
While I can recognize my voice's timbre, the amplitude is extremely low, and the waveform appears very weak.
-
When I previously tested "16 Bits Data on 32 Bits Frame", my voice sounded unnaturally deep, almost like a male voice.
I suspect there may be an issue with my bit extraction or size allocation. Here's a brief summary of my setup:
-
I declared an int32_t variable to store the raw I²S data and used the following function to record audio:
HAL_I2S_Receive_DMA(&hi2s3, (int32_t *)data_i2s, sizeof(data_i2s)/4);However, I am concerned that this might be incorrect since the function prototype expects a uint16_t * pointer. Given that I’m handling int32_t data, I’m unsure of the correct way to manage this typecast.
-
For extracting the 24-bit data, I have performed bit-shifting and swap the bytes to store in Little Endian format, but I’m not sure that I’ve done it correctly because the extracted audio I got is so low.
I have attached screenshots and code snippets for better context. I would greatly appreciate any insights on how to debug this issue.
Thank you so much!
void write2wave_file(uint8_t *data, uint16_t data_size) {
uint32_t temp_number;
myprintf("Writing...\n");
static int first_time = 0;
if (first_time == 0) {
fres = f_write(&fil, (void *)wav_file_header, sizeof(wav_file_header), (UINT *)&temp_number);
if (fres != FR_OK) {
myprintf("Header write error: %d\n", fres);
f_close(&fil);
return;
}
first_time = 1;
}
int sample_read = data_size / sizeof(int32_t); // 32-bit container for 24-bit data
for (int i = 0; i < sample_read; i+=2) {
int32_t raw_data = ((int32_t *)data)[i] >> 8;
uint8_t swapped_data[3];
swapped_data[2] = (raw_data>>0) & 0xFF; // LSB
swapped_data[1] = (raw_data >> & 0xFF;
swapped_data[0] = (raw_data >> 16) & 0xFF;
int retry = 0;
while (retry < 3) {
fres = f_write(&fil,swapped_data, 3, (UINT *)&temp_number); // Write 3 bytes per sample
if (fres == FR_OK) break;
myprintf("Write error %d, retry %d...\n", fres, retry + 1);
HAL_Delay(10);
retry++;
}
if (fres != FR_OK) {
myprintf("Write failed after retries: %d\n", fres);
f_close(&fil);
return;
}
}
wav_file_size += (sample_read / 2) * 3;
myprintf("how much: %d\n", wav_file_size);
// Periodically flush to prevent corruption
static int write_count = 0;
write_count++;
if (write_count % 10 == 0) {
f_sync(&fil);
}
}
