nRF9161 DK and an I2S microphone

I'm trying to convert some code from ESP32 to nRF, and I'm having problems with the microphone input. Mind you, I'm a beginner with nRF, so I'm sure I'm missing something!

I have this in the prj.conf file:

CONFIG_I2S=y
CONFIG_I2S_NRFX=y


and this nrf9161dk_nrf9161_ns.overlay:
&pinctrl {
    i2s0_default: i2s0_default {
        group1 {
            psels = 
                <NRF_PSEL(I2S_SCK_M, 0, 21)>,  /* BCLK */
                <NRF_PSEL(I2S_SDIN, 0, 22)>,   /* DOUT*/
                <NRF_PSEL(I2S_LRCK_M, 0, 23)>; /* LRCL */
        };
    };
};

&i2s0 {
    compatible = "nordic,nrf-i2s";
    status = "okay";
    pinctrl-0 = <&i2s0_default>;
    pinctrl-names = "default";
};

I can see this in the GPIO overview in VS Code, and I made sure those pins weren't in use. My SPH0645s BCLK is connected to P0.21, DOUT is connected to P0.22, LRCL is connected to P0.23. 

Here's the code, mic_input.c:

#define SAMPLE_RATE 48000
#define BLOCK_TIME_MS 125
#define SAMPLES_PER_BLOCK (SAMPLE_RATE * BLOCK_TIME_MS / 1000)
#define BLOCK_SIZE (SAMPLES_PER_BLOCK * sizeof(int16_t))

K_MEM_SLAB_DEFINE(i2s_rx_slabs, BLOCK_SIZE, 2, 4);
__aligned(4) static int16_t raw_buf[SAMPLE_RATE / 8];

static void mic_thread(void *, void *, void *)
{
    printf("Mic thread started!\n");
    printf("Block size: %d\n", BLOCK_SIZE);
    printf("Buffer size: %d\n", sizeof(raw_buf));

    // Finn I2S-enhet
    i2s_dev = DEVICE_DT_GET(I2S_DEV_NODE);
    __ASSERT(device_is_ready(i2s_dev), "I2S device not ready");
    __ASSERT(i2s_dev, "I2S device not found");

    // Konfigurer I2S
    struct i2s_config cfg = {
        .word_size      = 16,
        .channels       = 1,
        .format         = I2S_FMT_DATA_FORMAT_I2S,
        .options        = I2S_OPT_BIT_CLK_MASTER | I2S_OPT_FRAME_CLK_MASTER,
        .frame_clk_freq = 48000,
        .block_size     = 12000, // matcher slab blokk
        .mem_slab       = &i2s_rx_slabs,
        .timeout        = 2000,
    };

    //Configure I2S RX
    int ret = i2s_configure(i2s_dev, I2S_DIR_RX, &cfg);
    if(ret < 0) {
        LOG_ERR("I2S configure failed: %d", ret);
        return;
    }
    printf("i2S configured!\n");

    // Reset og gjør klar buffere
    ret = i2s_trigger(i2s_dev, I2S_DIR_RX, I2S_TRIGGER_PREPARE);
    if (ret < 0) {
        LOG_ERR("I2S trigger prepare failed: %d", ret);
        return;
    }
    printf("i2S prepared!\n");
    
    //Trigger I2S RX
    ret = i2s_trigger(i2s_dev, I2S_DIR_RX, I2S_TRIGGER_START);
    if (ret < 0) {
        printk("I2S trigger start failed: %d\n", ret);
        return;
    }
    printf("i2S triggered!\n");

    k_sleep(K_MSEC(1));   // Vent litt så clocks starter

    printf("Staring I2S RX...\n");
    
    void *mem_block;
    size_t size;
    
    while (true) {
        ret = i2s_read(i2s_dev, &mem_block, &size);
    
        if (ret == 0) {
            // Vi fikk en gyldig buffer!
            memcpy(raw_buf, mem_block, size);
    
            // Nå kan du bruke raw_buf fritt
            printk("First sample: %d\n", ((int32_t *)raw_buf)[0]);
    
            // Release buffer etter bruk!
            //i2s_release(i2s_dev, I2S_DIR_RX);
        }
        else if (ret == -EAGAIN) {
            printk("No audio available, waiting...\n");
            k_sleep(K_MSEC(10));
        }
        else {
            printk("i2s_read() error: %d\n", ret);
            k_sleep(K_MSEC(100));
        }
    }

}

K_THREAD_DEFINE(mic_thread_instance, 2048, mic_thread, NULL, NULL, NULL, 7, 0, 0);

... but I only get:

