teemuatlut / TMCStepper

MIT License
499 stars 194 forks source link

ESP32 compatibility #35

Open jangrewe opened 5 years ago

jangrewe commented 5 years ago

Hi, i wrote a sketch using your library on an Arduino Nano while waiting for an ESP32 to arrive, but when i tried to upload that sketch to the ESP32, VSCode threw an error that your library only supports the avr arch, which is a shame because of all the connectivity that the ESP32 provides.

Is there any chance you will make it also compatible with the ESP32 architecture?

Thanks!

WARNING: library TMCStepper claims to run on (avr) architecture(s) and may be incompatible with your current board which runs on (esp32) architecture(s).
foobar:39:61: error: invalid conversion from 'int' to 'Stream*' [-fpermissive]

 TMC2208Stepper driver = TMC2208Stepper(SW_RX, SW_TX, R_SENSE);

                                                             ^
teemuatlut commented 5 years ago

ESP32 is not listed as a SW Serial capable platform, mostly due to lack of testing, so there's not constructor to match that.

Try this branch where I added ESP32. Not sure how it works though. https://github.com/teemuatlut/TMCStepper/tree/esp32 (EDIT: Changes merged into master)

roberto1963 commented 5 years ago

Hello, I have tested this code for TMC2208 with ESP32.

#include <TMCStepper.h>
#define SW_RX            16 // TMC2208/TMC2224 SoftwareSerial receive pin
#define SW_TX            17 // TMC2208/TMC2224 SoftwareSerial transmit pin
#define EN_PIN    32  // LOW: Driver enabled. HIGH: Driver disabled
#define STEP_PIN  12  // Step on rising edge
#define SERIAL_PORT Serial2 // TMC2208/TMC2224 HardwareSerial port
#define R_SENSE 0.11  // SilentStepStick series use 0.11     Watterott TMC5160 uses 0.075
TMC2208Stepper driver = TMC2208Stepper(&SERIAL_PORT, R_SENSE); // Hardware Serial0

//***********************************************************************
void setup() { 
  Serial.begin(115200); 
  Serial2.begin(115200); // SW UART drivers
  pinMode(EN_PIN, OUTPUT);
  pinMode(STEP_PIN, OUTPUT);
  digitalWrite(EN_PIN, LOW);    // Enable driver in hardware

  driver.begin();               //  SPI: Init CS pins and possible SW SPI pins
  driver.rms_current(800);      // Set motor RMS current
  read_ms();
  driver.microsteps(16);     
  read_ms();

  driver.toff(5);               // Enables driver in software
//  driver.en_pwm_mode(true);     // Enable stealthChop
  driver.pwm_autoscale(true);   // Needed for stealthChop
}
//***********************************************************************
void read_ms() {
  uint16_t msread=driver.microsteps();
  Serial.print(" read:ms=");    Serial.println(msread); 
}
//***********************************************************************
void turn() {
  for(int i=0;i<=6400 ;i++) {
     digitalWrite(STEP_PIN, !digitalRead(STEP_PIN));
     delayMicroseconds(200); }
}
//***********************************************************************
void loop() {
  delay(1000);
  driver.shaft(0);  
  driver.microsteps(2);   
  read_ms();
  turn();

  delay(1000);
  driver.shaft(1);  
  driver.microsteps(32);   
  read_ms();
  turn();
}
//***********************************************************************

Connection works with hardware serial2 but microstep function doesn't works :

Did I made a mistake about microstep setting in this code ? Thanks.

teemuatlut commented 5 years ago

It seems I need to update the examples to add a few things for TMC2208.

Try adding this to setup:

  driver.pdn_disable(true);     // Use PDN/UART pin for communication
  driver.I_scale_analog(false); // Use internal voltage reference

You can also checkout the examples from the older TMC2208Stepper library https://github.com/teemuatlut/TMC2208Stepper/tree/master/examples

roberto1963 commented 5 years ago

I add these lines to setup and there is no change. So I test this new code and I had a look to the connection with a oscilloscope . Here is the code:

