nRF5340Dk configuration for Unicast Audio server with External I2S CODEC

Hi, 
I am using nRF5340 for my unicast Audio server example where the nRF5340DK is the headset and my mobile device is the audio source. I have taken the unicast audio server example from the Zephyr. Since this DK do not have a I2S Decoder I am using an external I2S DAC (CJMCU-1334 UDA1334A I2S DAC Audio Stereo Decoder Module) . I have added overlay file for configuring the I2S peripheral as follows. I am using SDK 2.7.0

&pinctrl {
    i2s0_default: i2s0_default {
        group1 {
            psels = <NRF_PSEL(I2S_SCK_M, 0, 15)>,
                   <NRF_PSEL(I2S_LRCK_M, 0, 12)>,
                   <NRF_PSEL(I2S_SDOUT, 0, 13)>,
                   <NRF_PSEL(I2S_SDIN, 0, 14)>;
        };
    };
};
&clock {
	hfclkaudio-frequency = <11289600>;
};

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

I have also made some changes in the main.c and also for initializing the I2S. The changed portions are also attaching .

#if defined(CONFIG_LIBLC3)

static void stream_recv_lc3_codec(struct bt_bap_stream *stream,
				  const struct bt_iso_recv_info *info,
				  struct net_buf *buf)
{
	const uint8_t *in_buf;
	uint8_t err = -1;
	const int octets_per_frame = buf->len / frames_per_sdu;
	void *tx_block;
	size_t tx_size;

	if (lc3_decoder == NULL) {
		printk("LC3 decoder not setup, cannot decode data.\n");
		return;
	}

	if ((info->flags & BT_ISO_FLAGS_VALID) == 0) {
		printk("Bad packet: 0x%02X\n", info->flags);

		in_buf = NULL;
	} else {
		in_buf = buf->data;
	}

	/* This code is to demonstrate the use of the LC3 codec. On an actual implementation
	 * it might be required to offload the processing to another task to avoid blocking the
	 * BT stack.
	 */
	for (int i = 0; i < frames_per_sdu; i++) {

		int offset = 0;

		err = lc3_decode(lc3_decoder, in_buf + offset, octets_per_frame,
				 LC3_PCM_FORMAT_S16, audio_buf, 1);

		if (in_buf != NULL) {
			offset += octets_per_frame;
		}
	}

	printk("RX stream %p len %u\n", stream, buf->len);

	if (err == 1) {
		printk("  decoder performed PLC\n");
		return;

	} else if (err < 0) {
		printk("  decoder failed - wrong parameters?\n");
		return;
	}

	if (!i2s_configured) {
        printk("Warning: I2S not configured, skipping audio output\n");
        return;
    }

	/* Write decoded audio data to I2S */
    err = i2s_buf_read(i2s_dev, &tx_block, &tx_size);
    if (err < 0) {
        printk("Failed to get I2S TX buffer: %d\n", err);
        return;
    }

    /* Copy decoded audio data to TX block */
    memcpy(tx_block, audio_buf, MIN(tx_size, sizeof(audio_buf)));

    /* Send the audio data */
    err = i2s_buf_write(i2s_dev, tx_block, MIN(tx_size, sizeof(audio_buf)));
    if (err < 0) {
        printk("Failed to write I2S TX buffer: %d\n", err);
        return;
    }
}

#include <zephyr/device.h>
#include <zephyr/drivers/i2s.h>
#include <zephyr/drivers/gpio.h>
#include <nrf.h>

/* Add these global variables for I2S */
static const struct device *i2s_dev;
#define NUM_SAMPLES 32
#define NUM_BLOCKS 8
static bool i2s_configured = false;
K_MEM_SLAB_DEFINE(i2s_tx_mem_slab, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU) * 2, NUM_BLOCKS, NUM_SAMPLES);

