From 0ff3dd97780a4c779907d5494100d45eaf9f27a4 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Mon, 16 Aug 2021 13:32:22 +0800 Subject: [PATCH] i2s: fix mono support issue --- components/driver/i2s.c | 42 +++++++++++---------- components/hal/esp32c3/include/hal/i2s_ll.h | 24 ++++++++++++ components/hal/esp32h2/include/hal/i2s_ll.h | 22 +++++++++++ components/hal/esp32s3/include/hal/i2s_ll.h | 24 ++++++++++++ components/hal/i2s_hal.c | 6 +++ components/hal/include/hal/i2s_types.h | 4 +- 6 files changed, 101 insertions(+), 21 deletions(-) diff --git a/components/driver/i2s.c b/components/driver/i2s.c index b91172819b..bffea378d9 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -885,7 +885,7 @@ float i2s_apll_get_fi2s(int bits_per_sample, int sdm0, int sdm1, int sdm2, int o /** * @brief Calculate APLL parameters to get a closest frequency */ -void i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm0, int *sdm1, int *sdm2, int *odir) +static void i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm0, int *sdm1, int *sdm2, int *odir) { int _odir, _sdm0, _sdm1, _sdm2; float avg; @@ -966,11 +966,13 @@ static uint32_t i2s_get_source_clock(i2s_port_t i2s_num, bool use_apll, uint32_t int sdm1 = 0; int sdm2 = 0; int odir = 0; - if (fixed_mclk / p_i2s[i2s_num]->hal_cfg.chan_bits / 16 < SOC_I2S_APLL_MIN_RATE) { - ESP_LOGW(TAG, "i2s sample rate is too small, use I2S_CLK_D2CLK as default clock source"); + if ((fixed_mclk / p_i2s[i2s_num]->hal_cfg.chan_bits / 16) < SOC_I2S_APLL_MIN_RATE) { + ESP_LOGW(TAG, "fixed_mclk is too small, use I2S_CLK_D2CLK as default clock source"); goto err; } - ESP_LOGD(TAG, "APLL coefficient: sdm0=%d, sdm1=%d, sdm2=%d, odir=%d", sdm0, sdm1, sdm2, odir); + i2s_apll_calculate_fi2s(p_i2s[i2s_num]->hal_cfg.sample_rate, p_i2s[i2s_num]->hal_cfg.sample_bits, + &sdm0, &sdm1, &sdm2, &odir); + ESP_LOGI(TAG, "APLL Enabled, coefficient: sdm0=%d, sdm1=%d, sdm2=%d, odir=%d", sdm0, sdm1, sdm2, odir); rtc_clk_apll_enable(true, sdm0, sdm1, sdm2, odir); return fixed_mclk; } @@ -1199,7 +1201,7 @@ static uint32_t i2s_get_max_channel_num(i2s_channel_t chan_mask) uint32_t max_chan = 0; uint32_t channel = chan_mask & 0xFFFF; for (int i = 0; channel && i < 16; i++, channel >>= 1) { - if (chan_mask & 0x01) { + if (channel & 0x01) { max_chan = i + 1; } } @@ -1562,6 +1564,8 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ #if !SOC_I2S_SUPPORTS_TDM cfg->active_chan = i2s_get_active_channel_num(cfg); cfg->total_chan = ch == I2S_CHANNEL_MONO ? 2 : cfg->active_chan; + /* Default */ + cfg->chan_fmt = cfg->chan_fmt < I2S_CHANNEL_FMT_ONLY_RIGHT ? I2S_CHANNEL_FMT_ONLY_RIGHT : cfg->chan_fmt; #endif } uint32_t data_bits = cfg->sample_bits; @@ -1578,7 +1582,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ /* If uising chips like ESP32 and ESP32S2 * Only need to calculate clock for MASTER mode - * Because BCK and WS clock are provide by external codec in SLAVE mode + * Because BCK and WS clock are provided by the external codec in SLAVE mode * In SLAVE mode, the mclk_div and bck_div will be set to 1 * So that we can get a high module clock which could detect the edges of externel clock more accurately * Otherwise the data we receive or send would get a large latency and go wrong due to the slow module clock @@ -1628,7 +1632,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ /* Reset the end-of-frame number */ i2s_hal_set_rx_eof_num(&(p_i2s[i2s_num]->hal), buf_size); } - /* Reset the queue to avoid receive invalid data */ + /* Reset the queue to avoid receiving invalid data */ xQueueReset(p_i2s[i2s_num]->rx->queue); xSemaphoreGive(p_i2s[i2s_num]->rx->mux); ESP_RETURN_ON_ERROR(ret, TAG, "I2S%d rx DMA buffer malloc failed", i2s_num); @@ -1756,20 +1760,25 @@ static esp_err_t i2s_driver_init(i2s_port_t i2s_num, const i2s_config_t *i2s_con /* Set chan_mask according to channel format */ switch (i2s_config->channel_format) { - case I2S_CHANNEL_FMT_RIGHT_LEFT: - case I2S_CHANNEL_FMT_ALL_RIGHT: + case I2S_CHANNEL_FMT_RIGHT_LEFT: // fall through + case I2S_CHANNEL_FMT_ALL_RIGHT: // fall through case I2S_CHANNEL_FMT_ALL_LEFT: p_i2s[i2s_num]->hal_cfg.chan_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1; + p_i2s[i2s_num]->hal_cfg.total_chan = 2; break; - case I2S_CHANNEL_FMT_ONLY_RIGHT: - p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->left_align ? I2S_TDM_ACTIVE_CH1 : I2S_TDM_ACTIVE_CH0; - break; + case I2S_CHANNEL_FMT_ONLY_RIGHT: // fall through case I2S_CHANNEL_FMT_ONLY_LEFT: - p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->left_align ? I2S_TDM_ACTIVE_CH0 : I2S_TDM_ACTIVE_CH1; + p_i2s[i2s_num]->hal_cfg.chan_mask = I2S_TDM_ACTIVE_CH0; + 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; + /* 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 */ + p_i2s[i2s_num]->hal_cfg.total_chan = p_i2s[i2s_num]->hal_cfg.total_chan < max_channel ? max_channel : + p_i2s[i2s_num]->hal_cfg.total_chan; break; default: ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_ARG, TAG, "wrong i2s channel format, going to uninstall i2s"); @@ -1777,11 +1786,7 @@ static esp_err_t i2s_driver_init(i2s_port_t i2s_num, const i2s_config_t *i2s_con /* Calculate actived channel number in channel mask */ p_i2s[i2s_num]->hal_cfg.active_chan = i2s_get_active_channel_num(&p_i2s[i2s_num]->hal_cfg); - /* 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 */ - p_i2s[i2s_num]->hal_cfg.total_chan = p_i2s[i2s_num]->hal_cfg.total_chan < max_channel ? max_channel : - p_i2s[i2s_num]->hal_cfg.total_chan; + #else /* Calculate actived channel number in channel mask */ p_i2s[i2s_num]->hal_cfg.active_chan = i2s_get_active_channel_num(&p_i2s[i2s_num]->hal_cfg); @@ -1878,7 +1883,6 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, #if SOC_I2S_SUPPORTS_ADC_DAC /* If using built-in ADC, we need to enable ADC power manerge*/ if (p_i2s[i2s_num]->hal_cfg.mode & I2S_MODE_ADC_BUILT_IN) { - printf("ADC power on\n"); adc_power_acquire(); } #endif diff --git a/components/hal/esp32c3/include/hal/i2s_ll.h b/components/hal/esp32c3/include/hal/i2s_ll.h index 30fbfb7e51..44f9142c1a 100644 --- a/components/hal/esp32c3/include/hal/i2s_ll.h +++ b/components/hal/esp32c3/include/hal/i2s_ll.h @@ -781,6 +781,30 @@ static inline void i2s_ll_set_single_data(i2s_dev_t *hw, uint32_t data) hw->conf_single_data = data; } +/** + * @brief Enable TX mono mode + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_tx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) +{ + hw->tx_conf.tx_mono = mono_ena; + hw->tx_conf.tx_chan_equal = mono_ena; +} + +/** + * @brief Enable RX mono mode + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_rx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) +{ + hw->rx_conf.rx_mono = mono_ena; + hw->rx_conf.rx_mono_fst_vld = mono_ena; +} + /** * @brief Enable loopback mode * diff --git a/components/hal/esp32h2/include/hal/i2s_ll.h b/components/hal/esp32h2/include/hal/i2s_ll.h index 9819a8ed4b..d9c70cd130 100644 --- a/components/hal/esp32h2/include/hal/i2s_ll.h +++ b/components/hal/esp32h2/include/hal/i2s_ll.h @@ -804,6 +804,28 @@ static inline void i2s_ll_set_pdm2pcm_conv_en(i2s_dev_t *hw, bool val) } +/** + * @brief Enable TX mono mode + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_tx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) +{ + abort(); +} + +/** + * @brief Enable RX mono mode + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_rx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) +{ + abort(); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s3/include/hal/i2s_ll.h b/components/hal/esp32s3/include/hal/i2s_ll.h index 791918fae0..8f5de0f56d 100644 --- a/components/hal/esp32s3/include/hal/i2s_ll.h +++ b/components/hal/esp32s3/include/hal/i2s_ll.h @@ -806,6 +806,30 @@ static inline void i2s_ll_set_single_data(i2s_dev_t *hw, uint32_t data) hw->conf_single_data = data; } +/** + * @brief Enable TX mono mode + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_tx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) +{ + hw->tx_conf.tx_mono = mono_ena; + hw->tx_conf.tx_chan_equal = mono_ena; +} + +/** + * @brief Enable RX mono mode + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_rx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) +{ + hw->rx_conf.rx_mono = mono_ena; + hw->rx_conf.rx_mono_fst_vld = mono_ena; +} + /** * @brief Enable loopback mode * diff --git a/components/hal/i2s_hal.c b/components/hal/i2s_hal.c index 46d6936359..431a887484 100644 --- a/components/hal/i2s_hal.c +++ b/components/hal/i2s_hal.c @@ -225,6 +225,8 @@ void i2s_hal_tx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t uint32_t chan_num = 2; uint32_t chan_bits = hal_cfg->chan_bits; uint32_t data_bits = hal_cfg->sample_bits; + bool is_mono = (hal_cfg->chan_fmt == I2S_CHANNEL_FMT_ONLY_RIGHT) || + (hal_cfg->chan_fmt == I2S_CHANNEL_FMT_ONLY_LEFT); /* Set channel number and valid data bits */ #if SOC_I2S_SUPPORTS_TDM @@ -232,6 +234,7 @@ void i2s_hal_tx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t i2s_ll_tx_set_chan_num(hal->dev, chan_num); #endif i2s_ll_tx_set_sample_bit(hal->dev, chan_bits, data_bits); + i2s_ll_tx_enable_mono_mode(hal->dev, is_mono); /* Set communication format */ bool shift_en = hal_cfg->comm_fmt == I2S_COMM_FORMAT_STAND_I2S ? true : false; @@ -248,12 +251,15 @@ void i2s_hal_rx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t uint32_t chan_num = 2; uint32_t chan_bits = hal_cfg->chan_bits; uint32_t data_bits = hal_cfg->sample_bits; + bool is_mono = (hal_cfg->chan_fmt == I2S_CHANNEL_FMT_ONLY_RIGHT) || + (hal_cfg->chan_fmt == I2S_CHANNEL_FMT_ONLY_LEFT); #if SOC_I2S_SUPPORTS_TDM chan_num = hal_cfg->total_chan; i2s_ll_rx_set_chan_num(hal->dev, chan_num); #endif i2s_ll_rx_set_sample_bit(hal->dev, chan_bits, data_bits); + i2s_ll_rx_enable_mono_mode(hal->dev, is_mono); /* Set communication format */ bool shift_en = hal_cfg->comm_fmt == I2S_COMM_FORMAT_STAND_I2S ? true : false; diff --git a/components/hal/include/hal/i2s_types.h b/components/hal/include/hal/i2s_types.h index 98a2c76bdf..d22dfc5c0e 100644 --- a/components/hal/include/hal/i2s_types.h +++ b/components/hal/include/hal/i2s_types.h @@ -107,8 +107,8 @@ typedef enum { I2S_CHANNEL_FMT_RIGHT_LEFT, /*!< Separated left and right channel */ I2S_CHANNEL_FMT_ALL_RIGHT, /*!< Load right channel data in both two channels */ I2S_CHANNEL_FMT_ALL_LEFT, /*!< Load left channel data in both two channels */ - I2S_CHANNEL_FMT_ONLY_RIGHT, /*!< Only load data in right channel */ - I2S_CHANNEL_FMT_ONLY_LEFT, /*!< Only load data in left channel */ + I2S_CHANNEL_FMT_ONLY_RIGHT, /*!< Only load data in right channel (mono mode) */ + I2S_CHANNEL_FMT_ONLY_LEFT, /*!< Only load data in left channel (mono mode) */ #if SOC_I2S_SUPPORTS_TDM // Multiple channels are available with TDM feature I2S_CHANNEL_FMT_MULTIPLE, /*!< More than two channels are used */