Dictaphone project - MKRZero hangs indefinitely

Hello everyone,

I just bought an MKRzero and I am trying to create a dictaphone with it. The idea is to use two I2S microphones and record their output at 20kHz on the SD card.

Unfortunately, I stumble one big issue: the board just stop reading correctly my I2S microphones after an apparently random duration. It can be down to several seconds and up to one hour. I wonder if I am missing something.

Here is a very simple sketch that pumps the I2S values from only one microphone on the serial port. The reference that I use is the ICS-43434.

/*
This code was created to get sound data from an i2s microphone and plot it to the serial output.
It uses:
    - Arduino MKRZero
    - ICS-43434
    - PIN 2 connected to SCK (Serial Clock)
    - PIN 3 connected to FS (Frame Select)
    - PIN A6 connected to SD (Serial Data)
*/

#include <I2S.h>

unsigned long timestamp;
int sample = 0;

void setup() {
    Serial.begin(115200);
    while (!Serial) {;}
    
    if (!I2S.begin(I2S_PHILIPS_MODE, 10000, 32)) {
        Serial.println("Failed to initialize I2S!");
        return;
    }
}

void loop() {
    timestamp = micros();
    sample = I2S.read();

    if (sample) {
        Serial.print(timestamp);
        Serial.print("\t");
        Serial.println(sample);
    }
}

With this code, everything is working fine until suddenly, nothing is printed in the serial console any more.

By removing the "if(sample)" condition, I saw that the MKRZero is in fact seeing only zeros, so it does not print them in the console.
I have tried to read the I2S pins with a logic analyzer and I see that my microphone continues to output data, so it is the MKRZero that seems to be in fault.
I also tried to use another mic or another MKRZero (I bought two of them!), with similar results.

FYI, I use the online Arduino Editor to write and upload my sketches.

I have some other issues in this project when writing on the SD card, but this is the most limiting one :confused:
Thank you in advance to those who will spend some time looking into my problem.

Hi @lehippie,

Have you tried to lower the sample rate to 8000 (instead of 10000)?

Also, what type of computer is your MKRZero connected to?

From what I have understood about these boards remove the

while (!Serial) {;}

line

--
Mark

sandeepmistry:
Hi @lehippie,

Have you tried to lower the sample rate to 8000 (instead of 10000)?

Also, what type of computer is your MKRZero connected to?

Hi @sandeepmistry, thank you for your answer.

Unfortunately, it does not change anything when I try to play with the sampling rate, it just stops after some time as usual. In fact, I know that the output is limited by the baud rate of the serial port but in the end, I want to record it on the SD card and I see the same effect on it. The corresponding code being longer, I just showed a simple one getting to the point of my issue.

I just did several tests and the arduino stops the correct I2S reading after respectively 29s, 3min18s, 16s, 21s and 41s...
During this entire time my logic analyser did get correct values :confused:

As for your other question, the MKRZero is connected on my Dell Precision M3800 that runs UbuntuGNOME 16.04. That reminds me that in my use case, I want to supply it from a wallplug. I will try this to see if it changes anything.

MarkDerbyshire:
From what I have understood about these boards remove the

while (!Serial) {;}

line

--
Mark

Thank you @Mark, I just copied this line from a tuto and I have to admitt I did not quite get its use... No impact on my issue, though :cry:

Hi @lehippie,

Thanks for the info!

During our tests we also found the SD card is too slow to capture audio data in real time. Erasing pages to write new data is very slow.

I can also take a look at your sketch if you post it here.

sandeepmistry:
Hi @lehippie,

Thanks for the info!

During our tests we also found the SD card is too slow to capture audio data in real time. Erasing pages to write new data is very slow.

Indeed, the slowness of the writing is something I found out too (one of the other issues I talked about in my first post). I hope to find some clever buffer/file management trick but I haven't looked into it yet.
What do you mean by "Erasing pages to write new data is very slow." ? And did you find a workaround ?

I can add to the list of issues I also have trouble to know what data is from which mic (left or right) because reading the FS pin after reading a sample seems quite random on my first try.

Anyway, I will upload my full sketch a bit later, when I will have some time to clean it a little from all my experimentations :slight_smile:

