Unknown Software Issue Causing Restart

Hi all,

This is my first post so please excuse me if I’m in the wrong board or my formatting’s a little weird. I’m working on a relatively simple project that I can’t get to run right because of what I believe is a software issue. My Arduino Uno board will sometimes run my sketch for hours without an issue and then randomly reset. Sometimes it won’t make a few loop iterations. I’ve rebuilt my circuit onto a perfboard shield to ensure it isn’t a connection issue and have supplied the Arduino with it’s own 12V supply so the regulator can keep it running independent of the system and it’s noise. Here’s a simple circuit diagram.

(I couldn’t find a good representation of the arduino plug input and the resistor value bands are incorrect as well, they are 10KΩ pulldown resistors.)

The basic operating procedure is this:

  1. The system is powered on and the Arduino initializes the SD reader.
  2. The SD card is cleared of the previous log file (“Output.csv”) and a fresh one is created.
  3. The system closes the first relay, waits 100 ms for the mechanical system on the other end to actuate.
  4. The Arduino reads the switches of the Unit Under Test (one is engaged at the beginning of travel while the other is actuated at the bottom) and stores the states using digital read.
  5. The data is logged to the SD card
  6. The relay is opened and the system waits another 100 ms.
  7. Repeat from 3 until 1,000,000 loop iterations have been cleared without triggering any failure conditions.

The failure conditions are if the UUT fails to register either switch three times consecutively or if the same step fails three times in a row.

I believe that the reason the unit keeps restarting is because of something I’m doing wrong in my code but I have no idea what it could be. I know the Arduino will fail if the RAM gets overloaded but I’ve gone through and tried to trim the fat and make sure I have some headroom for the system to work. However, since I’m using an Uno there isn’t a ton of memory to work with and I’m hoping that’s the issue. The Arduino IDE reports ~830 bytes are open in dynamic memory.

Below is my code in full.

#include <SD.h>

const unsigned char fs = 7; //footswitch enable input
const unsigned char fsb = 2; //footswitch boost input
const unsigned char rly_1 = 3;//relay 1
const unsigned char rly_2 = 4;//relay 2
const unsigned char rly_3 = 5;//relay 3
const unsigned char rly_4 = 6;//relay 4
const char* errordecode[4] = {"No error", "No enable", "No boost", "Both failed"};
const unsigned char steppause = 100;//pause between step

unsigned char fsstate = 0;//footswitch enabled
unsigned char fsbstate = 0;//boost enabled
unsigned long loopcount = 1;//current step
unsigned char step = 1;//4 side of footpedal per step counter
unsigned long errorarray[9][3];//counts errors for analysis
unsigned char currerrcode = 0;//0=none;1=no enable;2=no boost;3=both fail
File outputtxt;

void setup()
{
  //Serial.begin(115200);0
  pinMode(fs, INPUT);
  pinMode(fsb, INPUT);
  pinMode(rly_1, OUTPUT);
  pinMode(rly_2, OUTPUT);
  pinMode(rly_3, OUTPUT);
  pinMode(rly_4, OUTPUT);

  digitalWrite(rly_1, HIGH);
  digitalWrite(rly_2, HIGH);
  digitalWrite(rly_3, HIGH);
  digitalWrite(rly_4, HIGH);

  if (!SD.begin(10))
  {
    while (1)
    {
      //will not procceed without SD card
    }
  }

  delay(100);
  outputtxt = SD.open("Output.csv", FILE_WRITE);
  if (outputtxt)
  {}
  else
  {
    while (1);
    {}
  }
  outputtxt.println("Count,Step,Code");
  outputtxt.close();
}

