Accessing I2S mic

Hi,I have been using nrf5340 audio DK Board to access the I2S .I am using SPH0645 mic with that i need to get mic data .I am getting mic data continuously but sure that I am not getting correct data.I have checked with clock SCK 1.024 MHz and LRCL of 16kHz but don't know where it's going wrong.Can you help me regarding this,I am attaching overlay and my main file .Please check and  provide me a solution of getting correct mic data.I am converting 32 bit of data to 16 bit in process block function.

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/drivers/i2s.h>
#include <zephyr/drivers/gpio.h>
#include <string.h>
#include <zephyr/drivers/uart.h>

#define I2S_RX_NODE DT_NODELABEL(i2s_rxtx)

#define SAMPLE_FREQUENCY 16000
#define SAMPLE_BIT_WIDTH 32
#define BYTES_PER_SAMPLE sizeof(int16_t)
#define NUMBER_OF_CHANNELS 1
#define SAMPLES_PER_BLOCK ((SAMPLE_FREQUENCY / 10) * NUMBER_OF_CHANNELS)
#define INITIAL_BLOCKS 2
#define TIMEOUT 1000

#define BLOCK_SIZE (BYTES_PER_SAMPLE * SAMPLES_PER_BLOCK)
#define BLOCK_COUNT (INITIAL_BLOCKS + 2)
K_MEM_SLAB_DEFINE_STATIC(mem_slab, BLOCK_SIZE, BLOCK_COUNT, 4);

const struct device *const i2s_dev_rx = DEVICE_DT_GET(I2S_RX_NODE);
struct i2s_config config;

static int16_t echo_block[SAMPLES_PER_BLOCK];
uint8_t loopCnt = 0;

static void process_block_data(void *mem_block, uint32_t number_of_samples)
{
	for (int i = 0; i < number_of_samples; ++i)
	{
		int16_t *sample = &((int16_t *)mem_block)[i];
		echo_block[i] = *sample;
	  }
	 
}

static bool configure_streams(const struct device *i2s_dev_rx, const struct i2s_config *config)
{
	int ret = i2s_configure(i2s_dev_rx, I2S_DIR_RX, config);
	if (ret == 0)
	{
		printk("Configure Stream Successful.\n");
		return true;
	}
	printk("Failed to configure streams: %d\n", ret);
	return false;
}

static bool trigger_command(const struct device *i2s_dev_rx, enum i2s_trigger_cmd cmd)
{
	int ret = i2s_trigger(i2s_dev_rx, I2S_DIR_RX, cmd);
	if (ret == 0)
	{
		printk("Trigger Command Successful.\n");
		return true;
	}
	printk("Failed to trigger command %d: %d\n", cmd, ret);
	return false;
}

static void i2sStreamInit(void){

	printk("I2S echo sample\n");

	if (!device_is_ready(i2s_dev_rx))
	{
		printk("%s is not ready\n", i2s_dev_rx->name);
		return 0;
	}

	config.word_size = SAMPLE_BIT_WIDTH;
	config.channels = NUMBER_OF_CHANNELS;
	config.format = I2S_FMT_DATA_FORMAT_I2S;
	config.options = I2S_OPT_BIT_CLK_MASTER | I2S_OPT_FRAME_CLK_MASTER;
	config.frame_clk_freq = SAMPLE_FREQUENCY;
	config.mem_slab = &mem_slab;
	config.block_size = BLOCK_SIZE;
	config.timeout = TIMEOUT;

	if (!configure_streams(i2s_dev_rx, &config))
	{
		return 0;
	}

	if (!trigger_command(i2s_dev_rx, I2S_TRIGGER_START))
	{
		return 0;
	}
}



int main(void)
{
	i2sStreamInit();
	printk("Streams started\n");

	while (1)
	{
		void *mem_block;
		uint32_t block_size;
		int ret;

		ret = i2s_read(i2s_dev_rx, &mem_block, &block_size);
		if (ret < 0)
		{
			printk("Failed to read data: %d\n", ret);
			break;
		}

		process_block_data(mem_block, SAMPLES_PER_BLOCK);
		k_mem_slab_free(&mem_slab, mem_block);

	}
	printk("Exiting main loop\n");
	return 0;
}

