-
Notifications
You must be signed in to change notification settings - Fork 7k
/
i2s_es8311_example.c
198 lines (185 loc) · 7.12 KB
/
i2s_es8311_example.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/
#include <stdio.h>
#include <string.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2s_std.h"
#include "esp_system.h"
#include "esp_check.h"
#include "es8311.h"
#include "example_config.h"
static const char *TAG = "i2s_es8311";
static const char err_reason[][30] = {"input param is invalid",
"operation timeout"
};
static i2s_chan_handle_t tx_handle = NULL;
static i2s_chan_handle_t rx_handle = NULL;
/* Import music file as buffer */
#if CONFIG_EXAMPLE_MODE_MUSIC
extern const uint8_t music_pcm_start[] asm("_binary_canon_pcm_start");
extern const uint8_t music_pcm_end[] asm("_binary_canon_pcm_end");
#endif
static esp_err_t es8311_codec_init(void)
{
/* Initialize I2C peripheral */
#if !defined(CONFIG_EXAMPLE_BSP)
const i2c_config_t es_i2c_cfg = {
.sda_io_num = I2C_SDA_IO,
.scl_io_num = I2C_SCL_IO,
.mode = I2C_MODE_MASTER,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000,
};
ESP_RETURN_ON_ERROR(i2c_param_config(I2C_NUM, &es_i2c_cfg), TAG, "config i2c failed");
ESP_RETURN_ON_ERROR(i2c_driver_install(I2C_NUM, I2C_MODE_MASTER, 0, 0, 0), TAG, "install i2c driver failed");
#else
ESP_ERROR_CHECK(bsp_i2c_init());
#endif
/* Initialize es8311 codec */
es8311_handle_t es_handle = es8311_create(I2C_NUM, ES8311_ADDRRES_0);
ESP_RETURN_ON_FALSE(es_handle, ESP_FAIL, TAG, "es8311 create failed");
const es8311_clock_config_t es_clk = {
.mclk_inverted = false,
.sclk_inverted = false,
.mclk_from_mclk_pin = true,
.mclk_frequency = EXAMPLE_MCLK_FREQ_HZ,
.sample_frequency = EXAMPLE_SAMPLE_RATE
};
ESP_ERROR_CHECK(es8311_init(es_handle, &es_clk, ES8311_RESOLUTION_16, ES8311_RESOLUTION_16));
ESP_RETURN_ON_ERROR(es8311_sample_frequency_config(es_handle, EXAMPLE_SAMPLE_RATE * EXAMPLE_MCLK_MULTIPLE, EXAMPLE_SAMPLE_RATE), TAG, "set es8311 sample frequency failed");
ESP_RETURN_ON_ERROR(es8311_voice_volume_set(es_handle, EXAMPLE_VOICE_VOLUME, NULL), TAG, "set es8311 volume failed");
ESP_RETURN_ON_ERROR(es8311_microphone_config(es_handle, false), TAG, "set es8311 microphone failed");
#if CONFIG_EXAMPLE_MODE_ECHO
ESP_RETURN_ON_ERROR(es8311_microphone_gain_set(es_handle, EXAMPLE_MIC_GAIN), TAG, "set es8311 microphone gain faield");
#endif
return ESP_OK;
}
static esp_err_t i2s_driver_init(void)
{
#if !defined(CONFIG_EXAMPLE_BSP)
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM, I2S_ROLE_MASTER);
chan_cfg.auto_clear = true; // Auto clear the legacy data in the DMA buffer
ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle));
i2s_std_config_t std_cfg = {
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(EXAMPLE_SAMPLE_RATE),
.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
.gpio_cfg = {
.mclk = I2S_MCK_IO,
.bclk = I2S_BCK_IO,
.ws = I2S_WS_IO,
.dout = I2S_DO_IO,
.din = I2S_DI_IO,
.invert_flags = {
.mclk_inv = false,
.bclk_inv = false,
.ws_inv = false,
},
},
};
std_cfg.clk_cfg.mclk_multiple = EXAMPLE_MCLK_MULTIPLE;
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle));
#else
ESP_LOGI(TAG, "Using BSP for HW configuration");
i2s_std_config_t std_cfg = {
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(EXAMPLE_SAMPLE_RATE),
.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
.gpio_cfg = BSP_I2S_GPIO_CFG,
};
std_cfg.clk_cfg.mclk_multiple = EXAMPLE_MCLK_MULTIPLE;
ESP_ERROR_CHECK(bsp_audio_init(&std_cfg, &tx_handle, &rx_handle));
ESP_ERROR_CHECK(bsp_audio_poweramp_enable(true));
#endif
return ESP_OK;
}
#if CONFIG_EXAMPLE_MODE_MUSIC
static void i2s_music(void *args)
{
esp_err_t ret = ESP_OK;
size_t bytes_write = 0;
while (1) {
/* Write music to earphone */
ret = i2s_channel_write(tx_handle, music_pcm_start, music_pcm_end - music_pcm_start, &bytes_write, portMAX_DELAY);
if (ret != ESP_OK) {
/* Since we set timeout to 'portMAX_DELAY' in 'i2s_channel_write'
so you won't reach here unless you set other timeout value,
if timeout detected, it means write operation failed. */
ESP_LOGE(TAG, "[music] i2s write failed, %s", err_reason[ret == ESP_ERR_TIMEOUT]);
abort();
}
if (bytes_write > 0) {
ESP_LOGI(TAG, "[music] i2s music played, %d bytes are written.", bytes_write);
} else {
ESP_LOGE(TAG, "[music] i2s music play falied.");
abort();
}
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
#else
static void i2s_echo(void *args)
{
int *mic_data = malloc(EXAMPLE_RECV_BUF_SIZE);
if (!mic_data) {
ESP_LOGE(TAG, "[echo] No memory for read data buffer");
abort();
}
esp_err_t ret = ESP_OK;
size_t bytes_read = 0;
size_t bytes_write = 0;
ESP_LOGI(TAG, "[echo] Echo start");
while (1) {
memset(mic_data, 0, EXAMPLE_RECV_BUF_SIZE);
/* Read sample data from mic */
ret = i2s_channel_read(rx_handle, mic_data, EXAMPLE_RECV_BUF_SIZE, &bytes_read, 1000);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "[echo] i2s read failed, %s", err_reason[ret == ESP_ERR_TIMEOUT]);
abort();
}
/* Write sample data to earphone */
ret = i2s_channel_write(tx_handle, mic_data, EXAMPLE_RECV_BUF_SIZE, &bytes_write, 1000);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "[echo] i2s write failed, %s", err_reason[ret == ESP_ERR_TIMEOUT]);
abort();
}
if (bytes_read != bytes_write) {
ESP_LOGW(TAG, "[echo] %d bytes read but only %d bytes are written", bytes_read, bytes_write);
}
}
vTaskDelete(NULL);
}
#endif
void app_main(void)
{
printf("i2s es8311 codec example start\n-----------------------------\n");
/* Initialize i2s peripheral */
if (i2s_driver_init() != ESP_OK) {
ESP_LOGE(TAG, "i2s driver init failed");
abort();
} else {
ESP_LOGI(TAG, "i2s driver init success");
}
/* Initialize i2c peripheral and config es8311 codec by i2c */
if (es8311_codec_init() != ESP_OK) {
ESP_LOGE(TAG, "es8311 codec init failed");
abort();
} else {
ESP_LOGI(TAG, "es8311 codec init success");
}
#if CONFIG_EXAMPLE_MODE_MUSIC
/* Play a piece of music in music mode */
xTaskCreate(i2s_music, "i2s_music", 4096, NULL, 5, NULL);
#else
/* Echo the sound from MIC in echo mode */
xTaskCreate(i2s_echo, "i2s_echo", 8192, NULL, 5, NULL);
#endif
}