Arduino keeps crashing during serial print

I am trying to determine why my Arduino MKR NB 1500 code keeps crashing when the serial monitor is open and i look for data: Here is the code. I removed the string functions to prevent it from causing memory fragmentation, but does not seems to have helped.

#include <ArduinoMqttClient.h>
#include <MKRNB.h>

// Please enter your sensitive data in the Secret tab or arduino_secrets.h
// PIN Number
const char PINNUMBER[]     = "";

// MQTT Broker and Port
const char broker[] = "test.mosquitto.org"; //
int        port     = 1883;

// Pub/Sub Topics - Make it something unique since we are using a public broker
const char subscribeTopic[]  = "channel";
const char publishTopic[]  = "channel";

// To connect with SSL/TLS:
// 1) Change NBClient to NBSSLClient.
// 2) Change port value from 1883 to 8883.
// 3) Change broker value to a server with a known SSL/TLS root certificate 
//    flashed in the WiFi module.

NBClient client;
GPRS gprs;
NB nbAccess;
MqttClient mqttClient(client);

int LED = 6; // Onboard LED

// Publish interval
long previousMillis = 0; 
long interval = 2000;

void setup() {

  pinMode(LED_BUILTIN, OUTPUT); // Set built in LED pinMode
  
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
 /* while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }*/

  // attempt to connect to GSM and GPRS:
  Serial.print("Attempting to connect to GSM and GPRS");
   // connection state
  bool connected = false;

  // After starting the modem with GSM.begin()
  // attach the shield to the GPRS network with the APN, login and password
  while (!connected) {
    if ((nbAccess.begin(PINNUMBER) == NB_READY) &&
        (gprs.attachGPRS() == GPRS_READY)) {
      connected = true;
    } else {
      Serial.println("Not connected");
      delay(1000);
    }
  }

  Serial.println("You're connected to the network");
  Serial.println();


  Serial.print("Attempting to connect to the MQTT broker: ");
  Serial.println(broker);

  if (!mqttClient.connect(broker, port)) {
    Serial.print("MQTT connection failed! Error code = ");
    Serial.println(mqttClient.connectError());

    while (1);
  }

  Serial.println("You're connected to the MQTT broker!");
  Serial.println();

  // set the message receive callback
  mqttClient.onMessage(onMqttMessage);

  Serial.print("Subscribing to topic: ");
  Serial.println(subscribeTopic);
  Serial.println();

  // subscribe to a topic
  mqttClient.subscribe(subscribeTopic);


  Serial.print("Waiting for messages on topic: ");
  Serial.println(subscribeTopic);
  Serial.println();
}

void loop() {
  unsigned long currentMillis = millis(); 
  
  // call poll() regularly to allow the library to receive MQTT messages and
  // send MQTT keep alives which avoids being disconnected by the broker
  mqttClient.poll();

  // Enforce Interval
  if(currentMillis - previousMillis > interval) {
        previousMillis = currentMillis;

        // Call a function that handles publishing message
        publishSensorVal();
      
  }
}

void publishSensorVal() {
    // read the first Analog pin
    int sensorVal = analogRead(0);     
    //String speak = "The sensor val is " + String(sensorVal);
    char adc_sv[30] = {'T', 'h', 'e', ' ', 'a', 'd', 'c', ' '' ', 'v', 'a', 'l', 'u', 'e', ' ', 'i', 's', ' ', '\0'}; //adc_step value
    // Publish our sensor value to the publish topic
    mqttClient.beginMessage(publishTopic);
    mqttClient.print(adc_sv);
    mqttClient.print(sensorVal);
    mqttClient.endMessage();
      digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1400);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(100);                       // wait for a second
}

void handleCommand(String cmd) {
  if (cmd == "on"){
    digitalWrite(LED, HIGH);
  }else if(cmd == "off"){
    digitalWrite(LED, LOW);
  }
}

void onMqttMessage(int messageSize) {
  // we received a message, print out the topic and contents
  Serial.println("Received a message with topic '");
  Serial.print(mqttClient.messageTopic());
  Serial.print("', length ");
  Serial.print(messageSize);
  Serial.println(" bytes:");

  // We want to read each character into a useable String
  String content = "";
  char character;
  
  // use the Stream interface to print the contents
  while (mqttClient.available()) {
    character = (char)mqttClient.read();
    content.concat(character);
  }

  handleCommand(content); // This function does something with our incoming string

  Serial.println(content);
  Serial.println(); Serial.println(); // double spacing
}

