<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="https://devzone.nordicsemi.com/cfs-file/__key/system/syndication/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Zephyr I2S</title><link>https://devzone.nordicsemi.com/f/nordic-q-a/104790/zephyr-i2s</link><description>I have the following example running on an nrf52 dongle: 
 https://docs.zephyrproject.org/latest/samples/drivers/i2s/echo/README.html 
 However, when I add the following code 
 
 I get the following error: 
 
 It seems like it might be because I&amp;#39;m not</description><dc:language>en-US</dc:language><generator>Telligent Community 13</generator><lastBuildDate>Sun, 22 Oct 2023 06:14:16 GMT</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://devzone.nordicsemi.com/f/nordic-q-a/104790/zephyr-i2s" /><item><title>RE: Zephyr I2S</title><link>https://devzone.nordicsemi.com/thread/451589?ContentTypeID=1</link><pubDate>Sun, 22 Oct 2023 06:14:16 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:178369c3-9cc0-4622-a495-3fabfdf001e5</guid><dc:creator>Susheel Nuguru</dc:creator><description>&lt;p&gt;I see,&amp;nbsp;&lt;/p&gt;
&lt;p&gt;I think it would have been better to use PWN or SPI for controlling the LED strip but I2S can also work. A similar effort using another driver which uses PWM can be found &lt;a href="https://github.com/NordicPlayground/nrf52-ble-multi-link-multi-role/blob/master/common/drv_ws2812/drv_ws2812.c"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In your case, I think the huge memory being allocated in the global static region could be the issue.&lt;/p&gt;
&lt;p&gt;About the error you are getting, it seems like the buffer&amp;nbsp;m_i2s_led_buffer_tx is allocated in the &lt;a href="https://docs.zephyrproject.org/latest/kernel/memory_management/slabs.html"&gt;memory slab&lt;/a&gt;,&amp;nbsp; and it seems like K_MEM_SLAB_DEFINE_STATIC creates (&lt;span&gt;K_MEM_SLAB_DEFINE) with only the max space of&amp;nbsp;41664 and you are using more than the allocated space in the memory slab.&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Zephyr I2S</title><link>https://devzone.nordicsemi.com/thread/451374?ContentTypeID=1</link><pubDate>Thu, 19 Oct 2023 16:54:57 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:34a2d541-666e-4f94-aa15-a1d0cbf630b3</guid><dc:creator>parksj10</dc:creator><description>&lt;p&gt;Thanks for the consideration Susheel!&lt;/p&gt;
&lt;p&gt;As far as I understand, the codec is unnecessary unless you&amp;#39;re trying to (re)encode audio data. I&amp;#39;m simply creating a byte stream I&amp;#39;m trying to pipe over the I2S bus (because the bus has the correct timing requirements for the LED driver).&amp;nbsp;&lt;/p&gt;
&lt;p&gt;As for testing, I think Oscilloscope is how I&amp;#39;m planning on testing signal fidelity once I get it to run (I.e. no need for LEDs).&lt;/p&gt;
&lt;p&gt;For replication, the only changes I&amp;#39;ve made to the project are in the overlay file and main.c. Here&amp;#39;s the current code:&lt;/p&gt;
&lt;p&gt;&lt;span style="font-family:&amp;#39;courier new&amp;#39;, courier;"&gt;nrf52840dongle_nrf52840.overlay&lt;/span&gt;&lt;br /&gt;&lt;pre class="ui-code" data-mode="text"&gt;&amp;amp;pinctrl {
    i2s0_default_alt: i2s0_default_alt {
        group1 {
            psels = &amp;lt;NRF_PSEL(I2S_SCK_M, 1, 10)&amp;gt;,
                    &amp;lt;NRF_PSEL(I2S_LRCK_M, 1, 12)&amp;gt;,
                    &amp;lt;NRF_PSEL(I2S_SDOUT, 1, 11)&amp;gt;,
                    &amp;lt;NRF_PSEL(I2S_SDIN, 1, 14)&amp;gt;,
                    &amp;lt;NRF_PSEL(I2S_MCK, 1,15)&amp;gt;;
        };
    };
};

