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 "codec.h"
9 #include <zephyr/sys/printk.h>
10 #include <zephyr/drivers/i2s.h>
11 #include <zephyr/drivers/gpio.h>
12 #include <zephyr/audio/codec.h>
13 #include <string.h>
14 
15 
16 #if DT_NODE_EXISTS(DT_NODELABEL(i2s_rxtx))
17 #define I2S_RX_NODE  DT_NODELABEL(i2s_rxtx)
18 #define I2S_TX_NODE  I2S_RX_NODE
19 #else
20 #define I2S_RX_NODE  DT_NODELABEL(i2s_rx)
21 #define I2S_TX_NODE  DT_NODELABEL(i2s_tx)
22 #endif
23 
24 /* Reduce echo delay when running on low ram devices */
25 #if CONFIG_SRAM_SIZE <= 48
26 #define ECHO_DELAY 30
27 #else
28 #define ECHO_DELAY 10
29 #endif
30 
31 #define SAMPLE_FREQUENCY    44100
32 #define SAMPLE_BIT_WIDTH    16
33 #define BYTES_PER_SAMPLE    sizeof(int16_t)
34 #define NUMBER_OF_CHANNELS  2
35 /* Such block length provides an echo with the delay of 100ms or 33.33ms */
36 #define SAMPLES_PER_BLOCK   ((SAMPLE_FREQUENCY / ECHO_DELAY) * NUMBER_OF_CHANNELS)
37 #define INITIAL_BLOCKS      2
38 #define TIMEOUT             1000
39 
40 #define SW0_NODE        DT_ALIAS(sw0)
41 #ifdef CONFIG_TOGGLE_ECHO_EFFECT_SW0
42 static struct gpio_dt_spec sw0_spec = GPIO_DT_SPEC_GET(SW0_NODE, gpios);
43 #endif
44 
45 #define SW1_NODE        DT_ALIAS(sw1)
46 #ifdef CONFIG_STOP_START_STREAMS_SW1
47 static struct gpio_dt_spec sw1_spec = GPIO_DT_SPEC_GET(SW1_NODE, gpios);
48 #endif
49 
50 #define BLOCK_SIZE  (BYTES_PER_SAMPLE * SAMPLES_PER_BLOCK)
51 #define BLOCK_COUNT (INITIAL_BLOCKS + 4)
52 K_MEM_SLAB_DEFINE_STATIC(mem_slab, BLOCK_SIZE, BLOCK_COUNT, 4);
53 
54 static int16_t echo_block[SAMPLES_PER_BLOCK];
55 static volatile bool echo_enabled = true;
56 static K_SEM_DEFINE(toggle_transfer, 1, 1);
57 
58 #ifdef CONFIG_TOGGLE_ECHO_EFFECT_SW0
sw0_handler(const struct device * dev,struct gpio_callback * cb,uint32_t pins)59 static void sw0_handler(const struct device *dev, struct gpio_callback *cb,
60 			uint32_t pins)
61 {
62 	bool enable = !echo_enabled;
63 
64 	echo_enabled = enable;
65 	printk("Echo %sabled\n", (enable ? "en" : "dis"));
66 }
67 #endif
68 
69 #ifdef CONFIG_STOP_START_STREAMS_SW1
sw1_handler(const struct device * dev,struct gpio_callback * cb,uint32_t pins)70 static void sw1_handler(const struct device *dev, struct gpio_callback *cb,
71 			uint32_t pins)
72 {
73 	k_sem_give(&toggle_transfer);
74 }
75 #endif
76 
init_buttons(void)77 static bool init_buttons(void)
78 {
79 	int ret;
80 
81 #ifdef CONFIG_TOGGLE_ECHO_EFFECT_SW0
82 	static struct gpio_callback sw0_cb_data;
83 
84 	if (!gpio_is_ready_dt(&sw0_spec)) {
85 		printk("%s is not ready\n", sw0_spec.port->name);
86 		return false;
87 	}
88 
89 	ret = gpio_pin_configure_dt(&sw0_spec, GPIO_INPUT);
90 	if (ret < 0) {
91 		printk("Failed to configure %s pin %d: %d\n",
92 		       sw0_spec.port->name, sw0_spec.pin, ret);
93 		return false;
94 	}
95 
96 	ret = gpio_pin_interrupt_configure_dt(&sw0_spec,
97 					      GPIO_INT_EDGE_TO_ACTIVE);
98 	if (ret < 0) {
99 		printk("Failed to configure interrupt on %s pin %d: %d\n",
100 		       sw0_spec.port->name, sw0_spec.pin, ret);
101 		return false;
102 	}
103 
104 	gpio_init_callback(&sw0_cb_data, sw0_handler, BIT(sw0_spec.pin));
105 	gpio_add_callback(sw0_spec.port, &sw0_cb_data);
106 	printk("Press \"%s\" to toggle the echo effect\n", sw0_spec.port->name);
107 #endif
108 
109 #ifdef CONFIG_STOP_START_STREAMS_SW1
110 	static struct gpio_callback sw1_cb_data;
111 
112 	if (!gpio_is_ready_dt(&sw1_spec)) {
113 		printk("%s is not ready\n", sw1_spec.port->name);
114 		return false;
115 	}
116 
117 	ret = gpio_pin_configure_dt(&sw1_spec, GPIO_INPUT);
118 	if (ret < 0) {
119 		printk("Failed to configure %s pin %d: %d\n",
120 		       sw1_spec.port->name, sw1_spec.pin, ret);
121 		return false;
122 	}
123 
124 	ret = gpio_pin_interrupt_configure_dt(&sw1_spec,
125 					      GPIO_INT_EDGE_TO_ACTIVE);
126 	if (ret < 0) {
127 		printk("Failed to configure interrupt on %s pin %d: %d\n",
128 		       sw1_spec.port->name, sw1_spec.pin, ret);
129 		return false;
130 	}
131 
132 	gpio_init_callback(&sw1_cb_data, sw1_handler, BIT(sw1_spec.pin));
133 	gpio_add_callback(sw1_spec.port, &sw1_cb_data);
134 	printk("Press \"%s\" to stop/restart I2S streams\n", sw1_spec.port->name);
135 #endif
136 
137 	(void)ret;
138 	return true;
139 }
140 
process_block_data(void * mem_block,uint32_t number_of_samples)141 static void process_block_data(void *mem_block, uint32_t number_of_samples)
142 {
143 	static bool clear_echo_block;
144 
145 	if (echo_enabled) {
146 		for (int i = 0; i < number_of_samples; ++i) {
147 			int16_t *sample = &((int16_t *)mem_block)[i];
148 			*sample += echo_block[i];
149 			echo_block[i] = (*sample) / 2;
150 		}
151 
152 		clear_echo_block = true;
153 	} else if (clear_echo_block) {
154 		clear_echo_block = false;
155 		memset(echo_block, 0, sizeof(echo_block));
156 	}
157 }
158 
configure_streams(const struct device * i2s_dev_rx,const struct device * i2s_dev_tx,const struct i2s_config * config)159 static bool configure_streams(const struct device *i2s_dev_rx,
160 			      const struct device *i2s_dev_tx,
161 			      const struct i2s_config *config)
162 {
163 	int ret;
164 
165 	if (i2s_dev_rx == i2s_dev_tx) {
166 		ret = i2s_configure(i2s_dev_rx, I2S_DIR_BOTH, config);
167 		if (ret == 0) {
168 			return true;
169 		}
170 		/* -ENOSYS means that the RX and TX streams need to be
171 		 * configured separately.
172 		 */
173 		if (ret != -ENOSYS) {
174 			printk("Failed to configure streams: %d\n", ret);
175 			return false;
176 		}
177 	}
178 
179 	ret = i2s_configure(i2s_dev_rx, I2S_DIR_RX, config);
180 	if (ret < 0) {
181 		printk("Failed to configure RX stream: %d\n", ret);
182 		return false;
183 	}
184 
185 	ret = i2s_configure(i2s_dev_tx, I2S_DIR_TX, config);
186 	if (ret < 0) {
187 		printk("Failed to configure TX stream: %d\n", ret);
188 		return false;
189 	}
190 
191 	return true;
192 }
193 
prepare_transfer(const struct device * i2s_dev_rx,const struct device * i2s_dev_tx)194 static bool prepare_transfer(const struct device *i2s_dev_rx,
195 			     const struct device *i2s_dev_tx)
196 {
197 	int ret;
198 
199 	for (int i = 0; i < INITIAL_BLOCKS; ++i) {
200 		void *mem_block;
201 
202 		ret = k_mem_slab_alloc(&mem_slab, &mem_block, K_NO_WAIT);
203 		if (ret < 0) {
204 			printk("Failed to allocate TX block %d: %d\n", i, ret);
205 			return false;
206 		}
207 
208 		memset(mem_block, 0, BLOCK_SIZE);
209 
210 		ret = i2s_write(i2s_dev_tx, mem_block, BLOCK_SIZE);
211 		if (ret < 0) {
212 			printk("Failed to write block %d: %d\n", i, ret);
213 			return false;
214 		}
215 	}
216 
217 	return true;
218 }
219 
trigger_command(const struct device * i2s_dev_rx,const struct device * i2s_dev_tx,enum i2s_trigger_cmd cmd)220 static bool trigger_command(const struct device *i2s_dev_rx,
221 			    const struct device *i2s_dev_tx,
222 			    enum i2s_trigger_cmd cmd)
223 {
224 	int ret;
225 
226 	if (i2s_dev_rx == i2s_dev_tx) {
227 		ret = i2s_trigger(i2s_dev_rx, I2S_DIR_BOTH, cmd);
228 		if (ret == 0) {
229 			return true;
230 		}
231 		/* -ENOSYS means that commands for the RX and TX streams need
232 		 * to be triggered separately.
233 		 */
234 		if (ret != -ENOSYS) {
235 			printk("Failed to trigger command %d: %d\n", cmd, ret);
236 			return false;
237 		}
238 	}
239 
240 	ret = i2s_trigger(i2s_dev_rx, I2S_DIR_RX, cmd);
241 	if (ret < 0) {
242 		printk("Failed to trigger command %d on RX: %d\n", cmd, ret);
243 		return false;
244 	}
245 
246 	ret = i2s_trigger(i2s_dev_tx, I2S_DIR_TX, cmd);
247 	if (ret < 0) {
248 		printk("Failed to trigger command %d on TX: %d\n", cmd, ret);
249 		return false;
250 	}
251 
252 	return true;
253 }
254 
main(void)255 int main(void)
256 {
257 	const struct device *const i2s_dev_rx = DEVICE_DT_GET(I2S_RX_NODE);
258 	const struct device *const i2s_dev_tx = DEVICE_DT_GET(I2S_TX_NODE);
259 	struct i2s_config config;
260 
261 	printk("I2S echo sample\n");
262 
263 #if DT_ON_BUS(DT_NODELABEL(wm8731), i2c)
264 	if (!init_wm8731_i2c()) {
265 		return 0;
266 	}
267 
268 #elif DT_NODE_HAS_STATUS(DT_NODELABEL(audio_codec), okay)
269 	const struct device *const codec_dev = DEVICE_DT_GET(DT_NODELABEL(audio_codec));
270 	struct audio_codec_cfg audio_cfg;
271 
272 	audio_cfg.dai_route = AUDIO_ROUTE_PLAYBACK_CAPTURE;
273 	audio_cfg.dai_type = AUDIO_DAI_TYPE_I2S;
274 	audio_cfg.dai_cfg.i2s.word_size = SAMPLE_BIT_WIDTH;
275 	audio_cfg.dai_cfg.i2s.channels = NUMBER_OF_CHANNELS;
276 	audio_cfg.dai_cfg.i2s.format = I2S_FMT_DATA_FORMAT_I2S;
277 	audio_cfg.dai_cfg.i2s.options = I2S_OPT_FRAME_CLK_MASTER;
278 	audio_cfg.dai_cfg.i2s.frame_clk_freq = SAMPLE_FREQUENCY;
279 	audio_cfg.dai_cfg.i2s.mem_slab = &mem_slab;
280 	audio_cfg.dai_cfg.i2s.block_size = BLOCK_SIZE;
281 	audio_codec_configure(codec_dev, &audio_cfg);
282 	k_msleep(1000);
283 #endif
284 
285 #if DT_ON_BUS(MAX9867_NODE, i2c)
286 	if (!init_max9867_i2c()) {
287 		return 0;
288 	}
289 #endif
290 
291 	if (!init_buttons()) {
292 		return 0;
293 	}
294 
295 	if (!device_is_ready(i2s_dev_rx)) {
296 		printk("%s is not ready\n", i2s_dev_rx->name);
297 		return 0;
298 	}
299 
300 	if (i2s_dev_rx != i2s_dev_tx && !device_is_ready(i2s_dev_tx)) {
301 		printk("%s is not ready\n", i2s_dev_tx->name);
302 		return 0;
303 	}
304 
305 	config.word_size = SAMPLE_BIT_WIDTH;
306 	config.channels = NUMBER_OF_CHANNELS;
307 	config.format = I2S_FMT_DATA_FORMAT_I2S;
308 	/*
309 	 * On MAX32655FTHR, MAX9867 MCLK is connected to external 12.2880 crystal
310 	 * thus using slave mode
311 	 */
312 #if CONFIG_BOARD_MAX32655FTHR_MAX32655_M4
313 	config.options = I2S_OPT_BIT_CLK_SLAVE | I2S_OPT_FRAME_CLK_SLAVE;
314 #else
315 	config.options = I2S_OPT_BIT_CLK_MASTER | I2S_OPT_FRAME_CLK_MASTER;
316 #endif
317 	config.frame_clk_freq = SAMPLE_FREQUENCY;
318 	config.mem_slab = &mem_slab;
319 	config.block_size = BLOCK_SIZE;
320 	config.timeout = TIMEOUT;
321 	if (!configure_streams(i2s_dev_rx, i2s_dev_tx, &config)) {
322 		return 0;
323 	}
324 
325 	for (;;) {
326 		k_sem_take(&toggle_transfer, K_FOREVER);
327 
328 		if (!prepare_transfer(i2s_dev_rx, i2s_dev_tx)) {
329 			return 0;
330 		}
331 
332 		if (!trigger_command(i2s_dev_rx, i2s_dev_tx,
333 				     I2S_TRIGGER_START)) {
334 			return 0;
335 		}
336 
337 		printk("Streams started\n");
338 
339 		while (k_sem_take(&toggle_transfer, K_NO_WAIT) != 0) {
340 			void *mem_block;
341 			uint32_t block_size;
342 			int ret;
343 
344 			ret = i2s_read(i2s_dev_rx, &mem_block, &block_size);
345 			if (ret < 0) {
346 				printk("Failed to read data: %d\n", ret);
347 				break;
348 			}
349 
350 			process_block_data(mem_block, SAMPLES_PER_BLOCK);
351 
352 			ret = i2s_write(i2s_dev_tx, mem_block, block_size);
353 			if (ret < 0) {
354 				printk("Failed to write data: %d\n", ret);
355 				break;
356 			}
357 		}
358 
359 		if (!trigger_command(i2s_dev_rx, i2s_dev_tx,
360 				     I2S_TRIGGER_DROP)) {
361 			return 0;
362 		}
363 
364 		printk("Streams stopped\n");
365 	}
366 }
367