PDM data to speaker

Hi,I am working with pdm mic to read data .I can able to get the audio data using dmic_read api in pcm format.I got clock of 1280000 and sampling rate of 16000 of each 16 bit sample.Now I want to play that data in tas2562 speaker amplifier.I configured pins for i2s tx i.e,clock,fclk,data out pin and I got clock frequency of 507936 of sampling rate 15873.And I got following output.I am making buffer slab free for every loop.


00> [00:00:00.001,215] <inf> dmic_sample: DMIC sample
00> [00:00:00.001,229] <inf> dmic_nrfx_pdm: PDM clock frequency: 1280000, actual PCM rate: 16000
00> [00:00:00.001,268] <inf> i2s_nrfx: I2S MCK frequency: 507936, actual PCM rate: 15873
00> Configure Stream Successful.
00> Trigger Command Successful.
00> [00:00:10.911,696] <err> dmic_nrfx_pdm: No room in RX queue
00> [00:00:11.012,512] <err> i2s_nrfx: Next buffers not supplied on time
00> [00:00:11.952,097] <err> dmic_sample: read failed: -11

Parents
  • Error in line 42: Source code not found.

    Looks to me like you tried to start the I2S output before you have enough data from the DMIC in order to be able to feed it. Order of operation matters here a lot.

  • #include <zephyr/kernel.h>
    #include <zephyr/audio/dmic.h>
    #include <zephyr/drivers/i2s.h>
    #include <zephyr/drivers/i2c.h>
    #include <zephyr/logging/log.h>
    #include "tas.h"
    
    #define MAX_SAMPLE_RATE 16000
    #define SAMPLE_BIT_WIDTH 16
    #define BYTES_PER_SAMPLE sizeof(int16_t)
    #define READ_TIMEOUT 1000
    #define SAMPLES_PER_BLOCK 160 
    #define NUMBER_OF_CHANNELS 1
    #define I2S_TX_NODE DT_NODELABEL(i2s_tx)
    #define I2C1_NODE DT_NODELABEL(tas2563)
    
    #define BLOCK_SIZE (BYTES_PER_SAMPLE * SAMPLES_PER_BLOCK)
    #define MAX_BLOCK_SIZE BLOCK_SIZE
    #define BLOCK_COUNT 8
    
    LOG_MODULE_REGISTER(dmic_sample);
    K_MEM_SLAB_DEFINE_STATIC(mem_slab, MAX_BLOCK_SIZE, BLOCK_COUNT, 4);
    static const struct i2c_dt_spec dev_i2c = I2C_DT_SPEC_GET(I2C1_NODE);
    
    static bool configure_streams(const struct device *i2s_dev_tx, const struct i2s_config *config)
    {
    	int ret = i2s_configure(i2s_dev_tx, I2S_DIR_TX, config);
    	if (ret == 0)
    	{
    		printk("Configure Stream Successful.\n");
    		return true;
    	}
    	printk("Failed to configure streams: %d\n", ret);
    	return false;
    }
    static bool prepare_transfer(const struct device *i2s_dev_tx)
    {
    	int ret;
    
    	for (int i = 0; i < 2; ++i)
    	{
    		void *mem_block;
    
    		ret = k_mem_slab_alloc(&mem_slab, &mem_block, K_NO_WAIT);
    		if (ret < 0)
    		{
    			printk("Failed to allocate TX block %d: %d\n", i, ret);
    			return false;
    		}
    		memset(mem_block, 0, BLOCK_SIZE);
    
    		ret = i2s_write(i2s_dev_tx, mem_block, BLOCK_SIZE);
    		if (ret < 0)
    		{
    			printk("Failed to write block %d: %d\n", i, ret);
    			return false;
    		}
    	}
    
    	return true;
    }
    static bool trigger_command(const struct device *i2s_dev_tx, enum i2s_trigger_cmd cmd)
    {
    	int ret = i2s_trigger(i2s_dev_tx, I2S_DIR_TX, cmd);
    	if (ret == 0)
    	{
    		printk("Trigger Command Successful.\n");
    		return true;
    	}
    	printk("Failed to trigger command %d: %d\n", cmd, ret);
    	return false;
    }
    int main(void)
    {
    	const struct device *const dmic_dev = DEVICE_DT_GET(DT_NODELABEL(dmic_dev));
    	const struct device *const i2s_dev_tx = DEVICE_DT_GET(I2S_TX_NODE);
    	struct i2s_config config;
    	int ret;
    
    	LOG_INF("DMIC sample");
    
    	if (!device_is_ready(dmic_dev))
    	{
    		LOG_ERR("%s is not ready", dmic_dev->name);
    		return 0;
    	}
    
    	if (!device_is_ready(i2s_dev_tx))
    	{
    		printk("%s is not ready\n", i2s_dev_tx->name);
    		return 0;
    	}
    
    
    	struct pcm_stream_cfg stream = {
    		.pcm_width = SAMPLE_BIT_WIDTH,
    		.mem_slab = &mem_slab,
    	};
    	struct dmic_cfg cfg = {
    		.io = {
    			.min_pdm_clk_freq = 1000000,
    			.max_pdm_clk_freq = 3500000,
    			.min_pdm_clk_dc = 40,
    			.max_pdm_clk_dc = 60,
    		},
    		.streams = &stream,
    		.channel = {
    			.req_num_streams = 1,
    		},
    	};
    
    	cfg.channel.req_num_chan = 1;
    	cfg.channel.req_chan_map_lo =dmic_build_channel_map(0, 0, PDM_CHAN_LEFT);
    	cfg.streams[0].pcm_rate = MAX_SAMPLE_RATE;
    	cfg.streams[0].block_size = BLOCK_SIZE;
    
    	ret = dmic_configure(dmic_dev, &cfg);
    	if (ret < 0)
    	{
    		LOG_ERR("Failed to configure the driver: %d", ret);
    		return ret;
    	}
    
    	ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_START);
    	if (ret < 0)
    	{
    		LOG_ERR("START trigger failed: %d", ret);
    		return ret;
    	}
    	config.word_size = 16;
    	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 = MAX_SAMPLE_RATE;
    	config.mem_slab = &mem_slab;
    	config.block_size = BLOCK_SIZE;
    	config.timeout = READ_TIMEOUT;
    	if (!configure_streams(i2s_dev_tx, &config))
    	{
    		return 0;
    	}
    	if (!prepare_transfer(i2s_dev_tx))
    	{
    		return 0;
    	}
    	if (!trigger_command(i2s_dev_tx, I2S_TRIGGER_START))
    	{
    		return 0;
    	}
    
    	while (1)
    	{
    		void *buffer;
    		uint32_t size;
    		ret = dmic_read(dmic_dev, 0, &buffer, &size, READ_TIMEOUT);
    		if (ret < 0)
    		{
    			LOG_ERR("read failed: %d", ret);
    			return ret;
    		}
    
    		ret = i2s_buf_write(i2s_dev_tx, buffer, size);
    		if (ret)
    		{
    			printk("Failed to write I2S buffer: %d\n", ret);
    			return;
    		}
    
    		k_mem_slab_free(&mem_slab, buffer);
    	}
    	ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_STOP);
    	if (ret < 0)
    	{
    		LOG_ERR("STOP trigger failed: %d", ret);
    		return ret;
    	}
    
    	LOG_INF("Exiting");
    	return 0;
    }

    Can you please check the implementation of reading data from pdm mic and sending to speaker.I have included source code for same.