i2s_rxtx: &amp;amp;i2s0 {
    status = &amp;quot;okay&amp;quot;;
    pinctrl-0 = &amp;lt;&amp;amp;i2s0_default_alt&amp;gt;;
    pinctrl-names = &amp;quot;default&amp;quot;;
};&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-family:&amp;#39;courier new&amp;#39;, courier;"&gt;main.c&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;// #include &amp;lt;zephyr/kernel.h&amp;gt;
// #include &amp;lt;zephyr/drivers/gpio.h&amp;gt;
// #include &amp;lt;zephyr/device.h&amp;gt;

// /* 1000 msec = 1 sec */
// #define SLEEP_TIME_MS 1000

// /* The devicetree node identifier for the &amp;quot;led0&amp;quot; alias. */
// #define LED0_NODE DT_ALIAS(led0)

// // test GPIO voltage pin
// #define VOLT_PIN 15

// /*
//  * A build error on this line means your board is unsupported.
//  * See the sample documentation for information on how to fix this.
//  */
// static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);

// int main(void)
// {
// 	// // get the GPIO device
// 	// const struct device *dev = device_get_binding(&amp;quot;GPIO_0&amp;quot;);
// 	// // configure the LED pin as output
// 	// gpio_pin_configure(dev, VOLT_PIN, GPIO_OUTPUT_ACTIVE);

// 	int ret;
// 	int loop_number = 0;
// 	int blink_number = 0;

// 	if (!gpio_is_ready_dt(&amp;amp;led))
// 	{
// 		loop_number++;
// 		return 0;
// 	}

// 	ret = gpio_pin_configure_dt(&amp;amp;led, GPIO_OUTPUT_ACTIVE);
// 	if (ret &amp;lt; 0)
// 	{
// 		return 0;
// 	}

// 	while (1)
// 	{
// 		ret = gpio_pin_toggle_dt(&amp;amp;led);
// 		if (ret &amp;lt; 0)
// 		{
// 			return 0;
// 		}
// 		printk(&amp;quot;Blink number %d\n&amp;quot;, blink_number);
// 		blink_number++;
// 		k_msleep(SLEEP_TIME_MS);
// 	}
// 	return 0;
// }

/*
 * Copyright (c) 2021 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include &amp;lt;zephyr/kernel.h&amp;gt;
#include &amp;lt;zephyr/sys/printk.h&amp;gt;
#include &amp;lt;zephyr/drivers/i2s.h&amp;gt;
#include &amp;lt;zephyr/drivers/gpio.h&amp;gt;
#include &amp;lt;string.h&amp;gt;

#if DT_NODE_EXISTS(DT_NODELABEL(i2s_rxtx))
#define I2S_RX_NODE DT_NODELABEL(i2s_rxtx)
#define I2S_TX_NODE I2S_RX_NODE
#else
#define I2S_RX_NODE DT_NODELABEL(i2s_rx)
#define I2S_TX_NODE DT_NODELABEL(i2s_tx)
#endif

#define SAMPLE_FREQUENCY 104167 // 3.333333 MHz / 2 channels / 16 bits per sample
#define SAMPLE_BIT_WIDTH 16
#define BYTES_PER_SAMPLE sizeof(int16_t)
#define NUMBER_OF_CHANNELS 2
/* Such block length provides an echo with the delay of 100 ms. */
#define SAMPLES_PER_BLOCK ((SAMPLE_FREQUENCY / 10) * NUMBER_OF_CHANNELS)
#define INITIAL_BLOCKS 2
#define TIMEOUT 1000

#define NUM_LEDS 9
#define DATA_BYTES_PER_LED 3 // 24-bit GRB data structure
#define LEDS_DATA_BYTE_SIZE NUM_LEDS *DATA_BYTES_PER_LED

