Weird Behaviour with A-Star 32u4 Micro and Serial Monitor When Powering via Vin

If I power the A-Star 32u4 Micro board via USB and use the serial monitor, everything seems to run OK (stepper motor plus speed control via rotary encoder). If I power the board via Vin, though, the stepper motor does not spin and it doesn’t catch the button press on the rotary encoder via the ClickEncoder library. If I comment out the #define DEBUG_MODE line (as shown below), though, then all works fine again. I believe I noticed the same odd behaviour with the A-Star 328PB, too.

Anyone know why?

/*

Constant Speed stepper motor control using AccelStepper library



TODOs
=====

  1.  Switch to non-blocking LED blinking (e.g. https://www.arduino.cc/en/tutorial/BlinkWithoutDelay)


SilentStepStick TMC2208
=======================

https://shop.watterott.com/SilentStepStick-TMC2208-Stepper-Motor-Driver

1/2 step mode (MS1 > +5V; MS2 > GND)

Current limiter: Vref = 210mV (400mV for 2 motors)

SparkFun Rotary Encoder
=======================

https://www.sparkfun.com/products/9117


Rotary Encoder Wiring
=====================

https://bildr.org/blog/wp-content/uploads/2012/03/Rotary_Encoder_Switch_Arduino_Hookup.png


*/

/*

  IMPORTANT: COMMENT OUT THE LINE BELOW FOR PRODUCTION USE, OR WHEN POWERING BOARD
             VIA Vin PIN (i.e. when not connected go your computer via USB cable)

*/

//#define DEBUG_MODE


// Libraries
// =========
#include <AccelStepper.h>
#include <ClickEncoder.h>
#include <TimerOne.h>
#include <EEPROM.h>


// Define pins for stepper motor control, and others
#define DIR_PIN   6   // Req'd for AccelStepper
#define STEP_PIN  5   // Step on rising edge
#define EN_PIN    4   // LOW: Driver enabled. HIGH: Driver disabled
#define LED_PIN   LED_BUILTIN  // Speed adjustment indicator

// Set up accelStepper intance
AccelStepper stepper(AccelStepper::DRIVER, STEP_PIN, DIR_PIN); 

// Set up ClickEncoder instance
ClickEncoder *encoder;

// ClickEncoder Timer1 ISR
void timerIsr() {
  encoder->service();
}

// Set up stepper speed details 

// For NMB stepper with gear box reduction ratio of 1:41.66666:
//   Motor step angle 15 deg
//   Output shaft step angle 0.36 deg
//   1000 pulse output = 360 deg

float motorRPM = 660.0;  // # of steps per second (1/2 step)
float maxRPM = motorRPM*2.0;
float minRPM = motorRPM/2.0;
float adjFactor = 10.0;

// Set up variables with for ramping up during setup()
unsigned long timeStamp1;
unsigned long previousAccel = 0;
int interval = 15;     // # of milliseconds between speed increases (1/2 step)

bool motorRPMAdj = false;
unsigned long timeStamp2;
long elapsedTimeBeforeSave = 5000; // Wait 5sec after last change before saving new speed to EEPROM

int eeAddress = 0; // EEPROM address to start reading from

void setup()
{  

  // Prepare pins
  pinMode(EN_PIN, OUTPUT);
  digitalWrite(EN_PIN, HIGH);   // Disable driver in hardware

  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);   // Speed adj indicator should be off initially
  

  stepper.setMaxSpeed(maxRPM);
  stepper.setSpeed(10);         // Set to a really low value in anticipation of ramping up to
                                // motorRPM in setup()

  encoder = new ClickEncoder(A0, A1, 7, 4); // A0 = B; A1 = A; 7 = Btn; SparkFun rotary encoder has 12 indents = 4
  encoder->setAccelerationEnabled(false);
  encoder->setDoubleClickEnabled(false);
  
  Timer1.initialize(1000);
  Timer1.attachInterrupt(timerIsr);

  digitalWrite(EN_PIN, LOW);    // Enable driver in hardware

#ifdef DEBUG_MODE
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
#endif

  // Get the float data from the EEPROM at position 'eeAddress'
  float f = 0.00f;   // Variable to store data read from EEPROM.
  EEPROM.get( eeAddress, f );

#ifdef DEBUG_MODE
  Serial.print("EEPROM f val: ");
  Serial.println( f, 3 );  // This may print 'ovf, nan' if the data inside the EEPROM is not a valid float.
#endif

  if (!isnan(f)) {
    // EEPROM read yields numerical value, so set motorRPM to this if it's within min/max
    if ((f >= minRPM) && (f <= maxRPM)) {
      motorRPM = f;
    }  
  }

#ifdef DEBUG_MODE
  Serial.print("motorRPM: ");
  Serial.println(motorRPM);  // This may print 'ovf, nan' if the data inside the EEPROM is not a valid float.
#endif

  // Initial ramp up to motorRPM on startup
  while (stepper.speed() < motorRPM) {
    timeStamp1 = millis();
    if (timeStamp1 > previousAccel + interval) {
      previousAccel = timeStamp1;

      if (stepper.speed() + 2 > motorRPM) {
        stepper.setSpeed(motorRPM);
      } else {
        stepper.setSpeed(stepper.speed() + 2);
      }
    }
    
    stepper.runSpeed();
  }

}

