I2S microphone (RX)

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

Re: I2S microphone (RX)

Postby BuddyCasino » Sun May 14, 2017 1:54 pm

in this way you did - you use successful I2S0 ( I2S_NUM_0) for output and the I2S1 ( I2S_NUM_1) for input, right?
Yes.
so this config must be valid for run for the ICS.I2S as Left Channel example?
and for Left and Right ( 2 Mics ) example too?

perhabs you can look small time on this picture, please:
The ICS-43434 works similar to the SPH0645LM4H, so this looks good to me. You will have to clear the bits 25-32 and 58-64 because they're left floating instead of zero-padded, but I think thats it.

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

Re: I2S microphone (RX)

Postby rudi ;-) » Sun May 14, 2017 2:09 pm

thanks.
this is the way i like and why use this forum loved ( user2user ) .
would sometime be good if espressif would answere too, where are the guys ? :mrgreen:
but i know now over 3 years using ESP , we must drive the theme by self :mrgreen:
and espressif works on results :lol:
( i hear you laughing John :mrgreen: )

best wishes
rudi ;-)
-------------------------------------
love it, change it or leave it.
-------------------------------------
問候飛出去的朋友遍全球魯迪

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

Re: I2S microphone (RX)

Postby BuddyCasino » Sun May 14, 2017 3:06 pm

Correction: bits 25-32 are tristated too on the SPH0645LM4H, according to the timing diagram on page 7.

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

Re: I2S microphone (RX)

Postby andriy » Thu May 18, 2017 6:25 pm

As I struggled with this myself, this thread helped me getting started, and finally made it to capture the voice using SPH0645LM4H and playback to confirm. Thanks guys!

So, for future reference, here's the complete code I use combining all code posted earlier:

