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 confirming the I2S slave setup. To summarize and move forward clearly:

    1. I2S slave mode and clocks
      Since the nRF54L15 is configured as an I2S slave, it does not control BCLK or LRCK. MCK must be provided by the external device (codec), or explicitly enabled internally only if the external master cannot provide it. So If your codec provides MCK, please remove all master clock settings (mck_setup, ratio, clksrc) from the nrfx_i2s configuration to avoid clock conflicts.
      // REMOVE these
      .mck_setup
      .ratio
      .clksrc
    2. Pin routing on nRF54L15
      On nRF54L15, the I2S peripheral and TWIM2x (I2C20, I2C21, I2C22) instances must be routed to Port P1 pins only. TWIM30 is the only I2C instance that can use Port P0. So remember Port P2 cannot be used for these serial peripherals as shown in this block diagram. Please double-check that all I2S and I2C pins are assigned to Port 1 pins (or Port 0 pin for TWIM30/I2C30). Using pins on other ports can lead to communication failures, including the -5 (EIO) behavior you are seeing.
    3. I2S -11 (-EAGAIN)
      This is expected behavior when the TX queue is temporarily full and can be handled by retrying, as you are already doing.

    Once external clocks are stable and pin routing is corrected, both I2C and I2S behavior should be consistent. Best Regards,
    Syed Maysum

Reply
  • Hi,

    Thanks for confirming the I2S slave setup. To summarize and move forward clearly:

    1. I2S slave mode and clocks
      Since the nRF54L15 is configured as an I2S slave, it does not control BCLK or LRCK. MCK must be provided by the external device (codec), or explicitly enabled internally only if the external master cannot provide it. So If your codec provides MCK, please remove all master clock settings (mck_setup, ratio, clksrc) from the nrfx_i2s configuration to avoid clock conflicts.
      // REMOVE these
      .mck_setup
      .ratio
      .clksrc
    2. Pin routing on nRF54L15
      On nRF54L15, the I2S peripheral and TWIM2x (I2C20, I2C21, I2C22) instances must be routed to Port P1 pins only. TWIM30 is the only I2C instance that can use Port P0. So remember Port P2 cannot be used for these serial peripherals as shown in this block diagram. Please double-check that all I2S and I2C pins are assigned to Port 1 pins (or Port 0 pin for TWIM30/I2C30). Using pins on other ports can lead to communication failures, including the -5 (EIO) behavior you are seeing.
    3. I2S -11 (-EAGAIN)
      This is expected behavior when the TX queue is temporarily full and can be handled by retrying, as you are already doing.

    Once external clocks are stable and pin routing is corrected, both I2C and I2S behavior should be consistent. Best Regards,
    Syed Maysum

