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