zephyr 3.5.0 I2S on nrf52840

Hi. I have a new project using zephyr 3.5.0 and ZMK, so I don't think NCS SDK is an option. 
I am using pca10056/nrf52840dk

I am trying to configure I2S, and the examples I'm seeing for the above toolchain are inconsistent. 
For starters I just want to see MCK, SCK, LRCK and SDOUT on the logic analyzer before managing buffering. 
I am obviously not a zephyr pro, I've used it twice before for brief projects. 

1) the overlay file uses pinctrl, not 'mck-pin' or 'sck-pin' inside &i2s0 definition.

2) Certain pins on pca10056 are not functioning as intended. 

eg - I try the following, but I only see LRCK and SDOUT on the logic analyzer.
I had MCK working at one point but have lost that configuration with trial and error. 

i2s0_default: i2s0_default {
 group1 {
 psels = <NRF_PSEL(I2S_MCK, 0, 28)>,
  <NRF_PSEL(I2S_SCK_M, 0, 30)>,
  <NRF_PSEL(I2S_LRCK_M, 0, 29)>,
  <NRF_PSEL(I2S_SDOUT, 0, 31)>;
 };
};


In Vscode XPERIPHERALS, I check the register for pin mapping, 
Then I check MCKEN is set
This is my main.c. I'm currently not connected to the TAS2110, and just trying to validate the i2s signals. 
Is there something simple I can do to achieve this? 
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/i2s.h>
#include <zephyr/devicetree.h>
#include <zephyr/logging/log.h>
#include <math.h>

LOG_MODULE_REGISTER(i2s_sine, LOG_LEVEL_INF);

#define M_PI 3.14159265358979323846

#define I2S_NODE DT_NODELABEL(i2s0)

#define SAMPLE_RATE 48000
#define CHANNELS 1
#define BITS_PER_SAMPLE 16

#define FREQUENCY_HZ 60

#define SINE_WAVE_BUFFER_SIZE (SAMPLE_RATE / FREQUENCY_HZ)
#define BLOCK_SIZE (SINE_WAVE_BUFFER_SIZE * CHANNELS * (BITS_PER_SAMPLE / 8))

// Pre-computed sine wave data buffer
int16_t sine_wave_buffer[SINE_WAVE_BUFFER_SIZE];

// Memory slab for I2S DMA buffers
K_MEM_SLAB_DEFINE(mem_slab_tx, BLOCK_SIZE, 4, 1);

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

