Sketch resets unexpectedly

My project involves putting the Arduino to sleep and then waking it up at pre-determined times. While it is awake it waits for a brief time looking for incoming serial data. The serial data is meant to update the time intervals that it should wake up for. Once it completes this cycle it goes back to sleep and then wakes at the next predetermined time. I am working with a 328P on a breadboard running a 32khz external crystal. I set the seconds variable to run async with the external crystal and this is what keeps my time during sleep and creates the interupt to wake from. I use the 8mhz internal clock boot loader and the 0023 IDE. I don't use V1 IDE because it has issues with the 8mhz internal clock bootloader which I did not find a solution for yet.

The problem I run into is that about 60% of the time while the sketch is running and waiting for serial data it reboots. If I send serial data before the error it accepts the data and then goes to sleep just fine. The Arduino has a tendencay to reset when I just let it time out and no serial data is sent. I started to print millis() which verified that it is indeed rebooting mid-cycle. My reading on the forum suggests that I am likely running out of SRAM. My issue is that I don't understand things well enough to know how to figure out what is causing the memory issue. I have seen the MemoryFree library which I tried and it consistently shows 820 right up until it resets. Any suggestions on how I can trouble shoot a memory issue?

In case it is helpful here is my code.

#include <avr/sleep.h> 


//10801 = 24 hours, 7.5 = 1 minute
int time0 = 10;
int time1 = 0;
int time2 = 0;
int time3 = 0;
int time4 = 0;
int time5 = 0;
int time6 = 0;
int time7 = 0;
int time8 = 0;
int time9 = 0;
int time10 = 0;
int time11 = 0;
int reset = 10802;


char delimiters[30] = ",";
char* valPosition;


int interval[150] = {0, 0, 0};

int midnight = 1;

int gpsdata = 0;
int hours;
int minutes;
int update;
int gsmdata = 0;
int strend = 0;
int i = 0;

volatile int seconds = 10800;
volatile int timer = 0;

SIGNAL(TIMER2_OVF_vect){
  seconds++;
  timer++;
}


char inputString[100];       
int inByte = 0;

boolean stringComplete = false;  

void setup() {

  for(int x = 1 ; x < 18 ; x++){
    pinMode(x, INPUT);
    digitalWrite(x, HIGH); 
  }


  set_sleep_mode(SLEEP_MODE_PWR_SAVE);
  sleep_enable();

  Serial.begin(9600);
  

  //Power down various bits of hardware to lower power usage
  ADCSRA &= ~(1<<ADEN); //Disable ADC
  ACSR = (1<<ACD); //Disable the analog comparator
  DIDR0 = 0x3F; //Disable digital input buffers on all ADC0-ADC5 pins
  DIDR1 = (1<<AIN1D)|(1<<AIN0D); //Disable digital input buffer on AIN1/0

  //Setup TIMER2
  TCCR2A = 0x00;
  TCCR2B = (1<<CS22)|(1<<CS21)|(1<<CS20); /
  ASSR = (1<<AS2); 
  TIMSK2 = (1<<TOIE2); 

  sei(); //Enable global interrupts


}


