1 /*
2  * Copyright (c) 2021 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/audio/dmic.h>
9 
10 #include <zephyr/logging/log.h>
11 LOG_MODULE_REGISTER(dmic_sample);
12 
13 #define MAX_SAMPLE_RATE  16000
14 #define SAMPLE_BIT_WIDTH 16
15 #define BYTES_PER_SAMPLE sizeof(int16_t)
16 /* Milliseconds to wait for a block to be read. */
17 #define READ_TIMEOUT     1000
18 
19 /* Size of a block for 100 ms of audio data. */
20 #define BLOCK_SIZE(_sample_rate, _number_of_channels) \
21 	(BYTES_PER_SAMPLE * (_sample_rate / 10) * _number_of_channels)
22 
23 /* Driver will allocate blocks from this slab to receive audio data into them.
24  * Application, after getting a given block from the driver and processing its
25  * data, needs to free that block.
26  */
27 #define MAX_BLOCK_SIZE   BLOCK_SIZE(MAX_SAMPLE_RATE, 2)
28 #define BLOCK_COUNT      4
29 K_MEM_SLAB_DEFINE_STATIC(mem_slab, MAX_BLOCK_SIZE, BLOCK_COUNT, 4);
30 
do_pdm_transfer(const struct device * dmic_dev,struct dmic_cfg * cfg,size_t block_count)31 static int do_pdm_transfer(const struct device *dmic_dev,
32 			   struct dmic_cfg *cfg,
33 			   size_t block_count)
34 {
35 	int ret;
36 
37 	LOG_INF("PCM output rate: %u, channels: %u",
38 		cfg->streams[0].pcm_rate, cfg->channel.req_num_chan);
39 
40 	ret = dmic_configure(dmic_dev, cfg);
41 	if (ret < 0) {
42 		LOG_ERR("Failed to configure the driver: %d", ret);
43 		return ret;
44 	}
45 
46 	ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_START);
47 	if (ret < 0) {
48 		LOG_ERR("START trigger failed: %d", ret);
49 		return ret;
50 	}
51 
52 	for (int i = 0; i < block_count; ++i) {
53 		void *buffer;
54 		uint32_t size;
55 
56 		ret = dmic_read(dmic_dev, 0, &buffer, &size, READ_TIMEOUT);
57 		if (ret < 0) {
58 			LOG_ERR("%d - read failed: %d", i, ret);
59 			return ret;
60 		}
61 
62 		LOG_INF("%d - got buffer %p of %u bytes", i, buffer, size);
63 
64 		k_mem_slab_free(&mem_slab, buffer);
65 	}
66 
67 	ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_STOP);
68 	if (ret < 0) {
69 		LOG_ERR("STOP trigger failed: %d", ret);
70 		return ret;
71 	}
72 
73 	return ret;
74 }
75 
main(void)76 int main(void)
77 {
78 	const struct device *const dmic_dev = DEVICE_DT_GET(DT_NODELABEL(dmic_dev));
79 	int ret;
80 
81 	LOG_INF("DMIC sample");
82 
83 	if (!device_is_ready(dmic_dev)) {
84 		LOG_ERR("%s is not ready", dmic_dev->name);
85 		return 0;
86 	}
87 
88 	struct pcm_stream_cfg stream = {
89 		.pcm_width = SAMPLE_BIT_WIDTH,
90 		.mem_slab  = &mem_slab,
91 	};
92 	struct dmic_cfg cfg = {
93 		.io = {
94 			/* These fields can be used to limit the PDM clock
95 			 * configurations that the driver is allowed to use
96 			 * to those supported by the microphone.
97 			 */
98 			.min_pdm_clk_freq = 1000000,
99 			.max_pdm_clk_freq = 3500000,
100 			.min_pdm_clk_dc   = 40,
101 			.max_pdm_clk_dc   = 60,
102 		},
103 		.streams = &stream,
104 		.channel = {
105 			.req_num_streams = 1,
106 		},
107 	};
108 
109 	cfg.channel.req_num_chan = 1;
110 	cfg.channel.req_chan_map_lo =
111 		dmic_build_channel_map(0, 0, PDM_CHAN_LEFT);
112 	cfg.streams[0].pcm_rate = MAX_SAMPLE_RATE;
113 	cfg.streams[0].block_size =
114 		BLOCK_SIZE(cfg.streams[0].pcm_rate, cfg.channel.req_num_chan);
115 
116 	ret = do_pdm_transfer(dmic_dev, &cfg, 2 * BLOCK_COUNT);
117 	if (ret < 0) {
118 		return 0;
119 	}
120 
121 	cfg.channel.req_num_chan = 2;
122 	cfg.channel.req_chan_map_lo =
123 		dmic_build_channel_map(0, 0, PDM_CHAN_LEFT) |
124 		dmic_build_channel_map(1, 0, PDM_CHAN_RIGHT);
125 	cfg.streams[0].pcm_rate = MAX_SAMPLE_RATE;
126 	cfg.streams[0].block_size =
127 		BLOCK_SIZE(cfg.streams[0].pcm_rate, cfg.channel.req_num_chan);
128 
129 	ret = do_pdm_transfer(dmic_dev, &cfg, 2 * BLOCK_COUNT);
130 	if (ret < 0) {
131 		return 0;
132 	}
133 
134 	LOG_INF("Exiting");
135 	return 0;
136 }
137