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 Reply Children
  • #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.

Related