Hi,
I have a question after using the DMIC example on the nRF5340:
how do I adjust the PDM clock frequency to 1.28MHz, or how can I achieve this by changing the value of PDMCLKCTRL to 0x0A000000?
Below is my understanding after finding relevant documents. Please correct me if there are any errors, thank you.
I saw the following explanation about PCLK32M and ACLK in the PDM Documentation.


However, in the following overlay file of the DMIC sample, the clock source of &pdm0 is ACLK.
nrf5340dk_nrf5340_cpuapp.overlay (without any modifications)
&clock {
hfclkaudio-frequency = <12288000>;
};
&pinctrl {
pdm0_default_alt: pdm0_default_alt {
group1 {
psels = <NRF_PSEL(PDM_CLK, 0, 25)>,
<NRF_PSEL(PDM_DIN, 0, 26)>;
};
};
};
dmic_dev: &pdm0 {
status = "okay";
pinctrl-0 = <&pdm0_default_alt>;
pinctrl-names = "default";
clock-source = "ACLK";
};
Based on the above explanation and overlay file, does this mean I cannot change the PDM clock frequency to 1.28MHz using PDMCLKCTRL? Or how can I achieve this by modifying the overlay's clock-source to PCLK32M and modifying the main code?
If not using PDMCLKCTRL, how can I achieve this by modifying the main code of the DMIC sample using ACLK?
main.c (without any modifications)
#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 SAMPLE_BIT_WIDTH 16
#define BYTES_PER_SAMPLE sizeof(int16_t)
/* Milliseconds to wait for a block to be read. */
#define READ_TIMEOUT 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 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;
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);
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_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;
}
Thank you very much!
Kevin

