NRF5340 Audio DK - I2S - Multiple IRQ Invocations

I'm trying to setup a I2S module by referring the I2S module given in the nrf5340-audio application. This is my audio_i2s.c file.

/*
* Copyright (c) 2021, PACKETCRAFT, INC.
*
* SPDX-License-Identifier: LicenseRef-PCFT
*/

#include "audio_i2s.h"

#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/pinctrl.h>
#include <nrfx_i2s.h>
#include <nrfx_clock.h>
#include <audio_module/audio_module.h>

#define I2S_NL DT_NODELABEL(i2s0)

#define HFCLKAUDIO_12_288_MHZ 0x9BAE

enum audio_i2s_state {
AUDIO_I2S_STATE_UNINIT,
AUDIO_I2S_STATE_IDLE,
AUDIO_I2S_STATE_STARTED,
};

static enum audio_i2s_state state = AUDIO_I2S_STATE_UNINIT;

PINCTRL_DT_DEFINE(I2S_NL);

#if CONFIG_AUDIO_SAMPLE_RATE_16000_HZ
#define CONFIG_AUDIO_RATIO NRF_I2S_RATIO_384X
#elif CONFIG_AUDIO_SAMPLE_RATE_24000_HZ
#define CONFIG_AUDIO_RATIO NRF_I2S_RATIO_256X
#elif CONFIG_AUDIO_SAMPLE_RATE_48000_HZ
#define CONFIG_AUDIO_RATIO NRF_I2S_RATIO_128X
#else
#error "Current AUDIO_SAMPLE_RATE_HZ setting not supported"
#endif

static nrfx_i2s_t i2s_inst = NRFX_I2S_INSTANCE(0);

static nrfx_i2s_config_t cfg = {
/* Pins are configured by pinctrl. */
.skip_gpio_cfg = true,
.skip_psel_cfg = true,
.irq_priority = DT_IRQ(I2S_NL, priority),
.mode = NRF_I2S_MODE_MASTER,
.format = NRF_I2S_FORMAT_I2S,
.alignment = NRF_I2S_ALIGN_LEFT,
.ratio = CONFIG_AUDIO_RATIO,
.mck_setup = 0x66666000,
#if (CONFIG_AUDIO_BIT_DEPTH_16)
.sample_width = NRF_I2S_SWIDTH_16BIT,
#elif (CONFIG_AUDIO_BIT_DEPTH_32)
.sample_width = NRF_I2S_SWIDTH_32BIT,
#else
#error Invalid bit depth selected
#endif /* (CONFIG_AUDIO_BIT_DEPTH_16) */
.channels = NRF_I2S_CHANNELS_STEREO,
.clksrc = NRF_I2S_CLKSRC_ACLK,
.enable_bypass = false,
};

static i2s_blk_comp_callback_t i2s_blk_comp_callback;

static void i2s_comp_handler(nrfx_i2s_buffers_t const *released_bufs, uint32_t status)
{
uint32_t frame_start_ts = audio_sync_timer_capture_get();

if ((status == NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED) && released_bufs &&
i2s_blk_comp_callback && (released_bufs->p_rx_buffer || released_bufs->p_tx_buffer)) {
i2s_blk_comp_callback(frame_start_ts, released_bufs->p_rx_buffer,
released_bufs->p_tx_buffer);
}
}

void audio_i2s_set_next_buf(const uint8_t *tx_buf, uint32_t *rx_buf)
{
__ASSERT_NO_MSG(state == AUDIO_I2S_STATE_STARTED);
if (IS_ENABLED(CONFIG_STREAM_BIDIRECTIONAL) || (CONFIG_AUDIO_DEV == GATEWAY)) {
__ASSERT_NO_MSG(rx_buf != NULL);
}

if (IS_ENABLED(CONFIG_STREAM_BIDIRECTIONAL) || (CONFIG_AUDIO_DEV == HEADSET)) {
__ASSERT_NO_MSG(tx_buf != NULL);
}

const nrfx_i2s_buffers_t i2s_buf = { .p_rx_buffer = rx_buf,
.p_tx_buffer = (uint32_t *)tx_buf };

nrfx_err_t ret;

ret = nrfx_i2s_next_buffers_set(&i2s_inst, &i2s_buf);
__ASSERT_NO_MSG(ret == NRFX_SUCCESS);
}

void audio_i2s_start(const uint8_t *tx_buf, uint32_t *rx_buf)
{
__ASSERT_NO_MSG(state == AUDIO_I2S_STATE_IDLE);
if (IS_ENABLED(CONFIG_STREAM_BIDIRECTIONAL) || (CONFIG_AUDIO_DEV == GATEWAY)) {
__ASSERT_NO_MSG(rx_buf != NULL);
}

if (IS_ENABLED(CONFIG_STREAM_BIDIRECTIONAL) || (CONFIG_AUDIO_DEV == HEADSET)) {
__ASSERT_NO_MSG(tx_buf != NULL);
}

const nrfx_i2s_buffers_t i2s_buf = { .p_rx_buffer = rx_buf,
.p_tx_buffer = (uint32_t *)tx_buf };

nrfx_err_t ret;

/* Buffer size in 32-bit words */
ret = nrfx_i2s_start(&i2s_inst, &i2s_buf, I2S_SAMPLES_NUM, 0);
__ASSERT_NO_MSG(ret == NRFX_SUCCESS);

state = AUDIO_I2S_STATE_STARTED;
}

