From 86d78c15924718fd3e9e5395b287908c0ec9279b Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Tue, 18 Jan 2022 15:51:50 +0800 Subject: [PATCH] i2s: fix bug of switching mono/stereo mode by 'i2s_set_clk' on c3/s3 --- components/driver/i2s.c | 41 ++++++++++++++++-------- components/hal/i2s_hal.c | 4 +-- components/hal/include/hal/i2s_types.h | 44 +++++++++++++------------- 3 files changed, 52 insertions(+), 37 deletions(-) diff --git a/components/driver/i2s.c b/components/driver/i2s.c index 14ec904575..a9bff9f013 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -1213,7 +1213,7 @@ static esp_err_t i2s_calculate_clock(i2s_port_t i2s_num, i2s_hal_clock_cfg_t *cl static uint32_t i2s_get_max_channel_num(i2s_channel_t chan_mask) { uint32_t max_chan = 0; - uint32_t channel = chan_mask & 0xFFFF; + uint32_t channel = chan_mask >> 16; for (int i = 0; channel && i < 16; i++, channel >>= 1) { if (channel & 0x01) { max_chan = i + 1; @@ -1246,7 +1246,7 @@ static uint32_t i2s_get_active_channel_num(const i2s_hal_config_t *hal_cfg) #if SOC_I2S_SUPPORTS_TDM case I2S_CHANNEL_FMT_MULTIPLE: { uint32_t num = 0; - uint32_t chan_mask = hal_cfg->chan_mask & 0xFFFF; + uint32_t chan_mask = hal_cfg->chan_mask >> 16; for (int i = 0; chan_mask && i < 16; i++, chan_mask >>= 1) { if (chan_mask & 0x01) { num++; @@ -1566,18 +1566,36 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ ESP_RETURN_ON_FALSE(p_i2s[i2s_num], ESP_ERR_INVALID_ARG, TAG, "I2S%d has not installed yet", i2s_num); i2s_hal_config_t *cfg = &p_i2s[i2s_num]->hal_cfg; + + /* Stop I2S */ + i2s_stop(i2s_num); + /* If not the first time, update configuration */ if (p_i2s[i2s_num]->last_buf_size) { cfg->sample_rate = rate; cfg->sample_bits = bits_cfg & 0xFFFF; cfg->chan_bits = (bits_cfg >> 16) > cfg->sample_bits ? (bits_cfg >> 16) : cfg->sample_bits; #if SOC_I2S_SUPPORTS_TDM - cfg->chan_mask = ch; - cfg->chan_fmt = ch == I2S_CHANNEL_MONO ? I2S_CHANNEL_FMT_ONLY_RIGHT : cfg->chan_fmt; - cfg->active_chan = i2s_get_active_channel_num(cfg); - uint32_t max_channel = i2s_get_max_channel_num(cfg->chan_mask); - /* If total channel is smaller than max actived channel number then set it to the max active channel number */ - cfg->total_chan = p_i2s[i2s_num]->hal_cfg.total_chan < max_channel ? max_channel : p_i2s[i2s_num]->hal_cfg.total_chan; + if (ch & I2S_CHANNEL_MONO) { + cfg->chan_fmt = I2S_CHANNEL_FMT_ONLY_RIGHT; + cfg->chan_mask = I2S_TDM_ACTIVE_CH0; // Only activate one channel in mono + if (ch >> 16) { + cfg->total_chan = i2s_get_max_channel_num(ch); + } else { + cfg->total_chan = 2; + } + } else { + if (ch >> 16) { + cfg->chan_fmt = I2S_CHANNEL_FMT_MULTIPLE; + cfg->chan_mask = ch & 0xFFFF0000; + cfg->total_chan = i2s_get_max_channel_num(cfg->chan_mask); + } else { + /* If no TDM channels activated, use 2 channels as defualt */ + cfg->chan_fmt = I2S_CHANNEL_FMT_RIGHT_LEFT; + cfg->chan_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1; + cfg->total_chan = 2; + } + } #else /* Default */ cfg->chan_fmt = ch == I2S_CHANNEL_MONO ? I2S_CHANNEL_FMT_ONLY_RIGHT : cfg->chan_fmt; @@ -1601,9 +1619,6 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ ESP_RETURN_ON_FALSE((data_bits % 8 == 0), ESP_ERR_INVALID_ARG, TAG, "Invalid bits per sample"); ESP_RETURN_ON_FALSE((data_bits <= I2S_BITS_PER_SAMPLE_32BIT), ESP_ERR_INVALID_ARG, TAG, "Invalid bits per sample"); - /* Stop I2S */ - i2s_stop(i2s_num); - i2s_hal_clock_cfg_t clk_cfg; /* To get sclk, mclk, mclk_div bclk and bclk_div */ i2s_calculate_clock(i2s_num, &clk_cfg); @@ -1779,8 +1794,8 @@ static esp_err_t i2s_driver_init(i2s_port_t i2s_num, const i2s_config_t *i2s_con p_i2s[i2s_num]->hal_cfg.total_chan = 2; break; case I2S_CHANNEL_FMT_MULTIPLE: - ESP_RETURN_ON_FALSE(i2s_config->chan_mask, ESP_ERR_INVALID_ARG, TAG, "i2s all channel are disabled"); - p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->chan_mask; + ESP_RETURN_ON_FALSE((i2s_config->chan_mask >> 16), ESP_ERR_INVALID_ARG, TAG, "i2s all channel are disabled"); + p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->chan_mask & 0xFFFF0000; /* Get the max actived channel number */ uint32_t max_channel = i2s_get_max_channel_num(p_i2s[i2s_num]->hal_cfg.chan_mask); /* If total channel is smaller than max actived channel number then set it to the max active channel number */ diff --git a/components/hal/i2s_hal.c b/components/hal/i2s_hal.c index 13c7eaaca2..bd585af53b 100644 --- a/components/hal/i2s_hal.c +++ b/components/hal/i2s_hal.c @@ -172,7 +172,6 @@ void i2s_hal_tx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_config_t * i2s_ll_tx_clk_set_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default i2s_ll_mclk_use_tx_clk(hal->dev); - i2s_ll_tx_set_active_chan_mask(hal->dev, hal_cfg->chan_mask); // In TDM mode(more than 2 channels), the ws polarity should be high first. if (hal_cfg->total_chan > 2) { i2s_ll_tx_set_ws_idle_pol(hal->dev, true); @@ -198,7 +197,6 @@ void i2s_hal_rx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_config_t * i2s_ll_rx_clk_set_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default i2s_ll_mclk_use_rx_clk(hal->dev); - i2s_ll_rx_set_active_chan_mask(hal->dev, hal_cfg->chan_mask); // In TDM mode(more than 2 channels), the ws polarity should be high first. if (hal_cfg->total_chan > 2) { i2s_ll_rx_set_ws_idle_pol(hal->dev, true); @@ -238,6 +236,7 @@ void i2s_hal_tx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t /* Set channel number and valid data bits */ #if SOC_I2S_SUPPORTS_TDM chan_num = hal_cfg->total_chan; + i2s_ll_tx_set_active_chan_mask(hal->dev, hal_cfg->chan_mask >> 16); i2s_ll_tx_set_chan_num(hal->dev, chan_num); #endif i2s_ll_tx_set_sample_bit(hal->dev, chan_bits, data_bits); @@ -263,6 +262,7 @@ void i2s_hal_rx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t #if SOC_I2S_SUPPORTS_TDM chan_num = hal_cfg->total_chan; + i2s_ll_rx_set_active_chan_mask(hal->dev, hal_cfg->chan_mask >> 16); i2s_ll_rx_set_chan_num(hal->dev, chan_num); #endif i2s_ll_rx_set_sample_bit(hal->dev, chan_bits, data_bits); diff --git a/components/hal/include/hal/i2s_types.h b/components/hal/include/hal/i2s_types.h index c59220c89c..dcf0ab4d0b 100644 --- a/components/hal/include/hal/i2s_types.h +++ b/components/hal/include/hal/i2s_types.h @@ -44,31 +44,31 @@ typedef enum { * */ typedef enum { - I2S_CHANNEL_MONO = (0x01 << 31) | 0x03, /*!< I2S channel (mono), two channel enabled. In this mode, you only need to send one channel data but the fifo will copy same data for another channel automatically, then both channels will transmit same data. The highest bit is for differentiating I2S_CHANNEL_STEREO since they both use two channels */ - I2S_CHANNEL_STEREO = 0x03, /*!< I2S channel (stereo), two channel enabled. In this mode, two channels will transmit different data. */ + I2S_CHANNEL_MONO = 1, /*!< I2S channel (mono), one channel activated. In this mode, you only need to send one channel data but the fifo will copy same data for the other unactivated channels automatically, then both channels will transmit same data. */ + I2S_CHANNEL_STEREO = 2, /*!< I2S channel (stereo), two (or more) channels activated. In this mode, these channels will transmit different data. */ #if SOC_I2S_SUPPORTS_TDM - // Bit map of active chan. + // Bit map of activated chan. // There are 16 channels in TDM mode. - // For TX module, only the active channel send the audio data, the inactive channel send a constant(configurable) or will be skiped if 'skip_msk' is set. - // For RX module, only receive the audio data in active channels, the data in inactive channels will be ignored. - // the bit map of active channel can not exceed (0x1<