void loop()
{
  switch (step)
  {
    case 1://1st Press
      digitalWrite(rly_1, LOW);
      delay(steppause);
      fsstate = digitalRead(fs);
      fsbstate = digitalRead(fsb);
      if (fsstate == 0 || fsbstate == 0)
      {
        goto error;
      }
      else
      {
        currerrcode = 0;
        digitalWrite(rly_1, HIGH);
        step = 2;
        delay(steppause);
        break;
      }
    case 2://2nd Press
      digitalWrite(rly_2, LOW);
      delay(steppause);
      fsstate = digitalRead(fs);
      fsbstate = digitalRead(fsb);
      if (fsstate == 0 || fsbstate == 0)
      {
        goto error;
      }
      else
      {
        currerrcode = 0;
        digitalWrite(rly_2, HIGH);
        step = 3;
        delay(steppause);
        break;
      }
    case 3://3rd Press
      digitalWrite(rly_3, LOW);
      delay(steppause);
      fsstate = digitalRead(fs);
      fsbstate = digitalRead(fsb);
      if (fsstate == 0 || fsbstate == 0)
      {
        goto error;
      }
      else
      {
        currerrcode = 0;
        digitalWrite(rly_3, HIGH);
        step = 4;
        delay(steppause);
        break;
      }
    case 4://4th Press
      digitalWrite(rly_4, LOW);
      delay(steppause);
      fsstate = digitalRead(fs);
      fsbstate = digitalRead(fsb);
      if (fsstate == 0 || fsbstate == 0)
      {
        goto error;
      }
      else
      {
        currerrcode = 0;
        digitalWrite(rly_4, HIGH);
        step = 1;
        delay(steppause);
        break;
      }
error:
      digitalWrite(rly_1, HIGH);//disable all relays
      digitalWrite(rly_2, HIGH);
      digitalWrite(rly_3, HIGH);
      digitalWrite(rly_4, HIGH);
      if (fsstate == 0)
      {
        currerrcode = 1;
      }
      else if (fsbstate == 0)
      {
        currerrcode = 2;
      }
      else if (fsbstate == 0 && fsstate == 0)
      {
        currerrcode = 3;
      }
      delay(1000);
      if (step <= 3)//after 1 sec continue to next step
      {
        step++;
      }
      else
      {
        step = 1 ;
      }

      break;
  }
  //Log errors
    for (int i = 0; i < 9; i++)
    {
      if (i < 8)
      {
        errorarray[i][0] = errorarray[i + 1][0];
        errorarray[i][1] = errorarray[i + 1][1];
        errorarray[i][2] = errorarray[i + 1][2];
      }
      else
      {
        errorarray[8][0] = loopcount;
        errorarray[8][1] = step;
        errorarray[8][2] = currerrcode;
      }
    }
    if (errorarray[6][2] != 0 && errorarray[7][2] != 0 && errorarray[8][2] != 0)
    {
      outputtxt = SD.open("Output.csv", FILE_WRITE);
      outputtxt.print(loopcount); outputtxt.print(","); outputtxt.print(step); outputtxt.print(","); outputtxt.println(currerrcode);
      outputtxt.print("3 Consecutive failure shutdown - Past 9");
      outputtxt.close();
      while (1)
      {}//3 Consecutive failure shutdown - Past 9
    }
    if (errorarray[0][2] != 0 && errorarray[4][2] != 0 && errorarray[8][2] != 0)
    {
      outputtxt = SD.open("Output.csv", FILE_WRITE);
      outputtxt.print(loopcount); outputtxt.print(","); outputtxt.print(step); outputtxt.print(","); outputtxt.println(currerrcode);
      outputtxt.print("3 Sequential Step failure - Past 9");
      outputtxt.close();
      while (1)
      {}//3 Sequential Step failure - Past 9
    }

  }
  outputtxt = SD.open("Output.csv", FILE_WRITE);
  if (!outputtxt)
  {
    while (1)
    {}// Detects if SD card is removed
  }
  if (step > 1)
  {
    outputtxt.print(loopcount); outputtxt.print(", "); outputtxt.print(step - 1);   outputtxt.print(", "); outputtxt.println(errordecode[currerrcode]);
  }
  else
  {
    outputtxt.print(loopcount); outputtxt.print(", 4, "); outputtxt.println(errordecode[currerrcode]);
  }
  outputtxt.close();
  loopcount++;

  if (step >= 1000000 - 70000) //Success State
  {
    outputtxt = SD.open("Output.csv", FILE_WRITE);
    outputtxt.println("END");
    outputtxt.close();
    while (1)
    {}//Victory Condition
  }
}

and before you yell at me yes I know goto is the devil, but I couldn’t think of a cleaner way to do it. Suggestions on how to make that more concise would be appreciated. Also removed some serial debugging things I had in the comments to make my post shorter.

did you post it all?

Note that you define step like thisunsigned char step = 1;//4 side of footpedal per step counter so a value that will vary between 0 and 255 and then you compare with a large number  if (step >= 1000000 - 70000) //Success Stateso that sounds suspicious

instead of the goto error, just create an error function and call it before breaking out of the switch...

what's the deal with those while (1) {}? do you have a watchdog?

Also think about what this would do and then test this code on your arduino UNO

void setup() {
  Serial.begin(115200);
  int x = 1000000 - 70000;
  Serial.println(x);
  if (x == (1000000 - 70000)) Serial.println("it's the same value");
  else Serial.println("it's not the same value");
}

