11/*
2- * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
2+ * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
33 *
44 * SPDX-License-Identifier: Apache-2.0
55 */
@@ -33,9 +33,10 @@ static esp_err_t i2s_std_calculate_clock(i2s_chan_handle_t handle, const i2s_std
3333 uint32_t slot_bits = (slot_cfg -> slot_bit_width == I2S_SLOT_BIT_WIDTH_AUTO ) ||
3434 ((int )slot_cfg -> slot_bit_width < (int )slot_cfg -> data_bit_width ) ?
3535 slot_cfg -> data_bit_width : slot_cfg -> slot_bit_width ;
36+ slot_cfg -> slot_bit_width = slot_bits ;
3637 /* Calculate multiple
3738 * Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a) */
38- if (handle -> role == I2S_ROLE_MASTER ) {
39+ if (handle -> role == I2S_ROLE_MASTER || handle -> full_duplex_slave ) {
3940 clk_info -> bclk = rate * handle -> total_slot * slot_bits ;
4041 clk_info -> mclk = rate * clk_cfg -> mclk_multiple ;
4142 clk_info -> bclk_div = clk_info -> mclk / clk_info -> bclk ;
@@ -99,18 +100,13 @@ static esp_err_t i2s_std_set_slot(i2s_chan_handle_t handle, const i2s_std_slot_c
99100 ESP_RETURN_ON_ERROR (i2s_alloc_dma_desc (handle , buf_size ),
100101 TAG , "allocate memory for dma descriptor failed" );
101102 }
102- bool is_slave = handle -> role == I2S_ROLE_SLAVE ;
103103 /* Share bck and ws signal in full-duplex mode */
104104 if (handle -> controller -> full_duplex ) {
105105 i2s_ll_share_bck_ws (handle -> controller -> hal .dev , true);
106- /* Since bck and ws are shared, only tx or rx can be master
107- Force to set rx as slave to avoid conflict of clock signal */
108- if (handle -> dir == I2S_DIR_RX ) {
109- is_slave = true;
110- }
111106 } else {
112107 i2s_ll_share_bck_ws (handle -> controller -> hal .dev , false);
113108 }
109+ bool is_slave = handle -> role == I2S_ROLE_SLAVE ;
114110
115111 portENTER_CRITICAL (& g_i2s .spinlock );
116112 /* Configure the hardware to apply STD format */
@@ -154,46 +150,96 @@ static esp_err_t i2s_std_set_gpio(i2s_chan_handle_t handle, const i2s_std_gpio_c
154150 i2s_gpio_check_and_set (gpio_cfg -> din , i2s_periph_signal [id ].data_in_sig , true, false);
155151 }
156152
157- if ( handle -> role == I2S_ROLE_SLAVE ) {
158- /* For "tx + slave" mode, select TX signal index for ws and bck */
159- if ( handle -> dir == I2S_DIR_TX && ! handle -> controller -> full_duplex ) {
153+ /* Set mclk pin */
154+ ESP_RETURN_ON_ERROR ( i2s_check_set_mclk ( id , gpio_cfg -> mclk , std_cfg -> clk_cfg . clk_src , gpio_cfg -> invert_flags . mclk_inv ), TAG , "mclk config failed" );
155+
160156#if SOC_I2S_HW_VERSION_2
157+ /* Bind the MCLK signal to the TX or RX clock source */
158+ if (!handle -> controller -> full_duplex ) {
159+ if (handle -> dir == I2S_DIR_TX ) {
161160 i2s_ll_mclk_bind_to_tx_clk (handle -> controller -> hal .dev );
162- #endif
163- i2s_gpio_check_and_set (gpio_cfg -> ws , i2s_periph_signal [id ].s_tx_ws_sig , true, gpio_cfg -> invert_flags .ws_inv );
164- i2s_gpio_check_and_set (gpio_cfg -> bclk , i2s_periph_signal [id ].s_tx_bck_sig , true, gpio_cfg -> invert_flags .bclk_inv );
165- /* For "tx + rx + slave" or "rx + slave" mode, select RX signal index for ws and bck */
166161 } else {
167- i2s_gpio_check_and_set (gpio_cfg -> ws , i2s_periph_signal [id ].s_rx_ws_sig , true, gpio_cfg -> invert_flags .ws_inv );
168- i2s_gpio_check_and_set (gpio_cfg -> bclk , i2s_periph_signal [id ].s_rx_bck_sig , true, gpio_cfg -> invert_flags .bclk_inv );
162+ i2s_ll_mclk_bind_to_rx_clk (handle -> controller -> hal .dev );
169163 }
170- } else {
171- /* mclk only available in master mode */
172- #if SOC_I2S_SUPPORTS_APLL
173- bool is_apll = std_cfg -> clk_cfg .clk_src == I2S_CLK_SRC_APLL ;
174- #else
175- bool is_apll = false;
176- #endif
177- ESP_RETURN_ON_ERROR (i2s_check_set_mclk (id , gpio_cfg -> mclk , is_apll , gpio_cfg -> invert_flags .mclk_inv ), TAG , "mclk config failed" );
178- /* For "rx + master" mode, select RX signal index for ws and bck */
179- if (handle -> dir == I2S_DIR_RX && !handle -> controller -> full_duplex ) {
180- #if SOC_I2S_HW_VERSION_2
164+ } else if (handle -> role == I2S_ROLE_MASTER ) {
165+ if (handle -> dir == I2S_DIR_TX ) {
166+ i2s_ll_mclk_bind_to_tx_clk (handle -> controller -> hal .dev );
167+ } else {
181168 i2s_ll_mclk_bind_to_rx_clk (handle -> controller -> hal .dev );
169+ }
170+ }
182171#endif
183- i2s_gpio_check_and_set (gpio_cfg -> ws , i2s_periph_signal [id ].m_rx_ws_sig , false, gpio_cfg -> invert_flags .ws_inv );
184- i2s_gpio_check_and_set (gpio_cfg -> bclk , i2s_periph_signal [id ].m_rx_bck_sig , false, gpio_cfg -> invert_flags .bclk_inv );
185- /* For "tx + rx + master" or "tx + master" mode, select TX signal index for ws and bck */
172+
173+ uint32_t ws_sig = 0 ;
174+ uint32_t bck_sig = 0 ;
175+ bool is_input = handle -> role == I2S_ROLE_SLAVE ;
176+ if (handle -> role == I2S_ROLE_SLAVE ) {
177+ // Assign slave signals
178+ if (handle -> dir == I2S_DIR_TX ) {
179+ ws_sig = i2s_periph_signal [id ].s_tx_ws_sig ;
180+ bck_sig = i2s_periph_signal [id ].s_tx_bck_sig ;
186181 } else {
187- i2s_gpio_check_and_set (gpio_cfg -> ws , i2s_periph_signal [id ].m_tx_ws_sig , false, gpio_cfg -> invert_flags .ws_inv );
188- i2s_gpio_check_and_set (gpio_cfg -> bclk , i2s_periph_signal [id ].m_tx_bck_sig , false, gpio_cfg -> invert_flags .bclk_inv );
182+ ws_sig = i2s_periph_signal [id ].s_rx_ws_sig ;
183+ bck_sig = i2s_periph_signal [id ].s_rx_bck_sig ;
184+ }
185+ } else {
186+ // Assign master signals
187+ if (handle -> dir == I2S_DIR_TX ) {
188+ ws_sig = i2s_periph_signal [id ].m_tx_ws_sig ;
189+ bck_sig = i2s_periph_signal [id ].m_tx_bck_sig ;
190+ } else {
191+ ws_sig = i2s_periph_signal [id ].m_rx_ws_sig ;
192+ bck_sig = i2s_periph_signal [id ].m_rx_bck_sig ;
189193 }
190194 }
195+ i2s_gpio_check_and_set (gpio_cfg -> ws , ws_sig , is_input , gpio_cfg -> invert_flags .ws_inv );
196+ i2s_gpio_check_and_set (gpio_cfg -> bclk , bck_sig , is_input , gpio_cfg -> invert_flags .bclk_inv );
197+
191198 /* Update the mode info: gpio configuration */
192199 memcpy (& (std_cfg -> gpio_cfg ), gpio_cfg , sizeof (i2s_std_gpio_config_t ));
193200
194201 return ESP_OK ;
195202}
196203
204+ static esp_err_t s_i2s_channel_try_to_constitude_std_duplex (i2s_chan_handle_t handle , const i2s_std_config_t * std_cfg )
205+ {
206+ /* Get another direction handle */
207+ i2s_chan_handle_t another_handle = handle -> dir == I2S_DIR_RX ? handle -> controller -> tx_chan : handle -> controller -> rx_chan ;
208+ /* Condition: 1. Another direction channel is registered
209+ * 2. Not a full-duplex channel yet
210+ * 3. Another channel is initialized, try to compare the configurations */
211+ if (another_handle && another_handle -> state >= I2S_CHAN_STATE_READY ) {
212+ /* Judge if the two channels can constitute full-duplex */
213+ if (!handle -> controller -> full_duplex ) {
214+ i2s_std_config_t curr_cfg = * std_cfg ;
215+ /* Override the slot bit width to the actual slot bit width */
216+ curr_cfg .slot_cfg .slot_bit_width = (int )curr_cfg .slot_cfg .slot_bit_width < (int )curr_cfg .slot_cfg .data_bit_width ?
217+ curr_cfg .slot_cfg .data_bit_width : curr_cfg .slot_cfg .slot_bit_width ;
218+ /* Compare the hardware configurations of the two channels, constitute the full-duplex if they are the same */
219+ if (memcmp (another_handle -> mode_info , & curr_cfg , sizeof (i2s_std_config_t )) == 0 ) {
220+ handle -> controller -> full_duplex = true;
221+ ESP_LOGD (TAG , "Constitude full-duplex on port %d" , handle -> controller -> id );
222+ }
223+ #if SOC_I2S_HW_VERSION_1
224+ else {
225+ ESP_LOGE (TAG , "Can't set different channel configurations on a same port" );
226+ return ESP_ERR_INVALID_ARG ;
227+ }
228+ #endif
229+ }
230+ /* Switch to the slave role if needed */
231+ if (handle -> controller -> full_duplex &&
232+ handle -> role == I2S_ROLE_MASTER &&
233+ another_handle -> role == I2S_ROLE_MASTER ) {
234+ /* The later initialized channel must be slave for full duplex */
235+ handle -> role = I2S_ROLE_SLAVE ;
236+ handle -> full_duplex_slave = true;
237+ }
238+ }
239+
240+ return ESP_OK ;
241+ }
242+
197243esp_err_t i2s_channel_init_std_mode (i2s_chan_handle_t handle , const i2s_std_config_t * std_cfg )
198244{
199245#if CONFIG_I2S_ENABLE_DEBUG_LOG
@@ -211,7 +257,11 @@ esp_err_t i2s_channel_init_std_mode(i2s_chan_handle_t handle, const i2s_std_conf
211257 handle -> mode_info = calloc (1 , sizeof (i2s_std_config_t ));
212258 ESP_GOTO_ON_FALSE (handle -> mode_info , ESP_ERR_NO_MEM , err , TAG , "no memory for storing the configurations" );
213259 ESP_GOTO_ON_FALSE (handle -> state == I2S_CHAN_STATE_REGISTER , ESP_ERR_INVALID_STATE , err , TAG , "the channel has initialized already" );
214- ESP_GOTO_ON_ERROR (i2s_std_set_gpio (handle , & std_cfg -> gpio_cfg ), err , TAG , "initialize channel failed while setting gpio pins" );
260+ /* Try to constitute full-duplex mode if the STD configuration is totally same as another channel */
261+ ret = s_i2s_channel_try_to_constitude_std_duplex (handle , std_cfg );
262+ #if SOC_I2S_HW_VERSION_1
263+ ESP_GOTO_ON_ERROR (ret , err , TAG , "Failed to constitute full-duplex mode" );
264+ #endif
215265 /* i2s_set_std_slot should be called before i2s_set_std_clock while initializing, because clock is relay on the slot */
216266 ESP_GOTO_ON_ERROR (i2s_std_set_slot (handle , & std_cfg -> slot_cfg ), err , TAG , "initialize channel failed while setting slot" );
217267#if SOC_I2S_SUPPORTS_APLL
@@ -222,6 +272,7 @@ esp_err_t i2s_channel_init_std_mode(i2s_chan_handle_t handle, const i2s_std_conf
222272 }
223273#endif
224274 ESP_GOTO_ON_ERROR (i2s_std_set_clock (handle , & std_cfg -> clk_cfg ), err , TAG , "initialize channel failed while setting clock" );
275+ ESP_GOTO_ON_ERROR (i2s_std_set_gpio (handle , & std_cfg -> gpio_cfg ), err , TAG , "initialize channel failed while setting gpio pins" );
225276 ESP_GOTO_ON_ERROR (i2s_init_dma_intr (handle , I2S_INTR_ALLOC_FLAGS ), err , TAG , "initialize dma interrupt failed" );
226277#if SOC_I2S_HW_VERSION_2
227278 /* Enable clock to start outputting mclk signal. Some codecs will reset once mclk stop */
0 commit comments