@@ -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 ;
@@ -122,18 +123,13 @@ static esp_err_t i2s_std_set_slot(i2s_chan_handle_t handle, const i2s_std_slot_c
122123 ESP_RETURN_ON_ERROR (i2s_alloc_dma_desc (handle , buf_size ),
123124 TAG , "allocate memory for dma descriptor failed" );
124125 }
125- bool is_slave = handle -> role == I2S_ROLE_SLAVE ;
126126 /* Share bck and ws signal in full-duplex mode */
127127 if (handle -> controller -> full_duplex ) {
128128 i2s_ll_share_bck_ws (handle -> controller -> hal .dev , true);
129- /* Since bck and ws are shared, only tx or rx can be master
130- Force to set rx as slave to avoid conflict of clock signal */
131- if (handle -> dir == I2S_DIR_RX ) {
132- is_slave = true;
133- }
134129 } else {
135130 i2s_ll_share_bck_ws (handle -> controller -> hal .dev , false);
136131 }
132+ bool is_slave = handle -> role == I2S_ROLE_SLAVE ;
137133
138134 portENTER_CRITICAL (& g_i2s .spinlock );
139135 /* Configure the hardware to apply STD format */
@@ -178,43 +174,101 @@ static esp_err_t i2s_std_set_gpio(i2s_chan_handle_t handle, const i2s_std_gpio_c
178174 /* Set mclk pin */
179175 ESP_RETURN_ON_ERROR (i2s_check_set_mclk (handle , id , gpio_cfg -> mclk , std_cfg -> clk_cfg .clk_src , gpio_cfg -> invert_flags .mclk_inv ), TAG , "mclk config failed" );
180176
181- if (handle -> role == I2S_ROLE_SLAVE ) {
182- /* For "tx + slave" mode, select TX signal index for ws and bck */
183- if (handle -> dir == I2S_DIR_TX && !handle -> controller -> full_duplex ) {
184177#if SOC_I2S_HW_VERSION_2
178+ /* Bind the MCLK signal to the TX or RX clock source */
179+ if (!handle -> controller -> full_duplex ) {
180+ if (handle -> dir == I2S_DIR_TX ) {
185181 I2S_CLOCK_SRC_ATOMIC () {
186182 i2s_ll_mclk_bind_to_tx_clk (handle -> controller -> hal .dev );
187183 }
188- #endif
189- i2s_gpio_check_and_set (handle , gpio_cfg -> ws , i2s_periph_signal [id ].s_tx_ws_sig , true, gpio_cfg -> invert_flags .ws_inv );
190- i2s_gpio_check_and_set (handle , gpio_cfg -> bclk , i2s_periph_signal [id ].s_tx_bck_sig , true, gpio_cfg -> invert_flags .bclk_inv );
191- /* For "tx + rx + slave" or "rx + slave" mode, select RX signal index for ws and bck */
192184 } else {
193- i2s_gpio_check_and_set (handle , gpio_cfg -> ws , i2s_periph_signal [id ].s_rx_ws_sig , true, gpio_cfg -> invert_flags .ws_inv );
194- i2s_gpio_check_and_set (handle , gpio_cfg -> bclk , i2s_periph_signal [id ].s_rx_bck_sig , true, gpio_cfg -> invert_flags .bclk_inv );
185+ I2S_CLOCK_SRC_ATOMIC () {
186+ i2s_ll_mclk_bind_to_rx_clk (handle -> controller -> hal .dev );
187+ }
195188 }
196- } else {
197- /* For "rx + master" mode, select RX signal index for ws and bck */
198- if (handle -> dir == I2S_DIR_RX && !handle -> controller -> full_duplex ) {
199- #if SOC_I2S_HW_VERSION_2
189+ } else if (handle -> role == I2S_ROLE_MASTER ) {
190+ if (handle -> dir == I2S_DIR_TX ) {
191+ I2S_CLOCK_SRC_ATOMIC () {
192+ i2s_ll_mclk_bind_to_tx_clk (handle -> controller -> hal .dev );
193+ }
194+ } else {
200195 I2S_CLOCK_SRC_ATOMIC () {
201196 i2s_ll_mclk_bind_to_rx_clk (handle -> controller -> hal .dev );
202197 }
198+ }
199+ }
203200#endif
204- i2s_gpio_check_and_set (handle , gpio_cfg -> ws , i2s_periph_signal [id ].m_rx_ws_sig , false, gpio_cfg -> invert_flags .ws_inv );
205- i2s_gpio_check_and_set (handle , gpio_cfg -> bclk , i2s_periph_signal [id ].m_rx_bck_sig , false, gpio_cfg -> invert_flags .bclk_inv );
206- /* For "tx + rx + master" or "tx + master" mode, select TX signal index for ws and bck */
201+
202+ uint32_t ws_sig = 0 ;
203+ uint32_t bck_sig = 0 ;
204+ bool is_input = handle -> role == I2S_ROLE_SLAVE ;
205+ if (handle -> role == I2S_ROLE_SLAVE ) {
206+ // Assign slave signals
207+ if (handle -> dir == I2S_DIR_TX ) {
208+ ws_sig = i2s_periph_signal [id ].s_tx_ws_sig ;
209+ bck_sig = i2s_periph_signal [id ].s_tx_bck_sig ;
210+ } else {
211+ ws_sig = i2s_periph_signal [id ].s_rx_ws_sig ;
212+ bck_sig = i2s_periph_signal [id ].s_rx_bck_sig ;
213+ }
214+ } else {
215+ // Assign master signals
216+ if (handle -> dir == I2S_DIR_TX ) {
217+ ws_sig = i2s_periph_signal [id ].m_tx_ws_sig ;
218+ bck_sig = i2s_periph_signal [id ].m_tx_bck_sig ;
207219 } else {
208- i2s_gpio_check_and_set ( handle , gpio_cfg -> ws , i2s_periph_signal [id ].m_tx_ws_sig , false, gpio_cfg -> invert_flags . ws_inv ) ;
209- i2s_gpio_check_and_set ( handle , gpio_cfg -> bclk , i2s_periph_signal [id ].m_tx_bck_sig , false, gpio_cfg -> invert_flags . bclk_inv ) ;
220+ ws_sig = i2s_periph_signal [id ].m_rx_ws_sig ;
221+ bck_sig = i2s_periph_signal [id ].m_rx_bck_sig ;
210222 }
211223 }
224+ i2s_gpio_check_and_set (handle , gpio_cfg -> ws , ws_sig , is_input , gpio_cfg -> invert_flags .ws_inv );
225+ i2s_gpio_check_and_set (handle , gpio_cfg -> bclk , bck_sig , is_input , gpio_cfg -> invert_flags .bclk_inv );
226+
212227 /* Update the mode info: gpio configuration */
213228 memcpy (& (std_cfg -> gpio_cfg ), gpio_cfg , sizeof (i2s_std_gpio_config_t ));
214229
215230 return ESP_OK ;
216231}
217232
233+ static esp_err_t s_i2s_channel_try_to_constitude_std_duplex (i2s_chan_handle_t handle , const i2s_std_config_t * std_cfg )
234+ {
235+ /* Get another direction handle */
236+ i2s_chan_handle_t another_handle = handle -> dir == I2S_DIR_RX ? handle -> controller -> tx_chan : handle -> controller -> rx_chan ;
237+ /* Condition: 1. Another direction channel is registered
238+ * 2. Not a full-duplex channel yet
239+ * 3. Another channel is initialized, try to compare the configurations */
240+ if (another_handle && another_handle -> state >= I2S_CHAN_STATE_READY ) {
241+ /* Judge if the two channels can constitute full-duplex */
242+ if (!handle -> controller -> full_duplex ) {
243+ i2s_std_config_t curr_cfg = * std_cfg ;
244+ /* Override the slot bit width to the actual slot bit width */
245+ curr_cfg .slot_cfg .slot_bit_width = (int )curr_cfg .slot_cfg .slot_bit_width < (int )curr_cfg .slot_cfg .data_bit_width ?
246+ curr_cfg .slot_cfg .data_bit_width : curr_cfg .slot_cfg .slot_bit_width ;
247+ /* Compare the hardware configurations of the two channels, constitute the full-duplex if they are the same */
248+ if (memcmp (another_handle -> mode_info , & curr_cfg , sizeof (i2s_std_config_t )) == 0 ) {
249+ handle -> controller -> full_duplex = true;
250+ ESP_LOGD (TAG , "Constitude full-duplex on port %d" , handle -> controller -> id );
251+ }
252+ #if SOC_I2S_HW_VERSION_1
253+ else {
254+ ESP_LOGE (TAG , "Can't set different channel configurations on a same port" );
255+ return ESP_ERR_INVALID_ARG ;
256+ }
257+ #endif
258+ }
259+ /* Switch to the slave role if needed */
260+ if (handle -> controller -> full_duplex &&
261+ handle -> role == I2S_ROLE_MASTER &&
262+ another_handle -> role == I2S_ROLE_MASTER ) {
263+ /* The later initialized channel must be slave for full duplex */
264+ handle -> role = I2S_ROLE_SLAVE ;
265+ handle -> full_duplex_slave = true;
266+ }
267+ }
268+
269+ return ESP_OK ;
270+ }
271+
218272esp_err_t i2s_channel_init_std_mode (i2s_chan_handle_t handle , const i2s_std_config_t * std_cfg )
219273{
220274#if CONFIG_I2S_ENABLE_DEBUG_LOG
@@ -232,6 +286,11 @@ esp_err_t i2s_channel_init_std_mode(i2s_chan_handle_t handle, const i2s_std_conf
232286 handle -> mode_info = calloc (1 , sizeof (i2s_std_config_t ));
233287 ESP_GOTO_ON_FALSE (handle -> mode_info , ESP_ERR_NO_MEM , err , TAG , "no memory for storing the configurations" );
234288 ESP_GOTO_ON_FALSE (handle -> state == I2S_CHAN_STATE_REGISTER , ESP_ERR_INVALID_STATE , err , TAG , "the channel has initialized already" );
289+ /* Try to constitute full-duplex mode if the STD configuration is totally same as another channel */
290+ ret = s_i2s_channel_try_to_constitude_std_duplex (handle , std_cfg );
291+ #if SOC_I2S_HW_VERSION_1
292+ ESP_GOTO_ON_ERROR (ret , err , TAG , "Failed to constitute full-duplex mode" );
293+ #endif
235294 /* i2s_set_std_slot should be called before i2s_set_std_clock while initializing, because clock is relay on the slot */
236295 ESP_GOTO_ON_ERROR (i2s_std_set_slot (handle , & std_cfg -> slot_cfg ), err , TAG , "initialize channel failed while setting slot" );
237296#if SOC_I2S_SUPPORTS_APLL
0 commit comments