Merge branch 'bugfix/i2s_only_right_mode_v4.4' into 'release/v4.4'

i2s: fix only right case and mono stereo switch issue (v4.4)

See merge request espressif/esp-idf!18022
This commit is contained in:
morris 2022-05-07 22:46:45 +08:00
commit b021055190
5 changed files with 196 additions and 43 deletions

View File

@ -100,8 +100,9 @@ typedef struct {
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_handle_t pm_lock;
#endif
i2s_hal_context_t hal; /*!< I2S hal context*/
i2s_hal_config_t hal_cfg; /*!< I2S hal configurations*/
i2s_hal_context_t hal; /*!< I2S hal context*/
i2s_channel_fmt_t init_chan_fmt; /*!< The initial channel format while installing, used for keep left or right mono when switch between mono and stereo */
i2s_hal_config_t hal_cfg; /*!< I2S hal configurations*/
} i2s_obj_t;
static i2s_obj_t *p_i2s[SOC_I2S_NUM];
@ -1577,11 +1578,18 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_
cfg->chan_bits = (bits_cfg >> 16) > cfg->sample_bits ? (bits_cfg >> 16) : cfg->sample_bits;
#if SOC_I2S_SUPPORTS_TDM
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->chan_fmt = I2S_CHANNEL_FMT_MULTIPLE;
cfg->chan_mask = 1 << __builtin_ctz(ch & 0xFFFF0000); // mono the minimun actived slot
cfg->total_chan = i2s_get_max_channel_num(ch);
} else {
if (p_i2s[i2s_num]->init_chan_fmt == I2S_CHANNEL_FMT_ONLY_LEFT) {
cfg->chan_mask = I2S_TDM_ACTIVE_CH1; // left slot mono
cfg->chan_fmt = I2S_CHANNEL_FMT_ONLY_LEFT;
} else {
cfg->chan_mask = I2S_TDM_ACTIVE_CH0; // right slot mono
cfg->chan_fmt = I2S_CHANNEL_FMT_ONLY_RIGHT;
}
cfg->total_chan = 2;
}
} else {
@ -1598,7 +1606,15 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_
}
#else
/* Default */
cfg->chan_fmt = ch == I2S_CHANNEL_MONO ? I2S_CHANNEL_FMT_ONLY_RIGHT : cfg->chan_fmt;
if (ch & I2S_CHANNEL_MONO) {
if (p_i2s[i2s_num]->init_chan_fmt == I2S_CHANNEL_FMT_ONLY_LEFT) {
cfg->chan_fmt = I2S_CHANNEL_FMT_ONLY_LEFT;
} else {
cfg->chan_fmt = I2S_CHANNEL_FMT_ONLY_RIGHT;
}
} else {
cfg->chan_fmt = I2S_CHANNEL_FMT_RIGHT_LEFT;
}
cfg->active_chan = i2s_get_active_channel_num(cfg);
cfg->total_chan = 2;
#endif
@ -1763,6 +1779,7 @@ static esp_err_t i2s_driver_init(i2s_port_t i2s_num, const i2s_config_t *i2s_con
p_i2s[i2s_num]->fixed_mclk = i2s_config->fixed_mclk;
p_i2s[i2s_num]->mclk_multiple = i2s_config->mclk_multiple;
p_i2s[i2s_num]->tx_desc_auto_clear = i2s_config->tx_desc_auto_clear;
p_i2s[i2s_num]->init_chan_fmt = i2s_config->channel_format;
/* I2S HAL configuration assignment */
p_i2s[i2s_num]->hal_cfg.mode = i2s_config->mode;
@ -1788,7 +1805,10 @@ static esp_err_t i2s_driver_init(i2s_port_t i2s_num, const i2s_config_t *i2s_con
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: // fall through
case I2S_CHANNEL_FMT_ONLY_RIGHT:
p_i2s[i2s_num]->hal_cfg.chan_mask = I2S_TDM_ACTIVE_CH1;
p_i2s[i2s_num]->hal_cfg.total_chan = 2;
break;
case I2S_CHANNEL_FMT_ONLY_LEFT:
p_i2s[i2s_num]->hal_cfg.chan_mask = I2S_TDM_ACTIVE_CH0;
p_i2s[i2s_num]->hal_cfg.total_chan = 2;

View File

@ -17,6 +17,7 @@
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/i2s.h"
#include "hal/i2s_hal.h"
#include "driver/gpio.h"
#include "hal/gpio_hal.h"
#include "unity.h"
@ -181,15 +182,24 @@ TEST_CASE("I2S basic driver install, uninstall, set pin test", "[i2s]")
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, i2s_driver_uninstall(I2S_NUM_0));
}
TEST_CASE("I2S Loopback test(master tx and rx)", "[i2s]")
/**
* @brief Test mono and stereo mode of I2S by loopback
* @note Only rx channel distinguish left mono and right mono, tx channel does not
* @note 1. Check switch mono/stereo by 'i2s_set_clk'
* 2. Check rx right mono and left mono (requiring tx works in stereo mode)
* 3. Check tx mono (requiring rx works in stereo mode)
*/
TEST_CASE("I2S_mono_stereo_loopback_test", "[i2s]")
{
#define WRITE_BUF_LEN 2000
#define READ_BUF_LEN 4000
// master driver installed and send data
i2s_config_t master_i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX,
.sample_rate = SAMPLE_RATE,
.bits_per_sample = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
.communication_format = I2S_COMM_FORMAT_STAND_MSB,
.dma_buf_count = 6,
.dma_buf_len = 100,
.use_apll = 0,
@ -210,47 +220,148 @@ TEST_CASE("I2S Loopback test(master tx and rx)", "[i2s]")
.data_out_num = DATA_OUT_IO,
.data_in_num = DATA_IN_IO
};
/* Install I2S in duplex mode */
TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &master_i2s_config, 0, NULL));
TEST_ESP_OK(i2s_stop(I2S_NUM_0));
/* Config TX as stereo channel directly, because legacy driver can't support config tx&rx separately */
#if !SOC_I2S_SUPPORTS_TDM
i2s_ll_tx_set_chan_mod(&I2S0, 0);
#else
i2s_ll_tx_set_active_chan_mask(&I2S0, 0x03);
#endif
i2s_ll_tx_enable_mono_mode(&I2S0, false);
TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &master_pin_config));
i2s_test_io_config(I2S_TEST_MODE_LOOPBACK);
printf("\r\nheap size: %d\n", esp_get_free_heap_size());
uint8_t *data_wr = (uint8_t *)malloc(sizeof(uint8_t) * 400);
size_t i2s_bytes_write = 0;
size_t bytes_read = 0;
int length = 0;
uint8_t *i2s_read_buff = (uint8_t *)malloc(sizeof(uint8_t) * 10000);
TEST_ESP_OK(i2s_start(I2S_NUM_0));
for (int i = 0; i < 100; i++) {
data_wr[i] = i + 1;
uint16_t *w_buf = calloc(1, WRITE_BUF_LEN);
uint16_t *r_buf = calloc(1, READ_BUF_LEN);
size_t w_bytes = 0;
size_t r_bytes = 0;
for (int n = 0; n < WRITE_BUF_LEN / 2; n++) {
w_buf[n] = n%100;
}
int flag = 0; // break loop flag
int end_position = 0;
// write data to slave
i2s_write(I2S_NUM_0, data_wr, sizeof(uint8_t) * 400, &i2s_bytes_write, 1000 / portTICK_PERIOD_MS);
while (!flag) {
if (length >= 10000 - 500) {
/* rx right mono test
* tx format: 0x00[L] 0x01[R] 0x02[L] 0x03[R] ...
* rx receive: 0x01[R] 0x03[R] ... */
TEST_ESP_OK(i2s_write(I2S_NUM_0, w_buf, WRITE_BUF_LEN, &w_bytes, portMAX_DELAY));
TEST_ESP_OK(i2s_read(I2S_NUM_0, r_buf, READ_BUF_LEN, &r_bytes, portMAX_DELAY));
#if CONFIG_IDF_TARGET_ESP32
/* The data of tx/rx channels are flipped on ESP32 */
for (int n = 0; n < READ_BUF_LEN / 2; n += 2) {
int16_t temp = r_buf[n];
r_buf[n] = r_buf[n+1];
r_buf[n+1] = temp;
}
#endif
int i = 0;
for (i = 0; (i < READ_BUF_LEN / 2); i++) {
if (r_buf[i] == 1) {
printf("%d %d %d %d\n%d %d %d %d\n",
r_buf[i], r_buf[i+1], r_buf[i+2], r_buf[i+3],
r_buf[i+4], r_buf[i+5], r_buf[i+6], r_buf[i+7]);
break;
}
i2s_read(I2S_NUM_0, i2s_read_buff + length, sizeof(uint8_t) * 500, &bytes_read, 1000 / portMAX_DELAY);
if (bytes_read > 0) {
for (int i = length; i < length + bytes_read; i++) {
if (i2s_read_buff[i] == 100) {
flag = 1;
end_position = i;
break;
}
}
}
printf("Data start index: %d\n", i);
TEST_ASSERT(i < READ_BUF_LEN / 2 - 50);
for (int16_t j = 1; j < 100; j += 2) {
TEST_ASSERT_EQUAL_INT16(r_buf[i++], j);
}
printf("rx right mono test passed\n");
/* tx/rx stereo test
* tx format: 0x00[L] 0x01[R] 0x02[L] 0x03[R] ...
* rx receive: 0x00[L] 0x01[R] 0x02[L] 0x03[R] ... */
TEST_ESP_OK(i2s_set_clk(I2S_NUM_0, SAMPLE_RATE, SAMPLE_BITS, I2S_CHANNEL_STEREO));
TEST_ESP_OK(i2s_write(I2S_NUM_0, w_buf, WRITE_BUF_LEN, &w_bytes, portMAX_DELAY));
TEST_ESP_OK(i2s_read(I2S_NUM_0, r_buf, READ_BUF_LEN, &r_bytes, portMAX_DELAY));
for (i = 0; (i < READ_BUF_LEN / 2); i++) {
if (r_buf[i] == 1) {
printf("%d %d %d %d\n%d %d %d %d\n",
r_buf[i], r_buf[i+1], r_buf[i+2], r_buf[i+3],
r_buf[i+4], r_buf[i+5], r_buf[i+6], r_buf[i+7]);
break;
}
length = length + bytes_read;
}
// test the read data right or not
for (int i = end_position - 99; i <= end_position; i++) {
TEST_ASSERT_EQUAL_UINT8((i - end_position + 100), *(i2s_read_buff + i));
printf("Data start index: %d\n", i);
TEST_ASSERT(i < READ_BUF_LEN / 2 - 100);
for (int16_t j = 1; j < 100; j ++) {
TEST_ASSERT_EQUAL_INT16(r_buf[i++], j); // receive all number
}
free(data_wr);
free(i2s_read_buff);
i2s_driver_uninstall(I2S_NUM_0);
printf("tx/rx stereo test passed\n");
/* tx mono rx right mono test
* tx format: 0x01[L] 0x01[R] 0x02[L] 0x02[R] ...
* rx receive: 0x01[R] 0x02[R] ... */
TEST_ESP_OK(i2s_set_clk(I2S_NUM_0, SAMPLE_RATE, I2S_BITS_PER_SAMPLE_32BIT, I2S_CHANNEL_MONO));
TEST_ESP_OK(i2s_write(I2S_NUM_0, w_buf, WRITE_BUF_LEN, &w_bytes, portMAX_DELAY));
TEST_ESP_OK(i2s_read(I2S_NUM_0, r_buf, READ_BUF_LEN, &r_bytes, portMAX_DELAY));
for (i = 0; i < READ_BUF_LEN / 2; i++) {
if (r_buf[i] == 1) {
printf("%d %d %d %d\n%d %d %d %d\n",
r_buf[i], r_buf[i+1], r_buf[i+2], r_buf[i+3],
r_buf[i+4], r_buf[i+5], r_buf[i+6], r_buf[i+7]);
break;
}
}
printf("Data start index: %d\n", i);
TEST_ASSERT(i < READ_BUF_LEN / 2 - 100);
for (int16_t j = 1; j < 100; j ++) {
TEST_ASSERT_EQUAL_INT16(r_buf[i++], j);
}
printf("tx/rx mono test passed\n");
/* Reinstalling I2S to test rx left mono */
TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0));
master_i2s_config.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT;
TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &master_i2s_config, 0, NULL));
TEST_ESP_OK(i2s_stop(I2S_NUM_0));
#if !SOC_I2S_SUPPORTS_TDM
i2s_ll_tx_set_chan_mod(&I2S0, 0);
#else
i2s_ll_tx_set_active_chan_mask(&I2S0, 0x03);
#endif
i2s_ll_tx_enable_mono_mode(&I2S0, false);
i2s_ll_tx_enable_mono_mode(&I2S0, false);
TEST_ESP_OK(i2s_start(I2S_NUM_0));
/* rx left mono test
* tx format: 0x00[L] 0x01[R] 0x02[L] 0x03[R] ...
* rx receive: 0x00[R] 0x02[R] ... */
TEST_ESP_OK(i2s_write(I2S_NUM_0, w_buf, WRITE_BUF_LEN, &w_bytes, portMAX_DELAY));
TEST_ESP_OK(i2s_read(I2S_NUM_0, r_buf, READ_BUF_LEN, &r_bytes, portMAX_DELAY));
#if CONFIG_IDF_TARGET_ESP32
/* The data of tx/rx channels are flipped on ESP32 */
for (int n = 0; n < READ_BUF_LEN / 2; n += 2) {
int16_t temp = r_buf[n];
r_buf[n] = r_buf[n+1];
r_buf[n+1] = temp;
}
#endif
for (i = 0; (i < READ_BUF_LEN / 2); i++) {
if (r_buf[i] == 2) {
printf("%d %d %d %d\n%d %d %d %d\n",
r_buf[i], r_buf[i+1], r_buf[i+2], r_buf[i+3],
r_buf[i+4], r_buf[i+5], r_buf[i+6], r_buf[i+7]);
break;
}
}
printf("Data start index: %d\n", i);
TEST_ASSERT(i < READ_BUF_LEN / 2 - 50);
for (int16_t j = 2; j < 100; j += 2) {
TEST_ASSERT_EQUAL_INT16(r_buf[i++], j);
}
printf("rx left mono test passed\n");
free(w_buf);
free(r_buf);
TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0));
}
#if SOC_I2S_SUPPORTS_TDM

