1 /*
2  * Copyright 2023 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdio.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/drivers/i2s.h>
10 #include <zephyr/sys/iterable_sections.h>
11 
12 #define SAMPLE_NO 64
13 
14 /* The data represent a sine wave */
15 static int16_t data[SAMPLE_NO] = {
16 	  3211,   6392,   9511,  12539,  15446,  18204,  20787,  23169,
17 	 25329,  27244,  28897,  30272,  31356,  32137,  32609,  32767,
18 	 32609,  32137,  31356,  30272,  28897,  27244,  25329,  23169,
19 	 20787,  18204,  15446,  12539,   9511,   6392,   3211,      0,
20 	 -3212,  -6393,  -9512, -12540, -15447, -18205, -20788, -23170,
21 	-25330, -27245, -28898, -30273, -31357, -32138, -32610, -32767,
22 	-32610, -32138, -31357, -30273, -28898, -27245, -25330, -23170,
23 	-20788, -18205, -15447, -12540,  -9512,  -6393,  -3212,     -1,
24 };
25 
26 /* Fill buffer with sine wave on left channel, and sine wave shifted by
27  * 90 degrees on right channel. "att" represents a power of two to attenuate
28  * the samples by
29  */
fill_buf(int16_t * tx_block,int att)30 static void fill_buf(int16_t *tx_block, int att)
31 {
32 	int r_idx;
33 
34 	for (int i = 0; i < SAMPLE_NO; i++) {
35 		/* Left channel is sine wave */
36 		tx_block[2 * i] = data[i] / (1 << att);
37 		/* Right channel is same sine wave, shifted by 90 degrees */
38 		r_idx = (i + (ARRAY_SIZE(data) / 4)) % ARRAY_SIZE(data);
39 		tx_block[2 * i + 1] = data[r_idx] / (1 << att);
40 	}
41 }
42 
43 #define NUM_BLOCKS 20
44 #define BLOCK_SIZE (2 * sizeof(data))
45 
46 #ifdef CONFIG_NOCACHE_MEMORY
47 	#define MEM_SLAB_CACHE_ATTR __nocache
48 #else
49 	#define MEM_SLAB_CACHE_ATTR
50 #endif /* CONFIG_NOCACHE_MEMORY */
51 
52 static char MEM_SLAB_CACHE_ATTR __aligned(WB_UP(32))
53 	_k_mem_slab_buf_tx_0_mem_slab[(NUM_BLOCKS) * WB_UP(BLOCK_SIZE)];
54 
55 static STRUCT_SECTION_ITERABLE(k_mem_slab, tx_0_mem_slab) =
56 	Z_MEM_SLAB_INITIALIZER(tx_0_mem_slab, _k_mem_slab_buf_tx_0_mem_slab,
57 				WB_UP(BLOCK_SIZE), NUM_BLOCKS);
58 
main(void)59 int main(void)
60 {
61 	void *tx_block[NUM_BLOCKS];
62 	struct i2s_config i2s_cfg;
63 	int ret;
64 	uint32_t tx_idx;
65 	const struct device *dev_i2s = DEVICE_DT_GET(DT_ALIAS(i2s_tx));
66 
67 	if (!device_is_ready(dev_i2s)) {
68 		printf("I2S device not ready\n");
69 		return -ENODEV;
70 	}
71 	/* Configure I2S stream */
72 	i2s_cfg.word_size = 16U;
73 	i2s_cfg.channels = 2U;
74 	i2s_cfg.format = I2S_FMT_DATA_FORMAT_I2S;
75 	i2s_cfg.frame_clk_freq = 44100;
76 	i2s_cfg.block_size = BLOCK_SIZE;
77 	i2s_cfg.timeout = 2000;
78 	/* Configure the Transmit port as Master */
79 	i2s_cfg.options = I2S_OPT_FRAME_CLK_MASTER
80 			| I2S_OPT_BIT_CLK_MASTER;
81 	i2s_cfg.mem_slab = &tx_0_mem_slab;
82 	ret = i2s_configure(dev_i2s, I2S_DIR_TX, &i2s_cfg);
83 	if (ret < 0) {
84 		printf("Failed to configure I2S stream\n");
85 		return ret;
86 	}
87 
88 	/* Prepare all TX blocks */
89 	for (tx_idx = 0; tx_idx < NUM_BLOCKS; tx_idx++) {
90 		ret = k_mem_slab_alloc(&tx_0_mem_slab, &tx_block[tx_idx],
91 				       K_FOREVER);
92 		if (ret < 0) {
93 			printf("Failed to allocate TX block\n");
94 			return ret;
95 		}
96 		fill_buf((uint16_t *)tx_block[tx_idx], tx_idx % 3);
97 	}
98 
99 	tx_idx = 0;
100 	/* Send first block */
101 	ret = i2s_write(dev_i2s, tx_block[tx_idx++], BLOCK_SIZE);
102 	if (ret < 0) {
103 		printf("Could not write TX buffer %d\n", tx_idx);
104 		return ret;
105 	}
106 	/* Trigger the I2S transmission */
107 	ret = i2s_trigger(dev_i2s, I2S_DIR_TX, I2S_TRIGGER_START);
108 	if (ret < 0) {
109 		printf("Could not trigger I2S tx\n");
110 		return ret;
111 	}
112 
113 	for (; tx_idx < NUM_BLOCKS; ) {
114 		ret = i2s_write(dev_i2s, tx_block[tx_idx++], BLOCK_SIZE);
115 		if (ret < 0) {
116 			printf("Could not write TX buffer %d\n", tx_idx);
117 			return ret;
118 		}
119 	}
120 	/* Drain TX queue */
121 	ret = i2s_trigger(dev_i2s, I2S_DIR_TX, I2S_TRIGGER_DRAIN);
122 	if (ret < 0) {
123 		printf("Could not trigger I2S tx\n");
124 		return ret;
125 	}
126 	printf("All I2S blocks written\n");
127 	return 0;
128 }
129