#define I2S_BITS_PER_DATA_BIT 4
#define I2S_SK6812_ZERO 0x8							   // 0b&amp;#39;1000 (0.3us; 0.9us)
#define I2S_SK6812_ONE 0xC							   // 0b&amp;#39;1100 (0.6us; 0.6us)
#define I2S_WS2812B_ZERO 0x8						   // 0b&amp;#39;1000 (0.4us; 0.85us)
#define I2S_WS2812B_ONE 0xE							   // 0b&amp;#39;1110 (0.8us; 0.45us)
#define I2S_BYTES_PER_RESET 256 / 8					   // reset_pulse / period = 80us / 0.3125us = 256 bits
#define BYTES_TO_WORDS(n_bytes) (((n_bytes) + 3) &amp;gt;&amp;gt; 2) // (&amp;gt;&amp;gt; 2 === divide by 4... and + 3 to round up bytes)
#define I2S_LEDS_WORD_SIZE BYTES_TO_WORDS(LEDS_DATA_BYTE_SIZE *I2S_BITS_PER_DATA_BIT)
#define I2S_RESET_WORD_SIZE BYTES_TO_WORDS(I2S_BYTES_PER_RESET) // 8 words
#define I2S_LEDS_FRAME_WORD_SIZE I2S_LEDS_WORD_SIZE + I2S_RESET_WORD_SIZE

typedef struct
{
	uint8_t g;
	uint8_t r;
	uint8_t b;
} sk6812_led_t;

sk6812_led_t m_led_buffer_tx[NUM_LEDS];
uint32_t m_i2s_led_buffer_tx[I2S_LEDS_FRAME_WORD_SIZE];

/**
 * @brief Clears the LED and I2S data buffers
 */
nrfx_err_t sk6812_i2s_init_mem()
{
	// TODO: dynamically allocate memory when needed instead of using global arrays
	//    // Init memory for LED data
	//    if (p_led_buffer_tx) free(p_led_buffer_tx);
	//    p_led_buffer_tx = (sk6812_led_t *)malloc(LEDS_DATA_BYTE_SIZE);
	//    if (p_led_buffer_tx) memset(p_led_buffer_tx, 0, LEDS_DATA_BYTE_SIZE);
	//    else return NRF_ERROR_NO_MEM;
	//
	//    // Init memory for I2S data
	//    if (p_i2s_led_buffer_tx) free(p_i2s_led_buffer_tx);
	//    p_i2s_led_buffer_tx = (uint32_t *)malloc(I2S_LEDS_WORD_SIZE * 4);
	//    if (p_i2s_led_buffer_tx) memset(p_i2s_led_buffer_tx, 0, I2S_LEDS_WORD_SIZE * 4);
	//    else return NRF_ERROR_NO_MEM;

	// Reset data buffers
	memset(m_led_buffer_tx, 0, sizeof(m_led_buffer_tx));
	memset(m_i2s_led_buffer_tx, 0, sizeof(m_i2s_led_buffer_tx));

	return NRFX_SUCCESS;
}

/**
 * @brief Convert a byte of LED data to a word of I2S data
 * @brief 1 data bit   &amp;lt;--&amp;gt; 4 I2S bits
 * @brief 1 data byte  &amp;lt;--&amp;gt; 1 I2S word
 */
uint32_t convert_byte_to_i2s_bits(uint8_t data_byte)
{
	uint32_t data_bits = 0;

	// Set data_bits based on MSB, then left-shift data_byte
	for (int ii = 0; ii &amp;lt; 8; ii++)
	{
		// Extract the current most significant bit (MSB) of data_byte
		uint8_t msb = (data_byte &amp;amp; 0x80);

		// Determine the appropriate I2S pattern based on the MSB
		uint32_t i2s_pattern = (msb ? I2S_SK6812_ONE : I2S_SK6812_ZERO);

		// Calculate the shift amount to align the pattern with the current bit position
		int shift_amount = (8 - 1 - ii) * 4;

		// Left-shift the I2S pattern by the calculated amount
		i2s_pattern = i2s_pattern &amp;lt;&amp;lt; shift_amount;

		// Merge the shifted pattern with data_bits
		data_bits |= i2s_pattern;

		// prepare for reading next bit
		data_byte = data_byte &amp;lt;&amp;lt; 1;
	}
	return data_bits;
}

/**
 * @brief Sets I2S data from converted LED data
 */
void set_i2s_led_data()
{
	uint16_t jj = 0;
	for (uint16_t ii = 0; ii &amp;lt; NUM_LEDS; ii++)
	{
		m_i2s_led_buffer_tx[jj] = convert_byte_to_i2s_bits(m_led_buffer_tx[ii].g);
		m_i2s_led_buffer_tx[jj + 1] = convert_byte_to_i2s_bits(m_led_buffer_tx[ii].r);
		m_i2s_led_buffer_tx[jj + 2] = convert_byte_to_i2s_bits(m_led_buffer_tx[ii].b);
		jj += 3;
	}
}