Mic thread started!
Block size: 12000
Buffer size: 12000
i2S configured!
*** Booting nRF Connect SDK v3.0.0-3bfc46578e42 ***
*** Using Zephyr OS v4.0.99-3e0ce7636fa6 ***
[00:00:00.318,511] <inf> i2s_nrfx: I2S MCK frequency: 1523809, actual PCM rate: 47619
[00:00:00.319,976] <err> mic: I2S trigger prepare failed: -5

Where do I start?

Parents
  • Hi,

    I do not immediately see the problem, but you get -5 (-EIO) returned from i2s_trigger(). Can you debug and step down until you see more precisely where the error comes from?

  • Hei Einar, thanks for getting back to me.

    I get this error:
    Failed to read memory at 0x40028000

    ... but I'm not sure that's what I'm looking for. Stepping in gets me here in the end:

    Do I understand this correctly?
    When I run...

        ret = i2s_trigger(i2s_dev, I2S_DIR_RX, I2S_TRIGGER_PREPARE);

    ... cmd_allowed will be set to FALSE because the state error is not equal to I2S_STATE_ERROR...?
    Should it be?

  • I've made some progress, but nothing that really gives data. I've removed I2S_TRIGGER_PREPARE and of course the code now does... something. But still no valid data.

    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/drivers/i2s.h>
    #include <string.h>
    #include <stdio.h>
    #include <math.h>
    
    #include "mic_input.h"
    #include "filters.h"
    
    #define I2S_DEV_NODE DT_NODELABEL(i2s0)
    
    #define SAMPLE_RATE 48000
    //#define SAMPLE_BITS 24 //in .h file   
    #define BLOCK_TIME_MS 125
    #define CHANNELS 1
    #define SAMPLE_BYTES (SAMPLE_BITS / 8)
    #define SAMPLES_PER_BLOCK ((SAMPLE_RATE * BLOCK_TIME_MS) / 1000)
    #define BLOCK_SIZE (SAMPLES_PER_BLOCK * sizeof(int32_t))
    
    static const struct device *i2s_dev;
    
    __aligned(4) static float work_buf[SAMPLES_PER_BLOCK];
    K_MEM_SLAB_DEFINE(i2s_rx_slabs, BLOCK_SIZE, 4, 4);
    K_MSGQ_DEFINE(samples_msgq, sizeof(sum_queue_t), 8, 4);
    
    bool foundData = false;
    static void mic_thread(void *, void *, void *)
    {
        printf("Mic thread started\n");
    
        i2s_dev = DEVICE_DT_GET(I2S_DEV_NODE);
        __ASSERT(device_is_ready(i2s_dev), "I2S device not ready");
    
        struct i2s_config cfg = {
            .word_size = SAMPLE_BITS,
            .channels = CHANNELS,
            .format = I2S_FMT_DATA_FORMAT_I2S,
            .options = I2S_OPT_BIT_CLK_MASTER | I2S_OPT_FRAME_CLK_MASTER,
            .frame_clk_freq = SAMPLE_RATE,
            .block_size = BLOCK_SIZE,
            .mem_slab = &i2s_rx_slabs,
            .timeout = 200,
        };
    
        printf("Buffer size: %d\n", BLOCK_SIZE);
    
        int ret = i2s_configure(i2s_dev, I2S_DIR_RX, &cfg);
        if (ret < 0) {
            printf("I2S configure failed: %d\n", ret);
            return;
        }
    
        printf("I2S configured!\n");
    
        ret = i2s_trigger(i2s_dev, I2S_DIR_RX, I2S_TRIGGER_START);
        if (ret < 0) {
            printf("I2S trigger start failed: %d\n", ret);
            return;
        }
    
        printf("I2S triggered!\n");
    
        void *mem_block;
        size_t size;
    
        while (true)
        {
            foundData = false;
            ret = i2s_read(i2s_dev, &mem_block, &size);
    
            if (ret == 0)
            {
                const int32_t *samples = (int32_t *)mem_block;
                int printed = 0;
    
    	    //test if data is found
                for(int i = 0; i < SAMPLES_PER_BLOCK; i++) {
                    if (samples[i] != 0) {
                        foundData = true;
                        printf("Found data in sample[%d] = 0x%08X\n", i, samples[i]);
                        break;
                    }
                }
    
                // print 10 samples
                for (int i = 0; i < SAMPLES_PER_BLOCK && printed < 10; i++) {
                    int32_t s = samples[i];
                    if (s != 0) {
                        printf("sample[%d] = 0x%08X (%d)\n", i, s, s);
                        printed++;
                    }
                }
    
                for (int i = 0; i < SAMPLES_PER_BLOCK; i++) {
                    work_buf[i] = unpack_24bit(samples[i]) / 8388608.0f;  // 2^23
                }
    	    //do something smart with the work_buf[] here
    
                k_mem_slab_free(&i2s_rx_slabs, mem_block);
    
            }
            else if (ret == -EAGAIN)
            {
                printf("No data yet (possible timeout)...\n");
                k_sleep(K_MSEC(10));
            }
            else
            {
                printf("i2s_read() failed: %d\n", ret);
                k_sleep(K_MSEC(100));
            }
        }
    }
    
    K_THREAD_DEFINE(mic_thread_instance, 1024 * 4, mic_thread, NULL, NULL, NULL, 7, 0, 0);

