Good day! My code is adapted from the i2s echo example. I removed all the code regarding the button click and codec because it is not needed in my application. Below is the code. When i run the code, i get errors on configuring the Rx stream.
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/drivers/i2s.h>
#include <zephyr/drivers/gpio.h>
#include <string.h>
#include <zephyr/drivers/pwm.h>
#define I2S_RX_NODE DT_NODELABEL(i2s_rx)
#define SAMPLE_FREQUENCY 62500
#define SAMPLE_BIT_WIDTH 32
#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
// PWM DEFINES
static const struct pwm_dt_spec pwm_led0 = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led0));
static const struct pwm_dt_spec pwm_led1 = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led1));
#define BITCLK PWM_KHZ(4000U)
#define WORD_S PWM_HZ(62500U)
#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);
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 < number_of_samples; ++i) {
int16_t *sample = &((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 i2s_config *config)
{
int ret;
ret = i2s_configure(i2s_dev_rx, I2S_DIR_RX, config);
if (ret < 0) {
printk("Failed to configure RX stream: %d\n", ret);
return false;
}
return true;
}
static bool prepare_transfer(const struct device *i2s_dev_rx)
{
int ret;
for (int i = 0; i < INITIAL_BLOCKS; ++i) {
void *mem_block;
ret = k_mem_slab_alloc(&mem_slab, &mem_block, K_NO_WAIT);
if (ret < 0) {
printk("Failed to allocate TX block %d: %d\n", i, ret);
return false;
}
memset(mem_block, 0, BLOCK_SIZE);
}
return true;
}
static bool trigger_command(const struct device *i2s_dev_rx,
enum i2s_trigger_cmd cmd)
{
int ret;
ret = i2s_trigger(i2s_dev_rx, I2S_DIR_RX, cmd);
if (ret < 0) {
printk("Failed to trigger command %d on RX: %d\n", cmd, ret);
return false;
}
return true;
}
int main(void)
{
uint32_t bclk_period;
uint32_t ws_period;
int ret1;
int ret2;
printk("Starting main thread\n\r");
printk("PWM-based blinky\n");
if (!pwm_is_ready_dt(&pwm_led0)) {
printk("Error: PWM device %s is not ready\n",
pwm_led0.dev->name);
return 0;
}
if (!pwm_is_ready_dt(&pwm_led1)) {
printk("Error: PWM device %s is not ready\n",
pwm_led0.dev->name);
return 0;
}
/*
* In case the default MAX_PERIOD value cannot be set for
* some PWM hardware, decrease its value until it can.
*
* Keep its value at least MIN_PERIOD * 4 to make sure
* the sample changes frequency at least once.
*/
bclk_period = BITCLK;
while (pwm_set_dt(&pwm_led0, bclk_period, bclk_period / 2U)) {
bclk_period /= 2U;
printk("half bclk");
}
ws_period = WORD_S;
while (pwm_set_dt(&pwm_led1, ws_period, ws_period / 2U)) {
ws_period /= 2U;
printk("half ws");
}
ws_period = WORD_S;
bclk_period = BITCLK;
const struct device *const i2s_dev_rx = DEVICE_DT_GET(I2S_RX_NODE);
struct i2s_config config;
printk("I2S echo sample\n");
if (!device_is_ready(i2s_dev_rx)) {
printk("%s is not ready\n", i2s_dev_rx->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_SLAVE | I2S_OPT_FRAME_CLK_SLAVE;
config.frame_clk_freq = SAMPLE_FREQUENCY;
config.mem_slab = &mem_slab;
config.block_size = BLOCK_SIZE;
config.timeout = TIMEOUT;
if (!configure_streams(i2s_dev_rx, &config)) {
return 0;
}
for (;;) {
k_sem_take(&toggle_transfer, K_FOREVER);
if (!prepare_transfer(i2s_dev_rx)) {
return 0;
}
if (!trigger_command(i2s_dev_rx,
I2S_TRIGGER_START)) {
return 0;
}
printk("Streams started\n");
while (k_sem_take(&toggle_transfer, K_NO_WAIT) != 0) {
void *mem_block;
uint32_t block_size;
int ret;
ret = i2s_read(i2s_dev_rx, &mem_block, &block_size);
if (ret < 0) {
printk("Failed to read data: %d\n", ret);
break;
}
process_block_data(mem_block, SAMPLES_PER_BLOCK);
}
if (!trigger_command(i2s_dev_rx,
I2S_TRIGGER_DROP)) {
return 0;
}
printk("Streams stopped\n");
}
while (1) {
ret1 = pwm_set_dt(&pwm_led0, bclk_period, bclk_period / 2U);
if (ret1) {
printk("Error %d: failed to set pulse width\n", ret1);
return 0;
}
ret2 = pwm_set_dt(&pwm_led1, ws_period, ws_period / 2U);
if (ret2) {
printk("Error %d: failed to set pulse width\n", ret2);
return 0;
}
}
}
overlay
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
&pinctrl {
pwm0_custom: pwm0_custom {
group1 {
psels = <NRF_PSEL(PWM_OUT0, 0, 3)>;
nordic,invert;
};
};
pwm0_csleep: pwm0_csleep {
group1 {
psels = <NRF_PSEL(PWM_OUT0, 0, 3)>;
low-power-enable;
};
};
pwm1_custom: pwm1_custom {
group1 {
psels = <NRF_PSEL(PWM_OUT0, 0, 28)>;
nordic,invert;
};
};
pwm1_csleep: pwm1_csleep {
group1 {
psels = <NRF_PSEL(PWM_OUT0, 0, 28)>;
low-power-enable;
};
};
i2s0_default_alt: i2s0_default_alt {
group1 {
psels = <NRF_PSEL(I2S_SDIN, 0, 29)>;
};
};
i2s0_sleep: i2s0_sleep {
group1 {
psels = <NRF_PSEL(I2S_SDIN, 0, 29)>;
low-power-enable;
};
};
};
i2s_rx: &i2s0 {
status = "okay";
pinctrl-0 = <&i2s0_default_alt>;
pinctrl-names = "default";
};
&pwm0 {
status = "okay";
pinctrl-0 = <&pwm0_custom>;
pinctrl-1 = <&pwm0_csleep>;
pinctrl-names = "default", "sleep";
};
&pwm1 {
status = "okay";
pinctrl-0 = <&pwm1_custom>;
pinctrl-1 = <&pwm1_csleep>;
pinctrl-names = "default", "sleep";
};
/{
pwmleds {
compatible = "pwm-leds";
pwm_led0: pwm_led_0 {
pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
};
pwm_led1: pwm_led_1 {
pwms = <&pwm1 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
};
};
aliases {
pwm-led0 = &pwm_led0;
pwm-led1 = &pwm_led1;
};
};