i2S is gave after 1 to 6 index transmission get error code 11 why this happen ??

/*
 * Copyright 2023 NXP
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/i2s.h>
#include <zephyr/drivers/gpio.h>
#include <stdio.h>
#include "codec_header.h"



#define SAMPLE_NO   64
#define CHANNELS    2
#define NUM_BLOCKS  4


/* BLOCK_SIZE in bytes */
#define BLOCK_SIZE (CHANNELS * SAMPLE_NO * sizeof(int16_t))

const struct device *dev_i2s = DEVICE_DT_GET(DT_NODELABEL(i2s20));

/* Stereo interleaved buffers */
static int16_t tx_block[NUM_BLOCKS][CHANNELS * SAMPLE_NO];



/* Sine wave table */
static const int16_t sine[SAMPLE_NO] = {
     3211,  6392,  9511, 12539, 15446, 18204, 20787, 23169,
    25329, 27244, 28897, 30272, 31356, 32137, 32609, 32767,
    32609, 32137, 31356, 30272, 28897, 27244, 25329, 23169,
    20787, 18204, 15446, 12539,  9511,  6392,  3211,     0,
    -3212, -6393, -9512,-12540,-15447,-18205,-20788,-23170,
   -25330,-27245,-28898,-30273,-31357,-32138,-32610,-32767,
   -32610,-32138,-31357,-30273,-28898,-27245,-25330,-23170,
   -20788,-18205,-15447,-12540, -9512, -6393, -3212,    -1
};





static void fill_buf(int16_t *buf, int shift)
{
    for (int i = 0; i < SAMPLE_NO; i++) {
        buf[2 * i]     = sine[i] >> shift;                 /* Left */
        buf[2 * i + 1] = sine[(i + SAMPLE_NO / 4) % SAMPLE_NO] >> shift; /* Right */
    }
}

int main(void)
{
    struct i2s_config i2s_cfg;
    int ret;

    printk("=== System start ===\n");

   // POWER-UP DELAY
    k_msleep(300);
    // provide mclk clock
    //mclk_timer();

    // INIT I2C
    ret = i2c_init_codec();
    if (ret)
    {
        printk("Codec I2C init failed (%d). STOP.\n", ret);
        while (1)
        {
            k_sleep(K_FOREVER);
        }
    }
    printk("Codec I2C init OK\n");

    // CHECK I2S DEVICE
    if (!device_is_ready(dev_i2s)) {
        printk("I2S device not ready\n");
        return -ENODEV;
    }

    // CONFIGURE I2S
    memset(&i2s_cfg, 0, sizeof(i2s_cfg));

    i2s_cfg.word_size = 16;
    i2s_cfg.channels = CHANNELS;
    i2s_cfg.format = I2S_FMT_DATA_FORMAT_I2S;
    i2s_cfg.frame_clk_freq = 8000;
    i2s_cfg.block_size = BLOCK_SIZE;
    i2s_cfg.timeout =1000;
    i2s_cfg.options = I2S_OPT_FRAME_CLK_MASTER | I2S_OPT_BIT_CLK_MASTER;

    ret = i2s_configure(dev_i2s, I2S_DIR_TX, &i2s_cfg);
    if (ret)
    {
        printk("I2S configure failed (%d)\n", ret);
        return ret;
    }

    printk("I2S configured.........\n");

    // PREPARE AUDIO BUFFERS
    for (int i = 0; i < NUM_BLOCKS; i++)
    {
        fill_buf(tx_block[i], i % 3);
    }

    // QUEUE BUFFERS BEFORE START
    ret = i2s_write(dev_i2s, tx_block[0], BLOCK_SIZE);

    ret |= i2s_write(dev_i2s, tx_block[1], BLOCK_SIZE);

    if (ret)
    {
        printk("I2S write failed (%d)\n", ret);
        return ret;
    }

    printk("Initial TX buffers queued\n");

    // NOW START I2S -lrck
    ret = i2s_trigger(dev_i2s, I2S_DIR_TX, I2S_TRIGGER_START);
    if (ret)
    {
        printk("I2S start failed (%d)\n", ret);
        return ret;
    }

    printk("I2S started successfully\n");

 // remaining buffer
    int idx = 2;
    while (1)
    {
        ret = i2s_write(dev_i2s, tx_block[idx % NUM_BLOCKS], BLOCK_SIZE);
       // ret = i2s_write(dev_i2s, tx_block[idx % NUM_BLOCKS], BLOCK_SIZE);
        if (ret == 0)
        {
            idx++;
            k_msleep(1);
        }
        else if (ret == -EAGAIN)
        {
            i2s_trigger(dev_i2s, I2S_DIR_TX, I2S_TRIGGER_DRAIN);
            i2s_trigger(dev_i2s, I2S_DIR_TX, I2S_TRIGGER_START);
            k_msleep(2);
        }
        else
        {
            printk("I2S write error (%d)\n", ret);
            break;
        }
    }
   printk("i2s_write.............");
    return 0;
}


 ovelay file 

