MKR1400 freezes while modem activity (send/ receive sms or phone call)

Hi together,

I'm struggling with my MKR1400 since some months meanwhile. My MKR1400 consistently freezes either while checking for new received (unread) sms, sending a sms or establishing a phone call.


Here is an minimal example sketch, the Arudino support asked me to post here in the forum:

due to post length restrictions pls see my following post

Sry, if this is a quite long minimal example, but it is indeed a very brief roundup of the actual, longer code I'm working on. What is the given minimal sketch actually doing?

  • It utilizes the send/ receive sms and establish/ receive phone calls features of the MKR1400.
  • Check for new sms every 5 seconds.
  • If there is a new sms by remote A (e.g. me send by my mobile phone) forward it to Remote B, another module (e.g. Arduino Uno with GSM shield)
  • If the sms was sent by Remote B (remote module), just forward the sms to Remote A = me (mobile phone)
  • To check if Remote B (remote module) is still online, establish a phone call to B every some minutes (exact interval is random)
  • Additionally, sent a command (just sms with specific syntax) to Remote B, if phone call was established successful every some hours (exact interval random)
  • Check every 4 seconds if sb. tries to call the MKR1400. If so, just hang up.

Here is a example (debugging Serial) output of a run, where a freeze occurred:

booting modem... modem online!

***

calling +49175YYYYYY... successful

new SMS by +49151XXXXXXX

new SMS by +49175YYYYYY

calling +49175YYYYYY... successful

calling +49175YYYYYY... successful

calling +49175YYYYYY... successful

[...]

calling +49175YYYYYY... successful

calling +49175YYYYYY... successful

new SMS by +49175YYYYYY

calling +49175YYYYYY... successful

calling +49175YYYYYY... successful

calling +49175YYYYYY... successful

calling +49175YYYYYY... successful

calling +49175YYYYYY... successful

calling +49175YYYYYY... successful

calling +49175YYYYYY... successful

calling +49175YYYYYY... successful

calling +49175YYYYYY... successful

calling +49175YYYYYY...

The Arduino freezes arbitrary after some minutes or hours. Either directly after the sms.available() command, while trying to send an sms, or often at trying to establishing a phone call [voice.voiceCall(...)]. The complete code hangs (nothing is done anymore by the arduino) and additionally I can't call the arduino any longer by my phone from outside. It's just like the arduino is offline, i.e. has no connection to cellular network anymore (before the freeze I can call it and hear the ringing tone). Often (especially without a lipo battery connected) the arduino needs several restarts until the modem can successfully boot and connect to the cellular network (see setup routine).


My setup:

  • Arduino IDE 1.8.6
  • MKRGSM library, newest version, 1.2.0
  • Power setup according as follows:

Do you have any ideas, how to fix this issue. I tested a lot of different power setups (different Wall warts, w and w/o capacitators, w and w/o lipo battery) but nothing helped. Also pls let me know if you need more details to my setup or similar.

Thank you very much for your help,

kind regards,

Oliver

Here is my minimal example code, where I can reproduce the freezes with:

#include <MKRGSM.h>

#define SECRET_PIN "1234"
#define SECRET_TEL_NUMBER_A "+49151XXXXXXX"
#define SECRET_TEL_NUMBER_B "+49175YYYYYY"

//just some time definitions
#define _SMSINBOXCHECKINTERVAL_ 5000
#define _VOICECALLCHECKINTERVAL_ 4000UL

#define _EMAALIVETESTMININTERVALL_ 120000UL // 2min
#define _EMAALIVETESTMAXINTERVALL_ 300000UL // 5min
#define _MAXTIMOUTEMAVOICECALLS_ 12000UL
#define _TIMEAFTERFAILEDEMAVOICECALL_ 30000UL
#define _MAXNUMBERFAILSEMAVOICECALLS_ 3

#define _EMASTATUSREQUESTMININTERVALL_  3600000UL // 1h
#define _EMASTATUSREQUESTMAXINTERVALL_ 14400000UL // 4h

#define _MAXMOBILENUMBERLENGTH_ 16
#define _MAXSMSTEXTLENGTH_ 151

bool EMAOnline(true);
unsigned long timeLastEMAAliveCheck(0);


GSM gsm(false);
GSM_SMS sms;
GSMVoiceCall voice;





