I2S Zephyr SDOUT not working

I am trying to get I2S communication up and running but am unable to produce a signal on my SDOUT pin. MCLK, LRCLK and SCLK work as intended but trying to send any data does not work. I did notice that the TXD.PTR register is empty. I have tried multiple pins for my SDOUT and have nrf SDK 1.8.0 installed, using VScode. Any help would be appreciated.

#include <zephyr.h>
#include <drivers/gpio.h>
#include <init.h>
#include <nrf.h>
#include <nrfx.h>
#include <nrfx_gpiote.h>
#include <drivers/i2s.h>
#include "nrfx_i2s.h"
#include <errno.h>
#include <string.h>
#include <logging/log.h>

LOG_MODULE_REGISTER(Main);

#define AUDIO_SAMPLE_FREQ (44100)
#define AUDIO_NUM_CHANNELS (1)
#define AUDIO_SAMPLE_BIT_WIDTH (16)
#define AUDIO_SAMPLES_PER_CH_PER_FRAME (128)
#define AUDIO_SAMPLES_PER_FRAME (AUDIO_SAMPLES_PER_CH_PER_FRAME * AUDIO_NUM_CHANNELS)
#define AUDIO_SAMPLE_BYTES (sizeof(uint16_t))
#define AUDIO_FRAME_BUF_BYTES (AUDIO_SAMPLES_PER_FRAME * AUDIO_SAMPLE_BYTES)
#define I2S_PLAY_BUF_COUNT (500)

static const struct device *host_i2s_tx_dev;
static struct k_mem_slab i2s_tx_mem_slab;
static char tx_buffer[AUDIO_FRAME_BUF_BYTES * I2S_PLAY_BUF_COUNT];
static struct i2s_config config;
volatile int ret;

static void init(void)
{
	/*configure tx device*/
	host_i2s_tx_dev = device_get_binding("I2S_0");

	k_mem_slab_init(&i2s_tx_mem_slab, tx_buffer, AUDIO_FRAME_BUF_BYTES, I2S_PLAY_BUF_COUNT);

	/* configure i2s for audio playback */
	config.word_size = AUDIO_SAMPLE_BIT_WIDTH;
	config.channels = AUDIO_NUM_CHANNELS;
	config.format = I2S_FMT_DATA_FORMAT_I2S;
	config.options = (I2S_OPT_BIT_CLK_MASTER | I2S_OPT_FRAME_CLK_MASTER);
	config.frame_clk_freq = AUDIO_SAMPLE_FREQ;
	config.block_size = AUDIO_FRAME_BUF_BYTES;
	config.mem_slab = &i2s_tx_mem_slab;
	config.timeout = -1;
	ret = i2s_configure(host_i2s_tx_dev, I2S_DIR_TX, &config);
	if (ret < 0)
	{
		LOG_INF("tx config:%d", ret);
	}
}

void main(void)
{
	init();

	uint16_t buf[128];
	volatile size_t size = sizeof(buf);

	int i = 0;
	for (i = 0; i < size; i++)
	{
		if (i <= size / 4)
		{
			buf[i] = i;
		}
		else if (i > size / 4)
		{
			buf[i] = size / 2 - i;
		}
	}

	void *tx_mem_block;

	ret = i2s_trigger(host_i2s_tx_dev, I2S_DIR_TX, I2S_TRIGGER_START);

	while (1)
	{
		ret = k_mem_slab_alloc(&i2s_tx_mem_slab, &tx_mem_block, K_NO_WAIT);
		memcpy(tx_mem_block, &buf, size);
		ret = i2s_write(host_i2s_tx_dev, tx_mem_block, size);
		k_mem_slab_free(&i2s_tx_mem_slab, &tx_mem_block);
	}
}
# CONFIG_MULTITHREADING=n
# CONFIG_KERNEL_MEM_POOL=n
# CONFIG_NUM_PREEMPT_PRIORITIES=0
# CONFIG_SYS_CLOCK_EXISTS=n
# CONFIG_ARM_MPU=n
# CONFIG_SIZE_OPTIMIZATIONS=y
CONFIG_I2S=y
CONFIG_NRFX_I2S=y
# CONFIG_WATCHDOG=n
CONFIG_GPIO=y
# CONFIG_PINMUX=n
# CONFIG_SPI=n
# CONFIG_SERIAL=n
# CONFIG_FLASH=n
# CONFIG_PM=n
# CONFIG_DYNAMIC_INTERRUPTS=n
# CONFIG_IRQ_OFFLOAD=n
# CONFIG_THREAD_STACK_INFO=n
# CONFIG_THREAD_CUSTOM_DATA=n
# CONFIG_BOOT_BANNER=n
# CONFIG_BOOT_DELAY=0
# CONFIG_CONSOLE=n
# CONFIG_UART_CONSOLE=n
# CONFIG_STDOUT_CONSOLE=n
# CONFIG_EARLY_CONSOLE=n
CONFIG_BOARD_ENABLE_CPUNET=n
CONFIG_NRF_RTC_TIMER=n
CONFIG_CORTEX_M_SYSTICK=y
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=64000000
CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000000
CONFIG_LOG=y
CONFIG_USE_SEGGER_RTT=y
CONFIG_LOG_BACKEND_RTT=y