&pinctrl {
    i2c21_default: i2c22_default {
        group1 {
            psels =
                    <NRF_PSEL(TWIM_SCL, 1, 12)>,
                    <NRF_PSEL(TWIM_SDA, 1, 13)>;
                    bias-pull-up;
                   
        };
    };

    i2c21_sleep: i2c22_sleep {
        group1 {
            psels = <NRF_PSEL(TWIM_SCL, 1,12)>,
                    <NRF_PSEL(TWIM_SDA, 1, 13)>;
                    low-power-enable;
        };
    };

    i2s20_default: i2s20_default {
        group1 {
            psels = <NRF_PSEL(I2S_SDIN, 1, 6)>, <NRF_PSEL(I2S_SCK_S, 1, 3)>;
        };
    };

    i2s20_sleep: i2s20_sleep {
        group1 {
            psels = <NRF_PSEL(I2S_SDIN, 1, 6)>,
                    <NRF_PSEL(I2S_SDOUT, 1, 5)>,
                    <NRF_PSEL(I2S_SCK_S, 1, 3)>,
                    <NRF_PSEL(I2S_MCK, 1, 4)>,
                    <NRF_PSEL(I2S_LRCK_M, 1, 14)>;
        };
    };


};

&i2c21 {
    status = "disabled";
    pinctrl-0 = <&i2c22_default>;
    pinctrl-1 = <&i2c22_sleep>;
    pinctrl-names = "default", "sleep";

    audiocodec: audiocodec@18 {
        compatible = "i2c-device";
        status = "okay";
        reg = < 0x18 >;
    };
};

&i2s20 {
    status = "okay";
    pinctrl-0 = <&i2s20_default>;
    pinctrl-1 = <&i2s20_sleep>;
    pinctrl-names = "default", "sleep";
};



/ {
     custom_pins{
        compatible = "gpio-keys";

        codec_reset: codec-reset-node {
            gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
            label = "Codec Reset Pin";
        };
    };
};



&i2c21 {
    status = "okay";
};

/ {
    button0: button_0 {
        compatible = "gpio-keys";
        button0_key: button0_key {
            gpios = <&gpio1 15 0>;
            label = "MCUBoot Button";
        };
    };
    leds {
        compatible = "gpio-leds";

        led0: led_0 {
            gpios = <&gpio1 0 GPIO_ACTIVE_HIGH>;
            label = "User LED 0";
        };
    };
   
       

};

&uart20 {
    status = "okay";
};

&uart20_default {
    group1 {
        psels = <NRF_PSEL(UART_TX, 1, 8)>, <NRF_PSEL(UART_RX, 1, 7)>;
    };
};


/delete-node/ &{/pin-controller/i2c22_default/group2/};

&i2c22 {
    status = "disabled";
};

/delete-node/ &button0;
/delete-node/ &{/pin-controller/i2s20_default/group5/};
/delete-node/ &{/pin-controller/i2s20_default/group2/};
/delete-node/ &{/pin-controller/i2s20_default/group4/};
/delete-node/ &{/pin-controller/i2s20_default/group3/};
 should i implement mclk clock seprate in code ??  
