Uno freezes when stepping stepper

I have several Arduino-branded Uno R3 and I'm having a weird, intermittent problem where they sometimes completely lock up while stepping a stepper. While debugging, I noticed that I sometimes get this problem even when I've disconnected all the hardware from the Arduino, including the stepper, so I'm almost certain it's not a power problem or anything like that.

The weird thing is that the problem is intermittent, and uploading the same exact sketch will sometimes lead to a freeze, and then the next day it won't even though nothing else has changed.

Here's my example sketch. You can see I use dynamic memory allocation for the stepper object. That's because this is a stripped-down version of my real sketch (which is really big and complicated), and in the real sketch I'd prefer to use dynamic memory allocation for reasons I can get into if necessary. I've also had basically the same problem when I don't use dynamic memory allocation anyway.

/* Very simple protocol to test freezing problem.

Just creates a stepper object. Often freezes when trying to step it.
*/
#include "Stepper.h"

// hardware constants
#define ENABLE_STEPPER 12
#define PIN_STEPPER1 8
#define PIN_STEPPER2 9
#define PIN_STEPPER3 10
#define PIN_STEPPER4 11
#define __HWCONSTANTS_H_NUMSTEPS 200
#define __HWCONSTANTS_H_STP_POST_ENABLE_DELAY 100

Stepper *stimStepper = 0;

void setup() {
  Serial.begin(115200);
  stimStepper = new Stepper(__HWCONSTANTS_H_NUMSTEPS, 
    PIN_STEPPER1, PIN_STEPPER2, PIN_STEPPER3, PIN_STEPPER4); 
}

void loop() {
  Serial.println("DBG stepping");
  delay(500);
  rotate(1);  
}

int rotate(long n_steps)
{
  digitalWrite(ENABLE_STEPPER, HIGH);
  Serial.println("DBG stepping0");

  delay(__HWCONSTANTS_H_STP_POST_ENABLE_DELAY);
  Serial.println("DBG stepping1");

  // This is where the freeze usually happens
  stimStepper->step(n_steps);

  // never get here
  Serial.println("DBG stepping2");
  Serial.println("DBG stepping3");

  digitalWrite(ENABLE_STEPPER, LOW);  
  return 0;
}

As I said, the weird thing is that the problem doesn't occur reliably. But occasionally, when I upload this sketch and open the Serial Monitor from within the Arduino IDE, it does this:

DBG stepping
DBG stepping0
DBG stepping1

and then freezes forever. On other occasions, it does what it's supposed to: loops forever, printing all debug statements every time. I get the same result on several different Unos so I don't think it's a problem with the board.

Any ideas?? I am having trouble tracking this intermittent problem down! Are there tools that can check for memory leaks?

I haven't tried this yet, but it seems like it might be an interesting way to troubleshoot problems like this....

stimStepper->step(n_steps); //any idea what this piece of code is meant to do." -> "looks odd

maybe it not freezing just waiting until its done this line and it wont move until it has.

Could it be a power supply glitch created by the inductive load from the motor? How is the motor powered?

cxrodgers:
While debugging, I noticed that I sometimes get this problem even when I've disconnected all the hardware from the Arduino, including the stepper, so I'm almost certain it's not a power problem or anything like that.

Just to be absolutely clear - are you saying that the code fails in the same way when it is running with NOTHING connected to the Arduino ?

Have you tried creating the stepper instance with

Stepper stimStepper(__HWCONSTANTS_H_NUMSTEPS, PIN_STEPPER1, PIN_STEPPER2, PIN_STEPPER3, PIN_STEPPER4);