void loop() {}

did you get what you expected?

Yes, I've posted all I can fit. The things I cut out were serial commands I used to debug. I needed to get it under the 9000 character limit.

Wow, that first part is a big goof on my part. That's supposed to be

unsigned long loopcount = 1;//current step

not the 'step' variable. Thank you for pointing that out.

As for the function bit, yes I agree that's a much better solution. I'll implement that and see how it performs.

The infinite loops are designed to lock up the Arduino and prevent it from continuing the test. The UUT is a custom printed pedal which I'm performing a life test on. So as part of it I need to meter the presses on it, and if it fails it the unit needs to stop immediately so we can analyze the failure without pressing it any more. If it continues to press the pedal after it fails it might damage whatever failed so badly I won't be able to say exactly why it failed. This obviously presents a problem when the Arduino resets since I don't have any reset detection and the program deletes the existing dataset when the Arduino restarts.

Also for that last bit; the integer data type has a min/max value of ±32,767 so your x value would probably end up -32,767 since the implicit conversion wouldn't work right. Did I do that by accident somewhere, or is this solved by the fact I used the wrong variable as I mentioned before? Also, that 70,000 is my guestimate of how many presses I've done on the footpedal already, so if that can cause issues I can just do the math and change the number myself.

Thank you for your help :)

Can you post the fixed code ?

Here’s the full unedited code:

#include <SD.h>

const unsigned char fs = 7; //footswitch enable input
const unsigned char fsb = 2; //footswitch boost input
const unsigned char rly_1 = 3;//relay 1
const unsigned char rly_2 = 4;//relay 2
const unsigned char rly_3 = 5;//relay 3
const unsigned char rly_4 = 6;//relay 4
const char* errordecode[4] = {"No error", "No enable", "No boost", "Both failed"};
const unsigned char steppause = 100;//pause between step

unsigned char fsstate = 0;//footswitch enabled
unsigned char fsbstate = 0;//boost enabled
unsigned long loopcount = 1;//current step
unsigned char step = 1;//4 side of footpedal per step counter
unsigned long errorarray[9][3];//counts errors for analysis
unsigned char currerrcode = 0;//0=none;1=no enable;2=no boost;3=both fail
File outputtxt;

void setup()
{
  //Serial.begin(115200);
  pinMode(fs, INPUT);
  pinMode(fsb, INPUT);
  pinMode(rly_1, OUTPUT);
  pinMode(rly_2, OUTPUT);
  pinMode(rly_3, OUTPUT);
  pinMode(rly_4, OUTPUT);

  digitalWrite(rly_1, HIGH);
  digitalWrite(rly_2, HIGH);
  digitalWrite(rly_3, HIGH);
  digitalWrite(rly_4, HIGH);

  if (!SD.begin(10))
  {
    //Serial.println("SD card failed to initialize. Please troubleshoot and restart.");
    while (1)
    {
      //will not procceed without SD card
    }
  }

  //Serial.println("SD card initialized.");
  delay(100);
  //SD.remove("Output.csv");
  outputtxt = SD.open("Output.csv", FILE_WRITE);
  if (outputtxt)
  {
    //Serial.println("Output file created.");
  }
  else
  {
    //Serial.println("Failed to create file. Please troubleshoot and restart.");
    while (1);
    {}
  }
  outputtxt.println("Count,Step,Code");
  outputtxt.close();
}

