I2S microphone (RX)

BuddyCasino
Posts: 258
Joined: Sun Jun 19, 2016 12:00 am

Re: I2S microphone (RX)

Postby BuddyCasino » Thu May 25, 2017 4:57 pm

I like things small and digital, so its not for me. I can see the appeal though - good luck!

User avatar
rudi ;-)
Posts: 1293
Joined: Fri Nov 13, 2015 3:25 pm

Re: I2S microphone (RX)

Postby rudi ;-) » Thu May 25, 2017 5:53 pm

BuddyCasino wrote:I like things small and digital, so its not for me. I can see the appeal though - good luck!
you are right - perhabs i will try - - hope for the digi tiny ICS boards asap :)))
best wishes
rudi ;-)
-------------------------------------
love it, change it or leave it.
-------------------------------------
問候飛出去的朋友遍全球魯迪

BuddyCasino
Posts: 258
Joined: Sun Jun 19, 2016 12:00 am

Re: I2S microphone (RX)

Postby BuddyCasino » Thu May 25, 2017 6:28 pm

hope for the digi tiny ICS boards asap
Already packaged, will send them out tomorrow!

User avatar
rudi ;-)
Posts: 1293
Joined: Fri Nov 13, 2015 3:25 pm

Re: I2S microphone (RX)

Postby rudi ;-) » Thu May 25, 2017 6:59 pm

BuddyCasino wrote:
hope for the digi tiny ICS boards asap
Already packaged, will send them out tomorrow!
:D
-------------------------------------
love it, change it or leave it.
-------------------------------------
問候飛出去的朋友遍全球魯迪

meetri
Posts: 4
Joined: Tue May 30, 2017 8:10 am

Re: I2S microphone (RX)

Postby meetri » Tue May 30, 2017 8:26 am

I finally made some progress after updating to 2.1 of the SDK

I was able to use core elements of the code from BuddyCasino successfully to grab audio data from my i2s microphone ( SPH0645 )
I was able to successfully record audio, however the audio is quiet and easily peaks out.

I noticed when working on calculating the voltage of the audio signal that the min max of the signal is very high.

For example, in a quiet room the min reading ( converted to 16bit ) is: 63830, and the max is: 63865.
I'm expecting these numbers to be much much lower. Is there something i'm missing here?

i'm using the value for 'val' to determine the min / max thresholds...

Code: Select all

