Using a TMC2209 silent stepper motor driver with an arduino

Hello!

I am trying to set up a TMC2209 silentstepstick driver with an Arduino Uno instead of the more commonly used main boards meant for 3D printers. There is next to no resources on how this should be done, and any testing I've done so far has yielded very different outcomes.

Can anyone guide me on a simple setup and code just for me to start to understand how to run the driver with an Arduino Uno?

As of now, my setup is to have the VM jumper and GND connected to a 12V power source, EN to pin 7 on the Arduino Uno, and STEP pin and DIR pin on positions 4 and 5 on the Arduino Uno respectively. I've been trying to get some output I can understand by playing around with the example codes on the TMCstepper.h library, but have had no luck understanding anything thus far.

Are there any modifications to the setup I should make? And are there any easy to understand codes I could use as a starting point?

Hi,
Welcome to the forum.

Please read the post at the start of any forum , entitled "How to use this Forum".
OR
http://forum.arduino.cc/index.php/topic,148850.0.html.
Then look down to item #7 about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Can you post a link to spec/data TMC2209 silentstepstick driver?

Thanks.. Tom.... :slight_smile:

Hello, I don't want to create a new post, but I have exactly the same problem as aoriginal author: I would like to drive a stepper motor with TMC2209, the only difference is, that I use ESP32

My wiring looks like this:


(Bigger image here )

I used the code from this example and adapted it to match my wiring:

/*
  SilentStepStick TMC2208/TMC2209 Example
  Rsense: 0.11 Ohm

  Other examples/libraries can be found here:
  https://github.com/teemuatlut/TMCStepper
  https://github.com/trinamic/TMC-API
  https://github.com/manoukianv/TMC2208Pilot

  Example source code free to use.
  Further information: https://learn.watterott.com/license/
*/

#include <Arduino.h>

// Note: You also have to connect GND, 5V/VIO and VM.
//       A connection diagram can be found in the schematics.
#define EN_PIN    14 //enable (CFG6)
#define DIR_PIN   4 //direction
#define STEP_PIN  2 //step

void setup()
{
  //set pin modes
  pinMode(EN_PIN, OUTPUT);
  digitalWrite(EN_PIN, HIGH); //deactivate driver (LOW active)
  pinMode(DIR_PIN, OUTPUT);
  
  digitalWrite(DIR_PIN, LOW); //LOW or HIGH
  pinMode(STEP_PIN, OUTPUT);
  digitalWrite(STEP_PIN, LOW);

  digitalWrite(EN_PIN, LOW); //activate driver
  //LED BUILT_IN is GPIO 33
  pinMode(33, OUTPUT); // Set the pin as output

  Serial.begin(115200);
  Serial.println("Booting");
}

void loop()
{
 
  //make steps
  Serial.println("High");
  digitalWrite(STEP_PIN, HIGH);
  delay(2);
  Serial.println("Low");
  digitalWrite(STEP_PIN, LOW);
  delay(2);

/*
  digitalWrite(33, LOW); //Turn on
  delay (1000); //Wait 1 sec
  digitalWrite(33, HIGH); //Turn off
  delay (1000); //Wait 1 sec
*/
}

I can confirm, that the ESP32 is running, I can see the "High"/"Low" messages in the serial console, I was able to blink the internal LED (the commented out code). But the motor doesn't move a bit.

Here few links to the stepper driver:

https://learn.watterott.com/de/silentstepstick/

1 Like

Hi,
Welcome to the forum.

You code is just about unreadable due to format commands, please read the post at the start of any forum , entitled "How to use this Forum".
OR
http://forum.arduino.cc/index.php/topic,148850.0.html.
Then look down to item #7 about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?
We need clearer wiring with reguard to the 12V supply, a hand drawn circuit will not limit you to so few component symbols.
Please identify components and their pinout labels.
They show more than a Fritzy picture.

What is your power supply?
Are you really using a ESP32CAM?
Are you using an ASM1117 module or just the IC?

Do you have a DMM?
Have you identified the correct pairing of the stepper wires?
What stepper motor do you have, specs/data link?

Thanks.. Tom.. :slight_smile:

Hello Tom and thank you very much!

I am sorry about that "unreadable" code, somehow copying the code from my Vscode editor was done as a HTML and converted with the color tags. I fixed it in my original post.

As requested, here is the wiring diagram:


(Original size)