void loop() {

  sleep_mode(); 
  sleep_disable();

  ADCSRA &= ~(1<<ADEN); 
  ACSR = (1<<ACD); 
  DIDR0 = 0x3F; 
  DIDR1 = (1<<AIN1D)|(1<<AIN0D); 


  if (seconds == time0){
    reset_5s();
    initialize();
    Serial.println("type text now");
    serialEvent(); //looks for serial data for a fixed period of time
    Serial.println("going to sleep now");
  }

  if (seconds == time1){
    reset_5s();
    initialize();
    Serial.println("type text now");
    serialEvent(); //looks for serial data for a fixed period of time
    Serial.println("going to sleep now");
  }

  if (seconds == time2){
    reset_5s();
    initialize();
    Serial.println("type text now");
    serialEvent(); //looks for serial data for a fixed period of time
    Serial.println("going to sleep now");
  }

  if (seconds == time3){
    reset_5s();
    initialize();
    Serial.println("type text now");
    serialEvent(); //looks for serial data for a fixed period of time
    Serial.println("going to sleep now");
  }

  if (seconds == time4){
    reset_5s();
    initialize();
    Serial.println("type text now");
    serialEvent(); //looks for serial data for a fixed period of time
    Serial.println("going to sleep now");
  }

  if (seconds == time5){
    reset_5s();
    initialize();
    Serial.println("type text now");
    serialEvent(); //looks for serial data for a fixed period of time
    Serial.println("going to sleep now");
  }  

  if (seconds == time6){
    reset_5s();
    initialize();
    Serial.println("type text now");
    serialEvent(); //looks for serial data for a fixed period of time
    Serial.println("going to sleep now");
  }

  if (seconds == time7){
    reset_5s();
    initialize();
    Serial.println("type text now");
    serialEvent(); //looks for serial data for a fixed period of time
    Serial.println("going to sleep now");
  }

  if (seconds == time8){
    reset_5s();
    initialize();
    Serial.println("type text now");
    serialEvent(); //looks for serial data for a fixed period of time
    Serial.println("going to sleep now");
  }

  if (seconds == time9){
    reset_5s();
    initialize();
    Serial.println("type text now");
    serialEvent(); //looks for serial data for a fixed period of time
    Serial.println("going to sleep now");
  }

  if (seconds == time10){
    reset_5s();
    initialize();
    Serial.println("type text now");
    serialEvent(); //looks for serial data for a fixed period of time
    Serial.println("going to sleep now");
  }

  if (seconds == time11){
    reset_5s();
    initialize();
    Serial.println("type text now");
    serialEvent(); //looks for serial data for a fixed period of time
    Serial.println("going to sleep now");
  }  

  if (seconds == reset){
    Serial.print("this is millis ");
    Serial.println( millis());
    seconds = 1;
    if (midnight > 0){
      reset_5s();
      Serial.println("type text now");
      Serial.print("this is seconds ");
      Serial.println(seconds);
      Serial.print("this is timer before initialize ");
      Serial.println(timer);
      initialize();
      serialEvent(); //looks for serial data for a fixed period of time
      Serial.println("going to sleep now");
      Serial.print("this is millis ");
      Serial.println( millis());
    }
  }
}
//
// collect the serial data
//

void initialize(){
  gpsdata = 0;
  gsmdata = 0;
  strend = 0;
  minutes = 0;
  hours = 0;
  timer = 0;
  i = 0;
  }



void serialEvent(){
  Serial.flush();
  while (timer < 5){s
    Serial.print("this is timer ");
    Serial.println(timer);
    if (Serial.available() > 0) {
      inByte = Serial.read();
      inputString[i] = inByte;
      Serial.println(inputString[i], BYTE);
      i++;
      if (inByte == '!'){
        i = 0;
        Serial.println("gpsdata is now 1");
        gpsdata = 1; // set the gpsdata bit to 1 to force the update to GPS
      }

      if (inByte == '*'){
        i = 0;
        gsmdata= 1; // set the gsmdata bit to 1 to force the update to GSM 
        Serial.println("gsmdata is now 1");
      }

      if (inByte == '#') {
        if (gpsdata == 1){
          Serial.println("went to GPSdata");
          verifygps();
        }
        if (gsmdata == 1){
          Serial.println("went to GSMdata");
          verifygsm();
        }
      }
    }
  }
}
void verifygps(){
  Serial.println("went to verify GPS");
  valPosition = strtok(inputString, delimiters);
  for(int i = 0; i < 6; i++){
    Serial.print("this is i ");
    Serial.println(i);
    interval[i] = atoi(valPosition);
    Serial.println(interval[i]);
    valPosition = strtok(NULL, delimiters);
    Serial.println("this is interval 0");
    Serial.println(interval[0]);
    //do the math to create the seconds variable
    hours = interval[0]; 
    minutes = interval[1];
    hours = hours * 450;
    minutes = minutes * 7.5;
    update = minutes + hours + 5; // 5 added since seconds isnt recognized and it takes time to parse and update
    Serial.println("this is update");
    Serial.println(update);
    // if update is between the variables then it updates the seconds
    if (update > 0 && update < 10801){
      Serial.print("this is seconds before update ");
      Serial.println(seconds);
      seconds = update;
      Serial.print("this is seconds after the update ");
      Serial.println(seconds);
      //timer = 40; // forces it to go to sleep
      //dont do this so overlap cant happen with GPS times
    }

    else{
      Serial.println("GPS data was not verified and seconds was not updated");
    }
  }   


}