Reply
  • I've made some progress, but nothing that really gives data. I've removed I2S_TRIGGER_PREPARE and of course the code now does... something. But still no valid data.

    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/drivers/i2s.h>
    #include <string.h>
    #include <stdio.h>
    #include <math.h>
    
    #include "mic_input.h"
    #include "filters.h"
    
    #define I2S_DEV_NODE DT_NODELABEL(i2s0)
    
    #define SAMPLE_RATE 48000
    //#define SAMPLE_BITS 24 //in .h file   
    #define BLOCK_TIME_MS 125
    #define CHANNELS 1
    #define SAMPLE_BYTES (SAMPLE_BITS / 8)
    #define SAMPLES_PER_BLOCK ((SAMPLE_RATE * BLOCK_TIME_MS) / 1000)
    #define BLOCK_SIZE (SAMPLES_PER_BLOCK * sizeof(int32_t))
    
    static const struct device *i2s_dev;
    
    __aligned(4) static float work_buf[SAMPLES_PER_BLOCK];
    K_MEM_SLAB_DEFINE(i2s_rx_slabs, BLOCK_SIZE, 4, 4);
    K_MSGQ_DEFINE(samples_msgq, sizeof(sum_queue_t), 8, 4);
    
    bool foundData = false;
    static void mic_thread(void *, void *, void *)
    {
        printf("Mic thread started\n");
    
        i2s_dev = DEVICE_DT_GET(I2S_DEV_NODE);
        __ASSERT(device_is_ready(i2s_dev), "I2S device not ready");
    
        struct i2s_config cfg = {
            .word_size = SAMPLE_BITS,
            .channels = CHANNELS,
            .format = I2S_FMT_DATA_FORMAT_I2S,
            .options = I2S_OPT_BIT_CLK_MASTER | I2S_OPT_FRAME_CLK_MASTER,
            .frame_clk_freq = SAMPLE_RATE,
            .block_size = BLOCK_SIZE,
            .mem_slab = &i2s_rx_slabs,
            .timeout = 200,
        };
    
        printf("Buffer size: %d\n", BLOCK_SIZE);
    
        int ret = i2s_configure(i2s_dev, I2S_DIR_RX, &cfg);
        if (ret < 0) {
            printf("I2S configure failed: %d\n", ret);
            return;
        }
    
        printf("I2S configured!\n");
    
        ret = i2s_trigger(i2s_dev, I2S_DIR_RX, I2S_TRIGGER_START);
        if (ret < 0) {
            printf("I2S trigger start failed: %d\n", ret);
            return;
        }
    
        printf("I2S triggered!\n");
    
        void *mem_block;
        size_t size;
    
        while (true)
        {
            foundData = false;
            ret = i2s_read(i2s_dev, &mem_block, &size);
    
            if (ret == 0)
            {
                const int32_t *samples = (int32_t *)mem_block;
                int printed = 0;
    
    	    //test if data is found
                for(int i = 0; i < SAMPLES_PER_BLOCK; i++) {
                    if (samples[i] != 0) {
                        foundData = true;
                        printf("Found data in sample[%d] = 0x%08X\n", i, samples[i]);
                        break;
                    }
                }
    
                // print 10 samples
                for (int i = 0; i < SAMPLES_PER_BLOCK && printed < 10; i++) {
                    int32_t s = samples[i];
                    if (s != 0) {
                        printf("sample[%d] = 0x%08X (%d)\n", i, s, s);
                        printed++;
                    }
                }
    
                for (int i = 0; i < SAMPLES_PER_BLOCK; i++) {
                    work_buf[i] = unpack_24bit(samples[i]) / 8388608.0f;  // 2^23
                }
    	    //do something smart with the work_buf[] here
    
                k_mem_slab_free(&i2s_rx_slabs, mem_block);
    
            }
            else if (ret == -EAGAIN)
            {
                printf("No data yet (possible timeout)...\n");
                k_sleep(K_MSEC(10));
            }
            else
            {
                printf("i2s_read() failed: %d\n", ret);
                k_sleep(K_MSEC(100));
            }
        }
    }
    
    K_THREAD_DEFINE(mic_thread_instance, 1024 * 4, mic_thread, NULL, NULL, NULL, 7, 0, 0);

Children
No Data
Related