View File

@ -695,6 +695,17 @@ static inline void i2s_ll_tx_set_chan_mod(i2s_dev_t *hw, uint32_t val)
hw->conf_chan.tx_chan_mod = val;
}
/**
* @brief Set I2S rx chan mode
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx chan mode
*/
static inline void i2s_ll_rx_set_chan_mod(i2s_dev_t *hw, uint32_t val)
{
hw->conf_chan.rx_chan_mod = val;
}
/**
* @brief Enable TX mono mode
*
@ -705,7 +716,6 @@ static inline void i2s_ll_tx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena)
{
int data_bit = hw->sample_rate_conf.tx_bits_mod;
hw->fifo_conf.tx_fifo_mod = data_bit <= I2S_BITS_PER_SAMPLE_16BIT ? mono_ena : 2 + mono_ena;
hw->conf_chan.tx_chan_mod = mono_ena;
}
/**
@ -718,7 +728,6 @@ static inline void i2s_ll_rx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena)
{
int data_bit = hw->sample_rate_conf.rx_bits_mod;
hw->fifo_conf.rx_fifo_mod = data_bit <= I2S_BITS_PER_SAMPLE_16BIT ? mono_ena : 2 + mono_ena;
hw->conf_chan.rx_chan_mod = mono_ena;
}
/**

View File

@ -771,6 +771,17 @@ static inline void i2s_ll_tx_set_chan_mod(i2s_dev_t *hw, uint32_t val)
hw->conf_chan.tx_chan_mod = val;
}
/**
* @brief Set I2S rx chan mode
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx chan mode
*/
static inline void i2s_ll_rx_set_chan_mod(i2s_dev_t *hw, uint32_t val)
{
hw->conf_chan.rx_chan_mod = val;
}
/**
* @brief Set I2S tx bits mod
*
@ -804,7 +815,6 @@ static inline void i2s_ll_tx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena)
int data_bit = hw->sample_rate_conf.tx_bits_mod;
hw->fifo_conf.tx_fifo_mod = data_bit <= I2S_BITS_PER_SAMPLE_16BIT ? mono_ena : 2 + mono_ena;
hw->conf.tx_dma_equal = mono_ena;
hw->conf_chan.tx_chan_mod = mono_ena;
}
/**
@ -818,7 +828,6 @@ static inline void i2s_ll_rx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena)
int data_bit = hw->sample_rate_conf.rx_bits_mod;
hw->fifo_conf.rx_fifo_mod = data_bit <= I2S_BITS_PER_SAMPLE_16BIT ? mono_ena : 2 + mono_ena;
hw->conf.rx_dma_equal = mono_ena;
hw->conf_chan.rx_chan_mod = mono_ena;
}
/**

View File

@ -238,6 +238,8 @@ void i2s_hal_tx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t
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);
#else
i2s_ll_tx_set_chan_mod(hal->dev, hal_cfg->chan_fmt < I2S_CHANNEL_FMT_ONLY_RIGHT ? hal_cfg->chan_fmt : (hal_cfg->chan_fmt >> 1)); // 0-two channel;1-right;2-left;3-righ;4-left
#endif
i2s_ll_tx_set_sample_bit(hal->dev, chan_bits, data_bits);
i2s_ll_tx_enable_mono_mode(hal->dev, is_mono);
@ -264,6 +266,8 @@ void i2s_hal_rx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t
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);
#else
i2s_ll_rx_set_chan_mod(hal->dev, hal_cfg->chan_fmt < I2S_CHANNEL_FMT_ONLY_RIGHT ? hal_cfg->chan_fmt : (hal_cfg->chan_fmt >> 1)); // 0-two channel;1-right;2-left;3-righ;4-left
#endif
i2s_ll_rx_set_sample_bit(hal->dev, chan_bits, data_bits);
i2s_ll_rx_enable_mono_mode(hal->dev, is_mono);