Motor Driver Wont Detect Stall?

Hello all, i am working on a project. It entails a AMIS-30543 motor driver, driving a Nema17 1.5A 17hs16 stepper motor with a threaded rod attached to a linear glass scale (5um resolution). These are being ran by a pololu SV board. It is meant to extend a probe, then when a stall is detected (hits a hard surface) or after 12mm, it will return to a 0 position (bottom out until I cannot get any closer and reset the scale to 0). Currently, even when I grab the threaded rod and stop it from spinning, the driver is not detecting the stall. I am lost as for what to try next. Any help would be greatly appreciated.

Hello all, i am working on a project. It entails a AMIS-30543 motor driver, driving a Nema17 1.5A 17hs16 stepper motor with a threaded rod attached to a linear glass scale (5um resolution). These are being ran by a pololu SV board. It is meant to extend a probe, then when a stall is detected (hits a hard surface) or after 12mm, it will return to a 0 position (bottom out until I cannot get any closer and reset the scale to 0). Currently, even when I grab the threaded rod and stop it from spinning, the driver is not detecting the stall. I am lost as for what to try next. Any help would be greatly appreciated. 
#include <SPI.h>
#include <AMIS30543.h>

// ----- Motor Driver (AMIS-30543) Setup -----
const uint8_t amisDirPin       = 2;  // DIR pin
const uint8_t amisStepPin      = 3;  // STEP pin
const uint8_t amisSlaveSelect  = 4;  // CS pin

// Delay between steps (microseconds)
const unsigned int STEP_DELAY_US = 500;  // Adjust for speed/timing

// ----- Probe Routine Parameters -----
const unsigned long FORWARD_TIME_MS = 10000;   // Maximum time allowed for downward movement
const unsigned long RESET_TIME_MS   = 10000;     // Maximum time allowed for upward (reset) movement

// Maximum allowed travel in free air (if no stall occurs), in millimeters
const double MAX_TRAVEL_MM = 20.0;  
// Minimum displacement (in mm) required before a stall is accepted
const double MIN_DISPLACEMENT_MM = 2.0;  
// Conversion factor: if resolution is 5 µm/count, then each count = 0.005 mm.
const double CONVERSION_FACTOR = 0.005;

AMIS30543 stepper;

// ----- Glass Scale (TTL Quadrature) Setup -----
// Wiring assumption:
//   Red = +5V, Black = GND, Green = Signal A, Yellow = Signal B.
// Signal A is connected to digital pin 0 and Signal B to digital pin 1.
const int SCALE_A_PIN = 0;
const int SCALE_B_PIN = 1;

volatile long encoderPosition = 0;
volatile int lastEncoded = 0;

// Forward declarations:
uint8_t readSR0Manual();
void runProbeSequence();
void step();
void setDirection(bool dir);
void updateEncoder();

void setup() {
  Serial.begin(9600);
  
  // Initialize SPI and the motor driver:
  SPI.begin();
  pinMode(amisSlaveSelect, OUTPUT);
  digitalWrite(amisSlaveSelect, HIGH);
  stepper.init(amisSlaveSelect);
  
  pinMode(amisStepPin, OUTPUT);
  pinMode(amisDirPin, OUTPUT);
  digitalWrite(amisStepPin, LOW);
  digitalWrite(amisDirPin, LOW);
  delay(1);
  
  stepper.resetSettings();
  stepper.setCurrentMilliamps(350);   // Adjust current limit to match your force (27–31 N) calibration
  stepper.setStepMode(4);             // 1/4 stepping for smoother motion
  stepper.enableDriver();
  
  // Set up glass scale pins with pull-ups:
  pinMode(SCALE_A_PIN, INPUT_PULLUP);
  pinMode(SCALE_B_PIN, INPUT_PULLUP);
  int aVal = digitalRead(SCALE_A_PIN);
  int bVal = digitalRead(SCALE_B_PIN);
  lastEncoded = (aVal << 1) | bVal;
  attachInterrupt(digitalPinToInterrupt(SCALE_A_PIN), updateEncoder, CHANGE);
  attachInterrupt(digitalPinToInterrupt(SCALE_B_PIN), updateEncoder, CHANGE);
  
  delay(1000);
  Serial.println("A-Star ready.");
}

void loop() {
  // Wait for a "PROBE" command from the host (e.g., Raspberry Pi)
  if (Serial.available() > 0) {
    String cmd = Serial.readStringUntil('\n');
    cmd.trim();
    if (cmd.equalsIgnoreCase("PROBE")) {
      // Send an immediate preliminary value to avoid host timeout
      Serial.println("0");
      runProbeSequence();
    }
  }
}