&pinctrl {
    i2s0_default: i2s0_default {
        group1 {
            psels = <NRF_PSEL(I2S_SCK_M, 0, 26)>,
                    <NRF_PSEL(I2S_LRCK_M, 0, 25)>,
                    <NRF_PSEL(I2S_SDIN, 0, 7)>,
                    <NRF_PSEL(I2S_MCK, 1, 0)>,
                    <NRF_PSEL(I2S_SDOUT, 0, 6)>;
        };
    };
    i2s0_sleep: i2s0_sleep {
        group1 {
            psels = <NRF_PSEL(I2S_SCK_M, 0, 26)>,
                    <NRF_PSEL(I2S_LRCK_M, 0, 25)>,
                    <NRF_PSEL(I2S_SDIN, 0, 7)>,
                    <NRF_PSEL(I2S_MCK, 1, 0)>,
                    <NRF_PSEL(I2S_SDOUT, 0, 6)>;
        };
    };
};

&clock {
    hfclkaudio-frequency = <11289600>;
};


i2s_rxtx: &i2s0 {
    status = "okay";
    pinctrl-0 = <&i2s0_default>;
    pinctrl-1 = <&i2s0_sleep>;
    clock-source = "ACLK";
    pinctrl-names = "default","sleep";
};


Regards

Kashyap

  • Hi Kashyap,

    Please check the that these requirements from the SPH0645 datasheet are met:

    The screenshot is from page 8.

    From the datasheet I found that having SCK/BCLK below 2.048 kHz is out of spec for the microphone.

    You can check the timings with a logic analyser, for example.

    Based on the datasheet for the SPH0645 and nRF5340 SoC, a possible configuration to use is marked in yellow here:

    The table is from the Configuration examples section of the I2S peripheral for the nRF5340.

    Best regards,

    Maria

  • To be mentioned that is not the updated datasheet .The datasheet you are referring is REV-B but updated one is REV-C.As per updated datasheet I am using sampling rate as 16000 and Ratio 64x and source frequency 12288000 but data is not  coming correctly .Does the ACLK clock implementation\configuration correct?

  • Kashyap23 said:
    To be mentioned that is not the updated datasheet

    Thank you for letting me know. I see that the frequency range is updated in the new revision to include 1024 kHz.

    Kashyap23 said:
    Does the ACLK clock implementation\configuration correct?

    The new values looks to be correct in your written sentence. Please share your updated .overlay so I can verify that the configuration is correct there as well.

    In your previous overlay, the clock node is missing status = "okay";

    Also, have you investigated the timings as mentioned before?

    Best regards,

    Maria

  • &pinctrl {
    i2s0_default: i2s0_default {
    group1 {
    psels = <NRF_PSEL(I2S_SCK_M, 0, 26)>,
    <NRF_PSEL(I2S_LRCK_M, 0, 25)>,
    <NRF_PSEL(I2S_SDIN, 0, 7)>,
    <NRF_PSEL(I2S_SDOUT, 0, 6)>;
    };
    };
    i2s0_sleep: i2s0_sleep {
    group1 {
    psels = <NRF_PSEL(I2S_SCK_M, 0, 26)>,
    <NRF_PSEL(I2S_LRCK_M, 0, 25)>,
    <NRF_PSEL(I2S_SDIN, 0, 7)>,
    <NRF_PSEL(I2S_SDOUT, 0, 6)>;
    };
    };
    };

    &clock {
    status = "okay";
    hfclkaudio-frequency = <12288000>;
    };


    i2s_rxtx: &i2s0 {
    status = "okay";
    pinctrl-0 = <&i2s0_default>;
    pinctrl-1 = <&i2s0_sleep>;
    clock-source = "ACLK";
    pinctrl-names = "default","sleep";
    };


    By using this I can get SCLK==1.024MHz and LRCK=16kHz.
    Is there relation b/w hfclkaudio-frequency = <12288000> and SCLK,LRCK .As if I am removing the  hfclkaudio-frequency  in overlay file,I able to get SCLK as 1.024MHz and LRCK =16kHz
  • Thank you for sharing the new overlay file. It looks correct.

    I suspect the missing piece is to configure the MCK in the source code. This is not possible with the Zephyr I2S API, but can be done by setting the CONFIG.MCKFREQ register. You can compute the value with the MCKFREQ equation (Figure 3.) from the Master Clock section of the I2S peripheral and for fMCK = 1.024 MHz and fsource = 12.288 MHz the MCKFREQ value is 343597056 or 0x147AE000 this value can also be found in row four in the table I sent previously.

    Please see this reply from my colleague on a previous case for further considerations when configuring MCK.

    If you don't want to set the register directly you can use the nrfx: I2S driver to configure MCK. The result from the MCKFREQ equation is used as the mck_setup here as well, see the configuration from the nRF5340 Audio application here for reference.

    Best regards,

    Maria

Related