i2s: fix bug of switching mono/stereo mode by 'i2s_set_clk' on c3/s3

pull/8525/head
laokaiyao 2022-01-18 15:51:50 +08:00 zatwierdzone przez Kevin (Lao Kaiyao)
rodzic eff03cbbd9
commit 86d78c1592
3 zmienionych plików z 52 dodań i 37 usunięć

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

@ -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<<total_chan_num).
// For TX module, only the activated channel send the audio data, the unactivated channel send a constant(configurable) or will be skiped if 'skip_msk' is set.
// For RX module, only receive the audio data in activated channels, the data in unactivated channels will be ignored.
// the bit map of activated channel can not exceed the maximum enabled channel number (i.e. 0x10000 << total_chan_num).
// e.g: active_chan_mask = (I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH3), here the active_chan_number is 2 and total_chan_num is not supposed to be smaller than 4.
I2S_TDM_ACTIVE_CH0 = (0x1 << 0), /*!< I2S channel 0 enabled */
I2S_TDM_ACTIVE_CH1 = (0x1 << 1), /*!< I2S channel 1 enabled */
I2S_TDM_ACTIVE_CH2 = (0x1 << 2), /*!< I2S channel 2 enabled */
I2S_TDM_ACTIVE_CH3 = (0x1 << 3), /*!< I2S channel 3 enabled */
I2S_TDM_ACTIVE_CH4 = (0x1 << 4), /*!< I2S channel 4 enabled */
I2S_TDM_ACTIVE_CH5 = (0x1 << 5), /*!< I2S channel 5 enabled */
I2S_TDM_ACTIVE_CH6 = (0x1 << 6), /*!< I2S channel 6 enabled */
I2S_TDM_ACTIVE_CH7 = (0x1 << 7), /*!< I2S channel 7 enabled */
I2S_TDM_ACTIVE_CH8 = (0x1 << 8), /*!< I2S channel 8 enabled */
I2S_TDM_ACTIVE_CH9 = (0x1 << 9), /*!< I2S channel 9 enabled */
I2S_TDM_ACTIVE_CH10 = (0x1 << 10), /*!< I2S channel 10 enabled */
I2S_TDM_ACTIVE_CH11 = (0x1 << 11), /*!< I2S channel 11 enabled */
I2S_TDM_ACTIVE_CH12 = (0x1 << 12), /*!< I2S channel 12 enabled */
I2S_TDM_ACTIVE_CH13 = (0x1 << 13), /*!< I2S channel 13 enabled */
I2S_TDM_ACTIVE_CH14 = (0x1 << 14), /*!< I2S channel 14 enabled */
I2S_TDM_ACTIVE_CH15 = (0x1 << 15), /*!< I2S channel 15 enabled */
I2S_TDM_ACTIVE_CH0 = (0x1 << 16), /*!< I2S channel 0 activated */
I2S_TDM_ACTIVE_CH1 = (0x1 << 17), /*!< I2S channel 1 activated */
I2S_TDM_ACTIVE_CH2 = (0x1 << 18), /*!< I2S channel 2 activated */
I2S_TDM_ACTIVE_CH3 = (0x1 << 19), /*!< I2S channel 3 activated */
I2S_TDM_ACTIVE_CH4 = (0x1 << 20), /*!< I2S channel 4 activated */
I2S_TDM_ACTIVE_CH5 = (0x1 << 21), /*!< I2S channel 5 activated */
I2S_TDM_ACTIVE_CH6 = (0x1 << 22), /*!< I2S channel 6 activated */
I2S_TDM_ACTIVE_CH7 = (0x1 << 23), /*!< I2S channel 7 activated */
I2S_TDM_ACTIVE_CH8 = (0x1 << 24), /*!< I2S channel 8 activated */
I2S_TDM_ACTIVE_CH9 = (0x1 << 25), /*!< I2S channel 9 activated */
I2S_TDM_ACTIVE_CH10 = (0x1 << 26), /*!< I2S channel 10 activated */
I2S_TDM_ACTIVE_CH11 = (0x1 << 27), /*!< I2S channel 11 activated */
I2S_TDM_ACTIVE_CH12 = (0x1 << 28), /*!< I2S channel 12 activated */
I2S_TDM_ACTIVE_CH13 = (0x1 << 29), /*!< I2S channel 13 activated */
I2S_TDM_ACTIVE_CH14 = (0x1 << 30), /*!< I2S channel 14 activated */
I2S_TDM_ACTIVE_CH15 = (0x1 << 31), /*!< I2S channel 15 activated */
#endif
} i2s_channel_t;