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