My power-supply is a lab bench power supply set to 12V
I use ESP-32 CAM for two reasons:

  • I have one available
  • The motor should drive a baby swing for my newborn little girl, so the camera output can be nifty little upgrade :slight_smile: This is also the reason for the TMC2209 - I need a silent drive
  • I use an ASM1117 module

When DMM means a "Digital MultiMeter" than I have some
The motor description says 17HS4401S - is this one from german Amazon (The picture with a sleeping baby convinced me :smiley: )
I am not entirely sure about the motor-pair wiring, I found this image when searching for that motor type


My colors are different: 1. green 3. blue 4. black 6. red

Here is a picture of the wiring of the motor with the TMC2209


(Original Image)

Hi,
Use bigger step times, delay(2) is 2 milliseconds.
Try delay(100) to establish motor control.

Tom... :slight_smile:

I increased the step time

...

void loop()
{
 
  //make steps
  Serial.println("High");
  digitalWrite(STEP_PIN, HIGH);
  delay(100);
  Serial.println("Low");
  digitalWrite(STEP_PIN, LOW);
  delay(100);
}

but the motor does not move a bit. I can only see the "Low/High" in the serial console

Hi,
Check with DMM that EN is low ALL the time.

Put in delay to 5000, this will make the outputs pulse high and low for 5 seconds.
Check the step pin with DMM to see if you can see the 5 second pulse.

With the DMM check the four output pins on the driver, see if you can measure the 5 second pulses there?

ALL these measurements with respect to gnd.

Have you tried adjusting the current limit pot on the driver.
Check the voltage and current specs of the stepper. 3.6V 1.5A.

Tom... :slight_smile:

The EN pin is low, I even tried to put the EN on the driver to GND.

I can measure pulses on the ESP and on the STEP pin on the driver, I measure 3,16-3,18V. Maybe to low ? At the output of the ASM117 I measure 3,2V. Maybe I shall try another DC converter or 5V power supply ?

I already adjusted the the current limit as described here I used the calculator from the FYSTEC Wiki and set up the Vref to 1.7V which shall correspond to RMS of 1.2A. No luck so far

I got it! :smiley: The Problem lied in the TMC2209 pinout.

According to the description on the board I though the EN pin is the the second one from the edge but this is the MS1. Moving the EN to the right spot - the one on the edge solved a week of me-pulling-my-hair-out. So at least I got all the information summarized.

I was even able to use the TMCStepper library, even thought it might not be completely supported on ESP32 for the TMC2209. I used the example from here but you shall use the Hardware-Serial on ESP32, so I connected the Tx and Rx to pins 16 and 0 and had to initialize the Serial connection as:

#define RX2 16
#define TX2 0

...

SERIAL_PORT.begin(115200, SERIAL_8N1, RX2, TX2);

Full code example for the TMCStepper library is here:

#include <HardwareSerial.h>
#include <TMCStepper.h>

#define RX2 16
#define TX2 0
#define DIAG_PIN           15         // STALL motor 2
#define EN_PIN             14         // Enable
#define DIR_PIN             4         // Direction
#define STEP_PIN            2         // Step
#define SERIAL_PORT        Serial2    // TMC2208/TMC2224 HardwareSerial port
#define DRIVER_ADDRESS     0b00       // TMC2209 Driver address according to MS1 and MS2
#define R_SENSE            0.11f      // E_SENSE for current calc.  
#define STALL_VALUE        2          // [0..255]

hw_timer_t * timer1 = NULL;
TMC2209Stepper driver(&SERIAL_PORT, R_SENSE , DRIVER_ADDRESS );


void IRAM_ATTR onTimer() {

  digitalWrite(STEP_PIN, !digitalRead(STEP_PIN));
} 

void setup() {
  Serial.begin(250000);         // Init serial port and set baudrate
  while(!Serial);               // Wait for serial port to connect
  Serial.println("\nStart...");
  SERIAL_PORT.begin(115200, SERIAL_8N1, RX2, TX2);
  
  pinMode(DIAG_PIN ,INPUT);
  pinMode(EN_PIN ,OUTPUT);
  pinMode(STEP_PIN ,OUTPUT);
  pinMode(DIR_PIN ,OUTPUT);

  digitalWrite(EN_PIN ,LOW);
  digitalWrite(DIR_PIN ,LOW);

  driver.begin();
  driver.toff(4);
  driver.blank_time(24);
  driver.rms_current(500); 
  driver.microsteps(16);
  driver.TCOOLTHRS(0xFFFFF); // 20bit max
  driver.semin(0);
  driver.semax(2);
  driver.shaft(false);
  driver.sedn(0b01);
  driver.SGTHRS(STALL_VALUE);

  activate_interrupt();
}