#include <TMCStepper.h>
#define SW_RX            16 // TMC2208/TMC2224 SoftwareSerial receive pin
#define SW_TX            17 // TMC2208/TMC2224 SoftwareSerial transmit pin
#define EN_PIN    32  // LOW: Driver enabled. HIGH: Driver disabled
#define STEP_PIN  12  // Step on rising edge
#define SERIAL_PORT Serial2 // TMC2208/TMC2224 HardwareSerial port
#define R_SENSE 0.11  // SilentStepStick series use 0.11     Watterott TMC5160 uses 0.075
TMC2208Stepper driver = TMC2208Stepper(&SERIAL_PORT, R_SENSE); // Hardware Serial0
//***********************************************************************
void setup() { 
  Serial.begin(115200); 
  Serial2.begin(115200); // SW UART drivers
  pinMode(EN_PIN, OUTPUT);
  pinMode(STEP_PIN, OUTPUT);
  digitalWrite(EN_PIN, LOW);    // Enable driver in hardware
  driver.begin();               //  SPI: Init CS pins and possible SW SPI pins
  driver.pdn_disable(true);     // Use PDN/UART pin for communication
  driver.I_scale_analog(false); // Use internal voltage reference
  driver.rms_current(800);      // Set motor RMS current
  driver.microsteps(16);     
  driver.toff(5);               // Enables driver in software
//  driver.en_pwm_mode(true);     // Enable stealthChop
  driver.pwm_autoscale(true);   // Needed for stealthChop
}
//***********************************************************************
void loop() {
  driver.microsteps(32);   
  uint16_t msread=driver.microsteps();
  Serial.print(" read:ms=");  
  Serial.println(msread); 
  delay(5000);
}
//***********************************************************************

Here is the screen capture of the signal with decoding : Capture_tmc2208

Hope this can help ? Thanks for your help .

roberto1963 commented 5 years ago

I finally found the solution . It was necessary to call the mstep_reg_select function with parameter=1 to set GCONF register of TMC2208 as indicated in TMC220x_TMC222x_datasheet_Rev1.07.pdf (chapter 5.1: General Registers , page 24) Here is a code with works for esp32.

#include <TMCStepper.h>
#define SW_RX            16 // TMC2208/TMC2224 SoftwareSerial receive pin
#define SW_TX            17 // TMC2208/TMC2224 SoftwareSerial transmit pin
#define EN_PIN    32  // LOW: Driver enabled. HIGH: Driver disabled
#define STEP_PIN  12  // Step on rising edge
#define SERIAL_PORT Serial2 // TMC2208/TMC2224 HardwareSerial port
#define R_SENSE 0.11  // SilentStepStick series use 0.11     Watterott TMC5160 uses 0.075
TMC2208Stepper driver = TMC2208Stepper(&SERIAL_PORT, R_SENSE); // Hardware Serial0
//***********************************************************************
void setup() { 
  Serial.begin(115200); 
  Serial2.begin(115200); // SW UART drivers
  pinMode(EN_PIN, OUTPUT);
  pinMode(STEP_PIN, OUTPUT);
  digitalWrite(EN_PIN, LOW);    // Enable driver in hardware
  driver.begin();               //  SPI: Init CS pins and possible SW SPI pins
  driver.pdn_disable(true);     // Use PDN/UART pin for communication
  driver.I_scale_analog(false); // Use internal voltage reference
  driver.rms_current(800);      // Set motor RMS current
  driver.mstep_reg_select(1);  // necessary for TMC2208 to set microstep register with UART
  driver.microsteps(16);     
  driver.toff(5);               // Enables driver in software
//  driver.en_pwm_mode(true);     // Enable stealthChop
  driver.pwm_autoscale(true);   // Needed for stealthChop
}
//***********************************************************************
void read_ms() {
  Serial.print(" read:ms=");    Serial.println(driver.microsteps()); 
}
//***********************************************************************
void turn() {
  for(int i=0;i<=6400 ;i++) {
     digitalWrite(STEP_PIN, !digitalRead(STEP_PIN));
     delayMicroseconds(400); }
}
//***********************************************************************
void loop() {
  delay(1000);   driver.shaft(0);   driver.microsteps( 2);  read_ms();  turn();
  delay(1000);   driver.shaft(1);   driver.microsteps( 4);  read_ms();  turn();
  delay(1000);   driver.shaft(0);   driver.microsteps( 8);  read_ms();  turn();
  delay(1000);   driver.shaft(1);   driver.microsteps(16);  read_ms();  turn();
  delay(1000);   driver.shaft(0);   driver.microsteps(32);  read_ms();  turn();
  delay(1000);   driver.shaft(1);   driver.microsteps(64);  read_ms();  turn();
}
//***********************************************************************
teemuatlut commented 5 years ago

