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