#define NUM_CHANNELS 2
#define BIT_SIZE  I2S_BITS_PER_SAMPLE_32BIT
...
for (int i = 0; i < samples_read; i ++){
   uint16_t val = (rbuf[3] << 8 ) + rbuf[2];
   ...
   rbuf += NUM_CHANNELS * (BIT_SIZE / 8);
is it just me with this issue? Any suggestions for how to solve this? Any help would be appreciated.

User avatar
andriy
Posts: 11
Joined: Mon Dec 07, 2015 9:14 pm

Re: I2S microphone (RX)

Postby andriy » Tue May 30, 2017 6:03 pm

BuddyCasino wrote:Here is a complete example, I verified it works:

Code: Select all

/*
 * app_main.c
 *
 *  Created on: 30.03.2017
 *      Author: michaelboeckling
 */

#include <stdlib.h>
#include <stddef.h>
#include <inttypes.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <sys/time.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_log.h"
#include "driver/i2s.h"

#define TAG "main"

static void init_i2s()
{
	const int sample_rate = 44100;

	/* TX: I2S_NUM_0 */
    i2s_config_t i2s_config_tx = {
	.mode = I2S_MODE_MASTER | I2S_MODE_TX,
	.sample_rate = sample_rate,
	.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
	.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,   // 2-channels
	.communication_format = I2S_COMM_FORMAT_I2S_MSB,
	.dma_buf_count = 32,                            // number of buffers, 128 max.
	.dma_buf_len = 32 * 2,                          // size of each buffer
	.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1        // Interrupt level 1
    };

    i2s_pin_config_t pin_config_tx = {
			.bck_io_num = GPIO_NUM_26,
			.ws_io_num = GPIO_NUM_25,
			.data_out_num = GPIO_NUM_22,
			.data_in_num = GPIO_NUM_23
	};
    i2s_driver_install(I2S_NUM_0, &i2s_config_tx, 0, NULL);
    i2s_set_pin(I2S_NUM_0, &pin_config_tx);


    /* RX: I2S_NUM_1 */
    i2s_config_t i2s_config_rx = {
	.mode = I2S_MODE_MASTER | I2S_MODE_RX, // Only TX
	.sample_rate = sample_rate,
	.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,    // Only 8-bit DAC support
	.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,   // 2-channels
	.communication_format = I2S_COMM_FORMAT_I2S_MSB,
	.dma_buf_count = 32,                            // number of buffers, 128 max.
	.dma_buf_len = 32 * 2,                          // size of each buffer
	.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1        // Interrupt level 1
	};

	i2s_pin_config_t pin_config_rx = {
		.bck_io_num = GPIO_NUM_17,
		.ws_io_num = GPIO_NUM_18,
		.data_out_num = I2S_PIN_NO_CHANGE,
		.data_in_num = GPIO_NUM_5
	};

	i2s_driver_install(I2S_NUM_1, &i2s_config_rx, 0, NULL);
	i2s_set_pin(I2S_NUM_1, &pin_config_rx);

}


void task_megaphone(void *pvParams)
{
	uint16_t buf_len = 1024;
	char *buf = calloc(buf_len, sizeof(char));

	struct timeval tv = {0};
	struct timezone *tz = {0};
	gettimeofday(&tv, &tz);
	uint64_t micros = tv.tv_usec + tv.tv_sec * 1000000;
	uint64_t micros_prev = micros;
	uint64_t delta = 0;

	init_i2s();

	int cnt = 0;
	int bytes_written = 0;

	while(1)
	{
		char *buf_ptr_read = buf;
		char *buf_ptr_write = buf;

		// read whole block of samples
		int bytes_read = 0;
		while(bytes_read == 0) {
			bytes_read = i2s_read_bytes(I2S_NUM_1, buf, buf_len, 0);
		}

		uint32_t samples_read = bytes_read / 2 / (I2S_BITS_PER_SAMPLE_32BIT / 8);

		//  convert 2x 32 bit stereo -> 1 x 16 bit mono
		for(int i = 0; i < samples_read; i++) {

			// const char samp32[4] = {ptr_l[0], ptr_l[1], ptr_r[0], ptr_r[1]};

			// left
			buf_ptr_write[0] = buf_ptr_read[2]; // mid
			buf_ptr_write[1] = buf_ptr_read[3]; // high

			// right
			buf_ptr_write[2] = buf_ptr_write[0]; // mid
			buf_ptr_write[3] = buf_ptr_write[1]; // high


			buf_ptr_write += 2 * (I2S_BITS_PER_SAMPLE_16BIT / 8);
			buf_ptr_read += 2 * (I2S_BITS_PER_SAMPLE_32BIT / 8);
		}

		// local echo
		bytes_written = samples_read * 2 * (I2S_BITS_PER_SAMPLE_16BIT / 8);
		i2s_write_bytes(I2S_NUM_0, buf, bytes_written, portMAX_DELAY);

		cnt += samples_read;

		if(cnt >= 44100) {
			gettimeofday(&tv, &tz);
			micros = tv.tv_usec + tv.tv_sec * 1000000;
			delta = micros - micros_prev;
			micros_prev = micros;
			printf("%d samples in %" PRIu64 " usecs\n", cnt, delta);

			cnt = 0;
		}
	}
}

/**
 * entry point
 */
void app_main()
{
    printf("starting app_main()\n");
    xTaskCreatePinnedToCore(&task_megaphone, "task_megaphone", 16384, NULL, 20, NULL, 0);
}

Wow.... super thanks @BuddyCasino
I verify it works flawlessly!

I can also make it work if I use "bits_per_sample : I2S_BITS_PER_SAMPLE_32BIT" as I2S TX config, by changing the code a bit:

Code: Select all

        int bytes_read = 0;
        while(bytes_read == 0) {
            bytes_read = i2s_read_bytes(I2S_NUM_1, buf, sizeof(buf), portMAX_DELAY);
        }

        uint32_t samples_read = bytes_read / (I2S_BITS_PER_SAMPLE_32BIT / 8);

        for (int i = 0; i < samples_read; i++)
        {
            buf_ptr_write[0] = buf_ptr_read[2]; // mid
            buf_ptr_write[1] = buf_ptr_read[3]; // high        
        }

        int bytes_written = samples_read * (I2S_BITS_PER_SAMPLE_32BIT / 8);

        i2s_write_bytes(I2S_NUM_0, (const char*)buf, bytes_written, portMAX_DELAY);

meetri
Posts: 4
Joined: Tue May 30, 2017 8:10 am

Re: I2S microphone (RX)

Postby meetri » Wed May 31, 2017 12:47 am

I was able to confirm the code presented here works.
I have one problem though, when attempting to calculate the voltage of the audio signal, the min / max values coming in from i2s is really high. For example, in a silent room i'm getting a min max threshold of about min:62300, max: 62345

I am able to record audio. It's comes in quiet. But it maxes out really easy. All I have to do is whistle in the mic and the sound starts to break apart. Is this something you think may be specific to my i2s mic ( SPH0645 ). Any insight would be appreciated.

thank you,

BuddyCasino
Posts: 258
Joined: Sun Jun 19, 2016 12:00 am

Re: I2S microphone (RX)

Postby BuddyCasino » Wed May 31, 2017 6:28 am

Yeah its confusing. I'm not even sure about about the in-memory data representation. The I2S protocol is MSB first (big-endian) two's complement (signed) integer. I think the DMA controller / I2S peripheral take care of the MSB/LSB issue, and that the words are layed out big-endian in ESP32 memory, but its all guesswork and experimentation on my side.

So, make sure your bits are what you expect them to be. I'm very interested in your findings!

meetri
Posts: 4
Joined: Tue May 30, 2017 8:10 am

Re: I2S microphone (RX)

Postby meetri » Sun Jun 04, 2017 7:58 pm

from my tests, i have found that using "I2S_COMM_FORMAT_RAW_I2S" gave better precision and quality than using "I2S_COMM_FORMAT_I2S_MSB" for the i2s_config_t.communication_format.

To give an example: with "I2S_COMM_FORMAT_RAW_I2S" the min max values in a semi quiet room are:
min:~62130 to max:~62190

However with "I2S_COMM_FORMAT_I2S_MSB", the results are:
min:~63810 to max:~63740

65535-63740 = 1795 ( precision depth )
65535 - 62190 = 3345 ( precision depth )

almost twice as much room using RAW_I2S.

I tested the audio quality with the two modes and as expected RAW_I2S generates better audio quality.

To handle the peaking out I just replace all values that are less than 30000 with the last accepted sample that came in ( it seems to work, at least for my purpose but still... if we can do better i'd like to try )

I created a github repo with the code I used for conducting my tests: https://github.com/meetri/esp32-i2s-audio-test

I have a few questions.
1. i'd like to try this with a different i2s mems microhone. ( any suggestions, i'm using adafruit's SPH0645 )

2. any idea's why setting the communication_format to I2S_COMM_FORMAT_RAW_I2S would have this benefit and is there a way to tweak this further ?


---debug notes---
This is just notes from my testing. It may or may not mean anything. Just posting my observations.
my github code grabs the 4 bytes from the sample, and keeps track of the min and max and peak 2 peak values for each byte per sample page.

In general this is what i've found
byte X | P2P : MIN : MAX

byte 0 | 0 : 0 : 0
----------
this never changes no matter the configuration settings...

byte 1 | 128 : 0 : 128
----------
this also never changes ....

byte 2 | XX : YY : ZZ
----------
this is the only byte that has active variability.
However, blowing very slightly on this mic causes this byte to max out. ( i feel it maxes out much sooner than it should like soon as P2P gets to around 120 it just jumps to 255... )

byte 3 | 0 : 242 : 243
----------
This stays pretty much constant. byte 2 maxes out, the P2P begins climbing from a rested MIN:MAX of 242 (...
blowing slightly on the mic raises the peak to peak to to about 16 at max then it jumps to 255.

These are my observations. Looking at the data using my saleae logic analyzer, doesn't show any clear peaking.

Note. I am a super beginner in this world. I hope that these notes point to something I can do to get better audio quality from this.

BuddyCasino
Posts: 258
Joined: Sun Jun 19, 2016 12:00 am

Re: I2S microphone (RX)

Postby BuddyCasino » Mon Jun 05, 2017 5:07 pm

1. i'd like to try this with a different i2s mems microhone. ( any suggestions, i'm using adafruit's SPH0645 )
I've got some ICS-43434 breakout boards that I bought from here:
https://www.tindie.com/products/onehors ... icrophone/
It says ICS-43432 only on the store page but you can say that you want the ICS-43434 variety instead. I'll test them as soon as I can find the time.
2. any idea's why setting the communication_format to I2S_COMM_FORMAT_RAW_I2S would have this benefit and is there a way to tweak this further ?
Where do you get I2S_COMM_FORMAT_RAW_I2S from? I have the latest IDF and all I have are these:

Code: Select all

typedef enum {
    I2S_COMM_FORMAT_I2S         = 0x01, /*!< I2S communication format I2S*/
    I2S_COMM_FORMAT_I2S_MSB     = 0x02, /*!< I2S format MSB*/
    I2S_COMM_FORMAT_I2S_LSB     = 0x04, /*!< I2S format LSB*/
    I2S_COMM_FORMAT_PCM         = 0x08, /*!< I2S communication format PCM*/
    I2S_COMM_FORMAT_PCM_SHORT   = 0x10, /*!< PCM Short*/
    I2S_COMM_FORMAT_PCM_LONG    = 0x20, /*!< PCM Long*/
} i2s_comm_format_t;

Who is online

Users browsing this forum: Roudoudoux and 10 guests