88static i2s_chan_handle_t tx_chan ; // I2S tx channel handler
99void mixer_callback (void * opaque , uint8_t * stream , int free );
1010
11+ #ifndef MIXER_BUF_LEN
12+ #define MIXER_BUF_LEN 128
13+ #endif
14+
1115static void i2s_task (void * arg )
1216{
13- int16_t buf [128 ];
17+ int16_t buf [MIXER_BUF_LEN ];
1418 int core_id = esp_cpu_get_core_id ();
1519 fprintf (stderr , "i2s runs on core %d\n" , core_id );
1620
@@ -23,16 +27,114 @@ static void i2s_task(void *arg)
2327 i2s_channel_enable (tx_chan );
2428 for (;;) {
2529 size_t bwritten ;
26- memset (buf , 0 , 128 * 2 );
27- mixer_callback (globals .pc , (uint8_t * ) buf , 128 * 2 );
28- for (int i = 0 ; i < 128 ; i ++ ) {
30+ memset (buf , 0 , MIXER_BUF_LEN * 2 );
31+ mixer_callback (globals .pc , (uint8_t * ) buf , MIXER_BUF_LEN * 2 );
32+ for (int i = 0 ; i < MIXER_BUF_LEN ; i ++ ) {
2933 buf [i ] = buf [i ] / 16 ;
3034 }
31- i2s_channel_write (tx_chan , buf , 128 * 2 , & bwritten , portMAX_DELAY );
35+ i2s_channel_write (tx_chan , buf , MIXER_BUF_LEN * 2 , & bwritten , portMAX_DELAY );
3236 }
3337 i2s_channel_disable (tx_chan );
3438}
3539
40+ #ifndef I2S_NUM
41+ #define I2S_NUM I2S_NUM_AUTO
42+ #endif
43+
44+ #ifdef USE_ES8311
45+ // adapted from: examples/peripherals/i2s/i2s_codec/i2s_es8311/main/i2s_es8311_example.c
46+ static i2s_chan_handle_t rx_chan ; // I2S rx channel handler (not used)
47+ #include "esp_log.h"
48+ #include "driver/i2c_master.h"
49+ #include "esp_codec_dev_defaults.h"
50+ #include "esp_codec_dev.h"
51+ #include "esp_codec_dev_vol.h"
52+ static const char * TAG = "i2s" ;
53+
54+ static esp_err_t es8311_codec_init (void )
55+ {
56+ /* Initialize I2C peripheral */
57+ i2c_master_bus_handle_t i2c_bus_handle = NULL ;
58+ i2c_master_bus_config_t i2c_mst_cfg = {
59+ .i2c_port = ES8311_I2C_NUM ,
60+ .sda_io_num = ES8311_I2C_SDA ,
61+ .scl_io_num = ES8311_I2C_SCL ,
62+ .clk_source = I2C_CLK_SRC_DEFAULT ,
63+ .glitch_ignore_cnt = 7 ,
64+ /* Pull-up internally for no external pull-up case.
65+ Suggest to use external pull-up to ensure a strong enough pull-up. */
66+ .flags .enable_internal_pullup = true,
67+ };
68+ ESP_ERROR_CHECK (i2c_new_master_bus (& i2c_mst_cfg , & i2c_bus_handle ));
69+
70+ /* Create control interface with I2C bus handle */
71+ audio_codec_i2c_cfg_t i2c_cfg = {
72+ .port = ES8311_I2C_NUM ,
73+ .addr = ES8311_CODEC_DEFAULT_ADDR ,
74+ .bus_handle = i2c_bus_handle ,
75+ };
76+ const audio_codec_ctrl_if_t * ctrl_if = audio_codec_new_i2c_ctrl (& i2c_cfg );
77+ assert (ctrl_if );
78+
79+ /* Create data interface with I2S bus handle */
80+ audio_codec_i2s_cfg_t i2s_cfg = {
81+ .port = I2S_NUM ,
82+ .rx_handle = rx_chan ,
83+ .tx_handle = tx_chan ,
84+ };
85+ const audio_codec_data_if_t * data_if = audio_codec_new_i2s_data (& i2s_cfg );
86+ assert (data_if );
87+
88+ /* Create ES8311 interface handle */
89+ const audio_codec_gpio_if_t * gpio_if = audio_codec_new_gpio ();
90+ assert (gpio_if );
91+ es8311_codec_cfg_t es8311_cfg = {
92+ .ctrl_if = ctrl_if ,
93+ .gpio_if = gpio_if ,
94+ .codec_mode = ESP_CODEC_DEV_WORK_MODE_BOTH ,
95+ .master_mode = false,
96+ .use_mclk = I2S_MCLK >= 0 ,
97+ .pa_pin = ES8311_PA ,
98+ .pa_reverted = false,
99+ .hw_gain = {
100+ .pa_voltage = 5.0 ,
101+ .codec_dac_voltage = 3.3 ,
102+ },
103+ //.mclk_div = EXAMPLE_MCLK_MULTIPLE,
104+ };
105+ const audio_codec_if_t * es8311_if = es8311_codec_new (& es8311_cfg );
106+ assert (es8311_if );
107+
108+ /* Create the top codec handle with ES8311 interface handle and data interface */
109+ esp_codec_dev_cfg_t dev_cfg = {
110+ .dev_type = ESP_CODEC_DEV_TYPE_IN_OUT ,
111+ .codec_if = es8311_if ,
112+ .data_if = data_if ,
113+ };
114+ esp_codec_dev_handle_t codec_handle = esp_codec_dev_new (& dev_cfg );
115+ assert (codec_handle );
116+
117+ /* Specify the sample configurations and open the device */
118+ esp_codec_dev_sample_info_t sample_cfg = {
119+ .bits_per_sample = I2S_DATA_BIT_WIDTH_16BIT ,
120+ .channel = 2 ,
121+ .channel_mask = 0x03 ,
122+ .sample_rate = 44100 ,
123+ };
124+ if (esp_codec_dev_open (codec_handle , & sample_cfg ) != ESP_CODEC_DEV_OK ) {
125+ ESP_LOGE (TAG , "Open codec device failed" );
126+ return ESP_FAIL ;
127+ }
128+
129+ /* Set the initial volume and gain */
130+ if (esp_codec_dev_set_out_vol (codec_handle , 80 ) != ESP_CODEC_DEV_OK ) {
131+ ESP_LOGE (TAG , "set output volume failed" );
132+ return ESP_FAIL ;
133+ }
134+ return ESP_OK ;
135+ }
136+ #endif
137+
36138void i2s_main ()
37139{
38140#ifdef I2S_MCLK
@@ -41,9 +143,12 @@ void i2s_main()
41143 * it only requires the I2S controller id and I2S role
42144 * The tx and rx channels here are registered on different I2S controller,
43145 * Except ESP32 and ESP32-S2, others allow to register two separate tx & rx channels on a same controller */
44- i2s_chan_config_t tx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG (I2S_NUM_AUTO , I2S_ROLE_MASTER );
146+ i2s_chan_config_t tx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG (I2S_NUM , I2S_ROLE_MASTER );
147+ #ifdef USE_ES8311
148+ ESP_ERROR_CHECK (i2s_new_channel (& tx_chan_cfg , & tx_chan , & rx_chan ));
149+ #else
45150 ESP_ERROR_CHECK (i2s_new_channel (& tx_chan_cfg , & tx_chan , NULL ));
46-
151+ #endif
47152 /* Step 2: Setting the configurations of standard mode and initialize each channels one by one
48153 * The slot configuration and clock configuration can be generated by the macros
49154 * These two helper macros is defined in 'i2s_std.h' which can only be used in STD mode.
@@ -65,6 +170,9 @@ void i2s_main()
65170 },
66171 };
67172 ESP_ERROR_CHECK (i2s_channel_init_std_mode (tx_chan , & tx_std_cfg ));
173+ #ifdef USE_ES8311
174+ ESP_ERROR_CHECK (es8311_codec_init ());
175+ #endif
68176 xTaskCreatePinnedToCore (i2s_task , "i2s_task" , 4096 , NULL , 0 , NULL , 0 );
69177#endif
70178}
0 commit comments