What could trigger arduino to reset (software)?

I’m pulling my hair out right now. In my program after executing a subroutine, the arduino resets. I didn’t do anything radical. I just want to know what software conditions trigger atmega chip to reset. Like memory problem? Stack problem?

Here is the code inside my sub. Nothing particular though.

int recording[]={1,1,0,0};
 
void silly()
{

 for (int i=0;i<4;i++)
  {
    char msg5[10];
    strcpy(msg5,"Record   ");
    lcd.clear();
    msg5[7]=lowByte(i+1); 
    lcd.print(msg5);
    lcd.setCursor(0,1);

    if (recording[i]==0)
    {
      lcd.print("NO/LOW/0  ");
    }
    else if (recording[i]==1)
    {
      lcd.print("YES/HIGH/1");
    }

    recording[i]=hmi(recording[i],0,1,1);
    delay(100);
    temp1=btn_1.sense();
  }
}

hmi() is a bit long, if there's no problem on this section, I'll post hmim();

Help! Thank you very much!

Does the I/O also reset? (e.g. digital outputs set to high go low)

Coding badly, it didn't reset digital HIGH to LOW. I then did a reset via serial (opening serial monitor). The pin went LOW! How weird! I display a message only in the setup. So when I see that message I thought arduino chip did a reset. Now I'm really confused. It's like it just re-run the setup then loop? What's your take on this? Thank you!!! :'( :'(

My suspicion is a memory related problem (like the stack bumping into the heap or the stack bumping into static data)...

  • Are you using malloc? (or the String Library)

  • Identify the biggest SRAM consumers (long string constants, big string buffers, large arrays). Total the bytes used by the biggest consumers. Is it more than 50% of the SRAM size?

  • Do any functions take more than five parameters?

  • Do you have any large automatic (local) buffers?

Coding badly. I am indeed doing a large project. I tried everything to fit in an atnega168 with a working program. Today I ported to atmega328 with some change of code. That’s when all hell got loose. I don’t think it’s an obvious SRAM problem since I was able to do with 1K on 168 and only since changed a little bit (no big data structures defined). There might be non-obvious ones that I need to find. My code is aroudn 1,300 lines so I’m not sure if I want to post something that long.

Since the problem occured when this silly() returns, I assume the stack is somehow messed up so the return address is beyond 2K range. How do I view the stack content or track the stack pointer? I’m sure if you tell me ASM code I can crunch it in. I was able to write 2,000+ lines ASM in 386 protected mode, back in the 90’s. Thanks again.

BTW, I didn’t use malloc. I have PROGMEM commands but they’re all tested in separate programs to work fine.

Did some digging on the forum. Is SP the stack pointer and supposed to come down as function calls get deeper?
Mine is at 2263 when it’s displaying menu. I thought it’s supposed to be less than 2048?!
Then when I nest in more functions the SP increases (instead of decreasing) and eventually hits 2281 in silly(). Right before exiting it’s still 2281.

Since the problem occured when this silly() returns, I assume the stack is somehow messed up

From the symptom, that's a good starting theory.

How do I view the stack content or track the stack pointer?

Adding code to do that will add more risk (what if the stack debug code is buggy?). Initially, I suggest a "static analysis". Look for trouble (lots of paramters; functions calling functions calling functions; buffer overruns; etcetera). In my exerpience, with some patience, those things are fairly easy to spot.

Is SP the stack pointer and supposed to come down as function calls get deeper?

From the Instruction Set Manual, it looks like it.

Mine is at 2263 when it's displaying menu

That may simply be a problem with the display code or the compiler may not support direct access to SP.

Try this...

  • Start with an empty Sketch
  • In loop...
  • Output the value of SP
  • Assign SP to an unsigned variable
  • Output the unsigned variable
  • Call a function that outputs SP
  • delay

What is the value of SP? Is it the same value as the unsigned variable? Is SP a lower value in the function?

Do any functions take more than five parameters?

Could you explain the significance of this? I do have 4 integer parameters passed to subs. Thanks.

Mine is at 2263 when it's displaying menu. I thought it's supposed to be less than 2048?!

Don't forget RAM addresses start at 0x0100, not zero.

Do any functions take more than five parameters?

Could you explain the significance of this? I do have 4 integer parameters passed to subs. Thanks.

The first few bytes of parameter data are passed using registers. If a certain number of bytes are passed, registers are used and then stack space is used. My suspicion is the threshold is around three int parameters.

There are two extreme cases. On the most efficient side, only the return address is put on the stack (2 bytes). On the least efficient side, many bytes of paramter data are placed on the stack plus the return address.

In the worst case, 4 integer parameters is 10 bytes of stack space. This is very likely NOT the trouble spot. Unless this is a recursive routine. In which case, a dozen recursive calls is going to take a big chunk of memory.

The bottom line: I’m trying to give you guidance, based on my experiences, to help you find suspicious code. In my experience, functions that take five or more parameters are too complicated.

Thanks Groove. I still have some trouble understanding why stack is so high and gets higher unless it’s going up (like 8088) instead of coming down.

Here’s my hmi(), which takes arguments current value, lower and upper limits, and steps. This function interacts with user to set value to current value and makes sure it’s within lower and upper limit and increases in multiples of steps.

It calls wait_on_escape to wait on button push or escape after a set period of 50 ms. This way updates can go on if no button is pressed for 50ms.

Button.sense() just reads button pin status and outputs things like button is up, button is down (button is pressed), button is released (after it’s was up), button is held (after it’s down for a set period of time).

I don’t see anything recurring. Plus, it only restarts when it quits silly. While in silly the stack value is stable.

Coding badly, is there a limit on how many bytes can be popped at function return? I was thinking about 8088 asm where there is a command ret n. This emptys n bytes on return, besides the instruction pointer. If say this ret n in 328 or 168 is only up to 7, then the function will not leave stack intact on return. Say 11 bytes were pushed before a call address, then the sub can only pop up to 7 bytes due to this limit. Then Every time a function with too many parameters gets called, it leaves 4 bytes on the stack (which should butt up the return address of the caller). If even one of these calls is done, the the caller will not be able to reture to ITS caller. Make any sense? (couldn’t sleep well with this hanging in my mind)

int hmi(int current, int lower, int upper, byte inc)
{
  int number;
  int temp1;
  byte cond=1;
  int ret=0;
  number=current;
  while(cond)
  {
    temp1=wait_on_escape(50);
    switch (temp1)
    {
      case -1:
      cond=0;
      ret=-1;
      break;
      
      case 1:
      cond=0;
      ret=number;
      break;
      
      case 2:
      if (number+inc<=upper)
      {
        number+=inc;
      }
      break;
      
      case 3:
      if (number-inc>=lower)
      {
        number-=inc;
      }
      break;
      
      default:
      break;
    }

    lcd.setCursor(0,1);
    if (number==0)
    {
      lcd.print("NO/LOW/0  ");
    }
    else if (number==1)
    {
      lcd.print("YES/HIGH/1");
    }
    else 
    {
      char msg[10];
      sprintf(msg,"%5d     ",number);
      lcd.print(msg);
    }
  }
  return(ret);
}

int wait_on_escape(int ref_time)
{
//Wait on button push.
  long temp0;
  int cond=1;
  int ret=0;
  byte temp1, temp2, temp3;
  temp0=millis();
  while (cond&&((millis()-temp0<ref_time)))
  {
    temp1=btn_1.sense();
    temp2=btn_2.sense();
    temp3=btn_3.sense();
    if ((temp2==buttons_down)&&(temp3==buttons_down))
    {
      sys_stat=sys_not_ready;
      cond=0;
      ret=-1;
    }
    else
    {
      if(temp1==buttons_released)
      {
        cond=0;
        ret=1;
      }
      if((temp2==buttons_released)||(temp2==buttons_held))
      {
        cond=0;
        ret=2;
      }
      if((temp3==buttons_released)||(temp3==buttons_held))
      {
        cond=0;
        ret=3;
      }
    }
  }
  return (ret);
}

After looking at the atmel document I realized the ret in atmega has no operands, which means there is no way to release stack from the subroution. http://www.atmel.com/dyn/resources/prod_documents/doc8271.pdf

Then the caller has to do that. Somehow my caller is not able to do it properly. I will have to find out why.

Finally isolated the problem into one spot - me!

I'm too cheap! That's why. If you look at my code, I only created a 10-byte msg[] to hold 11 bytes. I had it under well control, 10 byte array, 8 characters, until my other printed stuff is too long and leaves trash so I covered them by extra space characters. I typed one too many spaces in the msg and triggered a whole night of hair-pull, debugging and raving.

Learned very few things today: Don't be too cheap on arrays that only exists in a for loop! ATMEGAs have stack upside down, very unconfortable for porters. :o ATMEGAs don't have RET number, just RET. Refreshed my memory on x86 instruction set. Always, always, the programmer is making stupid mistakes. I'm hungry, even after a trail mix. :-[

Always, always, the programmer is making stupid mistakes.

Or as I put it, never argue with the compiler.

I've learned this lesson well in my quest to learn Arduino C/C++. If I can't make the red errors go away I just assume I'm too stupid to develop that specific prgoram at that time in my life and move on to the next program. ;)

Lefty

If I can't make the red errors go away I just assume I'm too stupid to develop that specific prgoram at that time in my life and move on to the next program.

Or you post here and get help.

Right! Should always assume compilers are written by elite programmers or Microsoft. Ask yourself are you too smart to trust them? 8-)

If you look at my code, I only created a 10-byte msg to hold 11 bytes

Very well spotted! I’m glad you found the culprit!

Or you post here and get help.

And every so often we get it right…

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1282105521/6#6
Look for trouble (lots of paramters; functions calling functions calling functions; buffer overruns; etcetera).

;D

(feeling a bit cocky today…)

And every so often we get it right...

Even if it takes 8 people, 25 iterations, and 12 days.

Thank you very much Coding Badly! You gave me moral support when I was in the deepist hole. :'( Now I can move on and program more. There's now 1,500 lines of code, taking around 14K or flash. As I expect it will grow (not exponentially like virus) to possibly around 2,000 lines. I may exceed my record of 2,000 lines of 386 assembly code but that only compiled into like 4K. I have to admit that working on C++ gives programmers much more capabilities. Still fingers crossed for the well-being of the beloved compiler. ;D

By the way, this program is going to run on a physics lab apparatus that will hopefully be sitting on many highschool science lab benches. Brand-name stuff is so overpriced :P and this is my solution. Low-priced kits teachers can solder together and have fun! :D