void verifygsm(){
  valPosition = strtok(inputString, delimiters);
  for(int i = 0; i < 6; i++){
    Serial.print("this is i ");
    Serial.println(i);
    interval[i] = atoi(valPosition);
    Serial.println(interval[i]);
    valPosition = strtok(NULL, delimiters);

  }
  if(interval[1] > 0 && interval[1] < 10802){
    midnight = interval[0];
    Serial.print("this is midnight update ");
    Serial.println(interval[0]);
    time0 = interval[1];
    Serial.print("this is time0 ");
    Serial.println(time0);
    time1 = interval[2];
    Serial.print("this is time1 ");
    Serial.println(time1);
    time2 = interval[3];
    Serial.print("this is time2 ");
    Serial.println(time2);
    time3 = interval[4];
    Serial.print("this is time3 ");
    Serial.println(time3);
    time4 = interval[5];
    Serial.print("this is time4 ");
    Serial.println(time4);
    time5 = interval[6];
    Serial.print("this is time5 ");
    Serial.println(time5);
    timer = 40; //forces the serial to stop and go to sleep
  }   
  else{
    Serial.println("string did not match or time was outside of range");
  }
}
//turns the Telit on by holding the pin low for 5 seconds. 
//uses fake_msdelay to create the delay so no interupt is generated. It is not very accurate.
void reset_5s(){
  pinMode(A0, OUTPUT); 
  digitalWrite(A0, LOW); // needs to be LOW
  fake_msdelay(2000);
  digitalWrite(A0, HIGH); // needs to be HIGH
  pinMode(A0, INPUT); 
}

void fake_msdelay(int x){
  for( ; x > 0 ; x--)
    fake_usdelay(1000);
}

void fake_usdelay(int x){
  for( ; x > 0 ; x--) {
    __asm__("nop\n\t"); 
    __asm__("nop\n\t"); 
    __asm__("nop\n\t"); 
    __asm__("nop\n\t"); 
    __asm__("nop\n\t"); 
    __asm__("nop\n\t"); 
    __asm__("nop\n\t"); 
  }
}

Do you know when the computer opens or closes the serial port the arduino is reset?

I did not know that and I appreciate the information. I did try opening and closing my session on my terminal program while the sketch was running and I did not see it reboot. In my case the serial was open the entire time so I don't think that is what causes it to reset. Sometimes it will make it through a full cycle but not others.

Like Grumpy_Mike, the reset by starting a serial communication is what comes first to mind.

The DTR signal of the serial connection is connected with a capacitor of 100nF to the reset. If the ATmega is sleeping, some signals (TX perhaps ?) might be floating. That might influence the chip for the serial communication.
Can you disconnect everything from the /RESET and see if it still happens?
Did you already made a schematic? Perhaps you can upload it.

I am working with a 328P on a breadboard

The other thing that comes to mind is if you have enough decoupling capacitors in the circuit.
http://www.thebox.myzen.co.uk/Tutorial/De-coupling.html
Random resetting is often a symptom.

I attached a schematic of the Arduino setup i am using. Everything is SMT so removing components is difficult but not impossible. From the arduino I have a Sparkfun USB to serial board. I believe that I have the appropriate decoupling caps along with a 2.8V regulator.

The issue only occurs when the ATMega is awake and it only happens when it is in the while loop waiting for new serial data. I have other simpler code with no serial communications which acts as a timer which also seems to reset but I have never captured it. It will run perfectly happy for weeks or months before it resets. Now that I have added complexity and serial communications it resets frequently and I can easily replicate the problem.

Well not much in the way of decoupling, Aref should have a 0.1UF cap on it and it is better to have 2 small caps on each supply than one big one.
However:-