Good catch. I should've taken a look at the init section in Marlin that would've pointed this out. Have you tried SW UART? I'd like to add STM32 as a SW Serial capable platform in the next release.

roberto1963 commented 5 years ago

I have tried to compile this code with software serial :

include

include

define SW_RX 16 // TMC2208/TMC2224 SoftwareSerial receive pin

define SW_TX 17 // TMC2208/TMC2224 SoftwareSerial transmit pin

define EN_PIN 32 // LOW: Driver enabled. HIGH: Driver disabled

define STEP_PIN 12 // Step on rising edge

define R_SENSE 0.11 // SilentStepStick series use 0.11 Watterott TMC5160 uses 0.075

TMC2208Stepper driver = TMC2208Stepper(SW_RX, SW_TX, R_SENSE); // Software serial // void setup() { Serial.begin(115200); pinMode(EN_PIN, OUTPUT); pinMode(STEP_PIN, OUTPUT); digitalWrite(EN_PIN, LOW); // Enable driver in hardware driver.begin(); // SPI: Init CS pins and possible SW SPI pins driver.pdn_disable(true); // Use PDN/UART pin for communication driver.I_scale_analog(false); // Use internal voltage reference driver.rms_current(600); // Set motor RMS current driver.mstep_reg_select(1); driver.microsteps(16);
driver.toff(5); // Enables driver in software driver.pwm_autoscale(true); // Needed for stealthChop } //
void loop() {}

But compilation is not ok . Here is the error message from Arduino IDE : TMC2208_esp32_test04_swser:8:61: error: invalid conversion from 'int' to 'Stream*' [-fpermissive] TMC2208Stepper driver = TMC2208Stepper(SW_RX, SW_TX, R_SENSE); // Software serial

Must I open a software serial object in my code ?

thalesfsp commented 5 years ago

@teemuatlut Do you have plans (roadmap) to implement support to the MKR platform? What's the difference between this library and the TMC2208Stepper?

Thanks!

teemuatlut commented 5 years ago

@roberto1963 Try the esp32 branch of the library. The SW Serial constructor is limited to approved platforms that have the required library implemented.

@thalesfsp I've never had any of the MKR boards but fundamentally the library could/should be compatible as long as there are the requires prerequisites, like an SPI library. This library supercedes the older TMC2208 and TMC2130. The change was made to accommodate the increasing number of TMC drivers as I didn't want to have separate libraries for each that I'd have to maintain. Much of the interface remains the same, except the yet-not-implemented helper methods, but the underlying architecture and structure is completely rewritten.

roberto1963 commented 5 years ago

I tried this code with the esp32 branch. The compilation is ok, but it does not work . The stepper makes just a turn. Then it doesn't turn any more . The esp32 chip continues to work, so the TMC2208 chip was probably blocked by communication?

#include <TMCStepper.h>
#define SW_RX            16 // TMC2208/TMC2224 SoftwareSerial receive pin
#define SW_TX            17 // TMC2208/TMC2224 SoftwareSerial transmit pin
#define EN_PIN    32  // LOW: Driver enabled. HIGH: Driver disabled
#define STEP_PIN  12  // Step on rising edge
#define R_SENSE 0.11  // SilentStepStick series use 0.11     Watterott TMC5160 uses 0.075
TMC2208Stepper driver = TMC2208Stepper(SW_RX, SW_TX, R_SENSE); // Software serial
//***********************************************************************
void setup() { 
  Serial.begin(115200); 
  pinMode(EN_PIN, OUTPUT);
  pinMode(STEP_PIN, OUTPUT);
  digitalWrite(EN_PIN, LOW);    // Enable driver in hardware
  driver.begin();               //  SPI: Init CS pins and possible SW SPI pins
  driver.pdn_disable(true);     // Use PDN/UART pin for communication
  driver.I_scale_analog(false); // Use internal voltage reference
  driver.rms_current(600);      // Set motor RMS current
  driver.mstep_reg_select(1);
  driver.microsteps(16);     
  driver.toff(5);               // Enables driver in software
  driver.pwm_autoscale(true);   // Needed for stealthChop
}
//***********************************************************************
void read_ms() {Serial.print(" read:ms=");   Serial.println(driver.microsteps());}
//***********************************************************************
void turn() {
  for(int i=0;i<=6400 ;i++) {
     digitalWrite(STEP_PIN, !digitalRead(STEP_PIN));
     delayMicroseconds(400); }
}
//***********************************************************************
void loop() {
  delay(1000);   driver.shaft(0);  driver.microsteps( 2);  read_ms();  turn();
  delay(1000);   driver.shaft(1);  driver.microsteps( 4);  read_ms();  turn();
  delay(1000);   driver.shaft(0);  driver.microsteps( 8);  read_ms();  turn();
  delay(1000);   driver.shaft(1);  driver.microsteps(16);  read_ms();  turn();
  delay(1000);   driver.shaft(0);  driver.microsteps(32);  read_ms();  turn();
}
//***********************************************************************
bdring commented 5 years ago

