pdm clock configuration (nrf5340)

Have used the sample code (Dmic) and generated the output.
the default configurations 
overlay:

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

&pinctrl {
    pdm0_default_alt: pdm0_default_alt {
        group1 {
            psels = <NRF_PSEL(PDM_CLK, 1, 12)>,
                <NRF_PSEL(PDM_DIN, 1, 8)>;
        };
    };
};

dmic_dev: &pdm0 {
    status = "okay";
    pinctrl-0 = <&pdm0_default_alt>;
    pinctrl-names = "default";
    clock-source = "ACLK";
};

prj.conf:

CONFIG_AUDIO=y
CONFIG_AUDIO_DMIC=y

CONFIG_LOG=y
main.c :

#define MAX_SAMPLE_RATE  16000

    struct pcm_stream_cfg stream = {
        .pcm_width = SAMPLE_BIT_WIDTH,
        .mem_slab  = &mem_slab,
    };
    struct dmic_cfg cfg = {
        .io = {
            /* These fields can be used to limit the PDM clock
             * Configurations that the driver is allowed to use
             * To those supported by the microphone.
             */
            .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,
        },
    };

1) how to configure PCM with sampling frequency = 2KHz ?

have changed the MAX_SAMPLE_RATE to 2000

the output observed:
*** Booting Zephyr OS build 28a3fca7da5c ***
[00:00:00.543,640] <inf> dmic_sample: DMIC sample
[00:00:00.543,670] <inf> dmic_sample: PCM output rate: 2000, channels: 1
[00:00:00.543,701] <err> dmic_nrfx_pdm: Cannot find suitable PDM clock configuration.
[00:00:00.543,701] <err> dmic_sample: Failed to configure the driver: -22




is there any way to configure PCM with sampling frequency to 2khz? and how?

