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