// TODO: need to change this nrfx code
/**
 * @brief Initializes I2S and starts the data transfer
 * @brief Assumes data buffers have already been set
 */
void send_i2s_led_data()
{
	int ret;
	const struct device *const i2s_dev_tx = DEVICE_DT_GET(I2S_TX_NODE);
	ret = i2s_write(i2s_dev_tx, m_i2s_led_buffer_tx, I2S_LEDS_FRAME_WORD_SIZE + 1);

	// // Configure the I2S module and map IO pins
	// uint32_t err_code = sk6812_i2s_init();

	// if (ret &amp;lt; 0)
	// {
	// 	printk(&amp;quot;Failed to write data: %d\n&amp;quot;, ret);
	// 	return 0;
	// }

	// // Prevent starting a new data transfer if I2S already initialized
	// if (err_code == NRFX_SUCCESS)
	// {
	// 	// Configure TX data buffer
	// 	nrfx_i2s_buffers_t const initial_buffers = {
	// 		.p_tx_buffer = m_i2s_led_buffer_tx,
	// 		.p_rx_buffer = NULL};

	// 	Enable the I2S module and start data streaming
	// 	err_code = nrf_drv_i2s_start(&amp;amp;initial_buffers, I2S_LEDS_FRAME_WORD_SIZE + 1, 0);
	// 	APP_ERROR_CHECK(err_code);
	// }
	// else
	// {
	// 	// Reset to all I2S_SK6812_ZERO&amp;#39;s
	// 	memset(m_i2s_led_buffer_tx, 0x88, I2S_LEDS_WORD_SIZE * 4);
	// }
}

/**
 * @brief Set an RGB LED color data in the global sk6812_led_t array
 */
void set_led_pixel_RGB(uint16_t pos, uint8_t r, uint8_t g, uint8_t b)
{
	m_led_buffer_tx[pos].r = r;
	m_led_buffer_tx[pos].g = g;
	m_led_buffer_tx[pos].b = b;
}

#define SW0_NODE DT_ALIAS(sw0)
#if DT_NODE_HAS_STATUS(SW0_NODE, okay)
static struct gpio_dt_spec sw0_spec = GPIO_DT_SPEC_GET(SW0_NODE, gpios);
#endif

#define SW1_NODE DT_ALIAS(sw1)
#if DT_NODE_HAS_STATUS(SW1_NODE, okay)
static struct gpio_dt_spec sw1_spec = GPIO_DT_SPEC_GET(SW1_NODE, gpios);
#endif

#define BLOCK_SIZE (BYTES_PER_SAMPLE * SAMPLES_PER_BLOCK)
#define BLOCK_COUNT (INITIAL_BLOCKS + 2)
K_MEM_SLAB_DEFINE_STATIC(mem_slab, BLOCK_SIZE, BLOCK_COUNT, 4);

static int16_t echo_block[SAMPLES_PER_BLOCK];
static volatile bool echo_enabled = true;
static K_SEM_DEFINE(toggle_transfer, 1, 1);

#if DT_NODE_HAS_STATUS(SW0_NODE, okay)
static void sw0_handler(const struct device *dev, struct gpio_callback *cb,
						uint32_t pins)
{
	bool enable = !echo_enabled;

	echo_enabled = enable;
	printk(&amp;quot;Echo %sabled\n&amp;quot;, (enable ? &amp;quot;en&amp;quot; : &amp;quot;dis&amp;quot;));
}
#endif

#if DT_NODE_HAS_STATUS(SW1_NODE, okay)
static void sw1_handler(const struct device *dev, struct gpio_callback *cb,
						uint32_t pins)
{
	k_sem_give(&amp;amp;toggle_transfer);
}
#endif