void loop()
{
  //Serial.print(loopcount); Serial.print(" - ");
  switch (step)
  {
    case 1://1st Press
      //Serial.print(step); Serial.print(" - ");
      digitalWrite(rly_1, LOW);
      delay(steppause);
      fsstate = digitalRead(fs);
      fsbstate = digitalRead(fsb);
      if (fsstate == 0 || fsbstate == 0)
      {
        errorFlag();
      }
      else
      {
        currerrcode = 0;
        //Serial.println(currerrcode);
        digitalWrite(rly_1, HIGH);
        step = 2;
        delay(steppause);
        break;
      }
    case 2://2nd Press
      //Serial.print(step); Serial.print(" - ");
      digitalWrite(rly_2, LOW);
      delay(steppause);
      fsstate = digitalRead(fs);
      fsbstate = digitalRead(fsb);
      if (fsstate == 0 || fsbstate == 0)
      {
        errorFlag();
      }
      else
      {
        currerrcode = 0;
        //Serial.println(currerrcode);
        digitalWrite(rly_2, HIGH);
        step = 3;
        delay(steppause);
        break;
      }
    case 3://3rd Press
      //Serial.print(step); Serial.print(" - ");
      digitalWrite(rly_3, LOW);
      delay(steppause);
      fsstate = digitalRead(fs);
      fsbstate = digitalRead(fsb);
      if (fsstate == 0 || fsbstate == 0)
      {
        errorFlag();
      }
      else
      {
        currerrcode = 0;
        //Serial.println(currerrcode);
        digitalWrite(rly_3, HIGH);
        step = 4;
        delay(steppause);
        break;
      }
    case 4://4th Press
      //Serial.print(step); Serial.print(" - ");
      digitalWrite(rly_4, LOW);
      delay(steppause);
      fsstate = digitalRead(fs);
      fsbstate = digitalRead(fsb);
      if (fsstate == 0 || fsbstate == 0)
      {
        errorFlag();
      }
      else
      {
        currerrcode = 0;
        //Serial.println(currerrcode);
        digitalWrite(rly_4, HIGH);
        step = 1;
        delay(steppause);
        break;
      }
  }
  //Log errors
  if (loopcount <= 9)
  {
    errorarray[loopcount - 1][0] = loopcount;
    errorarray[loopcount - 1][1] = step;
    errorarray[loopcount - 1][2] = currerrcode;

    if (loopcount - 1 >= 2)
    {
      if (errorarray[loopcount - 1][2] != 0 && errorarray[loopcount - 2][2] != 0 && errorarray[loopcount - 3][2] != 0)
      {
        //Serial.println("3 Consecutive failure shutdown - First 9");
        outputtxt = SD.open("Output.csv", FILE_WRITE);
        outputtxt.print(loopcount); outputtxt.print(","); outputtxt.print(step); outputtxt.print(","); outputtxt.println(errordecode[currerrcode]);
        outputtxt.println("3 Consecutive failure shutdown - First 9");
        outputtxt.close();
        while (1)
        {}//3 Consecutive failure shutdown - First 9
      }
      if (loopcount == 9 && errorarray[0][2] != 0 && errorarray[4][2] != 0 && errorarray[8][2] != 0)
      {
        //Serial.println("3 Step failure shutdown - First 9");
        outputtxt = SD.open("Output.csv", FILE_WRITE);
        outputtxt.print(loopcount); outputtxt.print(","); outputtxt.print(step); outputtxt.print(","); outputtxt.println(errordecode[currerrcode]);
        outputtxt.println("3 Step failure shutdown - First 9");
        outputtxt.close();
        while (1)
        {}//3 Step failure shutdown - First 9
      }
    }
  }
  else
  {
    for (int i = 0; i < 9; i++)
    {
      if (i < 8)
      {
        errorarray[i][0] = errorarray[i + 1][0];
        errorarray[i][1] = errorarray[i + 1][1];
        errorarray[i][2] = errorarray[i + 1][2];
      }
      else
      {
        errorarray[8][0] = loopcount;
        errorarray[8][1] = step;
        errorarray[8][2] = currerrcode;
      }
    }
    if (errorarray[6][2] != 0 && errorarray[7][2] != 0 && errorarray[8][2] != 0)
    {
      //Serial.println("3 Consecutive failure shutdown - Past 9");
      outputtxt = SD.open("Output.csv", FILE_WRITE);
      outputtxt.print(loopcount); outputtxt.print(","); outputtxt.print(step); outputtxt.print(","); outputtxt.println(currerrcode);
      outputtxt.print("3 Consecutive failure shutdown - Past 9");
      outputtxt.close();
      while (1)
      {}//3 Consecutive failure shutdown - Past 9
    }
    if (errorarray[0][2] != 0 && errorarray[4][2] != 0 && errorarray[8][2] != 0)
    {
      //Serial.print("3 Sequential Step failure - Past 9");
      outputtxt = SD.open("Output.csv", FILE_WRITE);
      outputtxt.print(loopcount); outputtxt.print(","); outputtxt.print(step); outputtxt.print(","); outputtxt.println(currerrcode);
      outputtxt.print("3 Sequential Step failure - Past 9");
      outputtxt.close();
      while (1)
      {}//3 Sequential Step failure - Past 9
    }

  }
  outputtxt = SD.open("Output.csv", FILE_WRITE);
  if (!outputtxt)
  {
    //Serial.println("SD card removed. Please re - insert and restart.");
    while (1)
    {}// Detects if SD card is removed
  }
  if (step > 1)
  {
    outputtxt.print(loopcount); outputtxt.print(", "); outputtxt.print(step - 1);   outputtxt.print(", "); outputtxt.println(errordecode[currerrcode]);
  }
  else
  {
    outputtxt.print(loopcount); outputtxt.print(", 4, "); outputtxt.println(errordecode[currerrcode]);
  }
  outputtxt.close();
  loopcount++;

  if (loopcount >= 1000000 - 70000) //Success State
  {
    //Serial.println("Test Completed");
    outputtxt = SD.open("Output.csv", FILE_WRITE);
    outputtxt.println("END");
    outputtxt.close();
    while (1)
    {}//Victory Condition
  }
}