OK
[00:06:49.411,024] <inf> i2s_nrfx: I2S MCK frequency: 256000, actual PCM rate: 8000
Parents
  • Hi,

    Thanks for the updates. I think we may be mixing a few different topics, so just to make sure I understand you correctly and can help in the right direction, could we first align on one thing? Could you please confirm what you want the nRF54L15 to do for the I2S clocks:

    1. Option A:
      The nRF54L15 should generate the I2S clocks (BCLK, LRCK, and MCK), and the codec should use those clocks.
    2. Option B:
      The nRF54L15 should work as an I2S slave, and the clocks (BCLK/LRCK/MCK) are provided by an external source or the codec.

    These two setups are configured very differently, so confirming this first will help avoid confusion. Once this is clear, we can then look at: the I2S -11 (-EAGAIN) messages, and the I2C -5 (I/O error) issue separately if it still happens.

    Thanks for confirming, and we’ll take it step by step from there. Regards,
    Syed Maysum

    1. Option B:
      The nRF54L15 should work as an I2S slave, and the clocks (BCLK/LRCK/MCK) are provided by an external source or the codec.  this one
  • Hi

    Thanks for the update. I can see that I2C is still not stable in free-run. At this point, I won’t be able to help further until the I2C-only stress test (with I2S disabled) completes without -EIO.

    Best Regards,
    Syed Maysum

  • stress test is completed without i2s - is proper

  • /*
     * Copyright 2023 NXP
     *
     * SPDX-License-Identifier: Apache-2.0
     */

    #include <stdio.h>
    #include <zephyr/kernel.h>
    #include <zephyr/drivers/i2s.h>
    #include <zephyr/sys/iterable_sections.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include "codec/codec.h"
    #include <zephyr/drivers/gpio.h>

    #define SAMPLE_NO 64
    const struct device *dev_i2s = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(i2s20));

    /* The data represent a sine wave */
    static int16_t data[SAMPLE_NO] = {
          3211,   6392,   9511,  12539,  15446,  18204,  20787,  23169,
         25329,  27244,  28897,  30272,  31356,  32137,  32609,  32767,
         32609,  32137,  31356,  30272,  28897,  27244,  25329,  23169,
         20787,  18204,  15446,  12539,   9511,   6392,   3211,      0,
         -3212,  -6393,  -9512, -12540, -15447, -18205, -20788, -23170,
        -25330, -27245, -28898, -30273, -31357, -32138, -32610, -32767,
        -32610, -32138, -31357, -30273, -28898, -27245, -25330, -23170,
        -20788, -18205, -15447, -12540,  -9512,  -6393,  -3212,     -1,
    };

    /* Fill buffer with sine wave on left channel, and sine wave shifted by
     * 90 degrees on right channel. "att" represents a power of two to attenuate
     * the samples by
     */
    static void fill_buf(int16_t *tx_block, int att)
    {
        int r_idx;

        for (int i = 0; i < SAMPLE_NO; i++)
        {
            /* Left channel is sine wave */
            tx_block[2 * i] = data[i] / (1 << att);
            /* Right channel is same sine wave, shifted by 90 degrees */
            r_idx = (i + (ARRAY_SIZE(data) / 4)) % ARRAY_SIZE(data);
            tx_block[2 * i + 1] = data[r_idx] / (1 << att);
        }
    }

    #define NUM_BLOCKS 20
    /* BLOCK_SIZE in bytes: 2 channels * SAMPLE_NO samples * 2 bytes per sample */
    #define BLOCK_SIZE (2 * SAMPLE_NO * sizeof(int16_t))

    #ifdef CONFIG_NOCACHE_MEMORY
        #define MEM_SLAB_CACHE_ATTR __nocache
    #else
        #define MEM_SLAB_CACHE_ATTR
    #endif /* CONFIG_NOCACHE_MEMORY */

    /* backing buffer for mem_slab */
    static char MEM_SLAB_CACHE_ATTR __aligned(WB_UP(32))
        _k_mem_slab_buf_tx_0_mem_slab[(NUM_BLOCKS) * WB_UP(BLOCK_SIZE)];

    static STRUCT_SECTION_ITERABLE(k_mem_slab, tx_0_mem_slab) =
        Z_MEM_SLAB_INITIALIZER(tx_0_mem_slab, _k_mem_slab_buf_tx_0_mem_slab,
                    WB_UP(BLOCK_SIZE), NUM_BLOCKS);

    /* Release one played block returned by the I2S driver (buffer API) */
    static void release_played_block(const struct device *dev)
    {
        void *block;

        while (i2s_buf_read(dev, &block, NULL) == 0 && block)
        {
            k_mem_slab_free(&tx_0_mem_slab, &block);
        }
    }


    int main(void)
    {
        void *tx_block[NUM_BLOCKS];
        struct i2s_config i2s_cfg;
        int ret;
        int tx_idx;

        printf("Enter to main........\n");

        k_msleep(300);

        ret=pwm_4mhz(); // pwm 4mhz generation for i2s mclk

        if (ret < 0)
        {
            printf("PWM 4mhz generation is failed .\n");
        }

        if (!dev_i2s)
        {
            printf("I2S device node 'i2s20' not found. Check DT label.\n");
            return -ENODEV;
        }

        if (!device_is_ready(dev_i2s))
        {
            printf("I2S device not ready...\n");
            return -ENODEV;
        }
        ret = i2c_init_codec(); // init i2c codec
        // gpio_pin_configure_dt();

        if (ret < 0)
        {
            printf("I2c init is failed .\n");
        }

        /* Configure I2S stream */
        i2s_cfg.word_size = 16U;
        i2s_cfg.channels = 2U;
        i2s_cfg.format = I2S_FMT_DATA_FORMAT_I2S;
        i2s_cfg.frame_clk_freq = 8000; /* set to your desired sample rate */
        i2s_cfg.block_size = BLOCK_SIZE;
        i2s_cfg.timeout = 1000; /* ms */
        /* Configure the Transmit port as slave */
        i2s_cfg.options = I2S_OPT_FRAME_CLK_SLAVE | I2S_OPT_BIT_CLK_SLAVE;
        i2s_cfg.mem_slab = &tx_0_mem_slab;


        ret = i2s_configure(dev_i2s, I2S_DIR_TX, &i2s_cfg);
        if (ret < 0)
        {
            printf("Failed to configure I2S stream: %d\n", ret);
            return ret;
        }

        printf("I2S configured successfully.\n");

        printf("Preparing TX blocks..\n");

      /* Allocate + fill buffers */
        for (int i = 0; i < NUM_BLOCKS; i++) {
            k_mem_slab_alloc(&tx_0_mem_slab, &tx_block[i], K_FOREVER);
            fill_buf(tx_block[i], i % 3);
        }

        /* ---- CRITICAL FIX: queue ≥4 buffers BEFORE START ---- */
        for (int i = 0; i < 4; i++)
        {
            ret = i2s_write(dev_i2s, tx_block[i], BLOCK_SIZE);
            if (ret) return ret;
        }

        ret = i2s_trigger(dev_i2s, I2S_DIR_TX, I2S_TRIGGER_START);
        if (ret) return ret;

        /* Feed remaining buffers */
        for (int i = 4; i < NUM_BLOCKS; i++) {

            release_played_block(dev_i2s);

            ret = i2s_write(dev_i2s, tx_block[i], BLOCK_SIZE);
            if (ret == -EAGAIN) {
                i--;
                continue;
            }
            if (ret < 0) {
                /* proper recovery */
                i2s_trigger(dev_i2s, I2S_DIR_TX, I2S_TRIGGER_STOP);
                i2s_trigger(dev_i2s, I2S_DIR_TX, I2S_TRIGGER_DROP);
                break;
            }
           
        }

    }  hi , I have one problem here i got -5 error when i write i2s after 7th write why ??