void runProbeSequence() {
  // --- Downward (Probe) Phase ---
  setDirection(false);  // Set motor direction downward
  unsigned long startTime = millis();
  long measuredCounts = 0;
  double probeDepth_mm = 0.0;
  
  while (millis() - startTime < FORWARD_TIME_MS) {
    step();
    delay(1);  // Small delay to allow stall flag to update
    measuredCounts = encoderPosition;
    probeDepth_mm = measuredCounts * CONVERSION_FACTOR;
    
    // Debug: Print current counts and calculated depth
    Serial.print("Counts: ");
    Serial.print(measuredCounts);
    Serial.print("  Depth (mm): ");
    Serial.println(probeDepth_mm);
    
    uint8_t status = readSR0Manual();
    Serial.print("Stall status: ");
    Serial.println(status, BIN);
    
    // Only accept a stall if at least the minimum displacement has been reached
    if (probeDepth_mm > MIN_DISPLACEMENT_MM && (status & 0x80)) {
      Serial.println("Stall detected after valid displacement.");
      break;
    }
    
    // Stop if maximum travel (20 mm) is reached
    if (probeDepth_mm >= MAX_TRAVEL_MM) {
      Serial.println("Maximum travel reached.");
      break;
    }
  }
  
  double calcinationDepth = probeDepth_mm;  // Save the measured depth
  
  // --- Upward (Reset) Phase ---
  // Reverse motor until the probe mount bottoms out (stall detected) or timeout
// Upward (reset) phase: reverse until stall (i.e. mount bottoms out) or timeout
setDirection(true);  // Set motor direction upward
unsigned long resetStartTime = millis();
bool printedStatus = false;
while (millis() - resetStartTime < RESET_TIME_MS) {
    step();
    delay(1);
    uint8_t status = readSR0Manual();
    if (status & 0x80) {  // Stall detected during reset
        if (!printedStatus) {
            Serial.print("Reset stall status: ");
            Serial.println(status, BIN);
            Serial.println("Reset stall detected. Home reached.");
            printedStatus = true;
        }
        break;
    }
}
if (!printedStatus) {
    Serial.println("Reset phase completed without stall detection.");
}

  
  // Debug: Print final calcination depth before encoder reset
  Serial.print("Final calcination depth (mm): ");
  Serial.println(calcinationDepth);
  
  // Reset encoder to 0 (home position) after a short delay
  delay(100);
  noInterrupts();
  encoderPosition = 0;
  interrupts();
  
  // Print final depth for the host (GUI)
  Serial.println(calcinationDepth);
}

void step() {
  digitalWrite(amisStepPin, HIGH);
  delayMicroseconds(3);
  digitalWrite(amisStepPin, LOW);
  delayMicroseconds(3);
  delayMicroseconds(STEP_DELAY_US);
}

void setDirection(bool dir) {
  delayMicroseconds(1);
  digitalWrite(amisDirPin, dir);
  delayMicroseconds(1);
}

uint8_t readSR0Manual() {
  digitalWrite(amisSlaveSelect, LOW);
  SPI.transfer(0x40 | (0x0C & 0x3F)); // Command for reading SR0 (0x4C)
  uint8_t status = SPI.transfer(0x00);
  digitalWrite(amisSlaveSelect, HIGH);
  return status;
}

void updateEncoder() {
  int aVal = digitalRead(SCALE_A_PIN);
  int bVal = digitalRead(SCALE_B_PIN);
  int encoded = (aVal << 1) | bVal;
  int sum = (lastEncoded << 2) | encoded;
  lastEncoded = encoded;
  
  switch (sum) {
    case 0b0011:
    case 0b0100:
    case 0b1011:
    case 0b1100:
      encoderPosition++;
      break;
    case 0b0001:
    case 0b0110:
    case 0b1001:
    case 0b1110:
      encoderPosition--;
      break;
    // Transitional states (0b0000, 0b1111) are ignored.
  }
}

![image|621x500](upload://ts31aMgTjv6JngGZi0nwt6sCWX1.jpeg)

3 questions. Hope You will manage all 3. Else no more reply.

If it has a datasheet, please post a link.

Is the exact board a secret? The same thought as above.

How will stall be detected? An encoder is needed, built in or external.

  1. Pololu - AMIS-30543 Stepper Motor Driver Carrier . The data sheet is in the Overview section
  2. Pololu - A-Star 32U4 Mini SV. Same as before, this is the exact model
  3. It should be detected by the motor driver detecting a spike in current draw but when I grab the rod, a stall is not being detected because current doesn't change. (it is running on a power supply so I can see both current and voltage).

Welcome to the nature of stepper motors! There is a stall between each full step.

1 Like

You can either use a driver that has stall detection, e.g. TMC2209, or use an encoder or other feedback to sense the position of the motor.

Edit : according to the AMIS-30543 datasheet "The chip provides a soāˆ’called ā€œspeed and load angleā€ output. This allows the creation of stall detection algorithms and control loops based on loadāˆ’angle to adjust torque and speed. "

Unfortunately, it does not suggest what those algorithms are. Possibly they have a tech note on the subject, but it may be that you have to develop your own.

Edit 2; tech note here https://www.onsemi.com/download/application-notes/pdf/and8399-d.pdf. I think a TMC2209 would be easier to use.

1 Like

I have decided on an alternate method. I have added a section of code to detect if the linear scale measurement stabilizes, signaling the probe has stopped. Instead of using a stall.
thank you for your input and time :slight_smile:

Thanks! I'm impressed.

That does not apply to sterppers motors. DC motors behave like that but not steppers.