void errorFlag()
{
  digitalWrite(rly_1, HIGH);//disable all relays
  digitalWrite(rly_2, HIGH);
  digitalWrite(rly_3, HIGH);
  digitalWrite(rly_4, HIGH);
  //Serial.println(currerrcode);
  //Serial.print("Error @: "); Serial.print(loopcount); Serial.println(" ");
  if (fsstate == 0)
  {
    //Serial.println("No enable");
    currerrcode = 1;
  }
  else if (fsbstate == 0)
  {
    //Serial.println("No boost");
    currerrcode = 2;
  }
  else if (fsbstate == 0 && fsstate == 0)
  {
    //Serial.println("No response");
    currerrcode = 3;
  }
  delay(1000);
  if (step <= 3)//after 1 sec continue to next step
  {
    step++;
  }
  else
  {
    step = 1 ;
  }
}

You are missing breaks at the end of switch/cases (put them outside rhe if-else to be sure you break)

Done. Here's the switch cases now:

 switch (step)
  {
    case 1://1st Press
      //Serial.print(step); Serial.print(" - ");
      digitalWrite(rly_1, LOW);
      delay(steppause);
      fsstate = digitalRead(fs);
      fsbstate = digitalRead(fsb);
      if (fsstate == 0 || fsbstate == 0)
      {
        errorFlag();
        break;
      }
      else
      {
        currerrcode = 0;
        //Serial.println(currerrcode);
        digitalWrite(rly_1, HIGH);
        step = 2;
        delay(steppause);
        break;
      }
    case 2://2nd Press
      //Serial.print(step); Serial.print(" - ");
      digitalWrite(rly_2, LOW);
      delay(steppause);
      fsstate = digitalRead(fs);
      fsbstate = digitalRead(fsb);
      if (fsstate == 0 || fsbstate == 0)
      {
        errorFlag();
        break;
      }
      else
      {
        currerrcode = 0;
        //Serial.println(currerrcode);
        digitalWrite(rly_2, HIGH);
        step = 3;
        delay(steppause);
        break;
      }
    case 3://3rd Press
      //Serial.print(step); Serial.print(" - ");
      digitalWrite(rly_3, LOW);
      delay(steppause);
      fsstate = digitalRead(fs);
      fsbstate = digitalRead(fsb);
      if (fsstate == 0 || fsbstate == 0)
      {
        errorFlag();
        break;
      }
      else
      {
        currerrcode = 0;
        //Serial.println(currerrcode);
        digitalWrite(rly_3, HIGH);
        step = 4;
        delay(steppause);
        break;
      }
    case 4://4th Press
      //Serial.print(step); Serial.print(" - ");
      digitalWrite(rly_4, LOW);
      delay(steppause);
      fsstate = digitalRead(fs);
      fsbstate = digitalRead(fsb);
      if (fsstate == 0 || fsbstate == 0)
      {
        errorFlag();
        break;
      }
      else
      {
        currerrcode = 0;
        //Serial.println(currerrcode);
        digitalWrite(rly_4, HIGH);
        step = 1;
        delay(steppause);
        break;
      }
      default:
      while(1)
      {}
      
  }

Is this what you had in mind?

Ok - what I meant (for readability) was

switch (step)
  {
    case 1://1st Press
      //Serial.print(step); Serial.print(" - ");
      digitalWrite(rly_1, LOW);
      delay(steppause);
      fsstate = digitalRead(fs);
      fsbstate = digitalRead(fsb);
      if (fsstate == 0 || fsbstate == 0) errorFlag();
      else {
        currerrcode = 0;
        //Serial.println(currerrcode);
        digitalWrite(rly_1, HIGH);
        step = 2;
        delay(steppause);
      }
      break; // <<<< JUST ONE BREAK for clarity 
    case 2://2nd Press
...

Does it work any better now?

Ahh I see what you mean now. I'm going to let it run over the weekend. According to my math this should take just under three days to complete so I'll see if it can run without any pneumatics and just hold the switches closed.

Thank you sir, have a beer on me.