void loop() {
 static uint32_t last_time=0;
 uint32_t ms = millis();
 if((ms-last_time) > 100) { //run every 0.1s
    last_time = ms;

    Serial.print("0 ");
    Serial.print(driver.SG_RESULT(), DEC);
    Serial.print(" ");
    Serial.println(driver.cs2rms(driver.cs_actual()), DEC);
  }
}

void activate_interrupt(){
  {
    cli();//stop interrupts
    timer1 = timerBegin(3, 8,true); // Initialize timer 4. Se configura el timer,  ESP(0,1,2,3)
                                 // prescaler of 8, y true es una bandera que indica si la interrupcion se realiza en borde o en nivel
    timerAttachInterrupt(timer1, &onTimer, true); //link interrupt with function onTimer
    timerAlarmWrite(timer1, 8000, true); //En esta funcion se define el valor del contador en el cual se genera la interrupción del timer
    timerAlarmEnable(timer1);    //Enable timer        
    sei();//allow interrupts
  }
}

I need to decide, whether the additional complexity os worth it - even with the simplest code the motor is 99.9% silent - I want to swing my baby girl, not a bat :D, with the TMCStepper library my bench power supply draws a little bit more current - 0.95A vs. 0.87A, but I might use StallGuard feature ...

I will also order another DC-DC step-down converter so I can utilize a 19V power supply from old notebook, since in my understanding the higher the motor voltage, the lower the current, or am I wrong ?

1 Like

thanks for yor experience share, it is hard to find non 3d printer related tmc2209 information.
i want to ask a question about wiring.
i am using 2 tmc2209 driver with arduino nano without problem, but i want to use stallguard feature. as i understand it requires rx tx connection but nano has only one rx tx pins. how can i overcome this problem?

Hi Worms,
Maybe you can try SoftwareSerial on Arduino Nano.

Hello

Do you still need to use DIR & STEP pins, even if you are using it through UART? You schematics show DIR & STEP pins are connected.. i was under the impression that you could control it completely through UART?

Actually, you have not connected UART at all? But still initialize the serial2 port?

I'm trying to control this through UART with the TMCStepper library, just that i can't get the motor to move.. but if i change the amperage.. it changes. So its definately communicating with the driver. I'm also using ESP32 Wroom.

Also, the UART2 pins are 16 & 17, not 16 and 0 ?

I think you are using the TMCStepper library without actually using it, your example code is the example on how to adjust your StallGuard... but as you are not using UART at all.. i dont think it does anything at all. You are just running in STEP/DIR mode and pasting that code for no reason whatsoever?

EDIT: So yeah, apparently you do still need STEP/DIR pins. Works fine now. I assume there is still some way to run this completely through the UART connection.

1 Like

Here is a simple code to get TMC2209 working with basic functionalities. Meaning; current & microsteps without fiddling with jumpers or that pesky potentiometer.

You only need one UART wire, just TX (PIN 17) to get it working. For receiving you need RX pin also, and i think a 1k ohm resistor between them (PIN 16). I dont have one, so i cant test it but the example tries to read the current microsteps to test the connection (it reads as 256 if the connection does not work). It also changes the current for forward & backwards to test it out.

It also shows how to move the motor via only the UART connection.

It also uses SpeedyStepper library, that needs to be added. Its a really simple library, that gives you control over accelerations and relative steps.

Especially if karlitos was making a gradle, you want to control the acceleration to make it really smooth.

Also, you need to connect EN to GND:d to enable the driver. No need to connect it to ESP32.

EDIT. Got the 1kohm resistor, and yes UART now works both ways. So this is the correct way to wire up the UART:


You only need this to read from the driver, and i think the only real use is the stallguard option that i personally need. But if this is not needed, you can just use one TX wire.

#include <SpeedyStepper.h> //Simple & good stepper library, get it.

#include <TMCStepper.h>

#define DIR_PIN          14 // Direction
#define STEP_PIN         12 // Step
#define SERIAL_PORT Serial2 // HardwareSerial port pins 16 & 17
#define DRIVER_ADDRESS 0b00 // TMC2209 Driver address according to MS1 and MS2

#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

bool shaft = false;  // ONLY NEEDED FOR CHANGING DIRECTION VIA UART, NO NEED FOR DIR PIN FOR THIS