static void generate_sine_wave(void) {
    double freq = FREQUENCY_HZ;
    double amplitude = 32767.0; // Full-scale for 16-bit signed audio

    for (int i = 0; i < SINE_WAVE_BUFFER_SIZE; i++) {
        double t = (double)i / SAMPLE_RATE;
        double value = amplitude * sin(2.0 * M_PI * freq * t);
        sine_wave_buffer[i] = (int16_t)value;
    }
}

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

    if (!device_is_ready(i2s_dev)) {
        LOG_ERR("I2S device is not ready.");
        return 0;
    }

    // Generate the 60 Hz sine wave data
    generate_sine_wave();

    // I2S configuration structure
    i2s_cfg.word_size = BITS_PER_SAMPLE;
    i2s_cfg.channels = CHANNELS;
    i2s_cfg.format = I2S_FMT_DATA_FORMAT_I2S; // Standard I2S format
    i2s_cfg.options = I2S_OPT_FRAME_CLK_MASTER;
    i2s_cfg.frame_clk_freq = SAMPLE_RATE;
    i2s_cfg.mem_slab = &mem_slab_tx;
    i2s_cfg.block_size = BLOCK_SIZE;
    i2s_cfg.timeout = 100;

    ret = i2s_configure(i2s_dev, I2S_DIR_TX, &i2s_cfg);
    if (ret < 0) {
        LOG_ERR("I2S config failed: %d", ret);
        return 0;
    }

    // Trigger start of transmission
    ret = i2s_trigger(i2s_dev, I2S_DIR_TX, I2S_TRIGGER_START);
    if (ret < 0) {
        LOG_ERR("I2S trigger start failed: %d", ret);
        return 0;
    }

    while (1) {
        // Allocate a memory block from the slab
        ret = k_mem_slab_alloc(&mem_slab_tx, &mem_block_tx, K_FOREVER);
        if (ret < 0) {
            LOG_ERR("Failed to allocate memory block: %d", ret);
            continue;
        }

        // Copy the sine wave data to the allocated buffer
        memcpy(mem_block_tx, sine_wave_buffer, BLOCK_SIZE);

        // Write the filled buffer to the I2S TX queue
        ret = i2s_write(i2s_dev, mem_block_tx, BLOCK_SIZE);
        if (ret < 0) {
            LOG_ERR("I2S write failed: %d", ret);
            k_mem_slab_free(&mem_slab_tx, mem_block_tx);
        }
    }

    return 0;
}
  • This is my nrf52840dk_nrf52840.overlay
    With the above code, SDOUT and LRCLK_M look great, but I cannot see SCK_M or MCK.


    / {
    
    };
    
    &i2c1 {
        status = "okay";
        compatible = "nordic,nrf-twim";
        pinctrl-0 = <&i2c1_default>;    
    
        tas2110_i2c: tas2110_i2c@48 {
            compatible = "i2c-device";
            reg = <0x48>;
            status = "okay";
        };
    };
    
    &i2s0 {
        compatible = "nordic,nrf-i2s";
        status = "okay";
    	pinctrl-0 = <&i2s0_default>;
    	pinctrl-names = "default";
    };
    
    &pinctrl {
        i2c1_default: i2c1_default {
            group1 {
                psels = <NRF_PSEL(TWIM_SDA, 0, 26)>, // P0.26 for SDA
                        <NRF_PSEL(TWIM_SCL, 0, 27)>; // P0.27 for SCL
            };
        };
        i2s0_default: i2s0_default {
            group1 {
                psels = <NRF_PSEL(I2S_MCK, 0, 28)>, 
                        <NRF_PSEL(I2S_SCK_M, 0, 30)>, 
                        <NRF_PSEL(I2S_LRCK_M, 0, 29)>, 
                        <NRF_PSEL(I2S_SDOUT, 0, 31)>;
            };
        };
    };
    

  • Hi,

    Hi. I have a new project using zephyr 3.5.0 and ZMK, so I don't think NCS SDK is an option. 

    No if you need that then I guess not. I am not that familiar with ZMK, and since you're not able to use NCS here either I think you might be able to get more support in the Zephyr Discord group. A quick search here shows me that people might've asked there for help with this before.

    I am trying to configure I2S, and the examples I'm seeing for the above toolchain are inconsistent. 
    For starters I just want to see MCK, SCK, LRCK and SDOUT on the logic analyzer before managing buffering. 
    I am obviously not a zephyr pro, I've used it twice before for brief projects. 

    I also feel forced to mention that using a supported NCS version, and trying the courses in our DevAcademy is a great starting point if you are somewhat new. Though this doesn't really get you what you are trying to do here. We do offer other frameworks like nRF Desktop and CAF, but I guess we haven't gotten to ZMK yet.

    eg - I try the following, but I only see LRCK and SDOUT on the logic analyzer.
    I had MCK working at one point but have lost that configuration with trial and error. 

    i2s0_default: i2s0_default {
     group1 {
     psels = <NRF_PSEL(I2S_MCK, 0, 28)>,
      <NRF_PSEL(I2S_SCK_M, 0, 30)>,
      <NRF_PSEL(I2S_LRCK_M, 0, 29)>,
      <NRF_PSEL(I2S_SDOUT, 0, 31)>;
     };

    When it comes to this problem, are you seeing it on NCS versions as well?

    Regards,

    Elfving

  • yeah I just tried with NCS. same result. Only LRCK and SDOUT are wiggling on the logic analyzer. I attached my project. 
    ncs_i2s_test.zip

  • There are two obvious things that could be at fault here that comes to mind. One would be if you chose pins that were assigned to something else in the HW of the DK, and would maybe need to cut a SB to fix that (you can find these pins in the table underneath the DK). Another would be if you assigned another peripheral to the same pins. I am not seeing neither of this being at fault here.

    What NCS version were you using btw?

    Regards,

    Elfving

  • I thought the same things. 
    I'm using ncs v3.1.1

Related