nRF52840 USB Audio in and I2S out

Hello,

I'm using nrf52840 USB Audio headset application on nRF52840 DK. The nRF connect SDK version is v2.6.0.

I want to change the output to i2s out. The following are my modifications:

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

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

static void data_received(const struct device *dev,
			  struct net_buf *buffer,
			  size_t size)
{
	int ret;

	if (!buffer || !size) {
		/* This should never happen */
		return;
	}

	LOG_DBG("Received %d data, buffer %p", size, buffer);

	memcpy(data_buf+loop_times*size,buffer->data,size);
	loop_times++;

	if(loop_times == 100){
		loop_times = 0;
	
		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);
		}
	
		void *mem_block;
		ret = k_mem_slab_alloc(&mem_slab, &mem_block, K_NO_WAIT);
		if (ret < 0) {
			LOG_ERR("Failed to allocate TX block: %d", ret);
			return false;
		}

		/* Put data into the tx buffer */
		for (int i = 0; i < 19200; i++) {
			((uint8_t*)mem_block)[i] = data_buf[i];
		}

		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);
		}
	}
	net_buf_unref(buffer);
}

int main(void)
{
	const struct device *hs_dev;
	int ret;

	LOG_INF("Entered %s", __func__);
	hs_dev = DEVICE_DT_GET_ONE(usb_audio_hs);

	if (!device_is_ready(hs_dev)) {
		LOG_ERR("Device USB Headset is not ready");
		return 0;
	}

	LOG_INF("Found USB Headset Device");

	appAmpAD85020bInit();

	usb_audio_register(hs_dev, &ops);

	ret = usb_enable(NULL);
	if (ret != 0) {
		LOG_ERR("Failed to enable USB");
		return 0;
	}

	LOG_INF("USB enabled");

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

	return 0;
}

Here is my prj.conf.

CONFIG_STDOUT_CONSOLE=y

#USB related configs
CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_DEVICE_PRODUCT="Zephyr USB audio sample"
CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n

#LOG subsystem related configs
CONFIG_LOG=y
CONFIG_USB_DRIVER_LOG_LEVEL_ERR=y
CONFIG_USB_DEVICE_LOG_LEVEL_ERR=y

#net buf options
CONFIG_NET_BUF=y

#USB audio related configs
CONFIG_USB_DEVICE_AUDIO=y

CONFIG_I2S=y
CONFIG_I2C=y

Here is my app.overlay.

/*
 * Copyright (c) 2019 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */

&zephyr_udc0 {
	hs_0 {
		compatible = "usb-audio-hs";
		mic-feature-mute;
		mic-channel-l;
		mic-channel-r;

		hp-feature-mute;
		hp-channel-l;
		hp-channel-r;

		hp-feature-volume;
		volume-max = <0x0500>;
		volume-min = <0xBA00>;
		volume-res = <0x100>;
	};
};
&pinctrl {
	i2c0_default_alt: i2c0_default_alt {
		group1 {
			psels = <NRF_PSEL(TWIM_SDA, 0, 30)>,
				<NRF_PSEL(TWIM_SCL, 0, 31)>;
		};
	};

	i2c0_sleep_alt: i2c0_sleep_alt {
		group1 {
			psels = <NRF_PSEL(TWIM_SDA, 0, 30)>,
				<NRF_PSEL(TWIM_SCL, 0, 31)>;
			low-power-enable;
		};
	};

	i2s0_default_alt: i2s0_default_alt {
		group1 {
			psels = <NRF_PSEL(I2S_SCK_M, 1, 15)>,
				<NRF_PSEL(I2S_LRCK_M, 1, 12)>,
				<NRF_PSEL(I2S_SDOUT, 1, 13)>,
				<NRF_PSEL(I2S_SDIN, 1, 14)>;
		};
	};
};
 
&i2c0 {
	status = "okay";
	compatible = "nordic,nrf-twim";
	label = "I2C_0";
	pinctrl-0 = <&i2c1_default>;
	pinctrl-1 = <&i2c1_sleep>;
	pinctrl-names = "default", "sleep";
	clock-frequency = <100000>; 
};

i2s_rxtx: &i2s0 {
	status = "okay";
	pinctrl-0 = <&i2s0_default_alt>;
	pinctrl-names = "default";
};

After modifying, the speaker does not output any sound.

Judging from the log, no errors occurred during the process. I checked the I2S pin signal with a logic analyzer and the signal looks normal.

Is there anything else that needs to be modified?

Parents
  • Hi!

    I don't immediately see anything wrong with the code.

    I checked the I2S pin signal with a logic analyzer and the signal looks normal.

    And you have connected these signals to a speaker ? The signal looks ok, but the i2s-speaker does not output any sounds? Maybe the data and clk signal have been switched? or the speaker does not have enough supply voltage?

Reply
  • Hi!

    I don't immediately see anything wrong with the code.

    I checked the I2S pin signal with a logic analyzer and the signal looks normal.

    And you have connected these signals to a speaker ? The signal looks ok, but the i2s-speaker does not output any sounds? Maybe the data and clk signal have been switched? or the speaker does not have enough supply voltage?

Children
Related