teemuatlut / TMCStepper

MIT License
502 stars 196 forks source link

Nano + TMC2130 - SPI/StallGuard #122

Closed luizzanotello closed 4 years ago

luizzanotello commented 4 years ago

hi,

thanks for the amazing lib!

i'm experienced using TMC2100 drivers, and i've recently bought a TMC2130 to try running it through SPI and thus have the amazing load sensing capacity of these drivers (StallGuard).

however, i have tried myriads of different setups and configurations and i cannot seem to be able to run these drivers in SPI mode. i've checked pinout, code, checked power supply, correct current limiting, checked board pins with a multimeter and etc and everything seems to be running fine.

am I missing something? or did i get very unlucky to have bought a brand new motor driver that came with its SPI interface faulty? the motor does not even block while on SPI mode! in standalone mode (non-spi, soldered pads bellow) it works just fine though.

details:

/pic: https://forum.arduino.cc/index.php?action=dlattach;topic=674978.0;attach=355111

/parts: https://shop.watterott.com/SilentStepStick-TMC2130-Stepper-Motor-Driver http://anleitung.joy-it.net/?goods=arduino-nano-v3

/code:

/**
 * Author Teemu Mäntykallio
 *
 * Plot TMC2130 or TMC2660 motor load using the stallGuard value.
 * You can finetune the reading by changing the STALL_VALUE.
 * This will let you control at which load the value will read 0
 * and the stall flag will be triggered. This will also set pin DIAG1 high.
 * A higher STALL_VALUE will make the reading less sensitive and
 * a lower STALL_VALUE will make it more sensitive.
 *
 * You can control the rotation speed with
 * 0 Stop
 * 1 Resume
 * + Speed up
 * - Slow down
 */
#include <TMCStepper.h>

#define MAX_SPEED        40 // In timer value
#define MIN_SPEED      1000

#define STALL_VALUE      15 // [-64..63]

#define DIR_PIN    5
#define STEP_PIN   6
#define EN_PIN    7
#define CS_PIN    10
#define SCK_PIN   17
#define SW_MOSI  11
#define SW_MISO  12
#define SW_SCK   13

#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
//TMC2130Stepper driver(CS_PIN, R_SENSE);                           // Hardware SPI
TMC2130Stepper driver(CS_PIN, R_SENSE, SW_MOSI, SW_MISO, SW_SCK);   // Software SPI

using namespace TMC2130_n;

#define STEP_PORT     PORTF // Match with STEP_PIN
#define STEP_BIT_POS      0 // Match with STEP_PIN

ISR(TIMER1_COMPA_vect){
  //STEP_PORT ^= 1 << STEP_BIT_POS;
  digitalWrite(STEP_PIN, !digitalRead(STEP_PIN));
}

void setup() {
  SPI.begin();
  Serial.begin(250000);
  while(!Serial);
  Serial.println("\nStart...");

  pinMode(EN_PIN, OUTPUT);
  pinMode(STEP_PIN, OUTPUT);
  pinMode(CS_PIN, OUTPUT);
  pinMode(DIR_PIN, OUTPUT);
  pinMode(MISO, INPUT_PULLUP);
  digitalWrite(EN_PIN, LOW);

  driver.begin();
  driver.toff(4);
  driver.blank_time(24);
  driver.rms_current(400); // mA
  driver.microsteps(16);
  driver.TCOOLTHRS(0xFFFFF); // 20bit max
  driver.THIGH(0);
  driver.semin(5);
  driver.semax(2);
  driver.sedn(0b01);
  driver.sgt(STALL_VALUE);

  // Set stepper interrupt
  {
    cli();//stop interrupts
    TCCR1A = 0;// set entire TCCR1A register to 0
    TCCR1B = 0;// same for TCCR1B
    TCNT1  = 0;//initialize counter value to 0
    OCR1A = 256;// = (16*10^6) / (1*1024) - 1 (must be <65536)
    // turn on CTC mode
    TCCR1B |= (1 << WGM12);
    // Set CS11 bits for 8 prescaler
    TCCR1B |= (1 << CS11);// | (1 << CS10);
    // enable timer compare interrupt
    TIMSK1 |= (1 << OCIE1A);
    sei();//allow interrupts
  }
}