void setup() {
  Serial.begin(9600);
  
  // set BUILT_IN LED ON
  pinMode(LED_BUILTIN,      OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  
  // boot modem
  delay(2000);
  digitalWrite(LED_BUILTIN, HIGH);
  Serial.print("booting modem... ");
  boolean not_connected = true;
  while(not_connected)  {
    if(gsm.begin(SECRET_PIN) == GSM_READY) {
      not_connected = false;
      Serial.println("modem online!");
    }
    else {
      Serial.print("failed.\ntry again... ");
      delay(3000UL);
    }
  }
  digitalWrite(LED_BUILTIN, LOW);
  Serial.println("\n***\n");
  

}

void loop() {
  periodicSMSInboxCheck();
  delay(500);
  perdiodicEMAAliveTest();
  delay(500);
  periodicVoiceCallCheck();
  delay(500);
}

void periodicSMSInboxCheck(void) {

  static unsigned long timeLastSMSInboxCheck(0);
  if (timeElapsed(timeLastSMSInboxCheck, _SMSINBOXCHECKINTERVAL_)) {  // time to check Inbox
    digitalWrite(LED_BUILTIN, HIGH);
    if (sms.available()) {  // sms is available

      Serial.print("new SMS by ");
      // get remote number
      char remote_number[_MAXMOBILENUMBERLENGTH_];
      sms.remoteNumber(remote_number, _MAXMOBILENUMBERLENGTH_);
      remote_number[0] = '+';
      Serial.print(remote_number);
      Serial.println("\n");

      if (!strcmp(remote_number, SECRET_TEL_NUMBER_A)) { // = me
        // read sms into char array
        const byte sms_text_length(_MAXSMSTEXTLENGTH_);
        char sms_text[sms_text_length];
        readSMSIntoArray(sms_text, sms_text_length);

        // send sms text to remote module (EMA)
        sendSMSTo(SECRET_TEL_NUMBER_B, sms_text);
      }
      else if (!strcmp(remote_number, SECRET_TEL_NUMBER_B)) { // remote module (EMA)
        // read sms into char array
        const byte sms_text_length(_MAXSMSTEXTLENGTH_);
        char sms_text[sms_text_length];
        readSMSIntoArray(sms_text, sms_text_length);

        // send sms text to me (mobile phone)
        sendSMSTo(SECRET_TEL_NUMBER_A, sms_text);

        // set EMA status to "online"
        EMAOnline = true;
        timeLastEMAAliveCheck = millis();
      }
      else {
        // discard sms
        sms.peek();
        flushModemMemory();
      }
    }
    digitalWrite(LED_BUILTIN, LOW);
    timeLastSMSInboxCheck = millis();
  }
  return;
}

void readSMSIntoArray(char *sms_text, byte sms_text_length) {
  
  byte ndx = 0;
  char c;

  while ( (c=sms.read())!=255 && (ndx < sms_text_length-1) ) {
    sms_text[ndx++] = c;
    sms_text[ndx] = '\0'; // Keep string NULL terminated
  }
}

byte sendSMSTo(char *recipient_telnumber, char* txt_msg) {
  
  byte failed_loops(0);
  while(failed_loops < 5) {
    
    byte successfull_sms_begin = sms.beginSMS(recipient_telnumber);
    delay(500);
    
    sms.print(txt_msg);
    delay(500);
    byte successfull_sms_end = sms.endSMS();
    delay(500);
        
    if (successfull_sms_begin + successfull_sms_end == 2) {
      
      flushModemMemory();
      return(1);
    }
    
    // executed if not successfully sent
    failed_loops++;
    flushModemMemory();
  }
  return(0);
}

void perdiodicEMAAliveTest() {
  
  static unsigned long timeIntervallEMAAliveTest(_EMAALIVETESTMININTERVALL_);
  if (EMAOnline && timeElapsed(timeLastEMAAliveCheck, timeIntervallEMAAliveTest)) {  // time for EMA Alive Test (Intervall)
    
    randomSeed(analogRead(A2) + millis());
    EMAOnline = checkIfEMAStillAlive();
    Serial.println("");

    // do a addtional status sms request for a very long intervall
    static unsigned long timeIntervallEMAStatusRequest = _EMASTATUSREQUESTMININTERVALL_;
    static unsigned long timeLastEMAStatusRequest = 0;
    if (timeElapsed(timeLastEMAStatusRequest, timeIntervallEMAStatusRequest)) {
       sendSMSTo(SECRET_TEL_NUMBER_B, "getstatus 0001");
      // reset status sms intervall and time of last execution
      timeIntervallEMAStatusRequest = random(_EMASTATUSREQUESTMININTERVALL_, _EMASTATUSREQUESTMAXINTERVALL_);
      timeLastEMAStatusRequest = millis();
    }

    // reset alove test intervall and time of last execution
    timeIntervallEMAAliveTest = random(_EMAALIVETESTMININTERVALL_, _EMAALIVETESTMAXINTERVALL_);
    timeLastEMAAliveCheck = millis();
  }
}

bool checkIfEMAStillAlive(void) {
  
  byte try_counter(1);
  while(try_counter <= _MAXNUMBERFAILSEMAVOICECALLS_) {
    if (establishVoiceCallTo(SECRET_TEL_NUMBER_B, _MAXTIMOUTEMAVOICECALLS_)) {
      return(true);
    }
    if (try_counter > _MAXNUMBERFAILSEMAVOICECALLS_) {
      sendSMSTo(SECRET_TEL_NUMBER_A, "failed to establish voice call to ema");
      break;
    }
    
    unsigned long time_voicecall_failed = millis();
    while (!timeElapsed(time_voicecall_failed, _TIMEAFTERFAILEDEMAVOICECALL_)) {
      delay(500);
    }
  }
  return(false);
}

byte establishVoiceCallTo(const char *remote_number, unsigned long calling_timeout) {
  
  //call remote
  Serial.print("calling ");
  Serial.print(remote_number);
  voice.voiceCall(remote_number, calling_timeout);
  delay(500);
  int stat = voice.getvoiceCallStatus();

  Serial.print("... ");
  delay(333);
  voice.hangCall();
 
  if ( stat == TALKING) {
    //successfully established  
    Serial.println("successful");
    return(1);
  }
  else {
    // failed
    Serial.println("failed");
    return(0);
  }
}

void periodicVoiceCallCheck(void) {
  
  static unsigned long timeLastVoiceCallCheck(0);
  if (timeElapsed(timeLastVoiceCallCheck, _VOICECALLCHECKINTERVAL_)) { // time to check for incoming voice calls

    switch (voice.getvoiceCallStatus()) {
      case IDLE_CALL: // Nothing is happening
        break;
  
      case CALLING: // This should never happen, as we are not placing a call
        break;
  
      case RECEIVINGCALL: { // User (or whoever) is calling

        Serial.print("voice call incoming... ");
        
        // respond
        delay(1000);
        voice.hangCall();
        Serial.println("hangCall()\n");
        delay(333);
  
        break;
      }
  
      case TALKING:  // usually not possible as well    
        break;
    }
    
    timeLastVoiceCallCheck = millis();
  }
}

void flushModemMemory(void) {
  delay(500UL);
  for (byte x=0; x<3; x++) {
    sms.flush();
    delay(200UL);
  }
  delay(300UL);
}


byte timeElapsed(unsigned long start_time, unsigned long time_diff) {
  if (millis() - start_time >= time_diff)
    return(1);
  else
    return(0);
}

Looks like it is dying in calling the function in the GSMVoiceCall voice library area.... You've tried adding some serial output in this area and displaying the timeout setting etc?

voice.voiceCall(remote_number, calling_timeout);

Have you looked through the program for memory leaks, because if it's not something like that then it's sort of pointing at an issue within the library, might need to raise a defect against the library in github.

Link to chasing memory gremlins:

Strange error though, one of the other guys here complained of his sketch dying after an undetermined period of time on a regular basis as well, the only other things I can suggest with my limited knowledge is that you could look to add a watchdog which resets your unit if a function doesn't return within x seconds...

Hi ellokah i start to investigating on this issue thank you for your description and the sketch

Hey together,

thank you both for your replies.

smgs:
You've tried adding some serial output in this area and displaying the timeout setting etc?

I can remember I already tried to add some debugging output within the MKRGSM lib. However I stucked really soon, because I don't really understand the things going on in this lib. I think one would need to go into the deeper functions regarding the direct modem communication. However my skills of understanding about this are very limited :confused:

smgs:
Have you looked through the program for memory leaks, because if it's not something like that then it's sort of pointing at an issue within the library, might need to raise a defect against the library in github.

I checked my original sketch for memory problems, because at some point I thought it could be an issue of my too complex sketch (memory consumption). However, I had the feeling, it is a little bit more difficult to print out the current free memory (or used one) with the common MEMFREE libs etc. Can't explain it in detail anymore, but I can remember that it was much more difficult for the SAMD architecture than an Arduino Uno for example.

Anyway, the posted minimal sketch is far away from a too high memory consumption, I think. So I'm wondering, if anyone can confirm the freezes on his MKR1400. Tbh, I didn't question the integrity of the MKRGSM lib itself (regarding possible mem errors/ bugs) mainly because I'm not skilled enough to understand the stuff in the lib (let alone to correct any bugs).

smgs:
the only other things I can suggest with my limited knowledge is that you could look to add a watchdog which resets your unit if a function doesn't return within x seconds...

I already prepared my code for implementing an WDT, however of course this is not a good coding practise, because it's not solving the actual issue. Addtionally, if the Arduino freezes already after 1 hour this would lead to hundreds of restarts per week, which is not the kind of availability I'm looking for in my project. Let's define this option as some kind of last resort.

Riccardo_Rizzo:
Hi ellokah i start to investigating on this issue thank you for your description and the sketch

Thanks a lot Riccardo, I'm really looking forward to hear from u guys and hopefully we can find a solution. I'll addtionally try to further simplify the provided minimal sketch until the WE, as its still containing some useless code trash (which is not related to the core issue, I think).

Any further/other suggestions or ideas (even confirmations about failure reproduction) are welcome!

kind regards,

Oliver