1 /*
2 * Copyright (c) 2021 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr.h>
8 #include <audio/dmic.h>
9
10 #include <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 static K_MEM_SLAB_DEFINE(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 int ret;
56
57 ret = dmic_read(dmic_dev, 0, &buffer, &size, READ_TIMEOUT);
58 if (ret < 0) {
59 LOG_ERR("%d - read failed: %d", i, ret);
60 return ret;
61 }
62
63 LOG_INF("%d - got buffer %p of %u bytes", i, buffer, size);
64
65 k_mem_slab_free(&mem_slab, &buffer);
66 }
67
68 ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_STOP);
69 if (ret < 0) {
70 LOG_ERR("STOP trigger failed: %d", ret);
71 return ret;
72 }
73
74 return ret;
75 }
76
main(void)77 void main(void)
78 {
79 const struct device *dmic_dev = DEVICE_DT_GET(DT_NODELABEL(dmic_dev));
80 int ret;
81
82 LOG_INF("DMIC sample");
83
84 if (!device_is_ready(dmic_dev)) {
85 LOG_ERR("%s is not ready", dmic_dev->name);
86 return;
87 }
88
89 struct pcm_stream_cfg stream = {
90 .pcm_width = SAMPLE_BIT_WIDTH,
91 .mem_slab = &mem_slab,
92 };
93 struct dmic_cfg cfg = {
94 .io = {
95 /* These fields can be used to limit the PDM clock
96 * configurations that the driver is allowed to use
97 * to those supported by the microphone.
98 */
99 .min_pdm_clk_freq = 1000000,
100 .max_pdm_clk_freq = 3500000,
101 .min_pdm_clk_dc = 40,
102 .max_pdm_clk_dc = 60,
103 },
104 .streams = &stream,
105 .channel = {
106 .req_num_streams = 1,
107 },
108 };
109
110 cfg.channel.req_num_chan = 1;
111 cfg.channel.req_chan_map_lo =
112 dmic_build_channel_map(0, 0, PDM_CHAN_LEFT);
113 cfg.streams[0].pcm_rate = MAX_SAMPLE_RATE;
114 cfg.streams[0].block_size =
115 BLOCK_SIZE(cfg.streams[0].pcm_rate, cfg.channel.req_num_chan);
116
117 ret = do_pdm_transfer(dmic_dev, &cfg, 2 * BLOCK_COUNT);
118 if (ret < 0) {
119 return;
120 }
121
122 cfg.channel.req_num_chan = 2;
123 cfg.channel.req_chan_map_lo =
124 dmic_build_channel_map(0, 0, PDM_CHAN_LEFT) |
125 dmic_build_channel_map(1, 0, PDM_CHAN_RIGHT);
126 cfg.streams[0].pcm_rate = MAX_SAMPLE_RATE;
127 cfg.streams[0].block_size =
128 BLOCK_SIZE(cfg.streams[0].pcm_rate, cfg.channel.req_num_chan);
129
130 ret = do_pdm_transfer(dmic_dev, &cfg, 2 * BLOCK_COUNT);
131 if (ret < 0) {
132 return;
133 }
134
135 LOG_INF("Exiting");
136 }
137