TMCStepper
TMCStepper copied to clipboard
TMC2300, Stallguard, coolstep and more...
Hi,
I'm having an issue with my setup. I want to use a TMC2300 to detect a stall using StallGuard, and then use Coolstep to adapt the current when in use in order to save power since my setup is running on batteries. But I have reached a standstill in my progress.
I have configured a stall, and when I compare it to SG_RESULT, and when SG_VALUE ≤ SGTHRS*2, the motor does not stop, and the DIAG pin does not react. I have tried different configurations, microsteps, speed, Stall values, ect, but no matter the config the driver will not detect a stall. I can read values on the driver with no issue.
Another issue; The motor will not run before I have disconnected and reconnected power from the power supply
I am using an Arduino uno, PM35S-048 motor, TMC2300, 12V battery-power supply.
My test code is:
#include <Arduino.h>
#include <TMCStepper.h>
#define STALL_VALUE 60// [0... 255]
#define TOFF_VALUE 4 // [1... 15]
//#define STEP_PIN 10
//#define DIR_PIN 11
#define EN_PIN 8 // Enable pin
#define SW_RX 2 // SoftwareSerial receive pin
#define SW_TX 3 // SoftwareSerial transmit pin
//#define SERIAL_PORT 0 // HardwareSerial port
#define DRIVER_ADDRESS 0b00 // TMC2209 Driver address according to MS1 and MS2
#define DIAG_PIN 6 // diag input
#define R_SENSE 0.11f // Match to your driver
// SilentStepStick series use 0.11
// UltiMachine Einsy and Archim2 boards use 0.2
// Panucatt BSD2660 uses 0.1
// Watterott TMC5160 uses 0.075
// Select your stepper driver type
//TMC2209Stepper driver(SERIAL_PORT, R_SENSE, DRIVER_ADDRESS);
TMC2209Stepper driver(SW_RX, SW_TX, R_SENSE, DRIVER_ADDRESS);
using namespace TMC2209_n;
void setup() {
pinMode(EN_PIN, OUTPUT);
digitalWrite(EN_PIN, LOW);
digitalWrite(EN_PIN, HIGH);
delay(500);
Serial.begin(115200); // Init serial port and set baudrate
while (!Serial); // Wait for serial port to connect
Serial.println("\nStart...");
//SERIAL_PORT.begin(115200);
driver.beginSerial(115200);
driver.begin();
// driver.pdn_uart(true);
//driver.en_spreadCycle(true);
//stepper.setCurrentPositionInSteps(0);
// Sets the slow decay time (off time) [1... 15]. This setting also limits
// the maximum chopper frequency. For operation with StealthChop,
// this parameter is not used, but it is required to enable the motor.
// In case of operation with StealthChop only, any setting is OK.
driver.toff(TOFF_VALUE);
// VACTUAL allows moving the motor by UART control.
// It gives the motor velocity in +-(2^23)-1 [μsteps / t]
// 0: Normal operation. Driver reacts to STEP input.
// /=0: Motor moves with the velocity given by VACTUAL.
// Step pulses can be monitored via INDEX output.
// The motor direction is controlled by the sign of VACTUAL.
//driver.VACTUAL(10000);
// Comparator blank time. This time needs to safely cover the switching
// event and the duration of the ringing on the sense resistor. For most
// applications, a setting of 16 or 24 is good. For highly capacitive
// loads, a setting of 32 or 40 will be required.
driver.blank_time(24);
driver.rms_current(750); // mA
driver.microsteps(128); //microsteps 1/2, 1/4, 1/8, 1/16, 1/32, 1/64, 1/128 1/256
// Lower threshold velocity for switching on smart energy CoolStep and StallGuard to DIAG output
driver.TCOOLTHRS(0xFFFFF); // 20bit max
// CoolStep lower threshold [0... 15].
// If SG_RESULT goes below this threshold, CoolStep increases the current to both coils.
// 0: disable CoolStep
driver.semin(5);
// CoolStep upper threshold [0... 15].
// If SG is sampled equal to or above this threshold enough times,
// CoolStep decreases the current to both coils.
driver.semax(2);
// Sets the number of StallGuard2 readings above the upper threshold necessary
// for each current decrement of the motor current.
driver.sedn(0b01);
// StallGuard4 threshold [0... 255] level for stall detection. It compensates for
// motor specific characteristics and controls sensitivity. A higher value gives a higher
// sensitivity. A higher value makes StallGuard4 more sensitive and requires less torque to
// indicate a stall. The double of this value is compared to SG_RESULT.
// The stall output becomes active if SG_RESULT fall below this value.
driver.SGTHRS(STALL_VALUE); //stallvalue
Serial.print("\nTesting connection...");
uint8_t result = driver.test_connection();
if (result) {
Serial.println("failed!");
Serial.print("Likely cause: ");
switch (result) {
case 1: Serial.println("loose connection"); break;
case 2: Serial.println("no power"); break;
}
Serial.println("Fix the problem and reset board.");
// We need this delay or messages above don't get fully printed out
delay(100);
abort();
}
Serial.println("OK");
}
void loop() {
driver.VACTUAL(5120); // motor speed
Serial.print(driver.SG_RESULT() < STALL_VALUE, DEC); //check for stall
Serial.print("\n ");
Serial.print(driver.SG_RESULT()); // Motor load
}
my test setup: Note: DIAG is NOT on
But I would highly suggest you do not try to use driver definitions that do not match your hardware. You were setting all kinds of bits unintentionally. The code below works but is not how you should do it. The Release v1 branch supports the TMC2300 so I would suggest using that instead. I'll try to port this over to that branch when I have the time.
#include <Arduino.h>
#include <TMCStepper.h>
#define STALL_VALUE 60// [0... 255]
#define EN_PIN 8 // Enable pin
#define VIO_PIN 19 // Driver VIO pin used for resetting the driver
#define SW_RX 2 // SoftwareSerial receive pin
#define SW_TX 3 // SoftwareSerial transmit pin
//#define SERIAL_PORT 0 // HardwareSerial port
#define DRIVER_ADDRESS 0b00 // TMC2209 Driver address according to MS1 and MS2
#define DIAG_PIN 6 // diag input
#define R_SENSE 0.11f // Match to your driver
TMC2209Stepper driver(SW_RX, SW_TX, R_SENSE, DRIVER_ADDRESS);
using namespace TMC2209_n;
void setup() {
pinMode(EN_PIN, OUTPUT);
pinMode(DIAG_PIN, INPUT);
pinMode(VIO_PIN, OUTPUT);
digitalWrite(EN_PIN, LOW);
digitalWrite(EN_PIN, HIGH);
digitalWrite(VIO_PIN, LOW);
delay(500);
digitalWrite(VIO_PIN, HIGH);
Serial.begin(115200); // Init serial port and set baudrate
while (!Serial); // Wait for serial port to connect
Serial.println("\nStart...");
driver.beginSerial(19200);
driver.toff(1);
driver.irun(20);
driver.microsteps(128); //microsteps 1/2, 1/4, 1/8, 1/16, 1/32, 1/64, 1/128 1/256
driver.TCOOLTHRS(0xFFFFF); // 20bit max
driver.SGTHRS(50);
Serial.print("\nTesting connection...");
uint8_t result = driver.test_connection();
if (result) {
Serial.println("failed!");
Serial.print("Likely cause: ");
switch (result) {
case 1: Serial.println("loose connection"); break;
case 2: Serial.println("no power"); break;
}
Serial.println("Fix the problem and reset board.");
// We need this delay or messages above don't get fully printed out
delay(100);
abort();
}
Serial.println("OK");
driver.VACTUAL(15120); // motor speed
}
void loop() {
Serial.print(100 * digitalRead(DIAG_PIN)); //check for stall
Serial.print("\t");
Serial.print(driver.SG_RESULT()); // Motor load
Serial.print("\n ");
}
#include <Arduino.h>
#include <TMCStepper.h> // Branch: Release_v1
constexpr uint8_t EN_PIN = 8;
constexpr uint8_t VIO_PIN = 19;
constexpr uint8_t SW_RX = 2;
constexpr uint8_t SW_TX = 3;
constexpr uint8_t DIAG_PIN = 6;
constexpr uint8_t sgthrs = 130;
constexpr uint8_t semin = 6;
constexpr uint8_t semax = 2;
TMC_HAL::SWSerial ser(SW_RX, SW_TX); // Provides half-duplex mode
TMC2300Stepper driver(ser, 0.11, 0);
void setup() {
pinMode(EN_PIN, OUTPUT);
pinMode(DIAG_PIN, INPUT);
pinMode(VIO_PIN, OUTPUT);
Serial.begin(115200); // Init serial port and set baudrate
while (!Serial); // Wait for serial port to initialize
digitalWrite(VIO_PIN, LOW); // Reset driver memory
delay(50);
digitalWrite(VIO_PIN, HIGH);
driver.beginSerial(19200); // Set SW UART baudrate
auto version = driver.version();
while (version == 0) {
delay(10000);
Serial.print("Communication error ");
}
driver.GSTAT(0b111); // Reset error flags
driver.enable_drv(true); // Unnecessary as 1 is default
driver.rms_current(800);
driver.microsteps(128);
driver.TCOOLTHRS(0x3FF); // 10bit max
driver.semin(semin); // If SG value is below this * 32, the current will be increased
driver.semax(semax); // If SG value is over (this + semin + 1) * 32, the current will be decreased
driver.sedn(0b00); // Set current reduction rate
driver.seup(0b01); // Set current increase rate
driver.SGTHRS(sgthrs); // If SG value falls below this * 2 then the diag output will become active
digitalWrite(EN_PIN, HIGH);
driver.VACTUAL(50000);
Serial.println("StallGuard_value Actual_current Diag_pin semin semax sgthrs");
}
void loop() {
delay(100);
char buffer[128];
snprintf(buffer, sizeof(buffer), "%u %u %u %u %u %u",
driver.SG_VALUE(),
driver.cs2rms(driver.cs_actual()),
100 * digitalRead(DIAG_PIN),
semin*32, (semin+semax+1)*32, sgthrs*2
);
Serial.println(buffer);
}
Great, but when does v1 release so I can try this out? I'm currently running v0.71
You can try it out whenever you want. You just need to pull or download a different branch.
It's working.. kinda. My StallGuard value is consistantly very low, 200 max. without load. And actual current is unaffected. Any idea what could be causing this?
The value can depend on current, speed, motor characteristics and more. What more important is you get a response to applied load.
Is there any benefit in using the DIAG pin, instead of monitoring the stallguard value in software?
If i'm doing a simple homing, something like this where i'm waiting for the SG to hit 0.
driver.VACTUAL(-3000);
while (driver.SG_RESULT()!=0) {};
driver.VACTUAL(0);
Also, sorry if this interferes.. did not want to open a separate issue for this.
Hi cranefist.
In my experience monitoring in software is too unreliable and slow for my usage. Beside that I'm using DIAG as an interrupt in my program.