Does anybody have any working code for UART with StallGuard for this combo? I can get the motor to spin, I can get the Baud Rate Test example to show that it's communicating, but I cannot for the life of me find or modify any example sketch that gets the StallGuard feature working. Arduino Nano or Mega 2560 are both at my disposal.
The goal for forum is helping members learn and grow in programming, not being a free give away institution. It's a common beginners mistake to think there's a ready code to copy.
Please post code and schematics.
Motor rotates. Returns a stallguard result. Only way to get full power from the motor is if I cycle the power supply after uploading the code, but with this sketch it does not re-establish UART communication if I cycle the motor power suply.
#include <TMC2209.h>
// This example will not work on Arduino boards without HardwareSerial ports,
// such as the Uno, Nano, and Mini.
//
// See this reference for more details:
// https://www.arduino.cc/reference/en/language/functions/communication/serial/
HardwareSerial & serial_stream = Serial3;
const long SERIAL_BAUD_RATE = 115200;
const int DELAY = 200;
// current values may need to be reduced to prevent overheating depending on
// specific motor and power supply voltage
const uint8_t RUN_CURRENT_PERCENT = 100;
const int32_t VELOCITY = 200000;
const uint8_t STALL_GUARD_THRESHOLD = 99;
// Instantiate TMC2209
TMC2209 stepper_driver;
void setup()
{
Serial.begin(SERIAL_BAUD_RATE);
stepper_driver.setup(serial_stream);
stepper_driver.setRunCurrent(RUN_CURRENT_PERCENT);
stepper_driver.setStallGuardThreshold(STALL_GUARD_THRESHOLD);
stepper_driver.enable();
stepper_driver.moveAtVelocity(VELOCITY);
}
void loop()
{
if (not stepper_driver.isSetupAndCommunicating())
{
Serial.println("Stepper driver not setup and communicating!");
return;
}
Serial.print("run_current_percent = ");
Serial.println(RUN_CURRENT_PERCENT);
Serial.print("stall_guard_threshold = ");
Serial.println(STALL_GUARD_THRESHOLD);
uint16_t stall_guard_result = stepper_driver.getStallGuardResult();
Serial.print("stall_guard_result = ");
Serial.println(stall_guard_result);
Serial.println();
delay(DELAY);
}
This one shows all bauds as working.
#include <TMC2209.h>
// This example will not work on Arduino boards without HardwareSerial ports,
// such as the Uno, Nano, and Mini.
//
// See this reference for more details:
// https://www.arduino.cc/reference/en/language/functions/communication/serial/
HardwareSerial & serial_stream = Serial3;
const long SERIAL_BAUD_RATE = 115200;
const long SERIAL1_BAUD_RATE_COUNT = 10;
const long SERIAL1_BAUD_RATES[SERIAL1_BAUD_RATE_COUNT] =
{
500000,
250000,
115200,
57600,
38400,
31250,
28800,
19200,
14400,
9600
};
const uint8_t SUCCESSIVE_OPERATION_COUNT = 3;
const int DELAY = 2000;
// Instantiate TMC2209
TMC2209 stepper_driver;
uint8_t serial1_baud_rate_index = 0;
void setup()
{
Serial.begin(SERIAL_BAUD_RATE);
}
void loop()
{
long serial1_baud_rate = SERIAL1_BAUD_RATES[serial1_baud_rate_index++];
stepper_driver.setup(serial_stream,serial1_baud_rate);
if (serial1_baud_rate_index == SERIAL1_BAUD_RATE_COUNT)
{
serial1_baud_rate_index = 0;
}
bool test_further = false;
Serial.println("*************************");
Serial.print("serial1_baud_rate = ");
Serial.println(serial1_baud_rate);
if (stepper_driver.isSetupAndCommunicating())
{
Serial.println("Stepper driver setup and communicating!");
test_further = true;
}
else
{
Serial.println("Stepper driver not setup and communicating!");
}
if (test_further)
{
uint32_t microstep_sum = 0;
for (uint8_t i=0; i<SUCCESSIVE_OPERATION_COUNT; ++i)
{
microstep_sum += stepper_driver.getMicrostepsPerStep();
}
if (microstep_sum > 0)
{
Serial.println("Successive read test passed!");
}
else
{
Serial.println("Successive read test failed!");
}
uint8_t itc_begin = stepper_driver.getInterfaceTransmissionCounter();
for (uint8_t i=0; i<SUCCESSIVE_OPERATION_COUNT; ++i)
{
stepper_driver.disable();
}
uint8_t itc_end = stepper_driver.getInterfaceTransmissionCounter();
if (itc_begin != itc_end)
{
Serial.println("Successive write test passed!");
}
else
{
Serial.println("Successive write test failed!");
}
}
Serial.println("*************************");
Serial.println();
delay(DELAY);
}
This one does nothing at all.
#include <TMC2209.h>
// This example will not work on Arduino boards without HardwareSerial ports,
// such as the Uno, Nano, and Mini.
//
// See this reference for more details:
// https://www.arduino.cc/reference/en/language/functions/communication/serial/
HardwareSerial & serial_stream = Serial3;
const long SERIAL_BAUD_RATE = 115200;
const int DELAY = 500;
const int32_t VELOCITY = 20000;
// current values may need to be reduced to prevent overheating depending on
// specific motor and power supply voltage
const uint8_t RUN_CURRENT_PERCENT = 100;
const uint8_t LOOPS_BEFORE_TOGGLING = 3;
const TMC2209::CurrentIncrement CURRENT_INCREMENT = TMC2209::CURRENT_INCREMENT_8;
const TMC2209::MeasurementCount MEASUREMENT_COUNT = TMC2209::MEASUREMENT_COUNT_1;
const uint32_t COOL_STEP_DURATION_THRESHOLD = 2000;
const uint8_t COOL_STEP_LOWER_THRESHOLD = 1;
const uint8_t COOL_STEP_UPPER_THRESHOLD = 0;
uint8_t loop_count = 0;
bool cool_step_enabled = false;
// Instantiate TMC2209
TMC2209 stepper_driver;
void setup()
{
Serial.begin(SERIAL_BAUD_RATE);
stepper_driver.setup(serial_stream);
stepper_driver.setRunCurrent(RUN_CURRENT_PERCENT);
stepper_driver.setCoolStepCurrentIncrement(CURRENT_INCREMENT);
stepper_driver.setCoolStepMeasurementCount(MEASUREMENT_COUNT);
stepper_driver.setCoolStepDurationThreshold(COOL_STEP_DURATION_THRESHOLD);
stepper_driver.enable();
stepper_driver.moveAtVelocity(VELOCITY);
}
void loop()
{
if (not stepper_driver.isSetupAndCommunicating())
{
Serial.println("Stepper driver not setup and communicating!");
return;
}
if (cool_step_enabled)
{
Serial.println("cool step enabled");
}
else
{
Serial.println("cool step disabled");
}
uint32_t interstep_duration = stepper_driver.getInterstepDuration();
Serial.print("interstep_duration = ");
Serial.println(interstep_duration);
delay(DELAY);
uint16_t stall_guard_result = stepper_driver.getStallGuardResult();
Serial.print("stall_guard_result = ");
Serial.println(stall_guard_result);
delay(DELAY);
uint8_t pwm_scale_sum = stepper_driver.getPwmScaleSum();
Serial.print("pwm_scale_sum = ");
Serial.println(pwm_scale_sum);
delay(DELAY);
int16_t pwm_scale_auto = stepper_driver.getPwmScaleAuto();
Serial.print("pwm_scale_auto = ");
Serial.println(pwm_scale_auto);
delay(DELAY);
uint8_t pwm_offset_auto = stepper_driver.getPwmOffsetAuto();
Serial.print("pwm_offset_auto = ");
Serial.println(pwm_offset_auto);
delay(DELAY);
uint8_t pwm_gradient_auto = stepper_driver.getPwmGradientAuto();
Serial.print("pwm_gradient_auto = ");
Serial.println(pwm_gradient_auto);
delay(DELAY);
TMC2209::Status status = stepper_driver.getStatus();
Serial.print("status.current_scaling = ");
Serial.println(status.current_scaling);
TMC2209::Settings settings = stepper_driver.getSettings();
Serial.print("settings.irun_register_value = ");
Serial.println(settings.irun_register_value);
Serial.println();
if (++loop_count == LOOPS_BEFORE_TOGGLING)
{
loop_count = 0;
cool_step_enabled = not cool_step_enabled;
if (cool_step_enabled)
{
stepper_driver.enableCoolStep(COOL_STEP_LOWER_THRESHOLD,
COOL_STEP_UPPER_THRESHOLD);
}
else
{
stepper_driver.disableCoolStep();
}
}
}
I have screwed with various parts, copy pasted parts from working code into the non working code, fiddled with wires, done everything I can personally think of and I am out of ideas. The schematic, unless there is a useful tool for drawing it, will just be as follows.
EN_PIN to arduino pin 6
TMC2209 TX to Arduino pin 15
TMC2209 RX to Arduino pin 14
1k ohm resistor between pin 14 and 15
TMC Diag to Arduino pin 21 (for different things I was trying with interrupts)
+5v and gnd from arduino to power TMC2209
12-18VDC power supply to VS and GND on TMC2209
the 4 wires from the Creality Ender 3 Z Axis stepper motor to TMC2209 (Works, when the sketch works)
I added the EN_PIN lines to the non working sketch and now the motor spins and returns a stallguard value. Not sure what the feedback in Serial monitor means though. I would have expected that if EN_PIN was required, it would have been included in the example code.
Also I am still not getting more than .2 amps used on the power supply and has extremely low torque. With other (since deleted) sketches, if I cycle the power supply while the arduino is running (powered seperately), it goes up to 1-1.5 amps and the motor has strong torque. The sketches that allowed me to cycle the power supply may have been unidirectional UART, whereas the goal is to have bidirectional UART so I can use the stallguard feature to stop and reverse the motor. I am cycle testing an item and want it to go back and forth indefinitely. I was able to achieve this with limit switches, but I am trying to do it this way instead.
#include <TMC2209.h>
// This example will not work on Arduino boards without HardwareSerial ports,
// such as the Uno, Nano, and Mini.
//
// See this reference for more details:
// https://www.arduino.cc/reference/en/language/functions/communication/serial/
HardwareSerial & serial_stream = Serial3;
#define EN_PIN 6
const long SERIAL_BAUD_RATE = 115200;
const int DELAY = 500;
const int32_t VELOCITY = 20000;
// current values may need to be reduced to prevent overheating depending on
// specific motor and power supply voltage
const uint8_t RUN_CURRENT_PERCENT = 100;
const uint8_t LOOPS_BEFORE_TOGGLING = 3;
const TMC2209::CurrentIncrement CURRENT_INCREMENT = TMC2209::CURRENT_INCREMENT_8;
const TMC2209::MeasurementCount MEASUREMENT_COUNT = TMC2209::MEASUREMENT_COUNT_1;
const uint32_t COOL_STEP_DURATION_THRESHOLD = 2000;
const uint8_t COOL_STEP_LOWER_THRESHOLD = 1;
const uint8_t COOL_STEP_UPPER_THRESHOLD = 0;
uint8_t loop_count = 0;
bool cool_step_enabled = false;
// Instantiate TMC2209
TMC2209 stepper_driver;
void setup()
{
Serial.begin(SERIAL_BAUD_RATE);
stepper_driver.setup(serial_stream);
stepper_driver.setRunCurrent(RUN_CURRENT_PERCENT);
stepper_driver.setCoolStepCurrentIncrement(CURRENT_INCREMENT);
stepper_driver.setCoolStepMeasurementCount(MEASUREMENT_COUNT);
stepper_driver.setCoolStepDurationThreshold(COOL_STEP_DURATION_THRESHOLD);
stepper_driver.enable();
stepper_driver.moveAtVelocity(VELOCITY);
pinMode(EN_PIN, OUTPUT);
digitalWrite(EN_PIN, LOW);
}
void loop()
{
if (not stepper_driver.isSetupAndCommunicating())
{
Serial.println("Stepper driver not setup and communicating!");
return;
}
if (cool_step_enabled)
{
Serial.println("cool step enabled");
}
else
{
Serial.println("cool step disabled");
}
uint32_t interstep_duration = stepper_driver.getInterstepDuration();
Serial.print("interstep_duration = ");
Serial.println(interstep_duration);
delay(DELAY);
uint16_t stall_guard_result = stepper_driver.getStallGuardResult();
Serial.print("stall_guard_result = ");
Serial.println(stall_guard_result);
delay(DELAY);
uint8_t pwm_scale_sum = stepper_driver.getPwmScaleSum();
Serial.print("pwm_scale_sum = ");
Serial.println(pwm_scale_sum);
delay(DELAY);
int16_t pwm_scale_auto = stepper_driver.getPwmScaleAuto();
Serial.print("pwm_scale_auto = ");
Serial.println(pwm_scale_auto);
delay(DELAY);
uint8_t pwm_offset_auto = stepper_driver.getPwmOffsetAuto();
Serial.print("pwm_offset_auto = ");
Serial.println(pwm_offset_auto);
delay(DELAY);
uint8_t pwm_gradient_auto = stepper_driver.getPwmGradientAuto();
Serial.print("pwm_gradient_auto = ");
Serial.println(pwm_gradient_auto);
delay(DELAY);
TMC2209::Status status = stepper_driver.getStatus();
Serial.print("status.current_scaling = ");
Serial.println(status.current_scaling);
TMC2209::Settings settings = stepper_driver.getSettings();
Serial.print("settings.irun_register_value = ");
Serial.println(settings.irun_register_value);
Serial.println();
if (++loop_count == LOOPS_BEFORE_TOGGLING)
{
loop_count = 0;
cool_step_enabled = not cool_step_enabled;
if (cool_step_enabled)
{
stepper_driver.enableCoolStep(COOL_STEP_LOWER_THRESHOLD,
COOL_STEP_UPPER_THRESHOLD);
}
else
{
stepper_driver.disableCoolStep();
}
}
}
The Serial Monitor output.
cool step enabled
interstep_duration = 838
stall_guard_result = 0
pwm_scale_sum = 13
pwm_scale_auto = 0
pwm_offset_auto = 36
pwm_gradient_auto = 0
status.current_scaling = 7
settings.irun_register_value = 31
cool step disabled
interstep_duration = 838
stall_guard_result = 116
pwm_scale_sum = 36
pwm_scale_auto = 0
pwm_offset_auto = 36
pwm_gradient_auto = 0
status.current_scaling = 31
settings.irun_register_value = 31
Basically, once I get pointed in the right direction I can usually go from there for what I am trying to achieve. Nothing has been as infuriating as this driver in the past.
I'm interested in this as well. I just decided to give this a try for my project as one aspect of the project requires the ability to detect an object which is very hard for normal sensors to do (orI would have to have hundreds of sensors). It seems like its easier to just watch for motor load change and use that instead.
Most of the stuff (not all) I've seen is based on using printer controller boards. I"m looking to use an UNO r3 if possible, with the TMC2209 drivers.
If anyone knows of good tutorials for Stall Guard on Arduino out there, please post them! I've found very few so far.
Thanks.
Hi there! I'm working on a very similar issue, maybe we can learn from each other's projects. I too have found a pretty low amount of information, useful tutorials out there concerning Stallguard.
I am trying to replace limit switches with Stallguard. I am using the TMC2226 drivers, but from what I've read, the tmc2226 is nearly identical to the tmc2209. I currently have an arduino uno r3 running the system, and I think that may be an issue because it doesn't have a hardware serial port? I have been running into this error where all the example codes with "serial1, or serial3" won't compile ("Compilation error: 'Serial3' was not declared in this scope"). When I change it to serial, it compiles, but I am not sure that it will work as expected with that change.
I also have my enable pin permanently pulled LOW, so I may need to change the enable pin to a digital pin on the arduino, but I have ran out of pins, hence the need to get rid of the limit switches. And I also don't have the arduino power and ground hooked up to the drivers, because the previous system didn't have those connections. They work fine, but I think I may need to do that so the driver can use that power to control the DIAG pin.
I haven't been able to get stallguard configured because the DIAG pin reads as LOW (specifically 27mV when motors are stationary, and 90mV when motors are moving), and it's my understanding that it's supposed to be 5V at all times until a stall is detected and then the signal gets changed to LOW (0V).
My motors are the ReDREX.Tech SL42STH39-1504A, NEMA17 motors. I can't find a datasheet, so this is the closest i could get.
So my current next step is to get the DIAG pin to be high (assuming it's supposed to be), then try to implement Stallguard after that.
What specific arduino board are you using?
This website makes it seem like the arduino uno r3 is capable of serial communication?:
https://docs.arduino.cc/language-reference/en/functions/communication/serial/
I got this working on my Mega with the following code:
#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 = 900;
const int set_stall = 5;
const long set_tcools = 250;
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...");
}
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.