Parents
  • Hi thank you for your response,

    I tried on GPIO 36, 26, 0, 2 ,3. Removing "&" gives the same result unfortunately, and yes the data is properly populated within tx_mem_block before i2s_write() is called. To view the TXD.PTR I use "Cortex-Debug: View Memory" then set the address to 0x5002850C since 0x50028000 is the base address. I used this method to check the other registers and they all seem to be set correctly.

  • Hello,

    Would it be possible for me to reproduce this on a DK? Are you able to replicate this without any external I2C devices? If so, can you please send the project here? (Or if you can't share, please strip the project down to something smaller that is able to replicate the issue).

    Best regards,

    Edvin

  • Yes I forgot to mention I am using a DK, and yes this happens with no other peripherals attached to it.

    nRF5340_i2s_test.zip

  • Hello,

    How do you build your project? Do you use nRF Connect for VS Code? If so, can you please try to unzip it to an unmodified SDK and see if you can compile it? (I tried both this and using West from the command line, but in both cases, I get a ZEPHYR_FATAL_ERROR:

    00> [00:00:00.281,000] <err> fatal_error: Resetting system
    00> [00:00:00.004,000] <err> os: ***** BUS FAULT *****
    00> [00:00:00.004,000] <err> os:   Instruction bus error
    00> 
    00> [00:00:00.004,000] <err> os: r0/a1:  0x00000000  r1/a2:  0x00000001  r2/a3:  0x200002f8
    00> [00:00:00.004,000] <err> os: r3/a4:  0x2ef7fbb5 r12/ip:  0xffffffff r14/lr:  0x000004a5
    00> [00:00:00.004,000] <err> os:  xpsr:  0x69000000
    00> [00:00:00.004,000] <err> os: Faulting instruction address (r15/pc): 0x2ef7fbb4
    00> [00:00:00.004,000] <err> os: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0
    00> [00:00:00.004,000] <err> os: Current thread: 0x20000270 (unknown)
    00> [00:00:00.281,000] <err> fatal_error: Resetting system
    00> [00:00:00.004,000] <err> os: ***** BUS FAULT *****
    00> [00:00:00.004,000] <err> os:   Instruction bus error
    00> [00:00:00.004,000] <err> os: r0/a1:  0x00000000  r1/a2:  0x00000001  r2/a3:  0x200002f8
    00> [00:00:00.004,000] <err> os: r3/a4:  0x2ef7fbb5 r12/ip:  0xffffffff r14/lr:  0x000004a5[0m
    00> [00:00:00.004,000] <err> os:  xpsr:  0x69000000
    00> [00:00:00.004,000] <err> os: Faulting instruction address (r15/pc): 0x2ef7fbb4
    00> [00:00:00.004,000] <err> os: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0
    00> [00:00:00.004,000] <err> os: Current thread: 0x20000270 (unknown)
    00> [00:00:00.281,000] <err> fatal_error: Resetting system
    00> [00:00:00.004,000] <err> os: ***** BUS FAULT *****
    00> [00:00:00.004,000] <err> os:   Instruction bus error
    00> [00:00:00.004,000] <err> os: r0/a1:  0x00000000  r1/a2:  0x00000001  r2/a3:  0x200002f8
    00> [00:00:00.004,000] <err> os: r3/a4:  0x2ef7fbb5 r12/ip:  0xffffffff r14/lr:  0x000004a5
    00> [00:00:00.004,000] <err> os:  xpsr:  0x69000000
    00> [00:00:00.004,000] <err> os: Faulting instruction address (r15/pc): 0x2ef7fbb4
    00> [00:00:00.004,000] <err> os: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0

    I didn't look into what it points to, but I want to check whether you get the same when you are using the DK?

    Best regards,

    Edvin

  • Yes I use nrf connect for VS code, and I just recently tried it in an unmodified SDK. It runs without any errors for me but the DOUT line remains low while the clocks function.

  • Hello,

    So I was able to change the project so that I was able to compile without your custom files, and so that it ran on my nRF53DK "without errors". 

    Did you check the return value from i2s_write()? (It didn't print until I added "k_sleep(K_SECONDS(1))" to the end of your while loop (for the log to be processed), but in my case it returns -5 and prints "Cannot write in state: 4",  where 4 refers to I2S_STATE_ERROR.

    I haven't gotten to play around with I2S in NCS that much. Did you test the sample found in NCS\zephyr\samples\drivers\i2s?
    Best regards,
    Edvin
Reply
  • Hello,

    So I was able to change the project so that I was able to compile without your custom files, and so that it ran on my nRF53DK "without errors". 

    Did you check the return value from i2s_write()? (It didn't print until I added "k_sleep(K_SECONDS(1))" to the end of your while loop (for the log to be processed), but in my case it returns -5 and prints "Cannot write in state: 4",  where 4 refers to I2S_STATE_ERROR.

    I haven't gotten to play around with I2S in NCS that much. Did you test the sample found in NCS\zephyr\samples\drivers\i2s?
    Best regards,
    Edvin
Children
  • Hi, 

    Yes I did take a look at the sample projects there but unfortunately they did not work on my board. Not sure if something is being configured incorrectly or where the issue is stemming from. I had a delay at first but then it gave me the I2S_STATE_ERROR until I removed it. The state that I sent my code in ran for me with all returns of 0.

  • Can you please try to replace your while loop with this:

        ret = 0;
    	while (!ret)
    	{
    		ret = k_mem_slab_alloc(&i2s_tx_mem_slab, &tx_mem_block, K_NO_WAIT);
    		if (ret < 0)
    		{
    			LOG_INF("mem slab alloc: %d", ret);
    		}
    
    		memcpy(tx_mem_block, buf, size);
    
    	    ret = i2s_trigger(host_i2s_tx_dev, I2S_DIR_TX, I2S_TRIGGER_START);
    	    if (ret < 0)
    	    {
                LOG_INF("trigger: %d", ret);
            }
    
    		ret = i2s_write(host_i2s_tx_dev, tx_mem_block, size);
    		if (ret < 0)
    		{
    			LOG_INF("write: %d", ret);
    		}
    
    		k_mem_slab_free(&i2s_tx_mem_slab, &tx_mem_block);
    	}
        while (true)
        {
            LOG_INF("done");
            k_sleep(K_SECONDS(1));
        }
    }

    Is the last loop ever reached?

  • I did some more testing, removing the break and testing with the logic analyzer. This is the main.c I ended up using:

    /*
     * Copyright (c) 2020 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    #include <zephyr.h>
    #include <drivers/gpio.h>
    #include <init.h>
    #include <nrf.h>
    #include <nrfx.h>
    #include <nrfx_gpiote.h>
    #include <drivers/i2s.h>
    #include "nrfx_i2s.h"
    #include <errno.h>
    #include <string.h>
    #include <logging/log.h>
    #include <dk_buttons_and_leds.h>
    
    LOG_MODULE_REGISTER(Main);
    
    #define AUDIO_SAMPLE_FREQ (44100)
    #define AUDIO_NUM_CHANNELS (1)
    #define AUDIO_SAMPLE_BIT_WIDTH (16)
    #define AUDIO_SAMPLES_PER_CH_PER_FRAME (128)
    #define AUDIO_SAMPLES_PER_FRAME (AUDIO_SAMPLES_PER_CH_PER_FRAME * AUDIO_NUM_CHANNELS)
    #define AUDIO_SAMPLE_BYTES (sizeof(uint16_t))
    #define AUDIO_FRAME_BUF_BYTES (AUDIO_SAMPLES_PER_FRAME * AUDIO_SAMPLE_BYTES)
    #define I2S_PLAY_BUF_COUNT (500)
    
    #define RUN_STATUS_LED DK_LED1
    #define TEST_LED1 DK_LED1
    #define TEST_LED2 DK_LED2
    #define TEST_LED3 DK_LED3
    #define TEST_LED4 DK_LED4
    #define TEST_COUNT  10
    
    static const struct device *host_i2s_tx_dev;
    static struct k_mem_slab i2s_tx_mem_slab;
    static char tx_buffer[AUDIO_FRAME_BUF_BYTES * I2S_PLAY_BUF_COUNT];
    static struct i2s_config config;
    volatile int ret;
    
    
    
    static void init(void)
    {
    	host_i2s_tx_dev = device_get_binding("I2S_0");
    
    	k_mem_slab_init(&i2s_tx_mem_slab, tx_buffer, AUDIO_FRAME_BUF_BYTES, I2S_PLAY_BUF_COUNT);
    	//if (ret < 0)
    	{
    		LOG_INF("mem slab init: %d", ret);
    	}
    
    	config.word_size = AUDIO_SAMPLE_BIT_WIDTH;
    	config.channels = AUDIO_NUM_CHANNELS;
    	//config.format = I2S_FMT_DATA_FORMAT_I2S;
        config.format = I2S_FMT_DATA_FORMAT_LEFT_JUSTIFIED;
    	config.options = (I2S_OPT_BIT_CLK_MASTER | I2S_OPT_FRAME_CLK_MASTER);
    	config.frame_clk_freq = AUDIO_SAMPLE_FREQ;
    	config.block_size = AUDIO_FRAME_BUF_BYTES;
    	config.mem_slab = &i2s_tx_mem_slab;
    	config.timeout = 1000;
    
    	ret = i2s_configure(host_i2s_tx_dev, I2S_DIR_TX, &config);
    	//if (ret < 0)
    	{
    		LOG_INF("tx config: %d", ret);
    	}
    }
    
    void main(void)
    
    {
        uint32_t counter = 0;
    	init();
    
        LOG_INF("I2S sample started");
    
    
    
    	uint16_t buf[128];
    	size_t size = sizeof(buf);
    
    	int i;
    	for (i = 0; i < size; i++)
    	{
    		if (i <= size / 4)
    		{
    			buf[i] = i;
    		}
    		else if (i > size / 4)
    		{
    			buf[i] = size / 2 - i;
    		}
    	}
        LOG_INF("0x%04x", buf[0]);
        LOG_INF("0x%04x", buf[1]);
        LOG_INF("0x%04x", buf[2]);
        LOG_INF("0x%04x", buf[3]);
        LOG_INF("0x%04x", buf[4]);
    
    	void *tx_mem_block;
    
    
    
        ret = 0;
        
    	while ((ret == 0) && (counter < TEST_COUNT))
    	{
    
           	ret = i2s_trigger(host_i2s_tx_dev, I2S_DIR_TX, I2S_TRIGGER_START);
            if (ret < 0)
            {
                LOG_INF("trigger: %d", ret);
                break;
            }
    
    
    		ret = k_mem_slab_alloc(&i2s_tx_mem_slab, &tx_mem_block, K_NO_WAIT);
    		if (ret < 0)
    		{
    			LOG_INF("mem slab alloc: %d", ret);
                break;
    		}
    
    
    		memcpy(tx_mem_block, buf, size);
    
            ret = i2s_write(host_i2s_tx_dev, tx_mem_block, size);
    		if (ret != 0)
    		{
    			LOG_INF("write: %d", ret);
                break;
    		}
    		
    		k_mem_slab_free(&i2s_tx_mem_slab, &tx_mem_block);
            counter++;
            LOG_INF("counter %d", counter);
    	}
        while (true)
        {
            k_sleep(K_SECONDS(1));
            LOG_INF("done, counter = %d", counter);
        }
    }

    I am not familiar with I2S, and how to use it, but running it on an nRF5340DK, I get data on the DOUT pin:

    The reason I changed 

    config.format = I2S_FMT_DATA_FORMAT_I2S
    to
    config.format = I2S_FMT_DATA_FORMAT_LEFT_JUSTIFIED;
    was just so that I could see that the data was correct in the logic analyzer. There was data on the DOUT pin before I changed it as well.
Related