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