static int init_i2s(void)
{
    /* Configure I2S */
    struct i2s_config i2s_cfg;
    int ret;

    /* Get I2S device */
    i2s_dev = DEVICE_DT_GET(DT_NODELABEL(i2s0));
    if (!device_is_ready(i2s_dev)) {
        printk("I2S device not ready\n");
        return -ENODEV;
    }

    /* Configure I2S TX */
    i2s_cfg.word_size = 16;
    i2s_cfg.channels = 2;
    i2s_cfg.format = I2S_FMT_DATA_FORMAT_I2S;
    i2s_cfg.options = I2S_OPT_FRAME_CLK_MASTER | I2S_OPT_BIT_CLK_MASTER;
    i2s_cfg.frame_clk_freq = 48000;
    i2s_cfg.block_size = BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU);
    i2s_cfg.mem_slab = &i2s_tx_mem_slab;
    i2s_cfg.timeout = 0;
	
    ret = i2s_configure(i2s_dev, I2S_DIR_TX, &i2s_cfg);
    if (ret < 0) {
        printk("Failed to configure I2S TX: %d\n", ret);
        return ret;
    }

    /* Start I2S TX */
    ret = i2s_trigger(i2s_dev, I2S_DIR_TX, I2S_TRIGGER_START);
    if (ret < 0) {
        printk("Failed to start I2S TX: %d\n", ret);
        return ret;
    }

	i2s_configured = true;  // Set flag indicating I2S is configured

    printk("I2S initialized successfully\n");
    return 0;
}

with these changes I am able to build and flash the code to the nRF5340 Dk.  I am able to connect with the mobile device with the DK as a audio device, but i have faced some errors at the starting. The errors are also attached.

Ignoring the first error I connected the device and when I played  audio in the source , the error in the below screenshot happened causing the system halt.

I understand the errors happened due to some memory buffer issues. But couldn't able to point out the exact point.

Parents
  • First error is because you try to start I²S TX without a prefilled buffer. You needed to call i2s_write(...) first - the peripherial needs at least some data to send out.

    Second error is probably due to the i2s_buf_read() function call, which does not at all do what you may think it does. Also it could be a stack buffer overflow with how you use the tx_block variable that can only hold 4 bytes.

    RX Stream buf len printed as zero bytes does not sound too sane either..?

  • I have made some changes and still while playing an audio from the mobile device the system went to a system halt state. the error is attached.


    I have another doubt that since I am playing the audio from my mobile phone which supports BLE Audio but do not have LC3 Codec ( The default codec supported by the mobile device is SBC ) . Both the mobile phone and DK require LC3 codec for proper Audio streaming?. Is it possible to use like these SBC codec at the mobile phone side and LC3 Codec at the nRF5340 DK side. If not possible is there any other codec other than LC3 which supports the nRF5340 DK. 

    The next thing that I wish to integrate Matter in to this since the DK supports Matter . My objective is to use matter to control the volume and play/mute states.  I would like to know whether it is possible to integrate both unicast audio server along with matter in the same nrf5340 DK. 

  • Hi,

    Sivakumar128 said:
    I have another doubt that since I am playing the audio from my mobile phone which supports BLE Audio but do not have LC3 Codec ( The default codec supported by the mobile device is SBC ) . Both the mobile phone and DK require LC3 codec for proper Audio streaming?. Is it possible to use like these SBC codec at the mobile phone side and LC3 Codec at the nRF5340 DK side. If not possible is there any other codec other than LC3 which supports the nRF5340 DK. 

    You can read more about codec requirements in codecs and software codec requirements.

    Sivakumar128 said:
    The next thing that I wish to integrate Matter in to this since the DK supports Matter . My objective is to use matter to control the volume and play/mute states.  I would like to know whether it is possible to integrate both unicast audio server along with matter in the same nrf5340 DK. 

    Can you specify which protocol do you want to use Matter over?
    Are you planning to have the Matter gateway/central on the same device which transmits the audio?

    Best regards,
    Dejan

  • You can read more about codec requirements in codecs and software codec requirements.

    I have gone through this . I understand that LC3 is required for the unicast audio server . As I mentioned earlier the errors are still there. I am using  Samsung S23 as the audio source. While connecting with the DK it is identified as a Audio device by the mobile phone . But checking the Available Codec in the mobile  developer option not seen the LC3 codec. I am using the same code snippet shared before for the Tx of I2S.


    Can you specify which protocol do you want to use Matter over?
    Are you planning to have the Matter gateway/central on the same device which transmits the audio?

    I have started a new ticket for this at Matter over thread on unicast audio server

Reply Children
No Data
Related