static bool init_buttons(void)
{
	int ret;

#if DT_NODE_HAS_STATUS(SW0_NODE, okay)
	static struct gpio_callback sw0_cb_data;

	if (!device_is_ready(sw0_spec.port))
	{
		printk(&amp;quot;%s is not ready\n&amp;quot;, sw0_spec.port-&amp;gt;name);
		return false;
	}

	ret = gpio_pin_configure_dt(&amp;amp;sw0_spec, GPIO_INPUT);
	if (ret &amp;lt; 0)
	{
		printk(&amp;quot;Failed to configure %s pin %d: %d\n&amp;quot;,
			   sw0_spec.port-&amp;gt;name, sw0_spec.pin, ret);
		return false;
	}

	ret = gpio_pin_interrupt_configure_dt(&amp;amp;sw0_spec,
										  GPIO_INT_EDGE_TO_ACTIVE);
	if (ret &amp;lt; 0)
	{
		printk(&amp;quot;Failed to configure interrupt on %s pin %d: %d\n&amp;quot;,
			   sw0_spec.port-&amp;gt;name, sw0_spec.pin, ret);
		return false;
	}

	gpio_init_callback(&amp;amp;sw0_cb_data, sw0_handler, BIT(sw0_spec.pin));
	gpio_add_callback(sw0_spec.port, &amp;amp;sw0_cb_data);
	printk(&amp;quot;Press \&amp;quot;%s\&amp;quot; to toggle the echo effect\n&amp;quot;, sw0_spec.port-&amp;gt;name);
#endif

#if DT_NODE_HAS_STATUS(SW1_NODE, okay)
	static struct gpio_callback sw1_cb_data;

	if (!device_is_ready(sw1_spec.port))
	{
		printk(&amp;quot;%s is not ready\n&amp;quot;, sw1_spec.port-&amp;gt;name);
		return false;
	}

	ret = gpio_pin_configure_dt(&amp;amp;sw1_spec, GPIO_INPUT);
	if (ret &amp;lt; 0)
	{
		printk(&amp;quot;Failed to configure %s pin %d: %d\n&amp;quot;,
			   sw1_spec.port-&amp;gt;name, sw1_spec.pin, ret);
		return false;
	}

	ret = gpio_pin_interrupt_configure_dt(&amp;amp;sw1_spec,
										  GPIO_INT_EDGE_TO_ACTIVE);
	if (ret &amp;lt; 0)
	{
		printk(&amp;quot;Failed to configure interrupt on %s pin %d: %d\n&amp;quot;,
			   sw1_spec.port-&amp;gt;name, sw1_spec.pin, ret);
		return false;
	}

	gpio_init_callback(&amp;amp;sw1_cb_data, sw1_handler, BIT(sw1_spec.pin));
	gpio_add_callback(sw1_spec.port, &amp;amp;sw1_cb_data);
	printk(&amp;quot;Press \&amp;quot;%s\&amp;quot; to stop/restart I2S streams\n&amp;quot;, sw1_spec.port-&amp;gt;name);
#endif

	(void)ret;
	return true;
}

static void process_block_data(void *mem_block, uint32_t number_of_samples)
{
	static bool clear_echo_block;

	if (echo_enabled)
	{
		for (int i = 0; i &amp;lt; number_of_samples; ++i)
		{
			int16_t *sample = &amp;amp;((int16_t *)mem_block)[i];
			*sample += echo_block[i];
			echo_block[i] = (*sample) / 2;
		}

		clear_echo_block = true;
	}
	else if (clear_echo_block)
	{
		clear_echo_block = false;
		memset(echo_block, 0, sizeof(echo_block));
	}
}

static bool configure_streams(const struct device *i2s_dev_rx,
							  const struct device *i2s_dev_tx,
							  const struct i2s_config *config)
{
	int ret;

	if (i2s_dev_rx == i2s_dev_tx)
	{
		ret = i2s_configure(i2s_dev_rx, I2S_DIR_BOTH, config);
		if (ret == 0)
		{
			return true;
		}
		/* -ENOSYS means that the RX and TX streams need to be
		 * configured separately.
		 */
		if (ret != -ENOSYS)
		{
			printk(&amp;quot;Failed to configure streams: %d\n&amp;quot;, ret);
			return false;
		}
	}

	ret = i2s_configure(i2s_dev_rx, I2S_DIR_RX, config);
	if (ret &amp;lt; 0)
	{
		printk(&amp;quot;Failed to configure RX stream: %d\n&amp;quot;, ret);
		return false;
	}

	ret = i2s_configure(i2s_dev_tx, I2S_DIR_TX, config);
	if (ret &amp;lt; 0)
	{
		printk(&amp;quot;Failed to configure TX stream: %d\n&amp;quot;, ret);
		return false;
	}

	return true;
}

