Trouble extracting data using DMIC

Hi there!

I am using the DMIC sample on a nrf5340dk. I have got it working, and now I want to develop it further. I want to record some sound and then transfer it to my PC. I have a lot of questions that I struggle with finding the answers to.

Now I understand that the data stored should already be stored as PCM data. So I can easily convert them to WAV files with a script on my PC. Is this correct?

When I record now I can leave it one for multiple seconds, but the data collected only corresponds to a few milliseconds. I suspect this is due to a lot of time being used logging to the console. The way I do it now, is that I log the collected data to the console, and then extract it onto the PC from there. However I can imagine this is quite slow. I was thinking of printing it out after the recording is done instead. But I struggle with understanding how the memory allocation in this sample works. I use:

void *buffer;

But this buffer get owerwritten with new data. How do I go about not overwriting the data and retrieving it later? (The recording does not need to be longer than a few seconds, maybe even shorter)

I also struggle with understanding the part the memory slab plays in the program. Defined as:

K_MEM_SLAB_DEFINE_STATIC(mem_slab, MAX_BLOCK_SIZE, BLOCK_COUNT, 4);
Parents
  • I have manged to access the data. What I really need is a way to quickly transfer the data to my PC, about 16000*2 = 32kbytes/sec (sampling frequency multiplied with bytes per sample). I was planning to log everything to a terminal window. But it seems like it can't keep up. I got the error:  --- 3171 messages dropped ---.

    Might it be possible to use UART for this? Or is there something else?

  • Hi 

    What is your UART baudrate? 

    32kBytes/sec equals 256 kbps, which means you need to use a baudrate that is at a minimum 288 kbaud (to make room for the stop bit). Realistically though I would recommend at least 460800 baud, to have some overhead. 

    Secondly, how do you output the data? 

    If you use the LOG API and convert the raw audio data to ASCII then you are multiplying the amount of data significantly, since each raw byte becomes multiple bytes over the UART. Then you will surely not have enough bandwidth. 

    But this buffer get owerwritten with new data. How do I go about not overwriting the data and retrieving it later? (The recording does not need to be longer than a few seconds, maybe even shorter)

    If you only need to store a couple of seconds of data you can copy it into a larger secondary buffer. If your math is correct then 3 seconds of data equals 96kB. The nRF5340 appcore has 512kB of RAM in total, so setting aside 96kB for data storage should be fine. 

    I also struggle with understanding the part the memory slab plays in the program. Defined as:

    The DMIC driver will use the memory slab to allocate buffers for the PDM interface automatically in the PDM event handler, to ensure that the buffers are provided fast enough to avoid gaps in the data. All the application has to do is to free the buffers again after the data is processed, which you can see in the do_pdm_transfer(..) function in main.c. 

    The documentation for the driver is a bit slim, so in order to check out the details of the implementation you might want to just look at the source, zephyr/drivers/audio/dmic_nrfx_pdm.c. For instance to see how the buffers are allocated you can have a look here

    Best regards
    Torbjørn

  • Thanks you so much for the detailed answer!

    I am getting strange data when using the mic. I use basically the same code as the DMIC sample. When I print out the data, I get the exact same data each run. This is the code I use to read and print the data:

    void *buffer;
    uint32_t size;
    int ret;

    ret = dmic_read(dmic_dev, 0, &buffer, &size, READ_TIMEOUT);
    if (ret < 0) {
    LOG_ERR("%d - read failed: %d", i, ret);
         return ret;
    }
           
    uint16_t *data_ptr = (int *)buffer;

    for(int j = 0; j < size/2; j++){
            printk("%x ", *data_ptr);
            data_ptr++;
    }
    printk("\n");
    k_mem_slab_free(&mem_slab, &data_ptr);
    k_mem_slab_free(&mem_slab, &buffer);

    The terminal outputs bellow are from different runs, but the output in data is exactly the same (not all data logged is included here for convenience sake)

    *** Booting Zephyr OS build v3.3.99-ncs1 ***
    [00:00:00.453,460] <inf> dmic_sample: Size of sample: 2
    [00:00:00.453,460] <inf> dmic_sample: DMIC sample
    [00:00:00.453,460] <inf> dmic_sample: PCM output rate: 16000, channels: 1
    [00:00:00.453,491] <inf> dmic_nrfx_pdm: PDM clock frequency: 1024000, actual PCM rate: 16000
    00 0 0 ffff fffe 31 2e 61 5d 90 8b f4 b9 125 b5 158 b0 1bd dd 223 a1 28d 65 32b 26 3ff ff7a 541

    *** Booting Zephyr OS build v3.3.99-ncs1 ***
    [00:00:00.252,777] <inf> dmic_sample: Size of sample: 2
    [00:00:00.252,777] <inf> dmic_sample: DMIC sample
    [00:00:00.252,777] <inf> dmic_sample: PCM output rate: 16000, channels: 1
    [00:00:00.252,807] <inf> dmic_nrfx_pdm: PDM clock frequency: 1024000, actual PCM rate: 16000
    00 0 0 ffff fffe 31 2e 61 5d 90 8b f4 b9 125 b5 158 b0 1bd dd 223 a1 28d 65 32b 26 3ff ff7a 541

  • Hi

    Is your configuration sequence exactly the same as well? 

    The only error I can spot in your screenshot is that you are trying to free the same buffer twice, but I don't think that explains the problem you are seeing. 

    Could you check with a debugger what the value of the buffer pointer is after the read, and try to inspect the data at that address directly? 

    Best regards
    Torbjørn

  • I'm seeing a potentially similar issue. Using the default dmic sample I get 8 chunks of identical data with each run of the program.
    What is even more bizarre is that I get data no matter if the PDM mic is actually connected or not.
    Then I try to use a slightly different example meant for the 96_ArgonKey (https://github.com/nrfconnect/sdk-zephyr/tree/main/samples/boards/96b_argonkey/microphone) which seems almost identical but there the driver throws an error with:
    dmic_nrfx_pdm: Failed to allocate buffer: -12

    had to add this in order for the sample to not return with a configuration error

    cfg.channel.req_chan_map_lo =
            dmic_build_channel_map(0, 0, PDM_CHAN_LEFT);
  • Hi Timon

    Sorry for the slow response, I just got back from vacation. 

    Are you still having issues with this? 

    Does the data look the same whether or not the PDM mic is connected? 

    The PDM interface is not able to detect if anything is connected or not, so the example should run just as well regardless, but the data should reflect the state of the pin (most likely permanently high or low, unless it is floating between the two states).

    Best regards
    Torbjørn 

  • Hi Torbjørn, no worries!
    I opened a seperate issue here: PDM / DMIC not giving any sensible output
    That is good to know that there is no data detection being made, then I probably just get random memory without anything connected.
    I poked around a bit more and am able to extract actual audio data but am still experiencing weird popping artifacts that overlay the recording and shift my samples "up".
    If you have seen that before any pointers would be useful, I'm pretty sure that its related to how I handle the buffer and the mic streaming.

Reply Children
Related