CONTROLLINO MEGA apparently stuck during void loop

Hello! I am working on a project where I need to attach a CONTROLLINO to an industrial printer for controlling a particular phase of production.

Expected behaviour
After receiving the "start" signal from an outside source, the CONTROLLINO should hold an output on HIGH indefinitely. When the outside source sends a "stop" signal, the CONTROLLINO should:

  1. Command the output to OFF
  2. Send a sequence of five strings using TCP/IP to the printer
  3. Wait for the new "start" signal

Below is the full code (I have obscured data such as addresses and the strings being sent, however I can confirm that they are sent and received properly by the printer).

#include <Controllino.h>
#include <Ethernet.h>

// Ethernet
IPAddress localip([...]);
IPAddress serverip([...]);
int port = [...];
byte mac[] = {[...]};
EthernetClient client;

// Misc. variables
unsigned long startTime = 0;
unsigned long timeDelta = 0;

void setup() {
  pinMode(CONTROLLINO_A0, INPUT);  // printer ready (RDY)
  pinMode(CONTROLLINO_A1, INPUT);  // print stop (STP)

  attachInterrupt(digitalPinToInterrupt(CONTROLLINO_IN0), start_print, RISING);  // from ext. (GO)

  pinMode(CONTROLLINO_D0, OUTPUT);  // trigger (TRG)
  pinMode(CONTROLLINO_D1, OUTPUT);  // process finished monitor (FIN)
  pinMode(CONTROLLINO_D2, OUTPUT);  // connection error (CON)

  // Initialization
  Serial.begin(9600);
  Serial.println("\n\nSerial communication initialized.");

  Serial.print("Initializing ethernet connection... ");
  Ethernet.begin(mac, localip);
  delay(4000);
  if (client.connect(serverip, port)) {
  Serial.println("Ethernet connection OK.");
  } else {
  Serial.println("Ethernet connection failed. Please check network settings and reset the PLC.");
  digitalWrite(CONTROLLINO_D2, HIGH);  // connection error output (CON)
  while(1);  // Block startup if ethernet connection error detected
  }
  Serial.println("\nStart-up completed.\n\n");
}

void loop() {
  if (digitalRead(CONTROLLINO_A1) == HIGH) {
    startTime = millis();
    Serial.println("- - - Stop signal detected. Initiating stop sequence. - - -");
    digitalWrite(CONTROLLINO_D0, LOW);  // Trigger OFF
    sendMessage("string1");
    sendMessage("string2");
    sendMessage("string3");
    sendMessage("string4");
    sendMessage("string5");
    Serial.println("- - - Process complete. Waiting for new print start signal. - - -");
    digitalWrite(CONTROLLINO_D1, HIGH);  // Process finished monitor ON
    timeDelta = millis() - startTime;
    Serial.print("Elapsed time: ");
    Serial.print(timeDelta);
    Serial.println("ms.");
    }
Serial.println("Waiting...");
}

void start_print() {
  digitalWrite(CONTROLLINO_D1, LOW);  // Monitor OFF
  while (digitalRead(CONTROLLINO_A0) == LOW) {}  // wait for print ready (RDY)
  digitalWrite(CONTROLLINO_D0, HIGH);  // Trigger ON
}

String receiveReply() {
  String reply = "";
  while (client.available()) {
    char c = client.read();
    reply += c;
  }
  Serial.print("> ");
  Serial.println(reply);
  return reply;
}

String sendMessage(String message) {
  int retryAttempts = 3;
  for (int i = 0; i < retryAttempts; i++) {
    if (client.connected()) {
      client.println(message);
      Serial.print("< ");
      Serial.println(message);
      return receiveReply();
    } else {
      client.stop();
      delay(1000);
      if (client.connect(serverip, port)) {
        client.println("WARN: Reconnected after connection loss.");
        client.println(message);
        Serial.print("< ");
        Serial.println(message);
        return receiveReply();
      }
    delay(1000);
    }
  }
  Serial.println("ERR: Failed to send message after multiple attempts.");
  return "";
}

Actual behaviour
The CONTROLLINO behaves as expected most of the time. Looking at the serial monitor, it sends "Waiting..." continuously during normal operation. When the stop signal is input, it performs the stop sequence printing the correct data to the serial monitor. It then waits for the new print start.
However, every once in a while (not a lot, maybe 1 in 30) the CONTROLLINO will finish the stop sequence, but it will get stuck and won't accept any new inputs (either stop or start). What's more, it will not even print "Waiting..." to the serial monitor. The serial monitor will look something like:

- - - Process complete. Waiting for new print start signal. - - -
Elapsed time: 173ms.
Waiting...
Waiting...
Waiting...
Waiting...
Waiting...
Waiting...
Waiting...
Waiting...
W

The "W" is what bugs me: it seems like the serial.print() didn't even finish, the execution just stopped mid-line. The outputs that are already HIGH remain high, and the CONTROLLINO remains powered and in normal state, but it doesn't process any outputs (regular or interrupt) anymore.

What I have already tried to fix the issue

  • Removing the "println("Waiting...")" statement from the main body of void loop(): I use it as debugging, but I thought maybe it was creating issues. Removing it had no effect however, the problem still happened with the same frequency.
  • Trying to figure out which conditions trigger the issue: I tried with sending the start and stop signal multiple times, simultaneously, out of order, with very short breaks in-between them. I could not figure out what exactly causes the issue, it seems to happen with the same frequency.
  • Adding a delay() in the main body of void loop() to slow down the execution. I tried with 1ms, 5ms, 100ms delays. In all cases the problem still appeared with the same frequency.
  • Moving the whole print stop process to an interrupt function: I considered this, but I read that print() statements shouldn't be used in interrupts, and since the whole stop process consists of several client.print() statements, I abandoned the idea.

I would like to know what causes this issue and how I can avoid it. I think it's likely that it's due to some bad coding practice on my part, so if you have any advice I will gladly try it out.

Thanks!

Well the message gets transferred into (the ring buffer) memory and the first byte is being sent by the UART, and at 9600bps it will take about 1ms for every byte. It looks like your processor is crashing soon after. (or gets stuck in an endless loop)
To find out where it crashes in particular you will have to add delay() statements that are long enough to complete the whole transmission of the Serial.print()

The while() loop inside your ISR is actually a very likely cause of the problem, also since within the ISR, the Serial.print() statements and transfer from the ring buffer to the FIFO are not being completed (these are interrupt driven)
I suggest you abandon the ISR triggered method of waiting for signal, or at least move the while loop out of the ISR. Trigger a 'flag' variable and poll that within the main loop. You could also consider to create 2 separate ISR's for the pins you are checking, but it is most definitely not a good idea to hold the processor in the ISR waiting for a signal

1 Like

Thank you for your reply! I changed the code around a little, removed the while() from the ISR and moved it to the main body, and left only a flag in the ISR like you suggested. This didn't fix the problem unfortunately, but it made me wonder: I tried removing the while() and the problem stopped happening. So apparently that was the problem, although I have no idea why. Maybe that input was fluttering for some reason and it crashed the processor? No clue.

Anyway it was a redundant check since that input should be HIGH well before the print start signal arrives. So I just removed it.

Thank you for your help!

1 Like