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