Reply
  • #include <zephyr/kernel.h>
    #include <zephyr/audio/dmic.h>
    #include <zephyr/drivers/i2s.h>
    #include <zephyr/drivers/i2c.h>
    #include <zephyr/logging/log.h>
    #include "tas.h"
    
    #define MAX_SAMPLE_RATE 16000
    #define SAMPLE_BIT_WIDTH 16
    #define BYTES_PER_SAMPLE sizeof(int16_t)
    #define READ_TIMEOUT 1000
    #define SAMPLES_PER_BLOCK 160 
    #define NUMBER_OF_CHANNELS 1
    #define I2S_TX_NODE DT_NODELABEL(i2s_tx)
    #define I2C1_NODE DT_NODELABEL(tas2563)
    
    #define BLOCK_SIZE (BYTES_PER_SAMPLE * SAMPLES_PER_BLOCK)
    #define MAX_BLOCK_SIZE BLOCK_SIZE
    #define BLOCK_COUNT 8
    
    LOG_MODULE_REGISTER(dmic_sample);
    K_MEM_SLAB_DEFINE_STATIC(mem_slab, MAX_BLOCK_SIZE, BLOCK_COUNT, 4);
    static const struct i2c_dt_spec dev_i2c = I2C_DT_SPEC_GET(I2C1_NODE);
    
    static bool configure_streams(const struct device *i2s_dev_tx, const struct i2s_config *config)
    {
    	int ret = i2s_configure(i2s_dev_tx, I2S_DIR_TX, config);
    	if (ret == 0)
    	{
    		printk("Configure Stream Successful.\n");
    		return true;
    	}
    	printk("Failed to configure streams: %d\n", ret);
    	return false;
    }
    static bool prepare_transfer(const struct device *i2s_dev_tx)
    {
    	int ret;
    
    	for (int i = 0; i < 2; ++i)
    	{
    		void *mem_block;
    
    		ret = k_mem_slab_alloc(&mem_slab, &mem_block, K_NO_WAIT);
    		if (ret < 0)
    		{
    			printk("Failed to allocate TX block %d: %d\n", i, ret);
    			return false;
    		}
    		memset(mem_block, 0, BLOCK_SIZE);
    
    		ret = i2s_write(i2s_dev_tx, mem_block, BLOCK_SIZE);
    		if (ret < 0)
    		{
    			printk("Failed to write block %d: %d\n", i, ret);
    			return false;
    		}
    	}
    
    	return true;
    }
    static bool trigger_command(const struct device *i2s_dev_tx, enum i2s_trigger_cmd cmd)
    {
    	int ret = i2s_trigger(i2s_dev_tx, I2S_DIR_TX, cmd);
    	if (ret == 0)
    	{
    		printk("Trigger Command Successful.\n");
    		return true;
    	}
    	printk("Failed to trigger command %d: %d\n", cmd, ret);
    	return false;
    }
    int main(void)
    {
    	const struct device *const dmic_dev = DEVICE_DT_GET(DT_NODELABEL(dmic_dev));
    	const struct device *const i2s_dev_tx = DEVICE_DT_GET(I2S_TX_NODE);
    	struct i2s_config config;
    	int ret;
    
    	LOG_INF("DMIC sample");
    
    	if (!device_is_ready(dmic_dev))
    	{
    		LOG_ERR("%s is not ready", dmic_dev->name);
    		return 0;
    	}
    
    	if (!device_is_ready(i2s_dev_tx))
    	{
    		printk("%s is not ready\n", i2s_dev_tx->name);
    		return 0;
    	}
    
    
    	struct pcm_stream_cfg stream = {
    		.pcm_width = SAMPLE_BIT_WIDTH,
    		.mem_slab = &mem_slab,
    	};
    	struct dmic_cfg cfg = {
    		.io = {
    			.min_pdm_clk_freq = 1000000,
    			.max_pdm_clk_freq = 3500000,
    			.min_pdm_clk_dc = 40,
    			.max_pdm_clk_dc = 60,
    		},
    		.streams = &stream,
    		.channel = {
    			.req_num_streams = 1,
    		},
    	};
    
    	cfg.channel.req_num_chan = 1;
    	cfg.channel.req_chan_map_lo =dmic_build_channel_map(0, 0, PDM_CHAN_LEFT);
    	cfg.streams[0].pcm_rate = MAX_SAMPLE_RATE;
    	cfg.streams[0].block_size = BLOCK_SIZE;
    
    	ret = dmic_configure(dmic_dev, &cfg);
    	if (ret < 0)
    	{
    		LOG_ERR("Failed to configure the driver: %d", ret);
    		return ret;
    	}
    
    	ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_START);
    	if (ret < 0)
    	{
    		LOG_ERR("START trigger failed: %d", ret);
    		return ret;
    	}
    	config.word_size = 16;
    	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 = MAX_SAMPLE_RATE;
    	config.mem_slab = &mem_slab;
    	config.block_size = BLOCK_SIZE;
    	config.timeout = READ_TIMEOUT;
    	if (!configure_streams(i2s_dev_tx, &config))
    	{
    		return 0;
    	}
    	if (!prepare_transfer(i2s_dev_tx))
    	{
    		return 0;
    	}
    	if (!trigger_command(i2s_dev_tx, I2S_TRIGGER_START))
    	{
    		return 0;
    	}
    
    	while (1)
    	{
    		void *buffer;
    		uint32_t size;
    		ret = dmic_read(dmic_dev, 0, &buffer, &size, READ_TIMEOUT);
    		if (ret < 0)
    		{
    			LOG_ERR("read failed: %d", ret);
    			return ret;
    		}
    
    		ret = i2s_buf_write(i2s_dev_tx, buffer, size);
    		if (ret)
    		{
    			printk("Failed to write I2S buffer: %d\n", ret);
    			return;
    		}
    
    		k_mem_slab_free(&mem_slab, buffer);
    	}
    	ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_STOP);
    	if (ret < 0)
    	{
    		LOG_ERR("STOP trigger failed: %d", ret);
    		return ret;
    	}
    
    	LOG_INF("Exiting");
    	return 0;
    }

    Can you please check the implementation of reading data from pdm mic and sending to speaker.I have included source code for same.

Children
No Data
Related