static bool prepare_transfer(const struct device *i2s_dev_rx,
							 const struct device *i2s_dev_tx)
{
	int ret;

	for (int i = 0; i &amp;lt; INITIAL_BLOCKS; ++i)
	{
		void *mem_block;

		ret = k_mem_slab_alloc(&amp;amp;mem_slab, &amp;amp;mem_block, K_NO_WAIT);
		if (ret &amp;lt; 0)
		{
			printk(&amp;quot;Failed to allocate TX block %d: %d\n&amp;quot;, i, ret);
			return false;
		}

		memset(mem_block, 0, BLOCK_SIZE);

		ret = i2s_write(i2s_dev_tx, mem_block, BLOCK_SIZE);
		if (ret &amp;lt; 0)
		{
			printk(&amp;quot;Failed to write block %d: %d\n&amp;quot;, i, ret);
			return false;
		}
	}

	return true;
}

static bool trigger_command(const struct device *i2s_dev_rx,
							const struct device *i2s_dev_tx,
							enum i2s_trigger_cmd cmd)
{
	int ret;

	if (i2s_dev_rx == i2s_dev_tx)
	{
		ret = i2s_trigger(i2s_dev_rx, I2S_DIR_BOTH, cmd);
		if (ret == 0)
		{
			return true;
		}
		/* -ENOSYS means that commands for the RX and TX streams need
		 * to be triggered separately.
		 */
		if (ret != -ENOSYS)
		{
			printk(&amp;quot;Failed to trigger command %d: %d\n&amp;quot;, cmd, ret);
			return false;
		}
	}

	ret = i2s_trigger(i2s_dev_rx, I2S_DIR_RX, cmd);
	if (ret &amp;lt; 0)
	{
		printk(&amp;quot;Failed to trigger command %d on RX: %d\n&amp;quot;, cmd, ret);
		return false;
	}

	ret = i2s_trigger(i2s_dev_tx, I2S_DIR_TX, cmd);
	if (ret &amp;lt; 0)
	{
		printk(&amp;quot;Failed to trigger command %d on TX: %d\n&amp;quot;, cmd, ret);
		return false;
	}

	return true;
}

int main(void)
{
	// TODO: put the IO voltage up to 3.3V
	const struct device *const i2s_dev_rx = DEVICE_DT_GET(I2S_RX_NODE);
	const struct device *const i2s_dev_tx = DEVICE_DT_GET(I2S_TX_NODE);
	struct i2s_config config;

	printk(&amp;quot;I2S echo sample\n&amp;quot;);

	if (!init_buttons())
	{
		return 0;
	}

	if (!device_is_ready(i2s_dev_rx))
	{
		printk(&amp;quot;%s is not ready\n&amp;quot;, i2s_dev_rx-&amp;gt;name);
		return 0;
	}

	if (i2s_dev_rx != i2s_dev_tx &amp;amp;&amp;amp; !device_is_ready(i2s_dev_tx))
	{
		printk(&amp;quot;%s is not ready\n&amp;quot;, i2s_dev_tx-&amp;gt;name);
		return 0;
	}

	config.word_size = SAMPLE_BIT_WIDTH;
	config.channels = NUMBER_OF_CHANNELS;
	config.format = I2S_FMT_DATA_FORMAT_I2S;
	config.options = I2S_OPT_BIT_CLK_MASTER | I2S_OPT_FRAME_CLK_MASTER;
	config.frame_clk_freq = SAMPLE_FREQUENCY;
	config.mem_slab = &amp;amp;mem_slab;
	config.block_size = BLOCK_SIZE;
	config.timeout = TIMEOUT;
	if (!configure_streams(i2s_dev_rx, i2s_dev_tx, &amp;amp;config))
	{
		return 0;
	}

	while (true)
	{
		k_sem_take(&amp;amp;toggle_transfer, K_FOREVER);

		if (!prepare_transfer(i2s_dev_rx, i2s_dev_tx))
		{
			return 0;
		}

		if (!trigger_command(i2s_dev_rx, i2s_dev_tx,
							 I2S_TRIGGER_START))
		{
			return 0;
		}

		printk(&amp;quot;Streams started\n&amp;quot;);

		while (k_sem_take(&amp;amp;toggle_transfer, K_NO_WAIT) != 0)
		{
			void *mem_block;
			uint32_t block_size;
			int ret;

			// TODO remove block of reading (only writing)
			ret = i2s_read(i2s_dev_rx, &amp;amp;mem_block, &amp;amp;block_size);
			if (ret &amp;lt; 0)
			{
				printk(&amp;quot;Failed to read data: %d\n&amp;quot;, ret);
				break;
			}

			// TODO remove block of reading (only writing)
			process_block_data(mem_block, SAMPLES_PER_BLOCK);

			// ret = i2s_write(i2s_dev_tx, mem_block, block_size);
			// ret = i2s_write(i2s_dev_tx, m_i2s_led_buffer_tx, I2S_LEDS_FRAME_WORD_SIZE + 1);
			color_wipe(255, 0, 0, 50); // Red
			if (ret &amp;lt; 0)
			{
				printk(&amp;quot;Failed to write data: %d\n&amp;quot;, ret);
				break;
			}
		}

		if (!trigger_command(i2s_dev_rx, i2s_dev_tx,
							 I2S_TRIGGER_DROP))
		{
			return 0;
		}

		printk(&amp;quot;Streams stopped\n&amp;quot;);
	}
}

