ESP32, TMC2209, and UART Control of Microstepping

Mod edit:
Moved to jobs at the request of the OP who would like to commission someone to help with this. I leave the OP to provide the details.

Hi there-

I am attempting to drive a stepper with a simple bit of code. This project has evolved considerably since I first posted about it, so I am re-editing the initial post right now and changing the subject header. The original text of the first message will be reproduced below the hyphenated line, for the sake of historical preservation - but the real question, which begins around Post #22 revolves around this:

I am currently using an ESP32, a TMC2209, and a basic 12v, 1.5A NEMA17 Motor with 1.8 degrees/200 steps-per-revolution. I have the Step and Dir pins attached to the ESP32, as well as the TX/RX Pins (with specified 1k resistor) connected for the purpose of UART control.

My interest at this point is getting to "Fullstep" resolution - which, with ESP32's clock speeds of around 30khz, should be able to produce 1125 RPM or 18.75 rotations per second.

In order to do this, I apparently need to use MobaTools, since other stepper libraries do not meet the necessary spec... so I am trying to understand how to use MobaTools to provide a microstepping message to produce the desired RPM. Thanks!


Original Message:

I am attempting to drive a stepper with a simple bit of code.
The Arduino is attached to a driver board (pin 1 is the stepper, pin 4 is the direction control) and the board is connected to a two-phase motor. It is powered by 12v. This works well until I added the negative values, in order to create forward and backwards motion.
Now, the motor seems to pause every few seconds, but works as expected otherwise.

Any idea what causes this pause?


#include <AccelStepper.h>

// Define the stepper motor and the pins that is connected to
AccelStepper stepper1(1, 4, 1); // (Type of driver: with 2 pins, STEP, DIR)

void setup() {
  // Set maximum speed value for the stepper
  stepper1.setMaxSpeed(4096);
}

void loop() {
  stepper1.setSpeed((analogRead(A0)*8)-4096);
  // Step the motor with a constant speed previously set by setSpeed();
  stepper1.runSpeed();
}

the doc states that "Speeds of more than 1000 steps per second are unreliable"

can you try with

  int speed = analogRead(A0)-512;
  if ((speed > -20) && (speed < 20)) speed = 0; // create a dead zone in the middle
  stepper1.setSpeed(speed);
  stepper1.runSpeed();

Hi @J-M-L - your code runs better, but there are still pauses. It seems to me that the TMC2209 is overheating (evidenced by a light turning on when the pause occurs). It does have a heat sink, though. Maybe I need to adjust the trimpot?

The other thing, though, is that the maxSpeed of 1000 seems dreadfully slow. It is maybe around 6 times a minute for a 1.8 degree motor? Does that sound right?

No -- 1000pps/200ppr = 5 rev/sec. Times 60 gives 300rpm.

Have you not done this yet? Setting the coil current correctly is mandatory.
Please provide the technical data of your stepper (datasheet).

I dont know that TMC2209… can’t say

Here is the datasheet.

It's a two-phase motor and I'm using a 12v 3A power supply.
My understanding is that each phase wants roughly around 1A, so according to my equations, that puts me at reference voltage of 1.53v.
Is that correct?

Readjusting the trim (it seems to have drifed since the last use) has seemingly stopped the "pausing"/overheating issue. But I'm still getting roughly 60 RPM.

Did you adjust the current? 2A as continuous current is too much for the TMC2209. For continuous movement you shouldn't go above 1.4A

How is microstepping set?

Microstepping inputs

Yes - It required UART for a "full-step" speed, which definitely comes closer to 300 RPM. It's looking like I might need it to hit something around 600 RPM, though, still - is there a better stepper for this task?

The problem with AccelStepper is you can either use a blocking function for step-pulse-creation which means your code can do nothing else than step-pulses
or
you use the non-blocking function and then the maximum step-pulse-frequency depends on
how fast your function

void loop() is looping

If you have set microstepping to MS1 = 0 and MS2 = 0 it is 1/8 microstepping
This means on a 1.8 degree-motor which is 360 °/^.8° = 200 fullsteps per revolution

200 * 8 = 1600 steps per revolution

Let's assume your function loop is able to create step-pulses at a rate of 3200 steps per second
this would be 3200 / 1600 = 2 revoltions per second = 120 rpm

You haven't told anything about what microcontroller you are using.

"classical" arduinos like Ardunio Uno or Arduino Mega are limited to 2000 to 4000 steps per second.

Higher clocked microcontrollers like ESP32 can create much higher step-pulse-frequencies
The MobaTools library offers a maximum of 30.000 step-pulses per second

30000 steps per second which would result in