Writing to SD card can be done at CD audio speed (16 bit, 44.1KHz) in mono. I was playing with recording & playback a while ago with SDfat.h library and help from author fat16lib. Using a 16 MHz Arduino even. See here:
http://forum.arduino.cc/index.php?topic=180769.0

sandeepmistry:
I can also take a look at your sketch if you post it here.

Below is my current code. Some comment about this version :

  • I inserted a way to check via serial that the arduino has stopped writing data on the card.
  • The hasWritten variable is there not to hang before any value is read.
  • The real sampling is very slow (~38.5 Hz) because of the loop opening and closing the file for every data written. I am not very comfortable with how many data I can write before closing the file for actually writting it.
/*
This code reads sound data from i2s microphones and log it on a SD card.
It uses:
    - Arduino MKRZero
    - ICS-43434
    - PIN 2 connected to SCK (Serial Clock)
    - PIN 3 connected to FS (Frame Select)
    - PIN A6 connected to SD (Serial Data)
*/

#include <I2S.h>
#include <SD.h>

const int chipSelect = SS1;
File myFile;
char logName[] = "test";

unsigned long timestamp = 0;
int sample = 0;
int hangLimit = 10000;
int hangCount = hangLimit;
byte hasWritten = 0;

void setup() {
    // Open serial port
    Serial.begin(9600);
    while (!Serial) {;}
    
    // Init I2S communication
    if (!I2S.begin(I2S_PHILIPS_MODE, 10000, 32)) {
        Serial.println("Failed to initialize I2S!");
        while (1) {;}
    }
    Serial.println("I2S initialized.");
    
    // Init SD card
    if (!SD.begin(chipSelect)) {
        Serial.println("SD card initialization failed, or card not present!");
        while (1) {;}
    }
    Serial.println("SD card initialized.");
}

void loop() {
    timestamp = micros();
    sample = I2S.read();

    if (sample) {
        myFile = SD.open(logName, FILE_WRITE);
        if (myFile) {
            myFile.print(timestamp);
            myFile.print(",");
            myFile.println(sample);
            myFile.close();
        } else {
            Serial.println("Error opening file!");
            while (1) {;}
        }
        hasWritten = 1;
        hangCount = hangLimit;
    } else if (hasWritten) {
        --hangCount;
    }
    
    if(!hangCount) {
        Serial.println("Arduino has stops reading I2S!");
        while (1) {;}
    }
}

CrossRoads:
Writing to SD card can be done at CD audio speed (16 bit, 44.1KHz) in mono. I was playing with recording & playback a while ago with SDfat.h library and help from author fat16lib. Using a 16 MHz Arduino even. See here:
16-bit sample & store, then readback & play, finally store to SD - Programming Questions - Arduino Forum

Thank you for this link, @CrossRoads. I will look into it when I will have more time.
Just to know a bit more, as I am far from an expert in memory management. Will I need an external flash memory component ? I saw quickly that you used several 23LC1024 ?

Hi @lehippie,

Just tried out the sketch, instead of using a mic, I connected pin 3 (FS - frame select) to A6 (SD -serial data) to simulate I2S data. After a 20 minute test things are still going. How long does the condition take to occur?

In general, opening and closing the fie for each sample is going to have a big hit on performance, same applies to storing the value with a timestamp. This will result in dropped samples.

I'd suggest you explore the callback API calls, they are more advanced but for something performance oriented like this needed. There's a brief discussion in GitHub here: ICS43432 I2S sound recording and playback · Issue #2 · arduino-libraries/ArduinoSound · GitHub

Again, recording stereo audio data to an SD card is not something we explored in depth, because our tests showed it's not fast enough with the erase cycles. You could definitely look into storing mono data though.

Hi @lehippie, not sure if you've solved problem, but thought I'd share my experience anyway.

I've found that if the program, for any reason, stops reading the I2S buffer, then the whole I2s library stops.

I was running several other tasks in my main loop and found that if I didn't call i2s.read() fast enough then the i2s stopped.

This is probably not the case in your first example, however you're not calling I2S.available to check before reading data from I2S, which might be a problem.

I did a little digging, and found that the I2s uses DMA transfer with double buffer, so when data is available, it's actually a whole buffer's worth, not discrete samples direct from the I2S stream. You have to read the whole buffer before the DMA transfer finishes and switches back to the buffer you're reading from. If that makes sense.

Good luck