mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
208 lines
7.1 KiB
C
208 lines
7.1 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
|
|
*
|
|
* SPDX-License-Identifier: CC0-1.0
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "driver/i2s.h"
|
|
#include "esp_system.h"
|
|
#include "esp_check.h"
|
|
#include "es8311.h"
|
|
|
|
/* I2C port and GPIOs */
|
|
#define I2C_NUM (0)
|
|
#ifdef CONFIG_IDF_TARGET_ESP32C3
|
|
#define I2C_SDA_IO (GPIO_NUM_17)
|
|
#define I2C_SCL_IO (GPIO_NUM_16)
|
|
#else
|
|
#define I2C_SDA_IO (GPIO_NUM_15)
|
|
#define I2C_SCL_IO (GPIO_NUM_14)
|
|
#endif
|
|
|
|
/* I2S port and GPIOs */
|
|
#define I2S_NUM (0)
|
|
#define I2S_MCK_IO (GPIO_NUM_0)
|
|
#define I2S_BCK_IO (GPIO_NUM_4)
|
|
#define I2S_WS_IO (GPIO_NUM_5)
|
|
#define I2S_DO_IO (GPIO_NUM_18)
|
|
#define I2S_DI_IO (GPIO_NUM_19)
|
|
|
|
/* Example configurations */
|
|
#define EXAMPLE_RECV_BUF_SIZE (2048)
|
|
#define EXAMPLE_SAMPLE_RATE (16000)
|
|
#define EXAMPLE_MCLK_MULTIPLE I2S_MCLK_MULTIPLE_256
|
|
#define EXAMPLE_VOICE_VOLUME CONFIG_EXAMPLE_VOICE_VOLUME
|
|
#if CONFIG_EXAMPLE_MODE_ECHO
|
|
#define EXAMPLE_MIC_GAIN CONFIG_EXAMPLE_MIC_GAIN
|
|
#endif
|
|
|
|
static const char *TAG = "i2s_es8311";
|
|
static const char err_reason[][30] = {"input param is invalid",
|
|
"operation timeout"
|
|
};
|
|
|
|
/* 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 */
|
|
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");
|
|
|
|
/* 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");
|
|
es8311_clock_config_t es_clk = {
|
|
.mclk_inverted = false,
|
|
.sclk_inverted = false,
|
|
.mclk_from_mclk_pin = true,
|
|
.mclk_frequency = EXAMPLE_SAMPLE_RATE * EXAMPLE_MCLK_MULTIPLE,
|
|
.sample_frequency = EXAMPLE_SAMPLE_RATE
|
|
};
|
|
|
|
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)
|
|
{
|
|
i2s_config_t i2s_cfg = {
|
|
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX,
|
|
.sample_rate = EXAMPLE_SAMPLE_RATE,
|
|
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
|
|
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
|
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
|
|
.tx_desc_auto_clear = true,
|
|
#if SOC_I2S_SUPPORTS_TDM
|
|
.total_chan = 2,
|
|
.chan_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1,
|
|
.left_align = false,
|
|
.big_edin = false,
|
|
.bit_order_msb = false,
|
|
.skip_msk = false,
|
|
#endif
|
|
.dma_buf_count = 8,
|
|
.dma_buf_len = 64,
|
|
.use_apll = false,
|
|
.mclk_multiple = EXAMPLE_MCLK_MULTIPLE,
|
|
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
|
|
};
|
|
|
|
ESP_RETURN_ON_ERROR(i2s_driver_install(I2S_NUM, &i2s_cfg, 0, NULL), TAG, "install i2s failed");
|
|
i2s_pin_config_t i2s_pin_cfg = {
|
|
.mck_io_num = I2S_MCK_IO,
|
|
.bck_io_num = I2S_BCK_IO,
|
|
.ws_io_num = I2S_WS_IO,
|
|
.data_out_num = I2S_DO_IO,
|
|
.data_in_num = I2S_DI_IO
|
|
};
|
|
ESP_RETURN_ON_ERROR(i2s_set_pin(I2S_NUM, &i2s_pin_cfg), TAG, "set i2s pins failed");
|
|
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_write(I2S_NUM, 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_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 read failed, %s", err_reason[ret == ESP_ERR_TIMEOUT]);
|
|
abort();
|
|
}
|
|
/* Clear DMA buffer to avoid noise from legacy data in buffer */
|
|
i2s_zero_dma_buffer(I2S_NUM);
|
|
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_RATE_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_read(I2S_NUM, mic_data, EXAMPLE_RECV_BUF_SIZE, &bytes_read, 100);
|
|
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_write(I2S_NUM, mic_data, EXAMPLE_RECV_BUF_SIZE, &bytes_write, 100);
|
|
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)
|
|
{
|
|
/* Initialize i2s peripheral */
|
|
if (i2s_driver_init() != ESP_OK) {
|
|
ESP_LOGE(TAG, "i2s driver init failed");
|
|
abort();
|
|
}
|
|
/* Initialize i2c peripheral and config es8311 codec by i2c */
|
|
if (es8311_codec_init() != ESP_OK) {
|
|
ESP_LOGE(TAG, "es8311 codec init failed");
|
|
abort();
|
|
}
|
|
#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
|
|
}
|