I still have memory left on the arduino which should not be the reason for the crash:
Sketch uses 41676 bytes (15%) of program storage space. Maximum is 262144 bytes.
Global variables use 3456 bytes (10%) of dynamic memory, leaving 29312 bytes for local variables. Maximum is 32768 bytes.

What does that mean?

What output are you seeing? Does the code get through setup()? A post containing the output would be useful.

This (which is missing a comma)

  char adc_sv[30] = {'T', 'h', 'e', ' ', 'a', 'd', 'c', ' '' ', 'v', 'a', 'l', 'u', 'e', ' ', 'i', 's', ' ', '\0'}; //adc_step value

could more easily be written as

  char adc_sv[] = "The adc value is"; //adc_step value

The serial monitor will stop printing anything. I have to hit the reset button for it get started back on

put a serial print in loop() to see if it is really stopping.

Serial.println("A");

I fixed missing comma issue. Here is the output:

It would just get stuck there and will stop printing data

You know that inside a ISR that printing serial.prints are a bad idea? Your ISR should use minimal code.

is there a work around for that?

So if i remove the serial.print from that ISR it should prevent crashing?

Did you put a serial print in your loop() to see if is really stopping?

Remove it or not, that's up to you. I only offer that it is a bad idea to have extraneous code in a ISR.

1 Like

will give that a shot. Will update if that works or not.

The delays are concerning.

Have you used a MQTT viewer to see how the topic is behaving?

Yes I have been using MQTT.fx tool. When the Arduino is stuck, and I send on or off message or even wait to listen for messages I do not get any. That is how I am also determining that the Arduino is stuck or hung up.

I have added many serial. print in my other code which is based on this simple code. Even this simple code gets stuck so I wanted to determine the root cause of the issue. Just wanted to know if I have functions being called to perform any other work, having serial.print in those function will also break the code?

When your code runs mqttClient.poll your code does not check for a valid WiFi connection or a Valid MQTT connection before calling the poll.

Here is how I run a client.loop(), the same thing as a mqttClient.poll.

void MQTTkeepalive( void *pvParameters )
{
  sema_MQTT_KeepAlive   = xSemaphoreCreateBinary();
  xSemaphoreGive( sema_MQTT_KeepAlive ); // found keep alive can mess with a publish, stop keep alive during publish
  // setting must be set before a mqtt connection is made
  MQTTclient.setKeepAlive( 90 ); // setting keep alive to 90 seconds makes for a very reliable connection, must be set before the 1st connection is made.
  for (;;)
  {
    //check for a is-connected and if the WiFi 'thinks' its connected, found checking on both is more realible than just a single check
    if ( (wifiClient.connected()) && (WiFi.status() == WL_CONNECTED) )
    {
      xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY ); // whiles MQTTlient.loop() is running no other mqtt operations should be in process
      MQTTclient.loop();
      xSemaphoreGive( sema_MQTT_KeepAlive );
    }
    else {
      log_i( "MQTT keep alive found MQTT status %s WiFi status %s", String(wifiClient.connected()), String(WiFi.status()) );
      if ( !(wifiClient.connected()) || !(WiFi.status() == WL_CONNECTED) )
      {
        connectToWiFi();
      }
      connectToMQTT();
    }
    vTaskDelay( 250 ); //task runs approx every 250 mS
  }
  vTaskDelete ( NULL );
}

I check if there is a valid WiFi connection. If not then connect to WiFi. If do then check to see if connected to MQTT, if not connect.


It prints a bunch of A and then the data

Yes, when the program hangs up does the "A" keep printing?

Yeah, I am using watchdog timer. If no connection or the code is hung up I reset the micro so it initiates the connection again. So far it has been a few mins and it has not hung up yet. I have not removed the serial.print from the ISR section.

If your WiFi or MQTT is disconnected and the watch dog timer has not went off yet and client.poll runs, that's an issue.

MQTT Brokers like to disconnect.

Ok maybe I will add another check like you mentioned to check mqtt and internet connection. Reset if that stops.