2) if PCM is 2KHz. what should be the PDM clock configuration?

  • hi, I have got logic
    there is relation between PDM and PCM.
    PDM= 64 * PCM

    #define MAX_SAMPLE_RATE  2000

      
        struct dmic_cfg cfg = {
            .io = {
                /* These fields can be used to limit the PDM clock
                 * configurations that the driver is allowed to use
                 * to those supported by the microphone.
                 */
                .min_pdm_clk_freq = 128000, //1000000,
                .max_pdm_clk_freq = 128000, //3500000,
                .min_pdm_clk_dc   = 40,
                .max_pdm_clk_dc   = 60,
       
            },
            .streams = &stream,
            .channel = {
                .req_num_streams = 1,
            },
        };
  • Hello,

    Just to make sure I have understood your issue correctly, is the only issue here with how to generate a 2 kHz PDM?
    Is the PDM outputting the expected values when you configure it according to the examples in the documentation?

    is there any way to configure PCM with sampling frequency to 2khz? and how?

    2) if PCM is 2KHz. what should be the PDM clock configuration?

    As can be seen from the formula in Figure 3 of the PDM documentation the lowest possible value for PDMCLKCTRL is 1 000 000, which means that the lowest f_actual you can have is 11178000*1000000/1048576*4096= 2602 Hz, if you are using the ACLK at 11.178 MHz as the master clock source (lowest ACLK settings), if that is what you are asking about.

    I am not sure if I have understood you question and issue correctly, so please elaborate on your question and issue if this was not what you were asking about.

    Best regards,
    Karl

  • Iam currently using the configuration as:

        struct pcm_stream_cfg stream = {
            .pcm_width = SAMPLE_BIT_WIDTH,
            .mem_slab  = &mem_slab,
        };
        struct dmic_cfg cfg = {
            .io = {
                /* These fields can be used to limit the PDM clock
                 * configurations that the driver is allowed to use
                 * to those supported by the microphone.
                 */
                .min_pdm_clk_freq = 120000, //1000000,
                .max_pdm_clk_freq = 160000, //3500000,
                .min_pdm_clk_dc   = 40,
                .max_pdm_clk_dc   = 60,
       
            },
            .streams = &stream,
            .channel = {
                .req_num_streams = 1,
            },
        };

    overlay layer
    &clock {
        hfclkaudio-frequency = <12288000>;
    };

    &pinctrl {
        pdm0_default_alt: pdm0_default_alt {
            group1 {
                psels = <NRF_PSEL(PDM_CLK, 1, 12)>,
                    <NRF_PSEL(PDM_DIN, 1, 8)>;
            };
        };
    };

    dmic_dev: &pdm0 {
        status = "okay";
        pinctrl-0 = <&pdm0_default_alt>;
        pinctrl-names = "default";
        clock-source = "ACLK";
    };

    1) is the logic 
    correct? if not can you suggest me some another method?
    output for the above configuration
    *** Booting Zephyr OS build 28a3fca7da5c ***
    [00:00:00.250,976] <inf> dmic_sample: DMIC sample
    sizeof(int16_t)= 2
    [00:00:00.251,037] <inf> dmic_sample: PCM output rate: 2000, channels: 1
    [00:00:00.251,037] <inf> dmic_nrfx_pdm: PDM clock frequency: 128000, actual PCM rate: 2000
    [00:00:00.354,766] <inf> dmic_sample: 8084
    --- 169 messages dropped ---
    [00:00:00.354,766] <inf> dmic_sample: 808c
    [00:00:00.354,797] <inf> dmic_sample: 8094
    [00:00:00.354,797] <inf> dmic_sample: 809c
    [00:00:00.354,827] <inf> dmic_sample: 80a4
    [00:00:00.354,827] <inf> dmic_sample: 80ac
    [00:00:00.354,858] <inf> dmic_sample: 80b4
    [00:00:00.354,858] <inf> dmic_sample: 80bc
    [00:00:00.354,888] <inf> dmic_sample: 80c4
    [00:00:00.354,919] <inf> dmic_sample: 80cc
    [00:00:00.354,919] <inf> dmic_sample: 80d4
    [00:00:00.354,949] <inf> dmic_sample: 80dc
    [00:00:00.354,949] <inf> dmic_sample: 7fff
    [00:00:00.354,980] <inf> dmic_sample: 7fff
    [00:00:00.354,980] <inf> dmic_sample: 7fff
    [00:00:00.355,010] <inf> dmic_sample: 7fff
    [00:00:00.355,010] <inf> dmic_sample: 7fff
    [00:00:00.355,041] <inf> dmic_sample: 7fff
    [00:00:00.355,041] <inf> dmic_sample: 7fff
    [00:00:00.355,072] <inf> dmic_sample: 7fff
    [00:00:00.355,072] <inf> dmic_sample: 7fff
    [00:00:00.355,102] <inf> dmic_sample: 7fff
    [00:00:00.355,102] <inf> dmic_sample: 7fff
    [00:00:00.355,133] <inf> dmic_sample: 7fff
    [00:00:00.355,133] <inf> dmic_sample: 7fff
    [00:00:00.355,163] <inf> dmic_sample: 7fff
    [00:00:00.355,194] <inf> dmic_sample: 7fff
    [00:00:00.355,194] <inf> dmic_sample: 7fff
    [00:00:00.355,224] <inf> dmic_sample: 7fff
    [00:00:00.355,224] <inf> dmic_sample: 7fff
    [00:00:00.355,255] <inf> dmic_sample: 8053
    [00:00:00.355,255] <inf> dmic_sample: 805b
    [00:00:00.454,772] <inf> dmic_sample: 811b
    --- 169 messages dropped ---
    [00:00:00.454,772] <inf> dmic_sample: 8123
    [00:00:00.454,803] <inf> dmic_sample: 812b
    [00:00:00.454,803] <inf> dmic_sample: 8133
    [00:00:00.454,833] <inf> dmic_sample: 813b

    .............

    2) have used  LOG_INF(" %x ",sample); to print the data. 

    there are messages dropped. any way to rectify this?


    3) do u have any suggestions for the data validation?

    /*
     * Copyright (c) 2021 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr/kernel.h>
    #include <zephyr/audio/dmic.h>
    
    #include <zephyr/logging/log.h>
    LOG_MODULE_REGISTER(dmic_sample);
    
    // #define MAX_SAMPLE_RATE  16000
    #define MAX_SAMPLE_RATE  2000
    #define SAMPLE_BIT_WIDTH 16
    #define BYTES_PER_SAMPLE sizeof(int16_t)
    /* Milliseconds to wait for a block to be read. */
    #define READ_TIMEOUT    3000  //1000
    
    /* Size of a block for 100 ms of audio data. */
    #define BLOCK_SIZE(_sample_rate, _number_of_channels) \
    	(BYTES_PER_SAMPLE * (_sample_rate / 10) * _number_of_channels)
    
    /* Driver will allocate blocks from this slab to receive audio data into them.
     * Application, after getting a given block from the driver and processing its
     * data, needs to free that block.
     */
    #define MAX_BLOCK_SIZE   BLOCK_SIZE(MAX_SAMPLE_RATE, 2)
    #define BLOCK_COUNT      30 //50 //4
    K_MEM_SLAB_DEFINE_STATIC(mem_slab, MAX_BLOCK_SIZE, BLOCK_COUNT, 4);
    
    static int do_pdm_transfer(const struct device *dmic_dev,
    			   struct dmic_cfg *cfg,
    			   size_t block_count)
    {
    	int ret;
    
    	LOG_INF("PCM output rate: %u, channels: %u",
    		cfg->streams[0].pcm_rate, cfg->channel.req_num_chan);
    
    	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;
    	}
    
    	for (int i = 0; i < block_count; ++i) {
    		void *buffer;
    		uint32_t size;
    		int ret;
    
    		ret = dmic_read(dmic_dev, 0, &buffer, &size, READ_TIMEOUT);
    		if (ret < 0) {
    			LOG_ERR("%d - read failed: %d", i, ret);
    			return ret;
    		}
    
    		LOG_INF("%d - got buffer %p of %u bytes", i, buffer, size);
    		uint16_t *audio_data = (uint16_t *)buffer;
            uint32_t num_samples = size / sizeof(uint16_t);
    
    		for (uint32_t j = 0; j < num_samples ; ++j)
    		{
    			uint32_t sample = audio_data[j];
    			// LOG_INF("Processed Sample[%d]: %d ", j, sample);
    			// LOG_INF(" %d ",sample);
    			// printk("%02x ", sample);
    
    			// printk("%04x ", sample);
    			// LOG_HEXDUMP_INF(sample, sizeof(sample),"Sample Data!"); 
    			// LOG_HEXDUMP_INF(audio_data, sizeof(audio_data),"Sample Data!"); 
    			LOG_INF(" %x ",sample);
    			// printk("%08x ", sample);
    			
            }
    
    		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;
    	}
    
    	return ret;
    }
    
    int main(void)
    {
    	const struct device *const dmic_dev = DEVICE_DT_GET(DT_NODELABEL(dmic_dev));
    	int ret;
    
    	LOG_INF("DMIC sample");
    
    	if (!device_is_ready(dmic_dev)) {
    		LOG_ERR("%s is not ready", dmic_dev->name);
    		return 0;
    	}
    
    	struct pcm_stream_cfg stream = {
    		.pcm_width = SAMPLE_BIT_WIDTH,
    		.mem_slab  = &mem_slab,
    	};
    	struct dmic_cfg cfg = {
    		.io = {
    			/* These fields can be used to limit the PDM clock
    			 * configurations that the driver is allowed to use
    			 * to those supported by the microphone.
    			 */
    			// .min_pdm_clk_freq = 1000000,
    			// .max_pdm_clk_freq = 3500000,
    			.min_pdm_clk_freq = 120000,
    			.max_pdm_clk_freq = 160000,
    			.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(cfg.streams[0].pcm_rate, cfg.channel.req_num_chan);
    
    	ret = do_pdm_transfer(dmic_dev, &cfg, 2 * BLOCK_COUNT);
    	if (ret < 0) {
    		return 0;
    	}
    
    	cfg.channel.req_num_chan = 2;
    	cfg.channel.req_chan_map_lo = dmic_build_channel_map(0, 0, PDM_CHAN_LEFT) | dmic_build_channel_map(1, 0, PDM_CHAN_RIGHT);
    	cfg.streams[0].pcm_rate = MAX_SAMPLE_RATE;
    	cfg.streams[0].block_size =
    		BLOCK_SIZE(cfg.streams[0].pcm_rate, cfg.channel.req_num_chan);
    
    	ret = do_pdm_transfer(dmic_dev, &cfg, 2 * BLOCK_COUNT);
    	if (ret < 0) {
    		return 0;
    	}
    
    	LOG_INF("Exiting");
    	return 0;
    }
    

  • Hello,

    Thank you for your extreme patience with this.

    c3_nithin said:
    1) is the logic correct? if not can you suggest me some another method?

    What are the parameters of the microphone you are using?

    c3_nithin said:

    2) have used  LOG_INF(" %x ",sample); to print the data. 

    there are messages dropped. any way to rectify this?

    The logger will drop messages when it does not have the time to process the logs before new ones are coming in, such as if your application has very high CPU utilization.
    You could try to increase the log buffers, or to ensure that there is enough time to process the logs between each logging round of samples.

    Best regards,
    Karl

Related