[00:06:49.411,024] <inf> i2s_nrfx: I2S MCK frequency: 256000, actual PCM rate: 8000
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:
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
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
Hi,
To solve this efficiently, we need to validate one interface at a time. I’ve reviewed your code carefully and there are concrete I2C bugs that must be fixed before we continue with I2S.
Issue 1: Incorrect I2C transfer lengths (must be fixed)
In multiple places you request 2 bytes from the I2C driver but store them in 1-byte variables, which is invalid and can corrupt memory or cause the codec to NACK. Examples from your code:
codec_probe():
uint8_t read_back = 0; i2c_write_read_dt(&dev_i2c, ®0, 2, &read_back, 2);
read_eg():
uint8_t reg = 0xD4; uint8_t val = 0; i2c_write_read_dt(&dev_i2c, ®, 2, &val, 2);
Both are invalid and must be corrected everywhere in the code.
Issue 2: Wrong API used for register writes
You are using i2c_write_read_dt() for normal register writes (write-only operations). So for normal writes please try using i2c_write_dt(). Correct patterns (assuming 8-bit register + 8-bit data):
Register write:
uint8_t buf[2] = { reg, val };
ret = i2c_write_dt(&dev_i2c, buf, 2);
Register read:
ret = i2c_write_read_dt(&dev_i2c, ®, 1, &val, 1);
So before testing I2S again please disable I2S in the overlay (&i2s20 { status = "disabled"; };) or physically disconnect all I2S lines and first fix all I2C calls so that transfer lengths exactly match buffer sizes and i2c_write_dt() is used for write-only operations. Then read the same codec register 10,000 times in a loop (this test should complete with 0 occurrences of -EIO).
Once this I2C-only test is stable, we will move on to validating I2S in isolation. Thanks
Hi,
To solve this efficiently, we need to validate one interface at a time. I’ve reviewed your code carefully and there are concrete I2C bugs that must be fixed before we continue with I2S.
Issue 1: Incorrect I2C transfer lengths (must be fixed)
In multiple places you request 2 bytes from the I2C driver but store them in 1-byte variables, which is invalid and can corrupt memory or cause the codec to NACK. Examples from your code:
codec_probe():
uint8_t read_back = 0; i2c_write_read_dt(&dev_i2c, ®0, 2, &read_back, 2);
read_eg():
uint8_t reg = 0xD4; uint8_t val = 0; i2c_write_read_dt(&dev_i2c, ®, 2, &val, 2);
Both are invalid and must be corrected everywhere in the code.
Issue 2: Wrong API used for register writes
You are using i2c_write_read_dt() for normal register writes (write-only operations). So for normal writes please try using i2c_write_dt(). Correct patterns (assuming 8-bit register + 8-bit data):
Register write:
uint8_t buf[2] = { reg, val };
ret = i2c_write_dt(&dev_i2c, buf, 2);
Register read:
ret = i2c_write_read_dt(&dev_i2c, ®, 1, &val, 1);
So before testing I2S again please disable I2S in the overlay (&i2s20 { status = "disabled"; };) or physically disconnect all I2S lines and first fix all I2C calls so that transfer lengths exactly match buffer sizes and i2c_write_dt() is used for write-only operations. Then read the same codec register 10,000 times in a loop (this test should complete with 0 occurrences of -EIO).
Once this I2C-only test is stable, we will move on to validating I2S in isolation. Thanks
I am try to create external clock for mclk
Hi
I see you’re experimenting with generating a 4 MHz MCLK now. Just to make sure we’re aligned: I don’t yet have confirmation that the original I2C issue is resolved. Before we move further with MCLK/I2S, could you please confirm:
Once that’s confirmed, we can continue with the MCLK/I2S part. Thanks
Regards,
Syed Maysum