Reply
  • /*
     * Copyright 2023 NXP
     *
     * SPDX-License-Identifier: Apache-2.0
     */

    #include <stdio.h>
    #include <zephyr/kernel.h>
    #include <zephyr/drivers/i2s.h>
    #include <zephyr/sys/iterable_sections.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include "codec/codec.h"
    #include <zephyr/drivers/gpio.h>

    #define SAMPLE_NO 64
    const struct device *dev_i2s = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(i2s20));

    /* The data represent a sine wave */
    static int16_t data[SAMPLE_NO] = {
          3211,   6392,   9511,  12539,  15446,  18204,  20787,  23169,
         25329,  27244,  28897,  30272,  31356,  32137,  32609,  32767,
         32609,  32137,  31356,  30272,  28897,  27244,  25329,  23169,
         20787,  18204,  15446,  12539,   9511,   6392,   3211,      0,
         -3212,  -6393,  -9512, -12540, -15447, -18205, -20788, -23170,
        -25330, -27245, -28898, -30273, -31357, -32138, -32610, -32767,
        -32610, -32138, -31357, -30273, -28898, -27245, -25330, -23170,
        -20788, -18205, -15447, -12540,  -9512,  -6393,  -3212,     -1,
    };

    /* Fill buffer with sine wave on left channel, and sine wave shifted by
     * 90 degrees on right channel. "att" represents a power of two to attenuate
     * the samples by
     */
    static void fill_buf(int16_t *tx_block, int att)
    {
        int r_idx;

        for (int i = 0; i < SAMPLE_NO; i++)
        {
            /* Left channel is sine wave */
            tx_block[2 * i] = data[i] / (1 << att);
            /* Right channel is same sine wave, shifted by 90 degrees */
            r_idx = (i + (ARRAY_SIZE(data) / 4)) % ARRAY_SIZE(data);
            tx_block[2 * i + 1] = data[r_idx] / (1 << att);
        }
    }

    #define NUM_BLOCKS 20
    /* BLOCK_SIZE in bytes: 2 channels * SAMPLE_NO samples * 2 bytes per sample */
    #define BLOCK_SIZE (2 * SAMPLE_NO * sizeof(int16_t))

    #ifdef CONFIG_NOCACHE_MEMORY
        #define MEM_SLAB_CACHE_ATTR __nocache
    #else
        #define MEM_SLAB_CACHE_ATTR
    #endif /* CONFIG_NOCACHE_MEMORY */

    /* backing buffer for mem_slab */
    static char MEM_SLAB_CACHE_ATTR __aligned(WB_UP(32))
        _k_mem_slab_buf_tx_0_mem_slab[(NUM_BLOCKS) * WB_UP(BLOCK_SIZE)];

    static STRUCT_SECTION_ITERABLE(k_mem_slab, tx_0_mem_slab) =
        Z_MEM_SLAB_INITIALIZER(tx_0_mem_slab, _k_mem_slab_buf_tx_0_mem_slab,
                    WB_UP(BLOCK_SIZE), NUM_BLOCKS);

    /* Release one played block returned by the I2S driver (buffer API) */
    static void release_played_block(const struct device *dev)
    {
        void *block;

        while (i2s_buf_read(dev, &block, NULL) == 0 && block)
        {
            k_mem_slab_free(&tx_0_mem_slab, &block);
        }
    }


    int main(void)
    {
        void *tx_block[NUM_BLOCKS];
        struct i2s_config i2s_cfg;
        int ret;
        int tx_idx;

        printf("Enter to main........\n");

        k_msleep(300);

        ret=pwm_4mhz(); // pwm 4mhz generation for i2s mclk

        if (ret < 0)
        {
            printf("PWM 4mhz generation is failed .\n");
        }

        if (!dev_i2s)
        {
            printf("I2S device node 'i2s20' not found. Check DT label.\n");
            return -ENODEV;
        }

        if (!device_is_ready(dev_i2s))
        {
            printf("I2S device not ready...\n");
            return -ENODEV;
        }
        ret = i2c_init_codec(); // init i2c codec
        // gpio_pin_configure_dt();

        if (ret < 0)
        {
            printf("I2c init is failed .\n");
        }

        /* Configure I2S stream */
        i2s_cfg.word_size = 16U;
        i2s_cfg.channels = 2U;
        i2s_cfg.format = I2S_FMT_DATA_FORMAT_I2S;
        i2s_cfg.frame_clk_freq = 8000; /* set to your desired sample rate */
        i2s_cfg.block_size = BLOCK_SIZE;
        i2s_cfg.timeout = 1000; /* ms */
        /* Configure the Transmit port as slave */
        i2s_cfg.options = I2S_OPT_FRAME_CLK_SLAVE | I2S_OPT_BIT_CLK_SLAVE;
        i2s_cfg.mem_slab = &tx_0_mem_slab;


        ret = i2s_configure(dev_i2s, I2S_DIR_TX, &i2s_cfg);
        if (ret < 0)
        {
            printf("Failed to configure I2S stream: %d\n", ret);
            return ret;
        }

        printf("I2S configured successfully.\n");

        printf("Preparing TX blocks..\n");

      /* Allocate + fill buffers */
        for (int i = 0; i < NUM_BLOCKS; i++) {
            k_mem_slab_alloc(&tx_0_mem_slab, &tx_block[i], K_FOREVER);
            fill_buf(tx_block[i], i % 3);
        }

        /* ---- CRITICAL FIX: queue ≥4 buffers BEFORE START ---- */
        for (int i = 0; i < 4; i++)
        {
            ret = i2s_write(dev_i2s, tx_block[i], BLOCK_SIZE);
            if (ret) return ret;
        }

        ret = i2s_trigger(dev_i2s, I2S_DIR_TX, I2S_TRIGGER_START);
        if (ret) return ret;

        /* Feed remaining buffers */
        for (int i = 4; i < NUM_BLOCKS; i++) {

            release_played_block(dev_i2s);

            ret = i2s_write(dev_i2s, tx_block[i], BLOCK_SIZE);
            if (ret == -EAGAIN) {
                i--;
                continue;
            }
            if (ret < 0) {
                /* proper recovery */
                i2s_trigger(dev_i2s, I2S_DIR_TX, I2S_TRIGGER_STOP);
                i2s_trigger(dev_i2s, I2S_DIR_TX, I2S_TRIGGER_DROP);
                break;
            }
           
        }

    }  hi , I have one problem here i got -5 error when i write i2s after 7th write why ??
