1 /*
2 * Copyright 2024 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/sys/printk.h>
9 #include <zephyr/audio/dmic.h>
10 #include <zephyr/drivers/i2s.h>
11 #include <zephyr/audio/codec.h>
12 #include <string.h>
13
14
15 #define I2S_CODEC_TX DT_ALIAS(i2s_codec_tx)
16
17 #define SAMPLE_FREQUENCY CONFIG_SAMPLE_FREQ
18 #define SAMPLE_BIT_WIDTH (16U)
19 #define BYTES_PER_SAMPLE sizeof(int16_t)
20 #if CONFIG_USE_DMIC
21 #define NUMBER_OF_CHANNELS CONFIG_DMIC_CHANNELS
22 #else
23 #define NUMBER_OF_CHANNELS (2U)
24 #endif
25 /* Such block length provides an echo with the delay of 100 ms. */
26 #define SAMPLES_PER_BLOCK ((SAMPLE_FREQUENCY / 10) * NUMBER_OF_CHANNELS)
27 #define INITIAL_BLOCKS CONFIG_I2S_INIT_BUFFERS
28 #define TIMEOUT (2000U)
29
30 #define BLOCK_SIZE (BYTES_PER_SAMPLE * SAMPLES_PER_BLOCK)
31 #define BLOCK_COUNT (INITIAL_BLOCKS + 32)
32 K_MEM_SLAB_DEFINE_STATIC(mem_slab, BLOCK_SIZE, BLOCK_COUNT, 4);
33
configure_tx_streams(const struct device * i2s_dev,struct i2s_config * config)34 static bool configure_tx_streams(const struct device *i2s_dev, struct i2s_config *config)
35 {
36 int ret;
37
38 ret = i2s_configure(i2s_dev, I2S_DIR_TX, config);
39 if (ret < 0) {
40 printk("Failed to configure codec stream: %d\n", ret);
41 return false;
42 }
43
44 return true;
45 }
46
trigger_command(const struct device * i2s_dev_codec,enum i2s_trigger_cmd cmd)47 static bool trigger_command(const struct device *i2s_dev_codec,
48 enum i2s_trigger_cmd cmd)
49 {
50 int ret;
51
52 ret = i2s_trigger(i2s_dev_codec, I2S_DIR_TX, cmd);
53 if (ret < 0) {
54 printk("Failed to trigger command %d on TX: %d\n", cmd, ret);
55 return false;
56 }
57
58 return true;
59 }
60
main(void)61 int main(void)
62 {
63 const struct device *const i2s_dev_codec = DEVICE_DT_GET(I2S_CODEC_TX);
64 #if CONFIG_USE_DMIC
65 const struct device *const dmic_dev = DEVICE_DT_GET(DT_NODELABEL(dmic_dev));
66 #endif
67 const struct device *const codec_dev = DEVICE_DT_GET(DT_NODELABEL(audio_codec));
68 struct i2s_config config;
69 struct audio_codec_cfg audio_cfg;
70 int ret;
71
72 #if CONFIG_USE_DMIC
73 struct pcm_stream_cfg stream = {
74 .pcm_width = SAMPLE_BIT_WIDTH,
75 .mem_slab = &mem_slab,
76 };
77 struct dmic_cfg cfg = {
78 .io = {
79 /* These fields can be used to limit the PDM clock
80 * configurations that the driver is allowed to use
81 * to those supported by the microphone.
82 */
83 .min_pdm_clk_freq = 1000000,
84 .max_pdm_clk_freq = 3500000,
85 .min_pdm_clk_dc = 40,
86 .max_pdm_clk_dc = 60,
87 },
88 .streams = &stream,
89 .channel = {
90 .req_num_streams = 1,
91 },
92 };
93 #endif
94 printk("codec sample\n");
95
96 #if CONFIG_USE_DMIC
97 if (!device_is_ready(dmic_dev)) {
98 printk("%s is not ready", dmic_dev->name);
99 return 0;
100 }
101 #endif
102
103 if (!device_is_ready(i2s_dev_codec)) {
104 printk("%s is not ready\n", i2s_dev_codec->name);
105 return 0;
106 }
107
108
109 if (!device_is_ready(codec_dev)) {
110 printk("%s is not ready", codec_dev->name);
111 return 0;
112 }
113 audio_cfg.dai_route = AUDIO_ROUTE_PLAYBACK;
114 audio_cfg.dai_type = AUDIO_DAI_TYPE_I2S;
115 audio_cfg.dai_cfg.i2s.word_size = SAMPLE_BIT_WIDTH;
116 audio_cfg.dai_cfg.i2s.channels = 2;
117 audio_cfg.dai_cfg.i2s.format = I2S_FMT_DATA_FORMAT_I2S;
118 audio_cfg.dai_cfg.i2s.options = I2S_OPT_FRAME_CLK_MASTER;
119 audio_cfg.dai_cfg.i2s.frame_clk_freq = SAMPLE_FREQUENCY;
120 audio_cfg.dai_cfg.i2s.mem_slab = &mem_slab;
121 audio_cfg.dai_cfg.i2s.block_size = BLOCK_SIZE;
122 audio_codec_configure(codec_dev, &audio_cfg);
123 k_msleep(1000);
124
125 #if CONFIG_USE_DMIC
126 cfg.channel.req_num_chan = 2;
127 cfg.channel.req_chan_map_lo =
128 dmic_build_channel_map(0, 0, PDM_CHAN_LEFT) |
129 dmic_build_channel_map(1, 0, PDM_CHAN_RIGHT);
130 cfg.streams[0].pcm_rate = SAMPLE_FREQUENCY;
131 cfg.streams[0].block_size = BLOCK_SIZE;
132
133 printk("PCM output rate: %u, channels: %u\n",
134 cfg.streams[0].pcm_rate, cfg.channel.req_num_chan);
135
136 ret = dmic_configure(dmic_dev, &cfg);
137 if (ret < 0) {
138 printk("Failed to configure the driver: %d", ret);
139 return ret;
140 }
141 #endif
142
143 config.word_size = SAMPLE_BIT_WIDTH;
144 config.channels = NUMBER_OF_CHANNELS;
145 config.format = I2S_FMT_DATA_FORMAT_I2S;
146 config.options = I2S_OPT_BIT_CLK_MASTER | I2S_OPT_FRAME_CLK_MASTER;
147 config.frame_clk_freq = SAMPLE_FREQUENCY;
148 config.mem_slab = &mem_slab;
149 config.block_size = BLOCK_SIZE;
150 config.timeout = TIMEOUT;
151 if (!configure_tx_streams(i2s_dev_codec, &config)) {
152 printk("failure to config streams\n");
153 return 0;
154 }
155
156 printk("start streams\n");
157 for (;;) {
158 bool started = false;
159 #if CONFIG_USE_DMIC
160 ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_START);
161 if (ret < 0) {
162 printk("START trigger failed: %d", ret);
163 return ret;
164 }
165 #endif
166 while (1) {
167 void *mem_block;
168 uint32_t block_size = BLOCK_SIZE;
169 int ret;
170 int i;
171
172 for (i = 0; i < 2; i++) {
173 #if CONFIG_USE_DMIC
174 ret = dmic_read(dmic_dev, 0,
175 &mem_block, &block_size, TIMEOUT);
176 if (ret < 0) {
177 printk("read failed: %d", ret);
178 break;
179 }
180 #else
181 ret = k_mem_slab_alloc(&mem_slab,
182 &mem_block, Z_TIMEOUT_TICKS(TIMEOUT));
183 if (ret < 0) {
184 printk("Failed to allocate TX block\n");
185 return 0;
186 }
187 #endif
188 ret = i2s_write(i2s_dev_codec, mem_block, block_size);
189 if (ret < 0) {
190 printk("Failed to write data: %d\n", ret);
191 break;
192 }
193 }
194 if (ret < 0) {
195 printk("error %d\n", ret);
196 break;
197 }
198 if (!started) {
199 i2s_trigger(i2s_dev_codec, I2S_DIR_TX, I2S_TRIGGER_START);
200 started = true;
201 }
202 }
203 if (!trigger_command(i2s_dev_codec,
204 I2S_TRIGGER_DROP)) {
205 printk("Send I2S trigger DRAIN failed: %d", ret);
206 return 0;
207 }
208 #if CONFIG_USE_DMIC
209 ret = dmic_trigger(dmic_dev, DMIC_TRIGGER_STOP);
210 if (ret < 0) {
211 printk("STOP trigger failed: %d", ret);
212 return 0;
213 }
214 #endif
215 printk("Streams stopped\n");
216 return 0;
217 }
218 }
219