I have trouble with SoftwareSerial.h and ESP32 as well. I don't think that is included in the Arduino core for ESP32. I was able to get rid of the error by commenting out the ESP32 on this line in TMCStepper.h

#define SW_CAPABLE_PLATFORM defined(__AVR__) || defined(TARGET_LPC1768) // || defined(ARDUINO_ARCH_ESP32)

The ESP32 has 3 UARTS and 3 SPIs. I don't think soft version of these are needed in most applications.

phooji commented 5 years ago

@teemuatlut Happy to create a separate issue, but figured I'd try here first :)

Having looked over the code at current master, it looks like the ESP32 would still end up using the SW_SPI.cpp stuff; is that correct? If so, any interest in making that somewhat configurable? I might just jank it out locally and replace with one of the ESP32's hardware SPIs (which can then be mapped to most GPIO pins in hardware by specifying in the constructor). It'l be a little ugly, so it'd be great to know if I can potentially replace my kludge with a one-liner in the future :)

teemuatlut commented 5 years ago

If the code calls for the SW SPI constructor then the library sure will use the internal bit banging implementation. I'm not familiar with the ESP32 codebase but if you want you can make a pull request as a proof of concept and I can then refine it from there. A PoC does not need to be pretty =) I don't expect there to be a one-liner solution.

johnsmakar commented 4 years ago

ESP32 is not listed as a SW Serial capable platform, mostly due to lack of testing, so there's not constructor to match that.

Try this branch where I added ESP32. Not sure how it works though. https://github.com/teemuatlut/TMCStepper/tree/esp32 (EDIT: Changes merged into master)

I don't see in 0.7.1 master, is it still there?

teemuatlut commented 4 years ago

@johnsmakar See #59

OldCurmudgeon3DP commented 3 years ago

I have more than one sketch written before this thread started that uses SW serial. Maybe it's not relevant to this library, but the ESP32 can use it. If it's relevant, I'll have to dig back into the files to see what I changed to make it work. Andreas Spiess clued me into the process in one of his early ESP32 videos.

karlitos commented 3 years ago

Hello, I am coming here from this electronics.stackexchange post because I would like to drive a stepper motor with TMC2209 and ESP32.

I read though this thread and also looked at #59, but my understanding of the topic is not deep enough. Is there some possibility to use TMCStepper library on ESP32 or not ? Would be glad for an simple explanation, thanks.

teemuatlut commented 3 years ago

I believe the HW serial at least should work. I haven't done much (at all) testing with the ESP platform and the TMC drivers. But as long as the MCU sends out the correct UART signals, it should work. If you want a more tested setup, go with the 5160 as that has been proven by https://github.com/bdring/Grbl_Esp32

karlitos commented 3 years ago

Thanks for the answer. I actually found some more examples regarding ESP32 in other issues, event this repo 👍 I am unsure though, how is the wiring done with the HW serial - do I still connect the drivers Tx/Rx to the Tx/Rx pins on the ESP32 ?

Sorry for asking such noob questions - I am just a guy trying to get some silent motor drive for a swing oh his newborn baby girl :-) and so far I wasn't even able to get the motor running even using the simplest wiring.

teemuatlut commented 3 years ago

Watterott has gathered quite a lot of information about the TMC drivers they sell, including how to wire the serial based drivers. https://learn.watterott.com/silentstepstick/configurator/ Be sure to read their FAQ as well. In short, you connect the ESP RX to the driver UART pin and then the TX pin with a 1kOhm resistor.

