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?

Parents
  • 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

Reply
  • 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

Children
  • 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.

Related