Does that make a difference?
(I am not good at C++ so I'm not sure if there is any difference in the way the compiler deals with it)

...R

Thank you for the replies thus far. Has anyone tried to compile and run the sketch I posted? If so, did it freeze?

  1. @Robin2, @DrAzzy: Yes, this problem occurs in exactly the same way even when NOTHING is connected to the arduino (other than a USB cable for the serial connection). So, I am confident it is not a power supply glitch.

  2. @QDeathstar: great link to Arduino Watchdog. I will look into it. I do not know assembly though, so it will take some time.

  3. @gpop1: it looks weird because stimStepper is a pointer, so "->" is the dereferencing operation. You're right that it is a blocking operation, so it freezes until the step is completed. But it should finish the step in <100ms.

  4. @Robin2: You're right, I could initialize stimStepper as a global variable, as Robin2 said, and then NOT use dynamic memory allocation. Do we know if Stepper objects are not compatible with dynamic memory allocation??

The thing is, in my full sketch (which is too long to post here), I would prefer to use dynamic memory allocation and pass pointers around. But if we know for sure that Stepper is not compatible with dynamic memory allocation, I can do this.

cxrodgers:
4. @Robin2: You're right, I could initialize stimStepper as a global variable, as Robin2 said, and then NOT use dynamic memory allocation. Do we know if Stepper objects are not compatible with dynamic memory allocation??

The purpose of my question was to prompt you to try the "normal" way of doing it and see if it solves the problem.

If it does then it will be time to ask other questions.

The small memory of the Arduino is generally not a good place to play with dynamic memory allocation.

...R

Hi,

If your sketch is too big, use REPLY rather than QUICK REPLY and it has an attachment facility, so you can post your sketch as an attachment.
What version IDE are you using?
The sample you posted, compiled for me 1.5.5 and 1.6.3 versions.
Tom..... :slight_smile:

loaded the test code on my uno and it stops at the same point. from the arduino site it does say that the code will stop at this point (step) until the motor has finished the steps but as N-step shows as being 1 it almost feels like something is missing like a command for speed or something else. Never used this code on a stepper so I have no idea.

In the IDE, when I got to "About", I get version 1:1.0.5+dfsg2-2. This is running on Linux Mint.

@gpop1, thank you for replicating the problem. The speed defaults to 20 steps per second, or something like that. You can do stimStepper->setSpeed(100) to set it to 100rpm. Probably if you remove the last debugging statement [Serial.println("DBG stepping3")] it will start working.

@Robin2, I understand your point about avoiding dynamic memory allocation. It is true that if I replace the dynamic allocation with a global variable, then this test sketch now works. In my bigger sketch, the problem is not fixed. The bigger sketch is 1000s of lines spread over several files so I really don't think it would be useful to post. What I will do is try to find a small sketch that still shows the problem even using a global variable. It's just hard to track down because of how inconsistent the problem is.

Here is the version with the global variable that does work (at least, so far). Maybe this is really the only problem. If so it would be nice to document the Stepper library that it does not work with dynamic memory allocation. I searched but couldn't really find a clear statement on this point.

/* Very simple protocol to test freezing problem.

Just creates a stepper object. Often freezes when trying to step it.
*/
#include "Stepper.h"

// hardware constants
#define ENABLE_STEPPER 12
#define PIN_STEPPER1 8
#define PIN_STEPPER2 9
#define PIN_STEPPER3 10
#define PIN_STEPPER4 11
#define __HWCONSTANTS_H_NUMSTEPS 200
#define __HWCONSTANTS_H_STP_POST_ENABLE_DELAY 100

Stepper stimStepper(__HWCONSTANTS_H_NUMSTEPS, 
    PIN_STEPPER1, PIN_STEPPER2, PIN_STEPPER3, PIN_STEPPER4); 

void setup() {
  Serial.begin(115200);
  //~ stimStepper = new Stepper(__HWCONSTANTS_H_NUMSTEPS, 
    //~ PIN_STEPPER1, PIN_STEPPER2, PIN_STEPPER3, PIN_STEPPER4); 
}

void loop() {
  Serial.println("DBG stepping");
  delay(500);
  rotate(1);  
}

int rotate(long n_steps)
{
  digitalWrite(ENABLE_STEPPER, HIGH);
  Serial.println("DBG stepping0");

  delay(__HWCONSTANTS_H_STP_POST_ENABLE_DELAY);
  Serial.println("DBG stepping1");

  // This is where the freeze usually happens
  stimStepper.step(n_steps);

  // never get here
  Serial.println("DBG stepping2");
  Serial.println("DBG stepping3");

  digitalWrite(ENABLE_STEPPER, LOW);  
  return 0;
}

cxrodgers:
It is true that if I replace the dynamic allocation with a global variable, then this test sketch now works.

That suggests very clearly to me that the problem lies in your choice of implementation and that you probably need to revise your main to code to use the "normal" way.

I don't know enough about the innards of C/C++ to even hazard a guess as to why the "normal" way works and your way does not.

...R

Why can't you use the Stepper library the normal way as shown in the examples?

Ok, I think I've figured it out. I used Arduino Watchdog as @QDeathStar suggested. This tells me what memory address it's getting stuck on. Then I used the disassembler to find out which line of code this corresponds to.

It's this one in Stepper.cpp:

  // decrement the number of steps, moving one step each time:
  while(steps_left > 0) {
  // move only if the appropriate delay has passed:
  if (millis() - this->last_step_time >= this->step_delay) {

see also: https://github.com/arduino/Arduino/blob/master/libraries/Stepper/src/Stepper.cpp

Actually, @gpop1 was on the right track all along. The private variable "step_delay" is never initialized by the Stepper class. So, you need to set it explicitly (using setSpeed). Otherwise, when using static memory allocation this variable is highly likely to be zero and the conditional is satisfied immediately, resulting in maximum stepper speed. But when using dynamic memory allocation, this variable is somewhat likely to be a garbage non-zero value that is very large. Thus, the conditional never evaluates to True and the arduino freezes.

I consider this to be a bug in the Stepper code because it should either initialize this value explicitly, or at least document that a call to setSpeed is required. So I'm going to file a bug report.

In my full project application, I'm not sure this is the same problem I'm having, but now that I know how to use the watchdog I can probably figure out what's going on there too.

Thanks all for the suggestions!