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);

  • Hi,

    This code looks sensible. I assume you have had a look at the I2S echo sample?

    You write that you get no valid data. Does that mean no data at all, or not valid data? How do you determine it? Do you see anything from the logs? Also, what do you see if you check the I2S lines with a logic analyzer (most analyzers should be able to decode I2S)

  • The buffer is just zeros. But other than that, the code runs "fine" now.

    I have seen that sample, but I'll go through it again to see if there's anything I've missed. Tomorrow we'll use an oscilloscope to check the pins to see if clocks and such are working as they should.

Reply Children
No Data
Related