i2s: fix mono support issue

This commit is contained in:
laokaiyao 2021-08-16 13:32:22 +08:00
parent b26da6f115
commit 0ff3dd9778
6 changed files with 101 additions and 21 deletions

View File

@ -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

View File

@ -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
*

View File

@ -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

View File

@ -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
*

View File

@ -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;

View File

@ -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 */