I have a Sparkfun USB to serial board.

Would seem to imply that you are feeding a 5V TTL signal into a processor that you are powering with 2V8. That is way over the maximum specification of 0.5V above Vcc. If that is true it could be causing you the trouble.

int interval[150] = {0, 0, 0};

A 150 element array with 3 initializers. Why? What are the 150 intervals for?

That array uses 15% of your memory, by the way.

char delimiters[30] = ",";

Another apparently oversized array.

char inputString[100];       
int inByte = 0;

Perhaps you need a float variable called inChar, and a char variable called inInt, and a byte variable called inFloat to go along with the int inByte.

void serialEvent(){
  Serial.flush();

The serialEvent method is new for 1.0. In 1.0, Serial.flush() blocks until all outgoing serial data has been sent. Why, exactly, do you feel it is necessary to do this?

  while (timer < 5){s

What is the s for?

      inputString[i] = inByte;
      Serial.println(inputString[i], BYTE);
      i++;

The BYTE keyword is not supported in 1.0. This leads me to believe that this code has never even been compiled.

The BYTE keyword is not supported in 1.0.

In the first post the OP did say:-

I use the 8mhz internal clock boot loader and the 0023 IDE. I don't use V1 IDE because it has issues with the 8mhz internal clock bootloader which I did not find a solution for yet.

PaulS- I will try to reduce the size of the arrays. The code was borrowed from something else I found and I am trying to spend time in the tutorials to understand arrays better.

The errant "s" was a typo from when I was trying to copy and paste.

serialEvent is just a naming coincidence and I had no idea V1.0 used that name. I use IDE 0023 because the 8mhz breadboard internal clock boot loader has trouble with the new IDE for reasons I can not explain.

I guess I misunderstood the use of Serial.flush(). I thought it cleared the incoming serial buffer. My thought was the clear any garbage that might be on the line that would adversly effect my communications. I will remove that since it i not what I thought it was.

I am running 2.8V on the PCB and the USB to serial is 3.3v and I use the level converter also from Sparkfun in between them.

I have compiled and run the code hundreds of times in IDE 0023.

Since the comments generally point me towards problems with decoupling caps I breadboarded everything instead of running on my PCB as I have been. Interesting enough the breadboard version ran the sketch perfectly so most likely this is a hardware problem of some sort as opposed to a memory issue as I first suspected. You mention that 2 1uF decoupling caps are not much, what would be a more appropriate choice? I do have a larger 100uF tantulum cap before the vreg as well.

I guess I misunderstood the use of Serial.flush(). I thought it cleared the incoming serial buffer. My thought was the clear any garbage that might be on the line that would adversly effect my communications. I will remove that since it i not what I thought it was.

Prior to 1.0, Serial.flush() did indeed dump random amounts of unread data. However, with a name like serialEvent, this implies that the function is called when there is serial data to read. Dumping that data first thing means that there no longer is serial data to read.

I'd suggest that Serial.flush() is NOT what you need to do, or that you change the name of the function from serialEvent to something that reflects what it is for, or, better yet, both.

so most likely this is a hardware problem of some sort as opposed to a memory issue as I first suspected.

The reason that I pointed out all the oversized arrays is that I suspect that you are having memory issues. There may also be hardware issues, but I'm a software type, so that's my focus.

You mention that 2 1uF decoupling caps are not much, what would be a more appropriate choice?

Using four ceramic 0.1uF would be better. Decoupling is best when it is spread about between chips and pins. Ceramic is also better than any other capacitor type due to the high frequency response. Surface mount caps are the best because they are small and do not suffer from inductance of the leads. You can always solder them on the underside of the board directly across the pins.

As PaulS is a software type, so I am a hardware type, so that is my focus. Sometimes you need both of us :slight_smile:

I have continued to work on my project and I found the problem so I thought I would share. I have a GSM modem on the board which during transmission consumes a lot of current. This seemed to choke the voltage regulator for the Arduino which forced it to reset. I added additional capacitance and it solved my problems with resetting.

Thank you to everyone for the suggestions and I will work on making my arrays more efficient.