When you think you've got the wiring done, the first thing you should test is if the communication works. 90% of the problems I see are issues with the communication. While I won't claim there can be no bugs in the code and I hope that people will report them if they find any, I try to keep in mind that the library is used by quite a few users in their 3D printers. You can read back the driver firmware version with Serial.println(driver.version());

And congrats on a new family member =)

karlitos commented 3 years ago

@teemuatlut Many thanks, dealing with the pinout of TMC2209 brought me to my problem - I the wiring for the EN pin was wrong. I used the ESP32 example from this repository, connected the Tx and Rx to Pins 16 and 0 and initialized the hardware serial connection as:

#define RX2 16
#define TX2 0

...

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

The motor spins now 😄 , I wonder if it is due to the working Hardware Serial connection or if the motor would spin even if the serial connection would not work

teemuatlut commented 3 years ago

The 2208/9 have defaults in OTP memory and the driver is functional even without working comms. This all makes it a bit more confusing when the motor happily spins but you cannot change the configuration at all.

kirax999 commented 3 years ago

Do any of you finally get it to work?

I ended up finding ... for get example go to https://forum.arduino.cc/t/using-a-tmc2209-silent-stepper-motor-driver-with-an-arduino/666992/10

You copy and past laste code


#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
  }
}

After copy if you not find data by your driver change addr

#define DRIVER_ADDRESS 0b00 for #define DRIVER_ADDRESS 0b01 or 0b10 or 0b11

here are the pins that I use on my ESP

define RX2 GPIO_NUM_16

define TX2 GPIO_NUM_17

define DIAG_PIN GPIO_NUM_27 // STALL motor 2

define EN_PIN GPIO_NUM_13 // Enable

define DIR_PIN GPIO_NUM_25 // Direction

define STEP_PIN GPIO_NUM_14 // Step

define SERIAL_PORT Serial2 // TMC2208/TMC2224 HardwareSerial port

define DRIVER_ADDRESS 0b01 // TMC2209 Driver address according to MS1 and MS2a

define R_SENSE 0.11f // E_SENSE for current calc.

define STALL_VALUE 2 // [0..255]

and I have a resistance between TX and RX of 1kohm, and my cable from the TX pin to the PDN pin

teemuatlut commented 3 years ago

See this comment for ESP32 and the UART based drivers https://github.com/teemuatlut/TMCStepper/issues/192#issuecomment-831432951

vitalibr commented 3 years ago

See this comment for ESP32 and the UART based drivers #192 (comment)

teemuatlut, I've read this topic and others a few times, looked at the datasheet, tried dozens of codes

I can't understand what's wrong with my test, nothing I do works for esp32 and tmc2208 (fysetec) communication via UART. I tested the UART communication of my driver through the computer, it worked perfectly, I can open it via ScriptCommunicator, as described here: https://wiki.fysetc.com/TMC2208/#setting-method

the last code I tested was this

#include <TMCStepper.h>

#define EN_PIN 32
#define STEP_PIN 12      
#define SERIAL_PORT Serial1
#define R_SENSE 0.11

TMC2208Stepper driver = TMC2208Stepper(&SERIAL_PORT, R_SENSE);
void setup()
{
    Serial.begin(115200);
    Serial1.begin(115200);
    pinMode(EN_PIN, OUTPUT);
    pinMode(STEP_PIN, OUTPUT);
    digitalWrite(EN_PIN, LOW); 
    driver.begin();             
    driver.pdn_disable(true);     
    driver.I_scale_analog(false); 
    driver.rms_current(800);   
    driver.mstep_reg_select(1);   
    driver.microsteps(16);
    driver.toff(5);        
    driver.pwm_autoscale(true);
}

void loop()
{
    delay(10000);
    uint8_t result = driver.test_connection();
    Serial.println(result);
}

The result is always 2

tomfanning commented 3 years ago

Same here @vitalibr

Roxolasu commented 2 years ago

I had exactly the same problems as @vitalibr with a TMC2208 and ESP8266.

I found the problem using a scope:

I don't know if its the library, or something on the board (D1 Mini).

Solution: Use a lower value resistor between RX and TX, to pull LOW sufficiently low. 500 Ohms wasnt enough for me, but 330 Ohms seems to work fine.