This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Issues interfacing I2S MP34DT05 with nRF52840

Hello,

I am currently interfacing MP34DT05 with nRF52840 using I2S protocol. I have tried using nrfx I2S drivers but it gives me initialization error. I have used the sample code given as the solution in the following link as reference, but cant make it work for my DK.

  https://devzone.nordicsemi.com/f/nordic-q-a/63708/i2s-loopback-example-missing-in-installation-folder

Below is my main.c file for nRF52840. I have only defined 3 pins because i just want to read the data from sensor.

#include <zephyr.h>
#include <string.h>

#include "nrfx_i2s.h"

//#error Remember to define these pins before you run! // This assume you only have these 3 pins for I2S.
#define I2S_WS_PIN 20
#define I2S_SD_PIN 21
#define I2S_SCK_PIN 22

#define I2S_DATA_BLOCK_WORDS 512 //How many numbers do we want. time reorded = DATA_BLOCK_WORDS / freq

static uint32_t m_buffer_rx32u[I2S_DATA_BLOCK_WORDS];
static int32_t tmp[I2S_DATA_BLOCK_WORDS];
static nrfx_i2s_buffers_t initial_buffers;
static bool data_ready_flag = false;

ISR_DIRECT_DECLARE(i2s_isr_handler)
{
	data_ready_flag = false;
	nrfx_i2s_irq_handler();
	ISR_DIRECT_PM(); /* PM done after servicing interrupt for best latency
			  */
	return 1;		 /* We should check if scheduling decision should be made */
}

static void data_handler(nrfx_i2s_buffers_t const *p_released, uint32_t status)
{
	if (NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED == status)
	{
		nrfx_err_t err = nrfx_i2s_next_buffers_set(&initial_buffers);
		if (err != NRFX_SUCCESS)
		{
			printk("Error!, continuing running as if nothing happened, but you should probably investigate.\n");
		}
	}
	if (p_released)
	{
		if (p_released->p_rx_buffer != NULL)
		{
			data_ready_flag = true; //This is used in print_sound()
		}
	}
}

void print_sound()
{
	while (!data_ready_flag)
	{
		k_sleep(K_MSEC(1));
		//Wait for data. Since we do not want I2S_DATA_BLOCK_WORDS amount of prints inside the interrupt.
	}
	nrfx_i2s_stop();
	data_ready_flag = false;


	int64_t sum = 0;
	int64_t words = I2S_DATA_BLOCK_WORDS;

	for (int i = 0; i < I2S_DATA_BLOCK_WORDS; i++)
	{
		memcpy(tmp + i, m_buffer_rx32u + i, sizeof(uint32_t));
		tmp[i] >>= 8;
		sum += tmp[i];
	}

	int64_t mean = sum / words;
	for (int i = 0; i < I2S_DATA_BLOCK_WORDS; i++)
	{
		tmp[i] -= mean;
		printk("%d, ", tmp[i]);
		k_sleep(K_MSEC(16));
	}
	printk("\n\n");
	/**  End of formatted data print*/
}

nrfx_err_t get_sound_init()
{
	IRQ_DIRECT_CONNECT(I2S_IRQn, 0, i2s_isr_handler, 0);
	memset(&m_buffer_rx32u, 0x00, sizeof(m_buffer_rx32u));
	initial_buffers.p_rx_buffer = m_buffer_rx32u;

	//YOu should probably change this config to fit your I2S microphone and audio preferences.
	nrfx_i2s_config_t config =
		NRFX_I2S_DEFAULT_CONFIG(I2S_SCK_PIN, I2S_WS_PIN,
								NRFX_I2S_PIN_NOT_USED,
								NRFX_I2S_PIN_NOT_USED, I2S_SD_PIN);

	config.mode = NRF_I2S_MODE_MASTER;			//Microphone requirement
	config.ratio = NRF_I2S_RATIO_64X;			//Microphone requirement
	config.sample_width = NRF_I2S_SWIDTH_24BIT; //Microphone requirement
	config.mck_setup = NRF_I2S_MCK_32MDIV31;	//Preference     freq = (MCKfreq/ratio) =16.129 KHz.
	config.channels = NRF_I2S_CHANNELS_LEFT;	//Preference

	nrfx_err_t err_code = nrfx_i2s_init(&config, data_handler);
	if (err_code != NRFX_SUCCESS)
	{
		printk("I2S init error\n");
		return err_code;
	}
	err_code = nrfx_i2s_start(&initial_buffers, I2S_DATA_BLOCK_WORDS, 0); //start recording
	if (err_code != NRFX_SUCCESS)
	{
		printk("I2S start error\n");
		return err_code;
	}
	//nrfx_i2s_stop() //stop recording

	k_sleep(K_SECONDS(2));
	return err_code;
}

void main()
{
	nrfx_err_t err;
	err = get_sound_init();
	if (err != NRFX_SUCCESS)
	{
		return;
	}
	while (1)
	{
		k_sleep(K_SECONDS(5));
		print_sound();
	}
}

Here is my project.conf file.

#I2S
CONFIG_NRFX_I2S=y
CONFIG_SPM_NRF_I2S0_NS=y

#LOG
CONFIG_LOG=y
CONFIG_LOG_PRINTK=y
CONFIG_LOG_BACKEND_SHOW_COLOR=n

I have also enabled I2S to be used in the non-secure area by following this post devzone.nordicsemi.com/.../adafruit-i2s-mems-microphone-breakout-with-the-nrf9160-dk

Can anyone suggest what else i have to do for initializing and reading data via I2S on nRF52840.

Parents
No Data
Reply
  • Okay. I got that issue resolved. I am interfacing a PDM based MP34DT05 sensor using I2S driver. So its output will be PDM sample output.

    In the following github sample project https://github.com/siguhe/NCS_I2S_nrfx_driver_example

    in printSound function there is specific code related to MEMS sensor.

    What does the following code snippet does. Is it used convert PDM to PCM samples.

    	s64_t sum = 0;
    	s64_t words = I2S_DATA_BLOCK_WORDS;
    
    	for (int i = 0; i < I2S_DATA_BLOCK_WORDS; i++)
    	{
    		memcpy(tmp + i, m_buffer_rx32u + i, sizeof(u32_t));
    		tmp[i] >>= 8;
    		sum += tmp[i];
    	}
    
    	s64_t mean = sum / words;
    	for (int i = 0; i < I2S_DATA_BLOCK_WORDS; i++)
    	{
    		tmp[i] -= mean;
    		printk("%d, ", tmp[i]);
    		k_sleep(K_MSEC(16));
    	}
    	printk("\n\n");

    Because PDM output data needs decimation + low pass filtering to convert it into PCM. While decimation part is already done by I2S driver as my audio sampling freq is 16Khz, while clock to I2S is 1MHz. 

    So is that code used to convert PDM to PCM ? Or do you have any code refference to convert the PDM output to PCM output because the I2S driver output is already a decimated PDM output.

Children
Related