// TODO move to another file, these are the color animations
/**
 * @brief Ported Adafruit NeoPixel paint animation functions
 */
// Fill the dots one after the other with a color
void color_wipe(uint8_t r, uint8_t g, uint8_t b, uint8_t ms_delay)
{
	sk6812_i2s_init_mem();

	for (uint16_t ii = 0; ii &amp;lt; NUM_LEDS; ii++)
	{
		set_led_pixel_RGB(ii, r, g, b);
		set_i2s_led_data();
		send_i2s_led_data();
		k_msleep(ms_delay);
	}
}

// Input a value 0 to 255 to get a color value
sk6812_led_t wheel(uint8_t wheel_pos)
{
	sk6812_led_t color;
	wheel_pos = 255 - wheel_pos;

	if (wheel_pos &amp;lt; 85)
	{
		color.r = 255 - wheel_pos * 3;
		color.g = 0;
		color.b = wheel_pos * 3;
		return color;
	}

	if (wheel_pos &amp;lt; 170)
	{
		wheel_pos -= 85;
		color.r = 0;
		color.g = wheel_pos * 3;
		color.b = 255 - wheel_pos * 3;
		return color;
	}

	wheel_pos -= 170;
	color.r = wheel_pos * 3;
	color.g = 255 - wheel_pos * 3;
	color.b = 0;
	return color;
}

void rainbow(uint16_t ms_delay)
{
	uint16_t ii, jj;
	sk6812_led_t color;

	sk6812_i2s_init_mem();
	for (jj = 0; jj &amp;lt; NUM_LEDS; jj++)
	{
		for (ii = 0; ii &amp;lt; NUM_LEDS; ii++)
		{
			color = wheel(((ii * 256 / NUM_LEDS) + jj) &amp;amp; 255);
			set_led_pixel_RGB(ii, color.r, color.g, color.b);
		}
		set_i2s_led_data();
		send_i2s_led_data();
		k_msleep(ms_delay);
	}
}

// Slightly different, this makes the rainbow equally distributed throughout
void rainbow_cycle(uint16_t ms_delay)
{
	uint16_t ii, jj;
	sk6812_led_t color;

	sk6812_i2s_init_mem();
	for (jj = 0; jj &amp;lt; 256 * 3; jj++)
	{ // 3 cycles of all colors on wheel
		for (ii = 0; ii &amp;lt; NUM_LEDS; ii++)
		{
			color = wheel(((ii * 256 / NUM_LEDS) + jj) &amp;amp; 255);
			set_led_pixel_RGB(ii, color.r, color.g, color.b);
		}
		set_i2s_led_data();
		send_i2s_led_data();
		nrf_delay_ms(ms_delay);
	}
}