void audio_i2s_stop(void)
{
__ASSERT_NO_MSG(state == AUDIO_I2S_STATE_STARTED);

nrfx_i2s_stop(&i2s_inst);

state = AUDIO_I2S_STATE_IDLE;
}

void audio_i2s_blk_comp_cb_register(i2s_blk_comp_callback_t blk_comp_callback)
{
i2s_blk_comp_callback = blk_comp_callback;
}

void audio_i2s_init(void)
{
__ASSERT_NO_MSG(state == AUDIO_I2S_STATE_UNINIT);

nrfx_err_t ret;

nrfx_clock_hfclkaudio_config_set(HFCLKAUDIO_12_288_MHZ);

NRF_CLOCK->TASKS_HFCLKAUDIOSTART = 1;

/* Wait for ACLK to start */
while (!NRF_CLOCK_EVENT_HFCLKAUDIOSTARTED) {
k_sleep(K_MSEC(1));
}

ret = pinctrl_apply_state(PINCTRL_DT_DEV_CONFIG_GET(I2S_NL), PINCTRL_STATE_DEFAULT);
__ASSERT_NO_MSG(ret == 0);

IRQ_CONNECT(DT_IRQN(I2S_NL), DT_IRQ(I2S_NL, priority), nrfx_isr, nrfx_i2s_0_irq_handler, 0);
irq_enable(DT_IRQN(I2S_NL));

ret = nrfx_i2s_init(&i2s_inst, &cfg, i2s_comp_handler);
__ASSERT_NO_MSG(ret == NRFX_SUCCESS);

state = AUDIO_I2S_STATE_IDLE;
}

Now when I'm building this, I'm getting this weird error 
gen_isr_tables.py: error: multiple registrations at table_index 40 for irq 40 (0x28)
Existing handler 0x22407, new handler 0x22407
Has IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?

ninja: build stopped: subcommand failed.
 

I went through the Global Search to find if there are multiple instances of IRQ_CONNECT, but I found only 1 instance that is present in the audio_i2s_init() function in the code file which I have mentioned above. What could possibly cause this error and how do I fix it?

Also is there any other simpler way of setting up I2S service with both the CS47L63 Codec and the LC3 Codec?

  • Hello,

    I'm trying to setup a I2S module by referring the I2S module given in the nrf5340-audio application. This is my audio_i2s.c file.
    Also is there any other simpler way of setting up I2S service with both the CS47L63 Codec and the LC3 Codec?

    I am not sure that I've understood exactly what you intend to do with this.
    Is your intention to switch away from the CS47L64 onboard hardware codec? I.e bypassing the onboard codec and route the I2S to your external codec instead?
    If so, you could do so with the following steps:


    If this is not what you intend to do please elaborate on the functionality you need.

    Please also keep in mind that the LC3 codec is a mandatory software codec, not to be confused with the onboard hardware codec from Cirrus Logic.

    Best regards,
    Karl

  • No, I am trying to build a sort of contraption where the speaker is connected to the Headphone Jack that is present on the development board and be able to stream audio from my mobile device to the speaker. 

    I believe that the headphone jack is connected to the hardware codec and uses I2S, so I was trying to setup the I2S header file for my project but couldn't get it working due to this multiple IRQ invocations error.

    PS: I referenced the audio_i2s header file from the nrf5340 audio application.

  • I'm also interested in a possible solution because I've experienced the exact same error when trying to emulate the nrf5340_audio application's approach to creating my own I2S module.

    audio_i2s.c uses Nordic's nrfx_i2s library, as opposed to Zephyr's implementation, and while documentation exists, the nrf5340_audio app is the only example.

  • Hello,

    SohamGhugare said:
    No, I am trying to build a sort of contraption where the speaker is connected to the Headphone Jack that is present on the development board and be able to stream audio from my mobile device to the speaker. 

    I see, thank you for clarifying.

    SohamGhugare said:
    I believe that the headphone jack is connected to the hardware codec and uses I2S, so I was trying to setup the I2S header file for my project but couldn't get it working due to this multiple IRQ invocations error.

    I am not sure if I still understand why you would need to make any changes to the I2S usage in this case - as it is right now the digital audio stream is indeed sent to the hardware codec over I2S, who in turn outputs the analogue audio to the headphones jack.
    This way, you can play the audio received by the DK on your speaker by plugging it into the headphones jack directly.

    Could you clarify on what changes you are attempting to make to the I2S usage, or to elaborate on which functionality you are currently missing to have a working setup?

    ace.johnny said:
    audio_i2s.c uses Nordic's nrfx_i2s library, as opposed to Zephyr's implementation, and while documentation exists, the nrf5340_audio app is the only example.

      is your intention also to output the received audio to a speaker through the headphones jack, or are you primarily looking for general insight into the I2S peripheral usage?
    In case of the latter I would recommend opening a dedicated ticket for these questions, so that your questions can be worked on in parallel to the original questions in this ticket.

    Best regards,
    Karl

  • I don't intend to make any changes to the I2S usage as of now, but since its a long term project, I wanted to get acquainted to the working of I2S in general. So I just copied over the i2s header files from the audio application as it is and ran into the error which I mentioned above while building.

Related