void loop()
{  

  // Check if rotary button pressed
  ClickEncoder::Button b = encoder->getButton();
  if (b != ClickEncoder::Open) {
    
    switch (b) {
      case ClickEncoder::Released:
        // Enable speed adjustment via rotary encoder
        
        motorRPMAdj = true;             // Turn on state variable
        timeStamp2 = millis();          // Start timer to determine when ajustments are done
        
        digitalWrite(LED_PIN, HIGH);    // Turn on speed adj indicator
        
        break;
    }

  } 

  // Check if rotary encoder has changed & adjust speed accordingly
  if (motorRPMAdj == true) {
    checkEncoder();
  }

  stepper.runSpeed();

  // Save new motor RPM after appropriate elapsed time
  unsigned long currentTime = millis();

  if ( motorRPMAdj == true && ( (currentTime - timeStamp2) > elapsedTimeBeforeSave) ) {
    
//    EEPROM.put(eeAddress, motorRPM); // update EEPROM with new motorRPM

    motorRPMAdj = false;          // reset flag
    
    digitalWrite(LED_PIN, LOW);   // Turn off speed adj indicator
   
#ifdef DEBUG_MODE
    Serial.print("motorRPMAdj: ");
    Serial.println(motorRPMAdj);
    Serial.print("Saved motorRPM: ");
    Serial.println(motorRPM);
#endif
  
  }

  
}



/*
    Purpose: check if rotary encoder has been used and adjust stepper motor speed
    Parameters: none
    Returns: nothing
*/
void checkEncoder() {

  int16_t encVal = encoder->getValue(); // returns 1 for CW; -1 for CCW (dependng on A/B connectuon); 0 if untouched
  
  if (encVal != 0) {
    // Rotary encoder knob was turned left or right

    timeStamp2 = millis(); // reset timer every time the knob is turned
    
    // Update stepper speed, keeping within min/max values
    motorRPM = motorRPM + (encVal*adjFactor);
    if (motorRPM < minRPM) {
      motorRPM = minRPM;
    }
    if (motorRPM > maxRPM) {
      motorRPM = maxRPM;
    }
    
    stepper.setSpeed(motorRPM);

#ifdef DEBUG_MODE
    Serial.print("encVal: ");
    Serial.println(encVal);
    Serial.print("motorRPM: ");
    Serial.println(motorRPM);
#endif

  }

}

Hello.

It sounds like a power or noise issue. What are you using to power your system? Can you post pictures of your setup showing how everything is connected?

- Amanda

I’m using this 12V power supply:

If I upload the code with this line uncommented:

#define DEBUG_MODE

nothing happens (the stepper motors don’t move).

This is my setup:

The 12V goes in to Vin on the 32U4 as well as the Vmot on the TMC2208 SilentStepStick. The USB-B cable is NOT connected.

If, however I upload code with the above line commented out, all works fine.

#define DEBUG_MODE is a preprocessor directive, and it is used to disable or enable parts using the Serial port in the code you posted. In the setup() function, there’s this code block that waits for the USB CDC serial connection to be opened:

#ifdef DEBUG_MODE
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
#endif

When you uncommented #define DEBUG_MODE, that block of code becomes part of the program that’s compiled. The program will iterate in that while loop until you open a connection to the A-Star 32U4’s COM port using a serial terminal (e.g. Arduino IDE’s Serial Monitor). You can find more details about waiting for a serial connection in the Arduino IDE here.

- Amanda

Ugh. That makes perfect sense. I just removed the WHILE loop and it works fine with #define DEBUG_MODE. Thanks Amanda.

I’ve come back to this problem with a different project where I want to debug in the setup(), but I get absolutely nothing in the Serial Monitor with a 32U4 Micro whereas this code works just fine with an A* 328PB or an Arduino Pro Mini:

#define NUM_PWM_CHNLS 12            // max 12 for TLC5971

long ledBrightness[NUM_PWM_CHNLS];
long initBrightness = 50;
long minBrightness  = 0;
long maxBrightness  = 100;

bool loopOnce = true;

void setup()
{  

  Serial.begin(9600);
  //delay(1);

  
  // Set initial brightness of LEDs
  for (int i = 0; i < NUM_PWM_CHNLS; i++) {
    ledBrightness[i] = initBrightness;
  }

  Serial.println("In setup() ...");
  for (int i = 0; i < NUM_PWM_CHNLS; i++) {
    Serial.print("ledBrightness[");
    Serial.print(i);
    Serial.print("]: ");
    Serial.println(ledBrightness[i]);
  }

}

void loop()
{  

  if(loopOnce==true){
    Serial.println("In loop() ...");
    for (int i = 0; i < NUM_PWM_CHNLS; i++) {
      Serial.print("ledBrightness[");
      Serial.print(i);
      Serial.print("]: ");
      Serial.println(ledBrightness[i]);
    }
    
    loopOnce = false;
  }

}

There are no conditional compile statements, and again this works perfectly with other boards. I’ve tried with having power connected to Vin (+ GND) but that makes no difference. The board is connected to the Arduino IDE via mini USB. What am I doing wrong?

For USB connections to the 32u4, add back in the

while (!Serial);

Thanks Jim! That did it! I’ll just have to be careful not to copy that code to non-A*32u4 board sketches.