// Theater-style crawling lights.
void theater_chase(uint8_t r, uint8_t g, uint8_t b, uint16_t ms_delay)
{
	sk6812_i2s_init_mem();
	for (int jj = 0; jj &amp;lt; 10; jj++)
	{ // do 10 cycles of chasing
		for (int qq = 0; qq &amp;lt; 3; qq++)
		{
			for (uint16_t ii = 0; ii &amp;lt; NUM_LEDS; ii = ii + 3)
			{
				set_led_pixel_RGB(ii + qq, r, g, b); // turn every third pixel on
			}
			set_i2s_led_data();
			send_i2s_led_data();

			nrf_delay_ms(ms_delay);

			for (uint16_t ii = 0; ii &amp;lt; NUM_LEDS; ii = ii + 3)
			{
				set_led_pixel_RGB(ii + qq, 0, 0, 0); // turn every third pixel off
			}
		}
	}
}

// Theater-style crawling lights with rainbow effect
void theater_chase_rainbow(uint16_t ms_delay)
{
	sk6812_led_t color;
	sk6812_i2s_init_mem();
	for (int jj = 0; jj &amp;lt; 256; jj++)
	{ // cycle all 256 colors in the wheel
		for (int qq = 0; qq &amp;lt; 3; qq++)
		{
			for (uint16_t ii = 0; ii &amp;lt; NUM_LEDS; ii = ii + 3)
			{
				color = wheel((ii + jj) % 255);
				set_led_pixel_RGB(ii + qq, color.r, color.g, color.b); // turn every third pixel on
			}
			set_i2s_led_data();
			send_i2s_led_data();

			nrf_delay_ms(ms_delay);

			for (uint16_t ii = 0; ii &amp;lt; NUM_LEDS; ii = ii + 3)
			{
				set_led_pixel_RGB(ii + qq, 0, 0, 0); // turn every third pixel off
			}
		}
	}
}&lt;/pre&gt;&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Zephyr I2S</title><link>https://devzone.nordicsemi.com/thread/451183?ContentTypeID=1</link><pubDate>Thu, 19 Oct 2023 05:50:09 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:41ba1791-d3b7-4d74-8bcd-a7028219d08d</guid><dc:creator>Susheel Nuguru</dc:creator><description>&lt;p&gt;Josh, I am not experienced in this but I am trying to understand the error messages you are getting. Attempting to replicate it. How are you running the I2S sample on a nRF52840 dongle? Atleast the documentation says that you need a coded shield for it.&amp;nbsp;&lt;/p&gt;
[quote user="parksj10"]I’m bastardizing the interface because we’re driving a LED controller with very strict timing requirements. [/quote]
&lt;p&gt;Do not know how to test that at my end though :(&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Zephyr I2S</title><link>https://devzone.nordicsemi.com/thread/451158?ContentTypeID=1</link><pubDate>Wed, 18 Oct 2023 23:34:25 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:18219a64-79a0-42c7-b861-e4f560376aa3</guid><dc:creator>parksj10</dc:creator><description>&lt;p&gt;Adding some more information here:&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div&gt;I&amp;rsquo;m bastardizing the interface because we&amp;rsquo;re driving a LED controller with very strict timing requirements. This is something I&amp;rsquo;ve seen quite a few people do online (e..g&amp;nbsp;&lt;a href="https://github.com/cheehieu/nrf52-sk6812-led-driver"&gt;https://github.com/cheehieu/nrf52-sk6812-led-driver&lt;/a&gt;). I am having a block I&amp;rsquo;ve posted about on the DevZone if you&amp;rsquo;re interested/experienced:&amp;nbsp;&lt;a href="https://devzone.nordicsemi.com/f/nordic-q-a/104790/zephyr-i2s"&gt;https://devzone.nordicsemi.com/f/nordic-q-a/104790/zephyr-i2s&lt;/a&gt;. Just for reference, here are the timing requirements, in case there is indeed a better interface to use:&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;img style="max-height:240px;max-width:320px;" src="https://devzone.nordicsemi.com/resized-image/__size/640x480/__key/communityserver-discussions-components-files/4/pastedimage1697672042872v1.png" alt=" " /&gt;&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>