1 |
/*
|
2 |
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
3 |
*
|
4 |
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
5 |
*/
|
6 |
|
7 |
#include <stdint.h>
|
8 |
#include <stdlib.h>
|
9 |
#include "freertos/FreeRTOS.h"
|
10 |
#include "freertos/task.h"
|
11 |
#include "driver/i2s_std.h"
|
12 |
#include "driver/gpio.h"
|
13 |
#include "esp_check.h"
|
14 |
#include "sdkconfig.h"
|
15 |
#include "i2s_example_pins.h"
|
16 |
#include <math.h>
|
17 |
|
18 |
|
19 |
/* Set 1 to allocate rx & tx channels in duplex mode on a same I2S controller, they will share the BCLK and WS signal
|
20 |
* Set 0 to allocate rx & tx channels in simplex mode, these two channels will be totally separated,
|
21 |
* Specifically, due to the hardware limitation, the simplex rx & tx channels can't be registered on the same controllers on ESP32 and ESP32-S2,
|
22 |
* and ESP32-S2 has only one I2S controller, so it can't allocate two simplex channels */
|
23 |
#define EXAMPLE_I2S_DUPLEX_MODE CONFIG_USE_DUPLEX
|
24 |
|
25 |
#define EXAMPLE_STD_BCLK_IO1 EXAMPLE_I2S_BCLK_IO1 // I2S bit clock io number
|
26 |
#define EXAMPLE_STD_WS_IO1 EXAMPLE_I2S_WS_IO1 // I2S word select io number
|
27 |
#define EXAMPLE_STD_DOUT_IO1 EXAMPLE_I2S_DOUT_IO1 // I2S data out io number
|
28 |
#define EXAMPLE_STD_DIN_IO1 EXAMPLE_I2S_DIN_IO1 // I2S data in io number
|
29 |
#if !EXAMPLE_I2S_DUPLEX_MODE
|
30 |
#define EXAMPLE_STD_BCLK_IO2 EXAMPLE_I2S_BCLK_IO2 // I2S bit clock io number
|
31 |
#define EXAMPLE_STD_WS_IO2 EXAMPLE_I2S_WS_IO2 // I2S word select io number
|
32 |
#define EXAMPLE_STD_DOUT_IO2 EXAMPLE_I2S_DOUT_IO2 // I2S data out io number
|
33 |
#define EXAMPLE_STD_DIN_IO2 EXAMPLE_I2S_DIN_IO2 // I2S data in io number
|
34 |
#endif
|
35 |
|
36 |
#define EXAMPLE_BUFF_SIZE 2048
|
37 |
#define SAMPLE_RATE 22050
|
38 |
|
39 |
static i2s_chan_handle_t tx_chan; // I2S tx channel handler
|
40 |
static i2s_chan_handle_t rx_chan; // I2S rx channel handler
|
41 |
|
42 |
static void i2s_example_read_task(void *args)
|
43 |
{
|
44 |
uint8_t *r_buf = (uint8_t *)calloc(1, EXAMPLE_BUFF_SIZE);
|
45 |
assert(r_buf); // Check if r_buf allocation success
|
46 |
size_t r_bytes = 0;
|
47 |
|
48 |
/* Enable the RX channel */
|
49 |
ESP_ERROR_CHECK(i2s_channel_enable(rx_chan));
|
50 |
|
51 |
/* ATTENTION: The print and delay in the read task only for monitoring the data by human,
|
52 |
* Normally there shouldn't be any delays to ensure a short polling time,
|
53 |
* Otherwise the dma buffer will overflow and lead to the data lost */
|
54 |
while (1) {
|
55 |
/* Read i2s data */
|
56 |
if (i2s_channel_read(rx_chan, r_buf, EXAMPLE_BUFF_SIZE, &r_bytes, 1000) == ESP_OK) {
|
57 |
printf("Read Task: i2s read %d bytes\n-----------------------------------\n", r_bytes);
|
58 |
printf("[0] %x [1] %x [2] %x [3] %x\n[4] %x [5] %x [6] %x [7] %x\n\n",
|
59 |
r_buf[0], r_buf[1], r_buf[2], r_buf[3], r_buf[4], r_buf[5], r_buf[6], r_buf[7]);
|
60 |
} else {
|
61 |
printf("Read Task: i2s read failed\n");
|
62 |
}
|
63 |
vTaskDelay(pdMS_TO_TICKS(200));
|
64 |
}
|
65 |
free(r_buf);
|
66 |
vTaskDelete(NULL);
|
67 |
}
|
68 |
|
69 |
static void i2s_example_write_task(void *args)
|
70 |
{
|
71 |
uint8_t *w_buf = (uint8_t *)calloc(1, EXAMPLE_BUFF_SIZE);
|
72 |
assert(w_buf); // Check if w_buf allocation success
|
73 |
|
74 |
for (int i = 0; i < EXAMPLE_BUFF_SIZE / 2; i++) {
|
75 |
float phase = (2.0f * M_PI * i) / (SAMPLE_RATE / 220);
|
76 |
int16_t sample = (int16_t)(127 * sinf(phase));
|
77 |
w_buf[i] = sample; // Kein MSB nötig bei 8 Bit
|
78 |
w_buf[2 * i + 1] = (sample >> 8) & 0xFF; // MSB
|
79 |
}
|
80 |
|
81 |
|
82 |
size_t w_bytes = EXAMPLE_BUFF_SIZE;
|
83 |
|
84 |
/* (Optional) Preload the data before enabling the TX channel, so that the valid data can be transmitted immediately */
|
85 |
while (w_bytes == EXAMPLE_BUFF_SIZE) {
|
86 |
/* Here we load the target buffer repeatedly, until all the DMA buffers are preloaded */
|
87 |
ESP_ERROR_CHECK(i2s_channel_preload_data(tx_chan, w_buf, EXAMPLE_BUFF_SIZE, &w_bytes));
|
88 |
}
|
89 |
|
90 |
/* Enable the TX channel */
|
91 |
ESP_ERROR_CHECK(i2s_channel_enable(tx_chan));
|
92 |
while (1) {
|
93 |
/* Write i2s data */
|
94 |
if (i2s_channel_write(tx_chan, w_buf, EXAMPLE_BUFF_SIZE, &w_bytes, 1000) == ESP_OK) {
|
95 |
printf("Write Task: i2s write %d bytes\n", w_bytes);
|
96 |
} else {
|
97 |
printf("Write Task: i2s write failed\n");
|
98 |
}
|
99 |
vTaskDelay(pdMS_TO_TICKS(200));
|
100 |
}
|
101 |
free(w_buf);
|
102 |
vTaskDelete(NULL);
|
103 |
}
|
104 |
|
105 |
static void i2s_example_init_std_simplex(void)
|
106 |
{
|
107 |
/* Setp 1: Determine the I2S channel configuration and allocate two channels one by one
|
108 |
* The default configuration can be generated by the helper macro,
|
109 |
* it only requires the I2S controller id and I2S role
|
110 |
* The tx and rx channels here are registered on different I2S controller,
|
111 |
* Except ESP32 and ESP32-S2, others allow to register two separate tx & rx channels on a same controller */
|
112 |
i2s_chan_config_t tx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
|
113 |
ESP_ERROR_CHECK(i2s_new_channel(&tx_chan_cfg, &tx_chan, NULL));
|
114 |
i2s_chan_config_t rx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
|
115 |
ESP_ERROR_CHECK(i2s_new_channel(&rx_chan_cfg, NULL, &rx_chan));
|
116 |
|
117 |
/* Step 2: Setting the configurations of standard mode and initialize each channels one by one
|
118 |
* The slot configuration and clock configuration can be generated by the macros
|
119 |
* These two helper macros is defined in 'i2s_std.h' which can only be used in STD mode.
|
120 |
* They can help to specify the slot and clock configurations for initialization or re-configuring */
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
i2s_std_config_t std_cfg = {
|
126 |
.clk_cfg = {
|
127 |
.sample_rate_hz = SAMPLE_RATE,
|
128 |
.clk_src = I2S_CLK_SRC_DEFAULT,
|
129 |
.mclk_multiple = I2S_MCLK_MULTIPLE_256
|
130 |
},
|
131 |
.slot_cfg = {
|
132 |
.data_bit_width = I2S_DATA_BIT_WIDTH_16BIT,
|
133 |
.slot_bit_width = I2S_SLOT_BIT_WIDTH_16BIT,
|
134 |
.slot_mode = I2S_SLOT_MODE_STEREO,
|
135 |
.slot_mask = I2S_STD_SLOT_BOTH,
|
136 |
.ws_width = I2S_DATA_BIT_WIDTH_16BIT,
|
137 |
.ws_pol = false,
|
138 |
.bit_shift = true,
|
139 |
.msb_right = false
|
140 |
},
|
141 |
.gpio_cfg = {
|
142 |
.mclk = I2S_GPIO_UNUSED,
|
143 |
.bclk = GPIO_NUM_5,
|
144 |
.ws = GPIO_NUM_25,
|
145 |
.dout = GPIO_NUM_26,
|
146 |
.din = I2S_GPIO_UNUSED,
|
147 |
.invert_flags = {
|
148 |
.mclk_inv = false,
|
149 |
.bclk_inv = false,
|
150 |
.ws_inv = false
|
151 |
}
|
152 |
}
|
153 |
};
|
154 |
|
155 |
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_chan, &std_cfg));
|
156 |
|
157 |
|
158 |
i2s_std_config_t rx_std_cfg = {
|
159 |
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(22050),
|
160 |
.slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
|
161 |
.gpio_cfg = {
|
162 |
.mclk = I2S_GPIO_UNUSED, // some codecs may require mclk signal, this example doesn't need it
|
163 |
.bclk = EXAMPLE_STD_BCLK_IO2,
|
164 |
.ws = EXAMPLE_STD_WS_IO2,
|
165 |
.dout = EXAMPLE_STD_DOUT_IO2,
|
166 |
.din = EXAMPLE_STD_DIN_IO2,
|
167 |
.invert_flags = {
|
168 |
.mclk_inv = false,
|
169 |
.bclk_inv = false,
|
170 |
.ws_inv = false,
|
171 |
},
|
172 |
},
|
173 |
};
|
174 |
/* Default is only receiving left slot in mono mode,
|
175 |
* update to right here to show how to change the default configuration */
|
176 |
rx_std_cfg.slot_cfg.slot_mask = I2S_STD_SLOT_RIGHT;
|
177 |
ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_chan, &rx_std_cfg));
|
178 |
}
|
179 |
|
180 |
|
181 |
extern "C" void app_main(void)
|
182 |
{
|
183 |
#if EXAMPLE_I2S_DUPLEX_MODE
|
184 |
i2s_example_init_std_duplex();
|
185 |
#else
|
186 |
i2s_example_init_std_simplex();
|
187 |
#endif
|
188 |
|
189 |
/* Step 3: Create writing and reading task, enable and start the channels */
|
190 |
xTaskCreate(i2s_example_read_task, "i2s_example_read_task", 4096, NULL, 5, NULL);
|
191 |
xTaskCreate(i2s_example_write_task, "i2s_example_write_task", 4096, NULL, 5,
|