30000 / 1600 = 18.75 rev per second 30000 / 1600 * 60 = 1125 rpm

What would be the problem to use UART-mode of the TMC2209 to adjust to halfstep-mode?

You haven't written anything about your final application. The most common standard is 1.8 degree per step = 200 fullsteps per revolution

Surely you can buy stepper-motors with less than 200 fullsteps per revolution but they are not very common.

You might mean not the stepper but a stepper-driver.
Sure there are a lot of other stepper-drivers which over fullstep / halfstep configuration through hardware inputs

Depending on the current you really need A4988 (1 Ampere) DRV8825 (1 Ampere)

I think it is really time that you describe your project. What is the final purpose of rotating the stepper-motor at 600 rpm?

It might even turn out that a different type of motor would be better suited for your project
best regards Stefan

1 Like

Ah, yes, let me fill in some blanks here. My apologies. Thank you for the explanations, though, @StefanL38. It is very helpful to see the math, for me.

I am using an Arduino Nano at the moment, although I just ordered some micros and some ESP32s to experiment with, for various projects. I'm not sure if the Micro can provide a better step-pulse frequency - but it sounds like the ESP32 will be an interesting development.

The code I am using is posted here...I thought it would make sense to start a new thread, since I am no longer using AccelStepper and the "pause" issue seems, at least for the time-being, to have ceased. Out of curiosity, what happens when you attempt to code more step-pulses per second than the Arduino can actually produce? I suspect I have run into that now.

If I understand you correctly, there's no reason this motor cannot go faster than 300 RPM - it's just a matter of sending it a sufficiently fast pulse-step. I have also switched to UART, which hopefully simplifies things on that end also.

As for the nature of the project, I am using it as a percussive musical instrument - which is why there is such an emphasis on keeping it as-silent-as-possible, while having the ability to go to such extremely low speeds. I am noticing that the TMC2209 is not exactly "silent" either - but the sine wave tends to be more pleasant than other motor noise I've encountered.

Thanks again!

Hi

aha as a musical instrument. Still you did not tell very much about it.
It still might be a better choice to use a different kind of motor like a DC-motor
a synchron-motor or a brushless-motor

further more depending on what kind of musical instrument this is choosing a bigger stepper-motor driven at a rather small current to get it silent again might be an option too.

Though without a really detailed description of your musical instrument it is impossible to give any advice.

Hammond Organs are driven by a motor too. I don't own one but as it is a real instrument which can be played "soft" and or at low volume I assume that the electrical motor is pretty quiet too.

If your budget is not limited to $50 I suggest that you use a Teensy 4.0 or Teensy 4.1

A teensy 4.0 has a clock-frequency of 600 MHz. I have tested creating pulses with frequencies high as 200 kHz which means
at 1/256 steps: 200000 / (200 * 256) * 60 = 234 rpm
or
at
1/ 64 steps: 200000 / (200 * 64) * 60 = 937.5 rpm

A teensy 4.0 is around $40 but for a musical instrument this should be worth it.

https://www.pjrc.com/store/teensy40.html

2 Likes

Alright - I went for the ESP32 because my budget is a bit limited.

I used the code, posted below, and it works - but it still seems to be limited, in terms of speed. It is from this thread.

What I'm curious about still, though, is how to access the 30,000 step-pulses-per-second. The basic code below seems to do nothing if the baud-rate is increased. Can anyone help me to find more details about increasing the speed?

Thanks!

#include "FastAccelStepper.h"
#include <TMCStepper.h>

#define STEP_PIN 2
#define DIR_PIN 15

#define RXD2 16
#define TXD2 17

#define SHAFT true

#define SERIAL_PORT_2 Serial2  // TMC2208/TMC2224 HardwareSerial port - pins 16 & 17
#define DRIVER_ADDRESS_1 0b00    // TMC2209 Driver address according to MS1 and MS2
#define R_SENSE 0.11f          // E_SENSE for current calc, SilentStepStick series use 0.11

FastAccelStepperEngine engine = FastAccelStepperEngine();
FastAccelStepper *stepper = NULL;

TMC2209Stepper driver(&SERIAL_PORT_2, R_SENSE, DRIVER_ADDRESS_1);  // Create TMC driver

int current = 1500;
int stall = 10;
int accel = 8000;
int max_speed = 19000;
int tcools = (3089838.00 * pow(float(max_speed), -1.00161534)) * 1.5;  //*64 after max speed

int motor_microsteps = 16;
int motor_steps_per_rev = 200;