TMC2209Stepper driver(&SERIAL_PORT, R_SENSE, DRIVER_ADDRESS);

SpeedyStepper stepper;

void setup() {

stepper.connectToPins(STEP_PIN, DIR_PIN); // INITIALIZE SpeedyStepper
  
SERIAL_PORT.begin(115200);      // INITIALIZE UART TMC2209
Serial.begin(115200);
delay(500);
Serial.println(F("Serial Initialized"));

  driver.begin();                // Initialize driver
                           
  driver.toff(5);                 // Enables driver in software

  driver.rms_current(600);       // Set motor RMS current
  driver.microsteps(2);            // Set microsteps to 1/2

  driver.pwm_autoscale(true);    // Needed for stealthChop
  driver.en_spreadCycle(true);   // false = StealthChop / true = SpreadCycle

  stepper.setCurrentPositionInSteps(0);                   // Set zero position
  stepper.setSpeedInStepsPerSecond(400);              //Set Speed
  stepper.setAccelerationInStepsPerSecondPerSecond(400);   //Set acceleration, smaller value for super smooth direction changing

}

void loop() {

uint16_t msread=driver.microsteps();
Serial.print(F("Read microsteps via UART to test UART receive : "));    Serial.println(msread); 
  
Serial.println(F("Move 6400 steps forward at 600ma"));
driver.rms_current(600); 
stepper.moveToPositionInSteps(6400);

Serial.println(F("Wait 3sec and turn current low so you can turn the motor shaft"));
driver.rms_current(10); 
delay(3000);

Serial.println(F("Move back to 0 position at 300ma"));
driver.rms_current(300); 
stepper.moveToPositionInSteps(0);

//MOVE MOTOR VIA UART AND CHANGE DIRECTION VIA SOFTWARE, IT RUNS AS LONG AS YOU LET IT... PROBABLY ONLY USEFUL WITH ENCODER. THE VALUE SETS ONLY THE SPEED.

driver.VACTUAL(16000); //SET SPEED OF MOTOR
delay(2000); // MOTOR MOVES 2 SEC THEN STOPS
driver.VACTUAL(0); //STOP MOTOR BY SETTING SPEED TO 0
shaft = !shaft; // REVERSE DIRECTION
driver.shaft(shaft); // SET DIRECTION

} 
2 Likes

A post was split to a new topic: TMC2209 with a SAMD chip

Hello, I used the same setup you did but I'm using an Elegoo Mega2560 and powering the TMC2209 VIO from the Mega's 3.3V output instead of an off-board regulator. I'm using a 24V power supply to VM (no decoupling capacitor) and driving a Moon's C17HD2024.

When I run the same code, I see on my voltage supply that I immediately hit maximum current, the voltage drops from my set voltage, and the motor does not move at all. Please advise?

Hey @monkeyfist thank you so much for deep insight, code works but my motor vibrates while moving!
Is there something I am missing? Should I provide a connection diagram?
Thanks in advance!

Does it still move normally? Usually if the movement is erratic, you just have the motor wires crossed.

Or you are trying to run it too fast and it cant keep up. Or the current is too low for the requested speed, in my example the currents are set to quite low levels.

Set the speed & acceleration to 400 to be sure.
Also, set spreadcycle off = driver.en_spreadCycle(false);
And microstepping to 0 = driver.microsteps(0);

It actually might be spreadcycle. It does not work well on all motors, and i think it needs to be tuned. It still uses stealthchop by default, so its still silent.

I updated the example, by commenting spreadcycle out and adding one line for stealthchop. And reduced the microsteps to 2. So it should work better as a starting point. Also reduced the speed & acceleration to 400.

Try that, if it wont help its probably crossed wires.. but that results in totally erratic movement.

2 Likes

Thank you so much @monkeyfist
I messed up wiring but now it is working.
I will consider other suggestions also you have mentioned.
PS: I am making a camera slider.
I will update schematics and starter guide for others to follow along.

Thanks again!

EDIT: Schematic

1 Like

No problem, this is the first search result for TMC2209 & arduino, so its good to have some stuff here. Its a pain to get started with all the uart hassle, and the TMC library can seem intimidating at first, as there are so many settings. Saves people some time if there is an easy starting point.

Its really powerful controller, the dynamic current control is super nice for battery powered applications. Its just gives you so much more control.

Im no expert and rely on the these libraries, at least i can contribute something this way :slight_smile:

2 Likes