TMCstepper library and the tmc2209 issues

So I've been making progress trying to learn how to connect the tmc2209 and run the motors.
I wrote a series of sketches which ran perfectly but didn't test any Stall Guard issues.
So now I'm looking to get the Stallguard working. So far, zero results.
I'm running a Mega using UART and tx2 and rx2.
I have a 10k pullup resistor on the diag pin.
the sketch just increases stall guard settings, but nothing works, diag just reads 1 no matter what the load is (I'm stalling it with my fingers).

Here's the ino code:

#include <TMCStepper.h>

#define EN_PIN           9  // Enable
#define DIR_PIN          7  // Direction
#define STEP_PIN         8  // Step
#define SERIAL_PORT Serial2 // Use hardware serial port 2
#define DRIVER_ADDRESS 0b00 // TMC2209 Driver address according to MS1 and MS2
#define DIAG_PIN         13 // DIAG pin on Mega

#define R_SENSE 0.11f

TMC2209Stepper driver(&SERIAL_PORT, R_SENSE, DRIVER_ADDRESS);

void setup() {
  pinMode(EN_PIN, OUTPUT);
  pinMode(DIR_PIN, OUTPUT);
  pinMode(STEP_PIN, OUTPUT);
  pinMode(DIAG_PIN, INPUT);       // Set DIAG pin as input
  digitalWrite(EN_PIN, LOW);      // Enable driver in hardware

  SERIAL_PORT.begin(9600);        // Initialize hardware serial port at 9600 baud rate
  driver.begin();                 // Initialize the driver

  driver.toff(5);                 // Enables driver in software
  driver.rms_current(1200);       // Set motor current to 1200mA
  driver.microsteps(16);          // Set microsteps to 1/16th
  driver.en_spreadCycle(false);   // Disable SpreadCycle
  driver.TCOOLTHRS(0xFFFF);       // Set TCOOLTHRS for StallGuard
  driver.SGTHRS(0);               // Initialize StallGuard threshold to 0

  // Start Serial communication for debug
  Serial.begin(9600);             // Set Serial monitor to 9600 baud rate for debugging
  Serial.println("Setup complete.");
  Serial.print("Driver version: ");
  Serial.println(driver.version(), HEX);

  // Verify configuration
  Serial.print("toff: ");
  Serial.println(driver.toff(), DEC);
  Serial.print("rms_current: ");
  Serial.println(driver.rms_current(), DEC);
  Serial.print("microsteps: ");
  Serial.println(driver.microsteps(), DEC);
  Serial.print("SGTHRS: ");
  Serial.println(driver.SGTHRS(), DEC);
}

void loop() {
  // Move the motor in one direction
  digitalWrite(DIR_PIN, LOW);
  for (uint16_t i = 0; i < 1000; i++) {
    digitalWrite(STEP_PIN, HIGH);
    delayMicroseconds(160);
    digitalWrite(STEP_PIN, LOW);
    delayMicroseconds(160);
  }

  // Read and print StallGuard status and other debug information
  Serial.print("SG_RESULT: ");
  Serial.println(driver.SG_RESULT(), DEC);
  Serial.print("CS_ACTUAL: ");
  Serial.println(driver.cs_actual(), DEC);
  Serial.print("TSTEP: ");
  Serial.println(driver.TSTEP(), DEC);
  Serial.print("DIAG pin status: ");
  Serial.println(digitalRead(DIAG_PIN));

  // Increment SGTHRS value incrementally for tuning
  static int sgt = 0;
  if (sgt <= 255) {
    driver.SGTHRS(sgt);
    Serial.print("SGTHRS set to: ");
    Serial.println(sgt);
    sgt += 10; // Increment SGTHRS by 10 for quicker testing
  }

  delay(2000); // Add delay between loops
  Serial.println("Loop iteration complete.");
}

Any ideas what I'm doing wrong?

Here's a link to the wokwi and json diagram stallguard test - Wokwi ESP32, STM32, Arduino Simulator

PS, tested it without the resistor on diag pin as well. only result was endless zeros instead of endless 1s...

Pin 13 had the built-in LED attached to it. I would use a different pin.
Have to tried the stallguard example that comes with the library?

That sketch uses interrupts to continuously rotate the motor while your sketch just rotates the motor in your for() loop and then reads that status. The status may reflect that the motor is currently stopped, not that it stalled out previously - I don't know.

I changed the pin, same story. You could be right about the motor, I'll have to think about it.
As far as their example; I ran it but got errors.
One was:
'driver' was not declared in this scope.
As I'm using their library and their example code, seems like something is wrong with their file...

You need to uncomment one of the lines

// Select your stepper driver type
//TMC2209Stepper driver(&SERIAL_PORT, R_SENSE, DRIVER_ADDRESS);
//TMC2209Stepper driver(SW_RX, SW_TX, R_SENSE, DRIVER_ADDRESS);

Thank you, I missed that!

So I got their example working, and I got a screen that read 0 0 75
Adjusting the stall guard value seemed to have no effect although the last number changed. But activating stall guard means that the motor will stop turning, and that never happened.

I'm not quite sure how to parse that.

But just to be clear, Stallguard does not stop the motor, it just means that the driver indicates it detected a "stall condition". It is up to whatever is toggling the STEP pin to stop toggling the STEP pin, which stops the motor. Unless I seriously misunderstood the datasheet.

You are right. I wasn't thinking clearly. Or writing I guess :slight_smile:

hi @geoffreybaker, were you successful?
I am in the same situation you were. I can control the motor but stall detection does not work.
Various scenarios but none detected. The one inspired from the library could show a 55mA but when I was trying to put more load or stall the motor that value never changed.
Tried with both variant:
TMC2209Stepper driver(&SERIAL_PORT, R_SENSE, DRIVER_ADDRESS); <connected to Arduino's RX,TX
TMC2209Stepper driver(SW_RX, SW_TX, R_SENSE, DRIVER_ADDRESS);
or with the DIAG pin, but that always outputs 0.

Please let me know if you made it work and how :slight_smile:

Yes, I was, for a couple of days. Then I made some changes to the hardware and it all stopped communicating again.
I'm working on a different project but will get back to this shortly and I'll be in touch once I get it working again...

https://forum.arduino.cc/t/your-post-in-controlling-2-stepper-motors-simultaneously/1352581/5?u=geoffreybaker

This links to the sketch I have that successfully drives stallguard. Enjoy!

Thanks. I will try it.
For now I think is private:
“ Oops! That page doesn’t exist or is private.”

Probably is somewhere here(?): Controlling 2 stepper motors simultaneously

#include <Arduino.h>
#include "FastAccelStepper.h"
#include <HardwareSerial.h>
#include <TMCStepper.h>
#include <SPI.h>

// Motor Pins
#define STEP_PIN 8
#define DIR_PIN 7
#define ENABLE_PIN 9
#define STALLGUARD 3
#define RXD2 17
#define TXD2 16

// Switch Pins
#define ON_OFF_SWITCH 10   // HIGH = OFF, LOW = ON
#define UP_DOWN_SWITCH 11  // HIGH = Up, LOW = Down
#define E_STOP_SWITCH 12   // LOW = Emergency Stop active

#define R_SENSE 0.11f
#define DRIVER_ADDRESS 0b00

const long set_velocity = 30000;
const int set_acceleration =8000;
const int set_current = 500;
const int set_stall = 10;
const long set_tcools = 300;
const int motor_microsteps = 64;

volatile bool stalled_motor = false;
static bool lastWasEStop = false;  // Track if last command was e-stop

#define SERIAL_PORT_2 Serial2
FastAccelStepperEngine engine = FastAccelStepperEngine();
FastAccelStepper *stepper = NULL;
TMC2209Stepper driver(&SERIAL_PORT_2, R_SENSE, DRIVER_ADDRESS);

void stalled_position() {
  stalled_motor = true;
  Serial.println("STALL DETECTED!");
}

void setup() {
  Serial.begin(115200);
  SERIAL_PORT_2.begin(115200);

  pinMode(ON_OFF_SWITCH, INPUT_PULLUP);
  pinMode(UP_DOWN_SWITCH, INPUT_PULLUP);
  pinMode(E_STOP_SWITCH, INPUT_PULLUP);

  pinMode(ENABLE_PIN, OUTPUT);
  pinMode(STALLGUARD, INPUT);
  attachInterrupt(digitalPinToInterrupt(STALLGUARD), stalled_position, RISING);

  driver.begin();
  driver.toff(4);
  driver.blank_time(24);
  driver.I_scale_analog(false);
  driver.internal_Rsense(false);
  driver.mstep_reg_select(true);
  driver.microsteps(motor_microsteps);
  driver.TPWMTHRS(0);
  driver.semin(0);
  driver.shaft(true);
  driver.en_spreadCycle(false);
  driver.pdn_disable(true);
  driver.VACTUAL(0);
  driver.rms_current(set_current);
  driver.SGTHRS(set_stall);
  driver.TCOOLTHRS(set_tcools);

  engine.init();
  stepper = engine.stepperConnectToPin(STEP_PIN);
  stepper->setDirectionPin(DIR_PIN);
  stepper->setEnablePin(ENABLE_PIN);
  stepper->setAutoEnable(true);
  stepper->setSpeedInHz(set_velocity);
  stepper->setAcceleration(set_acceleration);

  // Move to top (UP) using runBackward()
  Serial.println("Initializing: Moving to Top...");
  stalled_motor = false;
  stepper->runBackward();
  while (!stalled_motor) {
    if (digitalRead(E_STOP_SWITCH) == LOW || digitalRead(ON_OFF_SWITCH) == HIGH) {
      stepper->forceStop();
      Serial.println("Startup interrupted by E-Stop or On/Off.");
      if (digitalRead(E_STOP_SWITCH) == LOW) lastWasEStop = true;  // Set flag during setup
      break;
    }
    Serial.print("SG_RESULT: "); Serial.println(driver.SG_RESULT());
    Serial.print("TSTEP: "); Serial.println(driver.TSTEP());
    delay(10);
  }
  stepper->forceStop();
  Serial.println("Reached Top at startup. Awaiting instructions...");
}

void loop() {
  static bool last_up_down_state = digitalRead(UP_DOWN_SWITCH);  // Initial state
  bool current_up_down_state = digitalRead(UP_DOWN_SWITCH);

  Serial.print("Loop running. Current state: "); Serial.print(current_up_down_state); 
  Serial.print(", Last state: "); Serial.println(last_up_down_state);

  // E-Stop check - only process if last command wasn't e-stop
  if (digitalRead(E_STOP_SWITCH) == LOW && !lastWasEStop) {
    stepper->forceStop();
    stepper->disableOutputs();
    Serial.println("Emergency Stop Activated!");
    while (digitalRead(E_STOP_SWITCH) == LOW) {
      delay(100);
      Serial.println("Waiting for E-Stop release...");
    }
    Serial.println("Emergency Stop Released. Awaiting instructions...");
    lastWasEStop = true;  // Mark that this was an e-stop
    last_up_down_state = digitalRead(UP_DOWN_SWITCH);  // Reset state
    return;
  } else if (digitalRead(E_STOP_SWITCH) == LOW && lastWasEStop) {
    Serial.println("Ignoring repeated E-Stop press...");
    while (digitalRead(E_STOP_SWITCH) == LOW) {
      delay(100);  // Wait for release without acting
    }
    Serial.println("Repeated E-Stop released. Awaiting instructions...");
    return;
  }

  // On/Off check
  if (digitalRead(ON_OFF_SWITCH) == HIGH) {
    stepper->forceStop();
    stepper->disableOutputs();
    Serial.println("System OFF");
    while (digitalRead(ON_OFF_SWITCH) == HIGH) {
      delay(100);
      Serial.println("Waiting for On/Off to enable...");
    }
    Serial.println("System ON. Awaiting instructions...");
    lastWasEStop = false;  // Clear e-stop flag
    last_up_down_state = digitalRead(UP_DOWN_SWITCH);  // Reset state
    return;
  }

  // Check for switch change and move
  if (current_up_down_state != last_up_down_state) {
    Serial.println("Switch changed to " + String(current_up_down_state ? "UP" : "DOWN") + ". Starting motion...");
    if (current_up_down_state == HIGH) {
      moveUp();
    } else {
      moveDown();
    }
    lastWasEStop = false;  // Clear e-stop flag after successful move
    last_up_down_state = current_up_down_state;  // Update state after move
  } else {
    Serial.println("No switch change. Awaiting instructions...");
  }
}

void moveUp() {
  Serial.println("Moving Up...");
  stalled_motor = false;
  stepper->runBackward();

  while (!stalled_motor) {
    if (digitalRead(E_STOP_SWITCH) == LOW || digitalRead(ON_OFF_SWITCH) == HIGH) return;

    bool new_state = digitalRead(UP_DOWN_SWITCH);
    if (new_state == LOW) {
      stepper->forceStop();
      Serial.println("Direction switched to Down.");
      return;
    }
    Serial.print("SG_RESULT: "); Serial.println(driver.SG_RESULT());
    Serial.print("TSTEP: "); Serial.println(driver.TSTEP());
    delay(10);
  }
  stepper->forceStop();
  Serial.println("Stalled (Top or Obstacle). Awaiting instructions...");
}

void moveDown() {
  Serial.println("Moving Down...");
  stalled_motor = false;
  stepper->runForward();

  while (!stalled_motor) {
    if (digitalRead(E_STOP_SWITCH) == LOW || digitalRead(ON_OFF_SWITCH) == HIGH) return;

    bool new_state = digitalRead(UP_DOWN_SWITCH);
    if (new_state == HIGH) {
      stepper->forceStop();
      Serial.println("Direction switched to Up.");
      return;
    }
    Serial.print("SG_RESULT: "); Serial.println(driver.SG_RESULT());
    Serial.print("TSTEP: "); Serial.println(driver.TSTEP());
    delay(10);
  }
  stepper->forceStop();
  Serial.println("Stalled (Bottom or Obstacle). Awaiting instructions...");
}

Any luck getting your 2209 to work properly?

Not yet unfortunately. Using the code or variations of it, didn’t rotate the motor.
I am away for few days, but once I get it working I will show the code.