void loop() {
  static uint32_t last_time=0;
  uint32_t ms = millis();

  while(Serial.available() > 0) {
    int8_t read_byte = Serial.read();
    #ifdef USING_TMC2660
      if (read_byte == '0')      { TIMSK1 &= ~(1 << OCIE1A); driver.toff(0); }
      else if (read_byte == '1') { TIMSK1 |=  (1 << OCIE1A); driver.toff(driver.savedToff()); }
    #else
      if (read_byte == '0')      { TIMSK1 &= ~(1 << OCIE1A); digitalWrite( EN_PIN, HIGH ); }
      else if (read_byte == '1') { TIMSK1 |=  (1 << OCIE1A); digitalWrite( EN_PIN,  LOW ); }
    #endif
    else if (read_byte == '+') { if (OCR1A > MAX_SPEED) OCR1A -= 20; }
    else if (read_byte == '-') { if (OCR1A < MIN_SPEED) OCR1A += 20; }
  }

  if((ms-last_time) > 100) { //run every 0.1s
    last_time = ms;

    DRV_STATUS_t drv_status{0};
    drv_status.sr = driver.DRV_STATUS();

    Serial.print("0 ");
    Serial.print(drv_status.sg_result, DEC);
    Serial.print(" ");
    Serial.println(driver.cs2rms(drv_status.cs_actual), DEC);
  }
}
teemuatlut commented 4 years ago

The motor should move if a few things are configured properly Off time (toff) is not 0. Run current (irun) is sufficient. Enable line is pulled low. VMOT is as per specifications. Step pin changes according to requested steps.

I'd suggest first getting the simple example working and experiment with stallGuard only after the very basic things are working properly. You can also tell a lot by testing if the motor is locked or free to rotate when powered on.

luizzanotello commented 4 years ago

hi! thank you for the reply and help! o/

i have done all that beforehand (code bellow for the Simple sketch). tried many types of configurations and settings as well. even when powered on, the motor does not lock nor moves. the only time it works, is by disabling spi and running the driver at standalone mode.

is there anything specific for the Nano and SPI that I am not aware of?

/**
 * Author Teemu Mäntykallio
 * Initializes the library and runs the stepper
 * motor in alternating directions.
 */

#include <TMCStepper.h>

#define EN_PIN           7  // Enable
#define DIR_PIN          5  // Direction
#define STEP_PIN         6  // Step
#define CS_PIN           10 // Chip select
#define SW_MOSI          11 // Software Master Out Slave In (MOSI)
#define SW_MISO          12 // Software Master In Slave Out (MISO)
#define SW_SCK           13 // Software Slave Clock (SCK)

#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
//TMC2130Stepper driver(CS_PIN, R_SENSE);                           // Hardware SPI
TMC2130Stepper driver(CS_PIN, R_SENSE, SW_MOSI, SW_MISO, SW_SCK);   // Software SPI

void setup() {
  pinMode(EN_PIN, OUTPUT);
  pinMode(STEP_PIN, OUTPUT);
  pinMode(DIR_PIN, OUTPUT);
  digitalWrite(EN_PIN, LOW);
  pinMode(SW_MISO, INPUT_PULLUP);
  pinMode(SW_MOSI, OUTPUT);
  pinMode(CS_PIN, OUTPUT);
  pinMode(SW_SCK, OUTPUT);

                                  // Enable one according to your setup
  SPI.begin();                    // SPI drivers
//SERIAL_PORT.begin(115200);      // HW UART drivers
//driver.beginSerial(115200);     // SW UART drivers

  driver.begin();                 //  SPI: Init CS pins and possible SW SPI pins
                                  // UART: Init SW UART (if selected) with default 115200 baudrate

  driver.toff(5);                 // Enables driver in software
  driver.rms_current(400);       // Set motor RMS current
  driver.microsteps(16);          // Set microsteps to 1/16th

  driver.en_pwm_mode(true);       // Toggle stealthChop on TMC2130/2160/5130/5160
//driver.en_spreadCycle(false);   // Toggle spreadCycle on TMC2208/2209/2224
  driver.pwm_autoscale(true);     // Needed for stealthChop
}

bool shaft = false;

void loop() {
  // Run 5000 steps and switch direction in software
  for (uint16_t i = 5000; i>0; i--) {
    digitalWrite(STEP_PIN, HIGH);
    delayMicroseconds(160);
    digitalWrite(STEP_PIN, LOW);
    delayMicroseconds(160);
  }
  shaft = !shaft;
  driver.shaft(shaft);
}
luizzanotello commented 4 years ago

i have found out by looking at this example from Watterott that the following TMC2130 registers were missing:

//TMC2130 registers
#define WRITE_FLAG     (1<<7) //write flag
#define READ_FLAG      (0<<7) //read flag
#define REG_GCONF      0x00
#define REG_GSTAT      0x01
#define REG_IHOLD_IRUN 0x10
#define REG_CHOPCONF   0x6C
#define REG_COOLCONF   0x6D
#define REG_DCCTRL     0x6E
#define REG_DRVSTATUS  0x6F

adding them to the code makes at least the motor run. however, StallGuard and the other features are still not yet running.

teemuatlut commented 4 years ago

Adding what where? Those are register addresses and the R/W flag. All of which are included in the library.

luizzanotello commented 4 years ago

i have no explanation as to why this has happened. but after uploading the code with the above register addresses, it worked. afterwards, i deleted the code, and it continued working. maybe it is something physical at my prototyping setup, i don't know.

but i am happy it worked, and I am surprised on how sensitive StallGuard can be. thanks for the support!