2021-06-15 03:53:44 -04:00
/*
2022-02-08 04:39:38 -05:00
* SPDX - FileCopyrightText : 2021 - 2022 Espressif Systems ( Shanghai ) CO LTD
2021-06-15 03:53:44 -04:00
*
* SPDX - License - Identifier : CC0 - 1.0
*/
# include <stdio.h>
# include <string.h>
# include "freertos/FreeRTOS.h"
# include "freertos/task.h"
2022-04-02 09:31:35 -04:00
# include "driver/i2s_std.h"
2021-06-15 03:53:44 -04:00
# 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)
2021-08-18 07:45:51 -04:00
# define EXAMPLE_MCLK_MULTIPLE (256)
2021-06-15 03:53:44 -04:00
# 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 "
} ;
2021-08-18 07:45:51 -04:00
static i2s_chan_handle_t tx_handle = NULL ;
static i2s_chan_handle_t rx_handle = NULL ;
2021-06-15 03:53:44 -04:00
/* 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_from_mclk_pin = true ,
. sample_frequency = EXAMPLE_SAMPLE_RATE
} ;
2021-08-18 07:45:51 -04:00
ESP_ERROR_CHECK ( es8311_init ( es_handle , & es_clk , ES8311_RESOLUTION_16 , ES8311_RESOLUTION_16 ) ) ;
2021-06-15 03:53:44 -04:00
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 )
{
2022-04-02 09:31:35 -04:00
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG ( I2S_NUM , I2S_ROLE_MASTER ) ;
2021-08-18 07:45:51 -04:00
ESP_ERROR_CHECK ( i2s_new_channel ( & chan_cfg , & tx_handle , & rx_handle ) ) ;
2022-04-02 09:31:35 -04:00
i2s_std_config_t std_cfg = {
. clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG ( EXAMPLE_SAMPLE_RATE ) ,
. slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG ( I2S_DATA_BIT_WIDTH_16BIT , I2S_SLOT_MODE_STEREO ) ,
. gpio_cfg = {
. mclk = GPIO_NUM_0 ,
. bclk = GPIO_NUM_4 ,
. ws = GPIO_NUM_5 ,
. dout = GPIO_NUM_18 ,
. din = GPIO_NUM_19
} ,
} ;
ESP_ERROR_CHECK ( i2s_init_std_channel ( tx_handle , & std_cfg ) ) ;
ESP_ERROR_CHECK ( i2s_init_std_channel ( rx_handle , & std_cfg ) ) ;
2021-08-18 07:45:51 -04:00
ESP_ERROR_CHECK ( i2s_start_channel ( tx_handle ) ) ;
ESP_ERROR_CHECK ( i2s_start_channel ( rx_handle ) ) ;
2021-06-15 03:53:44 -04:00
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 ;
2021-08-18 07:45:51 -04:00
if ( tx_handle = = NULL ) {
ESP_LOGE ( TAG , " [music] i2s tx channel has not been registered yet " ) ;
abort ( ) ;
}
2021-06-15 03:53:44 -04:00
while ( 1 ) {
/* Write music to earphone */
2021-08-18 07:45:51 -04:00
ret = i2s_write_channel ( tx_handle , music_pcm_start , music_pcm_end - music_pcm_start , & bytes_write , portMAX_DELAY ) ;
2021-06-15 03:53:44 -04:00
if ( ret ! = ESP_OK ) {
2021-08-18 07:45:51 -04:00
/* Since we set timeout to 'portMAX_DELAY' in 'i2s_write_channel'
2021-06-15 03:53:44 -04:00
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 ( ) ;
}
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 ( ) ;
}
2022-02-08 04:39:38 -05:00
vTaskDelay ( 1000 / portTICK_PERIOD_MS ) ;
2021-06-15 03:53:44 -04:00
}
vTaskDelete ( NULL ) ;
}
# else
static void i2s_echo ( void * args )
{
2021-08-18 07:45:51 -04:00
if ( rx_handle = = NULL | | tx_handle = = NULL ) {
ESP_LOGE ( TAG , " [echo] i2s rx or tx channel has not been registered yet " ) ;
abort ( ) ;
}
2021-06-15 03:53:44 -04:00
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 */
2021-08-18 07:45:51 -04:00
ret = i2s_read_channel ( rx_handle , mic_data , EXAMPLE_RECV_BUF_SIZE , & bytes_read , 100 ) ;
2021-06-15 03:53:44 -04:00
if ( ret ! = ESP_OK ) {
ESP_LOGE ( TAG , " [echo] i2s read failed, %s " , err_reason [ ret = = ESP_ERR_TIMEOUT ] ) ;
abort ( ) ;
}
/* Write sample data to earphone */
2021-08-18 07:45:51 -04:00
ret = i2s_write_channel ( tx_handle , mic_data , EXAMPLE_RECV_BUF_SIZE , & bytes_write , 100 ) ;
2021-06-15 03:53:44 -04:00
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
}