Children
  • hi 


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

        i2c21_sleep: i2c21_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_SDOUT, 1, 5)>,
                        <NRF_PSEL(I2S_SCK_S, 1, 3)>,
                        <NRF_PSEL(I2S_MCK, 1, 4)>,
                        <NRF_PSEL(I2S_LRCK_M, 1, 14)>;
            };
        };

        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{

        compatible = "nordic,nrf-twim";
        pinctrl-0 = <&i2c21_default>;
        pinctrl-1 = <&i2c21_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";
            };
            led1: led_1 {
                gpios = <&gpio1 8 0>;
                label = "PWM LED 1";
            };

        };
       
       
    };

    &uart20 {
        status = "disabled";
    };

    &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/};

    &timer22 {
        status = "okay";
    };



    &i2c30 {
        status = "disabled";
    }; this is my overlay
    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/drivers/i2s.h>
    #include <zephyr/sys/printk.h>
    #include <string.h>
    #include "codec_header.h"
    #include <stdbool.h>
    #include "nrf.h"
    #include <zephyr/drivers/gpio.h>


    /* CONFIG */
    #define SAMPLE_NO     64
    #define CHANNELS      2
    #define NUM_BLOCKS    4

    #define SAMPLE_RATE   8000
    #define WORD_SIZE     16

    #define BLOCK_SIZE (SAMPLE_NO * CHANNELS * sizeof(int16_t))

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

    // STATIC DMA-SAFE BUFFERS
    static int16_t tx_buf[NUM_BLOCKS][SAMPLE_NO * CHANNELS];

    /* SINE WAVE */
    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
    };

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

    int main(void)
    {
        struct i2s_config i2s_cfg = {0};
        int ret;
        int idx = 0;

        printk("=== I2S static buffer test ===\n");

        if (!device_is_ready(dev_i2s)) {
            printk("I2S device not ready\n");
            return 0;
        }

        // Timer

       //  start_timer();

        /* Codec init */
        ret = i2c_init_codec();

       // k_msleep(1000);

        if (ret) {
            printk("Codec init failed (%d)\n", ret);
            return 0;
        }

        // I2S CONFIG
        i2s_cfg.word_size      = WORD_SIZE;
        i2s_cfg.channels       = CHANNELS;
        i2s_cfg.format         = I2S_FMT_DATA_FORMAT_I2S;
        i2s_cfg.frame_clk_freq = SAMPLE_RATE;
        i2s_cfg.block_size     = BLOCK_SIZE;
        i2s_cfg.timeout        = 2000;
        i2s_cfg.options =
            I2S_OPT_FRAME_CLK_SLAVE |
            I2S_OPT_BIT_CLK_SLAVE;

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

        // Queue initial buffers
        for (int i = 0; i < NUM_BLOCKS; i++)
        {
            fill_buf(tx_buf[i], i);

            i2s_write(dev_i2s, tx_buf[i], BLOCK_SIZE);
        }

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

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

        while (1)
        {
            fill_buf(tx_buf[idx % NUM_BLOCKS], idx % 3);

            ret = i2s_write( dev_i2s, tx_buf[idx % NUM_BLOCKS],BLOCK_SIZE);

            if (ret == 0)
            {
                idx++;
            } else if (ret == -EAGAIN) {
                k_msleep(1);
            } else {
                printk("I2S write error (%d)\n", ret);
                break;
            }
        }

        i2s_trigger(dev_i2s, I2S_DIR_TX, I2S_TRIGGER_DROP);

        printf("I2S test done\n");
       
        return 0;
    } this is my main function and timer implementaion - 4 khz i need 
     
    #include <zephyr/kernel.h>
    #include <zephyr/drivers/i2c.h>
    #include <zephyr/drivers/gpio.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include "codec_header.h"


    #define CODEC_ADDR 0x18 // i2c slave adress
    //#define MAX_ADDR 0x55
    #define RESET_NODE DT_NODELABEL(led0)
    #define GPIO_TOGGLE_PIN  8

    static const struct gpio_dt_spec codec_reset_pin = GPIO_DT_SPEC_GET(DT_NODELABEL(codec_reset), gpios);

    static const struct i2c_dt_spec dev_i2c =I2C_DT_SPEC_GET(DT_NODELABEL(audiocodec));
    //static const struct  i2c_dt_spec *dev_i2c=DEVICE_DT_GET(DT_NODELABEL(audiocodec));

    //static const struct device *dev_i2c = DEVICE_DT_GET(DT_NODELABEL(i2c22));

    //static const struct gpio_dt_spec max_reset_pin = GPIO_DT_SPEC_GET(DT_NODELABEL(max_reset), gpios); // for max reset pin

    //static const struct gpio_dt_spec mfin_reset_pin = GPIO_DT_SPEC_GET(DT_NODELABEL(mfin_pin), gpios);// for mfin pin




    /**
     * Register declaration
     */

    const register_value REGISTER_DATA[] = {
        //          # reg[0][0]   = 0x00   ; Select Page 0
        {0, 0x00},
        //          # reg[0][1]   = 0x01   ; S/W Reset
        {1, 0x01},
        //          # reg[0][4]   = 0x03   ; PLL_CLKIN = MCLK = 4 MHz., CODEC_CLKIN = PLL_CLCK
        {4, 0x03},
        //          # reg[0][5]   = 0xD4   ; PLL Power up, P = 5, R = 4
        {5, 0xD4},
        //          # reg[0][6]   = 0x20   ; J = 32
        {6, 0x20},
        //          # reg[0][7]   = 0x00   ; D = 0000, D(13:8) = 0
        {7, 0x00},
        //          # reg[0][8]   = 0x00   ; D(7:0) = 0
        {8, 0x00},
        //          # reg[0][27]  = 0x0C   ; Mode = I2S, wordlength = 16, output mode
        {27, 0x0C},
        //          # reg[0][11]  = 0x84   ; DAC Powerup NDAC = 4 (DAC_MAC_CLK = 102.4 MHz/4 = 25.6 MHz.)
        {11, 0x84},
        //          # reg[0][12]  = 0x99   ; DAC Powerup MDAC = 25  (DAC_MOD_CLK = 25.6/ 25 = 1.024 MHz.)
        {12, 0x99},
        //          # reg[0][14]  = 0x80   ;  DOSR = 128 (ADC Fs = 1.024 / 128 = 8.0 KHz.)
        {14, 0x80},
        //          # reg[0][18]  = 0x84   ; ADC Powerup NADC = 4 (ADC_MAC_CLK = 102.4 MHz/4 = 25.6 MHz.)
        {18, 0x84},
        //          # reg[0][19]  = 0x99   ; ADC Powerup MADC = 25 (ADC_MOD_CLK = 25.6 MHz/25 = 1.024 MHz.)
        {19, 0x99},
        //          # reg[0][20]  = 0x80   ; AOSR = 20 (ADC Fs = 1.024 / 128 = 8.0 KHz.)
        {20, 0x80},
        //          # reg[0][29]  = 0X01   ; DAC_MOD_CLOCK
        {29, 0x01},
        //          # reg[0][30]  = 0x84   ; BCLK N-divider, BCLK divider N = 4
        {30, 0x84},
        //          # reg[0][0]   = 0x01   ; Select Page 1
        {0, 0x01},
        //          # reg[1][46]  = 0x0B   ; MICBIAS always on, MICBIAS = 2.5V
        {46, 0x0A},
        //          # reg[1][48]  = 0x40   ; MICLP is selected for left of Mic PGA P @ 10k input impedance
        {48, 0x40},
        //          # reg[1][49]  = 0x40   ; CM is selected for right of Mic PGA M @ 10k input impedance
        {49, 0x40},
        //          # reg[1][47]  = 0x0    ; MIC PGA ;  db
        {47, 0x00},
        //          # reg[0][0]   = 0x00   ; Select Page 0
        {0, 0x00},
        //          # reg[0][81]  = 0x80   ; Powerup ADC channel (soft step enable)
        {81, 0x80},
        //          # reg[0][83]  = 0x00   ; ADC volume = 0dB
        {83, 0x00},
        //           reg[0][82]  = 0x00   ; Unmute ADC channel
        {82, 0x00},

    };

    // const struct device *dev_i2c = DEVICE_DT_GET(DT_NODELABEL(i2c22)); // i2c


    static const struct gpio_dt_spec rst = GPIO_DT_SPEC_GET(RESET_NODE, gpios); // for reset pin

    const size_t REGISTER_LEN = sizeof(REGISTER_DATA) / sizeof(register_value);

    uint32_t cfg = I2C_MODE_CONTROLLER | I2C_SPEED_SET(I2C_SPEED_STANDARD); // configration of i2c

    /**
     * @brief codec_i2c_write
     * @param
     * device tree
     * adress
     * buffer
     * length of message
     */
    static int codec_i2c_write(const struct device *dev,
                               uint8_t addr, uint8_t *buf, uint32_t len)
    {
        struct i2c_msg msg = {
            .buf = buf,
            .len = len,
            .flags = I2C_MSG_WRITE | I2C_MSG_STOP,
        };

        return i2c_transfer(dev, &msg, 2, addr);
    }
    /**
     *
     */
    static int codec_i2c_write_read(const struct device *dev,
                                    uint16_t addr,
                                    const void *write_buf, size_t num_write,
                                    void *read_buf, size_t num_read)
    {

        struct i2c_msg msg[2];
        // printf("address...%x",addr);
        msg[0].buf = (uint8_t *)write_buf;
        msg[0].len = num_write;
        msg[0].flags = I2C_MSG_WRITE;

        msg[1].buf = (uint8_t *)read_buf;
        msg[1].len = num_read;
        msg[1].flags = I2C_MSG_READ | I2C_MSG_STOP;

        // return i2c_transfer(dev, &msg[0], 2, addr);
        return i2c_write_read_dt(&dev_i2c, write_buf, num_write, read_buf, num_read);
    }

    // reset pin
    void codec_reset_pulse(void)
    {
         int ret;

        ret=gpio_pin_set_dt(&codec_reset_pin, 1);
        k_msleep(10);

        // HIGH → reset released
        ret=gpio_pin_set_dt(&codec_reset_pin, 0);
        k_msleep(20); //20

        return 0;
       
    }

    /**
     * brief@
     * param@
     */

    static int codec_write_register(uint8_t page, uint8_t reg, uint8_t val)
    {
        static uint8_t last_page = 0xFF; // invalid page at start
        uint8_t tx_buf[2];
        uint8_t red_buff[2];
        int err;

        // Only update page register if page actually changed
        if (page != last_page)
        {
            tx_buf[0] = 0x00; // Page Select Register
            tx_buf[1] = page;

           //err = codec_i2c_write(&dev_i2c, CODEC_ADDR, tx_buf, 2);
           err=i2c_write_read_dt(&dev_i2c,tx_buf,2,red_buff,2);
           k_msleep(5);
            if (err)
            {
                printk("I2C: page switch failed (page=%u) err=%d\n", page, err);
                return err;
            }

            last_page = page; // update page tracking
            k_msleep(2);      // small delay for codec stability
        }

        // Now write the actual register
        tx_buf[0] = reg;
        tx_buf[1] = val;
        err=i2c_write_read_dt(&dev_i2c,tx_buf,2,red_buff,2);
        if (err)
        {
            printk("I2C: reg write ....read ...failed (p=%u reg=0x%02X val=0x%02X) err=%d\n",
                   page, reg, val, err);
        }
       

         printk("I2C: reg write ....read ...succc ( reg=0x%02X val=0x%02X) err=%d\n  read_buff[0]=0x%02X   read_buff[1]=0x%02X ",
                   page, reg, val, err,red_buff[0], red_buff[1]);
        return err;
    }

    /**
     *
     */

    static int codec_write_table(const register_value *table, size_t len)
    {
        uint8_t current_page = 0x00;
        uint8_t read_buff=0;
        int err;
     

        for (size_t i = 0; i < len; i++)
        {
            uint8_t reg = table[i].reg_no;
            uint8_t val = table[i].reg_value;

            // Page change
            if (reg == 0x00)
            {
                current_page = val;
                k_msleep(1);
                continue;
            }

            // Normal register write on current page
            err = codec_write_register(current_page, reg, val);
            if (err)
            {
                printf("fail.......reg=0x%02X val=0x%02X err=%d\n", reg, val, err);
                return err;
            }  

            printf("reg=0x%02X val=0x%02X err=%d\n", reg, val, err);
             

            k_msleep(10);
        }

        return 0;
    }

    /**
     *
     */
    static bool codec_probe(void)
    {
     
        uint8_t reg0[2] = {0x00,0x00};
        uint8_t read_back = 0;
         int err;

        err= i2c_write_read_dt(&dev_i2c, &reg0, 2, &read_back, 2);
       // k_msleep(5);
        if (err)
        {
            printk("I2C probe failed err=%d\n", err);
            return false;
        }

        printk("Codec responded: reg0 = 0x%02X\n", read_back);

        return true;
    }


    //nrf_drv_twi_tx();

    // read command
    int read_eg(void)
    {
        int ret;
        uint8_t reg = 0xD4;
        uint8_t val = 0;

        ret = i2c_write_read_dt(&dev_i2c,
                                &reg, 2,
                                &val, 2);
        if (ret)
        {
            printk("I2C read failed reg 0x%02x err %d\n", reg, ret);
            return ret;
        }

        printk("Read reg 0x%02x = 0x%02x\n", reg, val);

        return 0;
    }

    int codec_hw_reset(void)
     {
        int ret;

        ret=gpio_pin_set_dt(&codec_reset_pin, 1);
        k_msleep(10);

        /* HIGH → reset released */
        ret=gpio_pin_set_dt(&codec_reset_pin, 0);
        k_msleep(20);


        return 0;
    }

    static int codec_i2c_config(void)
    {
        if (!device_is_ready(dev_i2c.bus))
        {
            printk("Error: I2C bus %s is not ready!\n", dev_i2c.bus->name);
            return -1;
        }
       

        printk("I2C bus ready, addr=0x%02x\n", dev_i2c.addr); //dev_i2c.addr
     

        return 0;
    }

    static int codec_gpios_config(void)
    {
        int ret;

        if (!gpio_is_ready_dt(&codec_reset_pin))
        {
            printk("Error: Codec reset pin not ready\n");
            return -1;
        }
        ret=gpio_pin_configure_dt(&codec_reset_pin,
                                    GPIO_OUTPUT_ACTIVE |
                                    GPIO_ACTIVE_LOW);
       
        if (ret < 0)
        {
            printk("Error %d: Failed to configure codec reset pin\n", ret);
            return -1;
        }

        return 0;
    }

    int codec_init(void)
    {
       
        //
        int ret;

        ret = codec_gpios_config();
        if (ret != 0)
        {
            return ret;
        }

        ret = codec_i2c_config();
        if (ret != 0)
        {
            return ret;
        }

        ret = codec_hw_reset();
        if (ret != 0)
        {
            return ret;
        }
        k_msleep(20);
        read_eg();

        return 0;
    }


    //

    /**
     * i2c_init()
     *
     */
    int i2c_init_codec()
    {
        int err;

        int ret;

        ret = codec_gpios_config();
        k_msleep(20);

        if (ret)
        {
            return ret;
        }

        if (!device_is_ready(dev_i2c.bus))
        {
            printk("I2C bus %s is not ready!\n", dev_i2c.bus->name);
            return -1;
        }
        k_msleep(20);
        printk("I2C bus ready, addr=0x%02x\n",dev_i2c.addr);

       
        // reset pin config
        codec_reset_pulse();

        /*codec address check*/
        if (!codec_probe())
        {
            printk("Codec not found on I2C address 0x%02X\n", CODEC_ADDR);
            return -EIO;
        }
       //  k_msleep(20);
        printk("Writing codec register table...\n");

        err = codec_write_table(REGISTER_DATA, REGISTER_LEN);

        if (err)
        {
            printk("Codec register table FAILED: %d\n", err);
            return err;
        }

        k_msleep(20);

        printk("Codec init DONE.\n");

        printk("I2C ready\n");
        return 0;
    }

    // Timer start function
    void start_timer(void)
    {
        NRF_TIMER22->MODE      = TIMER_MODE_MODE_Timer;
        NRF_TIMER22->BITMODE   = TIMER_BITMODE_BITMODE_16Bit;
        NRF_TIMER22->PRESCALER = 0;          // 16 MHz timer clock

        NRF_TIMER22->CC[0] = 3999;            // 4 kHz

        // Auto clear timer on compare
        NRF_TIMER22->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Msk;

        // Enable interrupt
        NRF_TIMER22->INTENSET = TIMER_INTENSET_COMPARE0_Msk;
        NVIC_EnableIRQ(TIMER22_IRQn);

        NRF_TIMER22->TASKS_START = 1;
    }


    void TIMER22_IRQHandler(void)
    {
        if (NRF_TIMER22->EVENTS_COMPARE[0])
        {
            NRF_TIMER22->EVENTS_COMPARE[0] = 0;
            nrf_gpio_pin_toggle(GPIO_TOGGLE_PIN);
        }
    } this is my codec and timer file 
    1. Currently, I am facing an issue where I2C works correctly while debugging step by step, but fails with a -5 (EIO) error during free-run execution when the I2S pins are connected. When the I2S lines are disconnected, I2C register reads work properly. 
  • Expected behaviour, code is still missing the required k_mem_slab buffer handling code completely as far as I can tell.

  • /*
    * Copyright 2024–2025
    * SPDX-License-Identifier: Apache-2.0
    */

    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/drivers/i2s.h>
    #include <zephyr/sys/printk.h>
    #include <string.h>
    #include <stdbool.h>

    #include "codec_header.h"

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

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

    #define SAMPLE_RATE 8000
    #define WORD_SIZE 16

    #define BLOCK_SIZE (SAMPLE_NO * CHANNELS * sizeof(int16_t))
    #define TIMEOUT_MS 2000

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

    #define I2S_NODE DT_NODELABEL(i2s20)
    static const struct device *dev_i2s = DEVICE_DT_GET(I2S_NODE);

    /* ================= MEMORY SLAB ================= */
    /* DMA-safe memory pool for I2S */
    K_MEM_SLAB_DEFINE(tx_slab, BLOCK_SIZE, NUM_BLOCKS, 4);

    /* ================= SINE WAVE ================= */

    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
    };

    /* ================= BUFFER FILL ================= */

    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] >> shift; /* Right */
    }
    }

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

    int main(void)
    {
    struct i2s_config i2s_cfg = {0};
    int ret;
    int idx = 0;

    printk("\n=== I2S k_mem_slab TX test ===\n");

    /* ---------- Device ready ---------- */

    if (!device_is_ready(dev_i2s)) {
    printk("I2S device not ready\n");
    return 0;
    }

    /* ---------- Codec init ---------- */

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

    /* ---------- I2S CONFIG ---------- */

    i2s_cfg.word_size = WORD_SIZE;
    i2s_cfg.channels = CHANNELS;
    i2s_cfg.format = I2S_FMT_DATA_FORMAT_I2S;
    i2s_cfg.frame_clk_freq = SAMPLE_RATE;
    i2s_cfg.block_size = BLOCK_SIZE;
    i2s_cfg.timeout = TIMEOUT_MS;
    i2s_cfg.mem_slab = &tx_slab;

    i2s_cfg.options =
    I2S_OPT_FRAME_CLK_SLAVE |
    I2S_OPT_BIT_CLK_SLAVE;

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

    /* ---------- Queue initial buffers ---------- */

    for (int i = 0; i < NUM_BLOCKS; i++) {
    void *mem_block;

    ret = k_mem_slab_alloc(&tx_slab, &mem_block, K_FOREVER);
    if (ret) {
    printk("Slab alloc failed\n");
    return 0;
    }

    fill_buf((int16_t *)mem_block, i);
    i2s_write(dev_i2s, mem_block, BLOCK_SIZE);
    }

    /* ---------- Start I2S ---------- */

    ret = i2s_trigger(dev_i2s, I2S_DIR_TX, I2S_TRIGGER_START);
    if (ret) {
    printk("I2S start failed (%d)\n", ret);
    return 0;
    }

    printk("I2S streaming started\n");

    /* ---------- Streaming loop ---------- */

    while (1) {
    void *mem_block;

    ret = k_mem_slab_alloc(&tx_slab, &mem_block, K_FOREVER);
    if (ret) {
    printk("Slab alloc failed\n");
    break;
    }

    fill_buf((int16_t *)mem_block, idx % 3);

    ret = i2s_write(dev_i2s, mem_block, BLOCK_SIZE);

    if (ret == 0) {
    idx++;
    } else if (ret == -EAGAIN) {
    k_mem_slab_free(&tx_slab, mem_block);
    k_msleep(1);
    } else {
    printk("I2S write error (%d)\n", ret);
    k_mem_slab_free(&tx_slab, mem_block);
    break;
    }
    }

    /* ---------- Stop ---------- */

    i2s_trigger(dev_i2s, I2S_DIR_TX, I2S_TRIGGER_DROP);

    printk("I2S test done\n");
    return 0;
    }  cirrect it please check and solve my problem in i2c and i2s

Related