How to play pcm raw data on nrf52840 DK through I2S ?

Hello,

I'm using nrf52840 DK to test 1khz tone. The nRF Connect SDK version is v2.6.0.

I put a pcm raw data array of 1khz tone in the code and used i2s write to send the data to i2s out.

const struct device *const i2s_dev_tx = DEVICE_DT_GET(I2S_TX_NODE);
const struct device *const i2s_dev_rx = DEVICE_DT_GET(I2S_TX_NODE);
struct i2s_config config;
#define SAMPLE_FREQUENCY    48000
#define SAMPLE_BIT_WIDTH    16
#define BYTES_PER_SAMPLE    sizeof(int16_t)
#define NUMBER_OF_CHANNELS  2
/* Such block length provides an echo with the delay of 100 ms. */
#define SAMPLES_PER_BLOCK   ((SAMPLE_FREQUENCY / 10) * NUMBER_OF_CHANNELS)
#define INITIAL_BLOCKS      2
#define TIMEOUT             1000
#define BLOCK_SIZE  (BYTES_PER_SAMPLE * SAMPLES_PER_BLOCK)
#define BLOCK_COUNT (INITIAL_BLOCKS + 2)
K_MEM_SLAB_DEFINE_STATIC(mem_slab, BLOCK_SIZE, BLOCK_COUNT, 4);
static int16_t data_buf_tmp[9600];

static bool configure_streams(const struct device *i2s_dev_tx,const struct i2s_config *config);

static void i2s_init(void){
	int ret;

	if (!device_is_ready(i2s_dev_tx)) {
		LOG_ERR("%s is not ready", i2s_dev_tx->name);
	}
	config.word_size = SAMPLE_BIT_WIDTH;
	config.channels = NUMBER_OF_CHANNELS;
	config.format = I2S_FMT_DATA_FORMAT_I2S;
	config.options = I2S_OPT_BIT_CLK_MASTER | I2S_OPT_FRAME_CLK_MASTER;
	config.frame_clk_freq = SAMPLE_FREQUENCY;
	config.mem_slab = &mem_slab;
	config.block_size = BLOCK_SIZE;
	config.timeout = TIMEOUT;

	ret = configure_streams(i2s_dev_tx, &config);
	if (ret < 0) {
		LOG_ERR("Failed to configure TX stream: %d", ret);
	}
}
static bool configure_streams(const struct device *i2s_dev_tx,
			      const struct i2s_config *config)
{
	int ret;

	ret = i2s_configure(i2s_dev_tx, I2S_DIR_TX, config);
	if (ret < 0) {
		LOG_ERR("Failed to configure TX stream: %d\n", ret);
		return false;
	}

	return true;
}

static void *mem_block;
static bool prepare_transfer(const struct device *i2s_dev_tx)
{
	int ret;

	for (int i = 0; i < INITIAL_BLOCKS; ++i) {

		ret = k_mem_slab_alloc(&mem_slab, &mem_block, K_NO_WAIT);
		if (ret < 0) {
			LOG_ERR("Failed to allocate TX block %d: %d", i, ret);
			return false;
		}

		memset(mem_block, 0, BLOCK_SIZE);

		ret = i2s_write(i2s_dev_tx, mem_block, BLOCK_SIZE);
		if (ret < 0) {
			LOG_ERR("Failed to write block %d: %d", i, ret);
			return false;
		}
	}

	return true;
}

int main(void)
{
  int ret;
  i2s_init();

  for(;;){
    prepare_transfer(i2s_dev_tx);
    ret = i2s_trigger(i2s_dev_tx, I2S_DIR_TX, I2S_TRIGGER_START);
    if (ret < 0) {
      LOG_ERR("Failed to trigger command I2S_TRIGGER_START on TX: %d\n", ret);
    }
    // Put data into the buffer
    for (int i = 0; i < 9600; i++) {
      ((int16_t*)mem_block)[i] = data[i];
    }

    for (int i = 0; i < SAMPLES_PER_BLOCK; ++i) {
      int16_t *sample = &((int16_t *)mem_block)[i];
      *sample += data_buf_tmp[i];
      data_buf_tmp[i] = (*sample) / 2;
    }
  
    ret = i2s_write(i2s_dev_tx, mem_block, BLOCK_SIZE);
    if (ret < 0) {
      LOG_ERR("Failed to write data: %d", ret);
    }else{
      LOG_INF("Success to write data.");
    }
    ret = i2s_trigger(i2s_dev_tx, I2S_DIR_TX, I2S_TRIGGER_DROP);
    if (ret < 0) {
      LOG_ERR("Failed to trigger command I2S_TRIGGER_DROP on TX: %d\n", ret);
    }
  }
  return 0;
}

My pcm raw data array is an int16 stereo array, arranged as:
[left_data0,right_data0,left_data1,right_data1,....]

After testing, it is found that the output sound is distorted. Is there anything that needs to be adjusted?

Related