void setup() {
  pinMode(DIR_PIN, OUTPUT);
  pinMode(STEP_PIN, OUTPUT);

  // INTITIALIZE SERIAL0 ITERFACE
  Serial.begin(115200);
  delay(500);
  Serial.println(F("---------------------------------------------------"));
  Serial.println(F("UART0 serial output interface intitialized @ 115200"));

  // INITIALIZE SERIAL2 UART FOR TMC2209
  SERIAL_PORT_2.begin(115200);  // INITIALIZE UART TMC2209, SERIAL_8N1, 16, 17
  Serial.println(F("UART2 interface for TMC2209 intitialized   @ 115200"));
  Serial.println(F("---------------------------------------------------"));

  //TMCSTEPPER SETTINGS
  driver.begin();
  driver.pdn_disable(true);      // Use PDN/UART pin for communication
  driver.toff(5);                // [1..15] enable driver in software
  driver.blank_time(24);         // [16, 24, 36, 54]
  driver.I_scale_analog(false);  // Use internal voltage reference
  driver.rms_current(current);   // motor RMS current (mA) "rms_current will by default set ihold to 50% of irun but you can set your own ratio with additional second argument; rms_current(1000, 0.3)."

  driver.mstep_reg_select(true);
  read_ms();
  driver.microsteps(motor_microsteps);  //note that MicroPlyer will interpolate to 256
  read_ms();

  driver.TCOOLTHRS(tcools);
  driver.seimin(1);  // minimum current for smart current control 0: 1/2 of IRUN 1: 1/4 of IRUN
  driver.semin(0);
  driver.iholddelay(3);  // 0 - 15 smooth current drop
  driver.shaft(SHAFT);
  driver.intpol(true);  // interpolate to 256 microsteps
  driver.SGTHRS(stall);

  driver.pwm_autoscale(true);    // Needed for stealthChop
  driver.en_spreadCycle(false);  // false = StealthChop / true = SpreadCycle, Spreadcycle can have higher RPM but is louder
  driver.internal_Rsense(false);
  driver.TPWMTHRS(0);

  engine.init();
  stepper = engine.stepperConnectToPin(STEP_PIN);
  stepper->setDirectionPin(DIR_PIN);
  stepper->setAutoEnable(true);

  stepper->setSpeedInHz(max_speed);
  stepper->setAcceleration(accel);
}

//***********************************************************************
void read_ms() {
  uint16_t msread = driver.microsteps();
  Serial.print("Microsteps: ");
  Serial.println(msread);
}
//***********************************************************************

void loop() {

  driver.microsteps(16);
  read_ms();
  driver.VACTUAL(19000);  //SET SPEED OF MOTOR
  delay(3000);            // MOTOR MOVES 2 SEC THEN STOPS


  driver.VACTUAL(0);  //STOP MOTOR BY SETTING SPEED TO 0
  delay(1000);

  driver.microsteps(0);
  read_ms();
  driver.VACTUAL(-19000);  //SET SPEED OF MOTOR
  delay(3000);             // MOTOR MOVES 2 SEC THEN STOPS

  driver.VACTUAL(0);  //STOP MOTOR BY SETTING SPEED TO 0
  delay(1000);
}

works only with the MobaTools library

OK - now using MobaTools library - and the basic example code, as posted below, modified to put out a speed of 25,000 (30,000 doesn't seem to operate as expected). Having said that, I'm not sure if it is actually coming in at 1125 RPM - it seems a bit slower than that.

I'm wondering if there a way to further adjust/specify the microstep control that I am missing. The TMC2209 is connected to the ESP32 via UART, so I am wondering if there is an additional command.

Thanks for all the help!

/* ====== minimumStepper =======================================
 *  Bare minimum to get a stepper with step/dir driver turning
 */
#include <MobaTools.h>
// Stepper connections - Please adapt to your own needs.
const byte stepPin = D6;
const byte dirPin = D5;

const int stepsPerRev = 200;    // Steps per revolution - may need to be adjusted

MoToStepper stepper1( stepsPerRev, STEPDIR );  // create a stepper instance

void setup() {
  stepper1.attach( stepPin, dirPin );
  stepper1.setSpeed( 25000 );              // 30 rev/min (if stepsPerRev is set correctly)
  stepper1.setRampLen( stepsPerRev / 2); // Ramp length is 1/2 revolution
  stepper1.rotate(1);                    // start turning, 1=vorward, -1=backwards                    
}

void loop() {
}

From the TMC2209 datasheet, it looks like a combination of the UART GCONF and MRES registers would produce 1,2,4,8,16,32,64,128, or 256 step microstepping. So you might be able to get 8x the RPM per steps/sec as with the pin-coded MS1_AD0&MS2_AD1 = 0b00 8-step microstepping.