Code: Select all

	i2s_config_t i2s_config_rx = {
		mode: (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
		sample_rate: 44100,
		bits_per_sample: I2S_BITS_PER_SAMPLE_32BIT,
		channel_format: I2S_CHANNEL_FMT_RIGHT_LEFT,
		communication_format: (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
		intr_alloc_flags: ESP_INTR_FLAG_LEVEL1,
		dma_buf_count: 14,
		dma_buf_len: 64
	};

	i2s_config_t i2s_config_tx = {
		mode: (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
		sample_rate: 44100,
		bits_per_sample: I2S_BITS_PER_SAMPLE_32BIT,
		channel_format: I2S_CHANNEL_FMT_RIGHT_LEFT,
		communication_format: (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
		intr_alloc_flags: ESP_INTR_FLAG_LEVEL1,
		dma_buf_count: 32,
		dma_buf_len: 64
	};

        i2s_pin_config_t pin_config = {
            .bck_io_num = 21,
            .ws_io_num = 26,
            .data_out_num = 22,//I2S_PIN_NO_CHANGE
            .data_in_num = 23
        };

	//Somehow it's needed. If not, noise!
 	pinMode(23, INPUT);

	//for recording
	i2s_driver_install(I2S_NUM_1, &i2s_config_rx, 0, NULL);
    	i2s_set_pin(I2S_NUM_1, &pin_config);

	//for playback
	i2s_driver_install(I2S_NUM_0, &i2s_config_tx, 0, NULL);
    	i2s_set_pin(I2S_NUM_0, &pin_config);

	uint32_t cnt = 0;
        uint32_t buffer;
   	uint32_t buffer_out = 0;
   	while(1)
   	{
		cnt++;
		buffer = 0;
		int bytes_popped = i2s_pop_sample(I2S_NUM_1, (char*)&buffer, portMAX_DELAY);
		
		buffer_out = buffer << 5;

		if (buffer_out == 0) {
			//For debugging, if out is zero
			Serial.printf("%d -> %x\n", cnt, (int)buffer_out);
			delay(50);
		}
		else {
			//Just playback for now
			i2s_push_sample(I2S_NUM_0, (char*)&buffer_out, portMAX_DELAY);
		}
   	}

ppisljar
Posts: 19
Joined: Wed Feb 22, 2017 4:36 pm

Re: I2S microphone (RX)

Postby ppisljar » Thu May 18, 2017 7:04 pm

thanks a lot @andriy .... so it seems i am getting some feedback now, but its still going between periods with data and periods without data ... using serial plotter i can see this:
mic.png
mic.png (24.46 KiB) Viewed 22650 times
any idea what could be causing that ?

my complete code:

Code: Select all

#include <WiFi.h>
#include "driver/i2s.h"

void i2s_config() {
  // http://esp-idf.readthedocs.io/en/latest/api/peripherals/i2s.html
  // input
  i2s_config_t i2s_in_config = {
    mode: (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
    sample_rate: 44100,
    bits_per_sample: (i2s_bits_per_sample_t)32,
    channel_format: I2S_CHANNEL_FMT_RIGHT_LEFT,
    communication_format: (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
    intr_alloc_flags: ESP_INTR_FLAG_LEVEL1,
    dma_buf_count: 14,
    dma_buf_len: 64
  };
  i2s_pin_config_t i2s_in_pin_config = {
    bck_io_num: 16,
    ws_io_num: 4,
    data_out_num: -1, //Not used
    data_in_num: 17
  };

	pinMode(17, INPUT);
	pinMode(16, OUTPUT);
	pinMode(4, OUTPUT);

  i2s_driver_install((i2s_port_t)0, &i2s_in_config, 0, NULL);
  i2s_set_pin((i2s_port_t)0, &i2s_in_pin_config);
}

void read_i2s() {
  uint32_t sample_val[2] = {0, 0};
  uint8_t bytes_read = i2s_pop_sample((i2s_port_t)0, (char *)sample_val, portMAX_DELAY);
  Serial.println(sample_val[0] << 5);
}

void setup()
{
    Serial.begin(115200);
    delay(4000);

    i2s_config();
}

void loop()
{
  read_i2s();
}


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

Re: I2S microphone (RX)

Postby BuddyCasino » Thu May 18, 2017 7:17 pm

Actually I don't think the bit shift is correct. I have since switched to a more efficient version that does block transfers, and avoids endianness issues by working only on bytes. The signal will be more silent, but I think that is because the mic is quite sensitive and now reflects its fully dynamic range (truncated from 18 to 16 bit).

Here is an example that converts from 32 bit single-channel stereo mic input to dual-channel 16 bit output. You can leave out the conversion if both I2S interfaces have identical parameters.

Code: Select all

	int cnt = 0;
	uint64_t buffer = 0;
	char buf[4096];

	while(1)
	{
		cnt++;
		buffer = 0;

		int bytes_read = i2s_read_bytes(I2S_NUM_1, buf, sizeof(buf), 0);
		int samples_read = bytes_read / 2 / (I2S_BITS_PER_SAMPLE_32BIT / 8);

		char *buf_ptr_read = buf[0];
		char *buf_ptr_write = buf[0];
		const char samp64[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

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

		int readable_bytes = samples_read * (I2S_BITS_PER_SAMPLE_16BIT / 8);

		// 2 * mono
		i2s_write_bytes(I2S_NUM_0, &buf, readable_bytes, 0);
		i2s_write_bytes(I2S_NUM_0, &buf, readable_bytes, 0);
	}

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

Re: I2S microphone (RX)

Postby andriy » Fri May 19, 2017 12:11 am

BuddyCasino wrote:

Code: Select all

	int cnt = 0;
	uint64_t buffer = 0;
	char buf[4096];

	while(1)
	{
		cnt++;
		buffer = 0;

		int bytes_read = i2s_read_bytes(I2S_NUM_1, buf, sizeof(buf), 0);
		int samples_read = bytes_read / 2 / (I2S_BITS_PER_SAMPLE_32BIT / 8);

		char *buf_ptr_read = buf[0];
		char *buf_ptr_write = buf[0];
		const char samp64[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

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

		int readable_bytes = samples_read * (I2S_BITS_PER_SAMPLE_16BIT / 8);

		// 2 * mono
		i2s_write_bytes(I2S_NUM_0, &buf, readable_bytes, 0);
		i2s_write_bytes(I2S_NUM_0, &buf, readable_bytes, 0);
	}

Super thanks for your update. But is that the right code @BuddyCasino ?

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

Re: I2S microphone (RX)

Postby BuddyCasino » Thu May 25, 2017 1:44 pm

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);
}


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

Re: I2S microphone (RX)

Postby rudi ;-) » Thu May 25, 2017 1:51 pm

:)
-------------------------------------
love it, change it or leave it.
-------------------------------------
問候飛出去的朋友遍全球魯迪

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

Re: I2S microphone (RX)

Postby rudi ;-) » Thu May 25, 2017 3:21 pm

@buddy
what you think
can we take for a short test UDA1380 too ?
it has Tx and Rx and I²C for Vol and others.

Sheet SRC
pinHeader.png
pinHeader.png (262.92 KiB) Viewed 22520 times
best wishes
rudi ;-)
Last edited by rudi ;-) on Thu May 25, 2017 7:00 pm, edited 1 time in total.
-------------------------------------
love it, change it or leave it.
-------------------------------------
問候飛出去的朋友遍全球魯迪

Who is online

Users browsing this forum: HighVoltage and 102 guests