Children
  • external clcok is use, 4mhz generated here , after thata i2c write is prorper niw and but i2s is failed 

  • /*
     * Codec-style I2S SLAVE playback (continuous)
     * Stable design for nRF54L15 + external codec
     *
     * SPDX-License-Identifier: Apache-2.0
     */

    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include <zephyr/drivers/i2s.h>
    #include <zephyr/sys/printk.h>
    #include <zephyr/sys/iterable_sections.h>
    #include "codec/codec.h"

    /* ================= CONFIG ================= */

    #define I2S_NODE DT_NODELABEL(i2s20)

    /* Audio format */
    #define SAMPLE_RATE_HZ     8000
    #define SAMPLE_BIT_WIDTH   16
    #define CHANNELS           2

    /* 100 ms audio block */
    #define SAMPLES_PER_BLOCK  (SAMPLE_RATE_HZ / 10)   /* 800 frames */
    #define BYTES_PER_SAMPLE   sizeof(int16_t)
    #define BLOCK_SIZE         (SAMPLES_PER_BLOCK * CHANNELS * BYTES_PER_SAMPLE)

    /* Buffering */
    #define INIT_BLOCKS        6
    #define BLOCK_COUNT        (INIT_BLOCKS + 6)
    #define TIMEOUT_MS         2000

    /* ================= DEVICE ================= */

    static const struct device *i2s_dev = DEVICE_DT_GET(I2S_NODE);

    /* ================= SINE LUT ================= */
    /* Small lookup table – expanded into big buffers */

    static const int16_t sine_lut[] = {
         3211,  6392,  9511, 12539, 15446, 18204, 20787, 23169,
        25329, 27244, 28897, 30272, 31356, 32137, 32609, 32767,
        -3212, -6393, -9512,-12540,-15447,-18205,-20788,-23170,
       -25330,-27245,-28898,-30273,-31357,-32138,-32610,-32767
    };

    /* ================= MEM SLAB ================= */

    K_MEM_SLAB_DEFINE_IN_SECT_STATIC(
        tx_mem_slab,
        __nocache,
        BLOCK_SIZE,
        BLOCK_COUNT,
        4
    );

    /* ================= HELPERS ================= */

    static void fill_audio_block(int16_t *buf)
    {
        int lut_len = ARRAY_SIZE(sine_lut);

        for (int i = 0; i < SAMPLES_PER_BLOCK; i++) {
            int16_t s = sine_lut[i % lut_len];
            buf[2 * i]     = s;   /* Left */
            buf[2 * i + 1] = s;   /* Right */
        }
    }

    /* ================= MAIN ================= */

    int main(void)
    {
        struct i2s_config cfg;
        void *block;
        int ret;
        int queued = 0;

        printk("Codec-style I2S SLAVE (continuous)\n");

        /* Start external clocks + codec */
        ret = pwm_4mhz();
        if (ret < 0) {
            printk("MCLK start failed\n");
            return ret;
        }

        ret = i2c_init_codec();
        if (ret < 0) {
            printk("Codec init failed\n");
            return ret;
        }

        if (!device_is_ready(i2s_dev)) {
            printk("I2S device not ready\n");
            return -ENODEV;
        }

        /* -------- I2S CONFIG (SLAVE) -------- */
        cfg.word_size      = SAMPLE_BIT_WIDTH;
        cfg.channels       = CHANNELS;
        cfg.format         = I2S_FMT_DATA_FORMAT_I2S;
        cfg.options        = I2S_OPT_FRAME_CLK_SLAVE |
                             I2S_OPT_BIT_CLK_SLAVE;
        cfg.frame_clk_freq = SAMPLE_RATE_HZ;
        cfg.block_size     = BLOCK_SIZE;
        cfg.mem_slab       = &tx_mem_slab;
        cfg.timeout        = TIMEOUT_MS;

        ret = i2s_configure(i2s_dev, I2S_DIR_TX, &cfg);
        if (ret < 0)
        {
            printk("I2S configure failed: %d\n", ret);
            return ret;
        }

        /* -------- Prefill buffers BEFORE START -------- */
        for (int i = 0; i < INIT_BLOCKS; i++)
        {
            ret = k_mem_slab_alloc(&tx_mem_slab, &block, K_FOREVER);
            if (ret < 0)
            {
                printk("Slab alloc failed\n");
                return ret;
            }

            fill_audio_block((int16_t *)block);

            ret = i2s_write(i2s_dev, block, BLOCK_SIZE);
            printk("fill_audio_block %d buffers\n", (int16_t *)block);
            if (ret == -EAGAIN) {
            printk("TX queue full after %d buffers\n", queued);
            k_mem_slab_free(&tx_mem_slab, block);
            break;
        }
        if (ret < 0) {
            printk("i2s_write failed: %d\n", ret);
            return ret;
        }

        queued++;
        }

        /* -------- START ONCE -------- */
        ret = i2s_trigger(i2s_dev, I2S_DIR_TX, I2S_TRIGGER_START);
        if (ret < 0)
        {
            printk("I2S START failed: %d\n", ret);
            return ret;
        }

        printk("Playback running...\n");

        /* -------- Continuous refill (safe) -------- */
        // while (1) {
        //     void *released;

        //     if (i2s_buf_read(i2s_dev, &released, NULL) == 0 && released)
        //     {
        //         fill_audio_block((int16_t *)released);
        //         i2s_write(i2s_dev, released, BLOCK_SIZE);
               
         
        //     }
        // }
       while (1) {
        void *released;
        size_t size;

        int r = i2s_buf_read(i2s_dev, &released, &size);

        if (r == 0 && released) {
            printk("TX buffer completed\n");

            fill_audio_block((int16_t *)released);
            i2s_write(i2s_dev, released, BLOCK_SIZE);
        } else if (r == -EAGAIN) {
            /* No completed buffer yet – this is normal */
            k_msleep(1);
        } else {
            printk("i2s_buf_read error: %d\n", r);
            break;
        }
    }

       
    }
Related