teemuatlut / TMCStepper

MIT License
514 stars 202 forks source link

TMC5160 consumes more current than configured, power supply is turned off with overcurrent protection #165

Open fenixil opened 3 years ago

fenixil commented 3 years ago

I use Bigtreetech TMC5160 v1.2 driver in the full SPI mode (SPI_MODE - high, SD_MODE - low). I set RMS current to 750mA however when there is a load on the stepper motor, driver sucks more current from the power supply and it is turned off with overcurrent protection. I noticed that the current can spike up to 2A when the motor stall. I see the same behavior for both StealthChop and SpreadCycle modes.

Why current exceeds configured RMS? Is there a way to limit the current so that my power supply is not turned off? How can I calculate max current which can be consumed by the motor?

Code for back and forth rotation of the steppers, just apply the load on the motor and monitor the current:

#include <TMCStepper.h> // https://github.com/teemuatlut/TMCStepper

#define MICROSTEPS 16

class DriverConfig {
private:
  constexpr static int32_t min_target_position = 100 * MICROSTEPS;

  Stream * serial;
  int32_t  target_position = min_target_position * 2;

public:
  DriverConfig(): DriverConfig(&Serial) {}
  DriverConfig(Stream * logger) { this->serial = logger; }

  uint32_t VSTART = 0;
  uint32_t VSTOP  = 100;

  uint32_t V1   = 5;
  uint32_t A1   = 1;
  uint32_t D1   = 5;
  uint32_t AMAX = 50;
  uint32_t DMAX = 50;
  uint32_t VMAX = 10 * 200 * MICROSTEPS;
  uint32_t RMS_CURRENT = 750; // mA

  int32_t targetPosition() { return target_position; }
  void    targetPosition(int32_t tp) {
    if(tp < min_target_position) {
      target_position = min_target_position;
      serial->print("WARNING: Target position cannot be less than ");
      serial->println(min_target_position);
    } else {
      target_position = tp;
    }
    serial->print("New Target Position:");
    serial->println(target_position / MICROSTEPS);
  }

  void printToSerial() {
    serial->print("{");
    uint32_t arrValues[] =
        {target_position, VSTART, VSTOP, V1, A1, D1, AMAX, DMAX, VMAX, RMS_CURRENT};
    char * arrTitles[] = {"target_position",
                          "VSTART",
                          "VSTOP",
                          "V1",
                          "A1",
                          "D1",
                          "AMAX",
                          "DMAX",
                          "VMAX",
                          "RMS_CURRENT"};
    for(int i = 0; i < sizeof(arrValues) / sizeof(uint32_t); i++) {
      serial->print(arrTitles[i]);
      serial->print(": ");
      serial->print(arrValues[i]);
      serial->print(", ");
    }

    serial->println("}");
  }

  void initializeDriver(TMC5160Stepper * drv) {
    drv->begin();
    testConnection(drv);
    applyStaticConfig(drv);
    apply(drv);
  };

  void testConnection(TMC5160Stepper * drv) {
    serial->print("\nTesting connection...");
    uint8_t result = drv->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->print("Driver firmware version: ");
    serial->println(drv->version());
  }

  void applyStaticConfig(TMC5160Stepper * drv) {
    // RAMPMODE:
    // 0: Positioning mode (using all A, D and V
    // parameters)
    // 1: Velocity mode to positive VMAX (using
    // AMAX acceleration)
    // 2: Velocity mode to negative VMAX (using
    // AMAX acceleration)
    // 3: Hold mode (velocity remains unchanged,
    // unless stop event occurs)
    drv->RAMPMODE(0);
    drv->en_pwm_mode(false);
    drv->pwm_autoscale(1);
    drv->pwm_autograd(0);
    drv->microsteps(MICROSTEPS);

    // Sets the upper velocity for StealthChop voltage PWM mode.
    // TSTEP ≥ TPWMTHRS
    // - StealthChop PWM mode is enabled, if configured
    // When the velocity exceeds the limit set by TPWMTHRS, the
    // driver switches to SpreadCycle.
    // 0: Disabled
    drv->TPWMTHRS(100);

    // This is the lower threshold velocity for switching on smart
    // energy CoolStep and StallGuard feature. (unsigned)
    // Set this parameter to disable CoolStep at low speeds, where it
    // cannot work reliably. The stop on stall function (enable with
    // sg_stop when using internal motion controller) and the stall
    // output signal become enabled when exceeding this velocity. In
    // non-DcStep mode, it becomes disabled again once the velocity
    // falls below this threshold.
    // TCOOLTHRS ≥ TSTEP ≥ THIGH:
    // - CoolStep is enabled, if configured
    // - StealthChop voltage PWM mode is disabled
    // TCOOLTHRS ≥ TSTEP
    // - Stop on stall is enabled, if configured
    // - Stall output signal (DIAG0/1) is enabled, if configured
    drv->TCOOLTHRS(100);

    // This velocity setting allows velocity dependent switching into
    // a different chopper mode and fullstepping to maximize torque.
    // (unsigned)
    // The stall detection feature becomes switched off for 2-3
    // electrical periods whenever passing THIGH threshold to
    // compensate for the effect of switching modes.
    // TSTEP ≤ THIGH:
    // - CoolStep is disabled (motor runs with normal current
    // scale)
    // - StealthChop voltage PWM mode is disabled
    // - If vhighchm is set, the chopper switches to chm=1
    // with TFD=0 (constant off time with slow decay, only).
    // - If vhighfs is set, the motor operates in fullstep mode
    // and the stall detection
    drv->THIGH(0xFFFF);

    // 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.
    drv->toff(3);
    // 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.
    drv->blank_time(36);

    // CoolStep lower threshold [0... 15].
    // If SG_RESULT goes below this threshold, CoolStep increases the current
    // to both coils. 0: disable CoolStep
    // 4-bit unsigned integer that sets a lower threshold.
    // If SG goes below this threshold, CoolStep
    // increases the current to both coils. The 4-bit
    // SEMIN value is scaled by 32 to cover the lower
    // half of the range of the 10-bit SG value. (The
    // name of this parameter is derived from
    // smartEnergy, which is an earlier name for
    // CoolStep.). threshold is SEMIN*32
    drv->semin(0);

    // CoolStep upper threshold [0... 15].
    // If SG is sampled equal to or above this threshold enough times,
    // CoolStep decreases the current to both coils.
    //     4-bit unsigned integer that controls an upper
    // threshold. If SG is sampled equal to or above this
    // threshold enough times, CoolStep decreases the
    // current to both coils. The upper threshold is
    // (SEMIN + SEMAX + 1)*32. threshold is (SEMIN+SEMAX+1)*32

    drv->semax(2);

    // Sets the number of StallGuard2 readings above the upper threshold
    // necessary for each current decrement of the motor current.
    drv->sedn(0b01);
  }

  void apply(TMC5160Stepper * driver) {
    driver->VSTART(VSTART);
    driver->VSTOP(VSTOP);
    driver->AMAX(AMAX);
    driver->V1(V1);
    driver->D1(D1);
    driver->A1(A1);
    driver->DMAX(DMAX);
    driver->VMAX(VMAX);
    driver->rms_current(RMS_CURRENT);
  }
};

// Drivers setup
#define ENABLE_PIN 8
#define CHIP_SELECT_1 9
#define CHIP_SELECT_2 7
DriverConfig * conf;
TMC5160Stepper driverLeft(CHIP_SELECT_1);
TMC5160Stepper driverRight(CHIP_SELECT_2);

void setup() {
  Serial.begin(250000);
  while(!Serial)
    ; // Wait for serial port to connect
  Serial.println("\nStart...");
  conf = new DriverConfig(&Serial);

  pinMode(ENABLE_PIN, OUTPUT);
  digitalWrite(ENABLE_PIN, HIGH);

  SPI.begin();

  conf->initializeDriver(&driverLeft);
  conf->initializeDriver(&driverRight);

  Serial.println("Enabling Drivers...");
  digitalWrite(ENABLE_PIN, LOW);
}

void loop() {
  static uint32_t    last_time             = 0;
  static signed char last_encoder_position = 0;
  static bool        forward;

  uint32_t ms = millis();

  // Serial control experiments
  while(Serial.available() > 0) {
    int8_t read_byte = Serial.read();
  }

  if((ms - last_time) > 100) { // run every 0.1s
    RAMP_STAT_t rs{driverLeft.RAMP_STAT()};
    if(rs.position_reached) {
      forward        = !forward;
      auto targetPos = forward ? conf->targetPosition() : 0;
      driverLeft.XTARGET(targetPos);
      // invert the position to rotate in the opposite direction
      driverRight.XTARGET(-targetPos);
      Serial.print("POS: ");
      Serial.println(targetPos);
    }

    last_time = ms;
  }
}
daniel-frenkel commented 3 years ago

RMS current is Root Mean Square. It is the average current used in the moment.

Max current is RMS x 1.41

Also be sure your sense resistor value is correct as that will affect the current

Antonio-Citati commented 2 years ago

Just a side question: is there any way to read the motor current from the TMC5160? Since it can limit the current allowed to the motor I guess there must be a measurement of it somewhere. Is this information somehow accessible?

daniel-frenkel commented 2 years ago

You can only read back the current that you set, you can’t monitor it in real time. I use my power supply to monitor current when testing things out.

Is there a reason you need to keep track of the current?

Remember that the current you set is the RMS current. It’s just an average and can max out at 1.41 times the RMS current that you set. The current is constantly changing depending on the load, speed, and acceleration.

On Apr 5, 2022, at 10:43 PM, Antonio-Citati @.***> wrote:

 Just a side question: is there any way to read the motor current from the TMC5160? Since it can limit the current allowed to the motor I guess there must be a measurement of it somewhere. Is this information somehow accessible?

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.

Antonio-Citati commented 2 years ago

Thank you for the reply, I know it is an RMS and that current always changes. I run with 2 TMC5160 the 2 motors of a totally automatic telescope on a gondola attached to a weather balloon at around 35km altitude and need to monitor power consumption closely as a way to optimize battery usage, and to address any issue which could lead to spikes in motor power consumption. Will just design circuit with additional 2 more current sensors. We have quite a few already and just wondered if these could be substituted by a current measurement function on the chip.

daniel-frenkel commented 2 years ago

That project sounds incredible. Do you have more info on it so I can learn more?

On Apr 6, 2022, at 8:41 PM, Antonio-Citati @.***> wrote:

 Thank you for the reply, I know it is an RMS and that current always changes. I run with 2 TMC5160 the 2 motors of a totally automatic telescope on a gondola attached to a weather balloon at around 35km altitude and need to monitor power consumption closely as a way to optimize battery usage, and to address any issue which could lead to spikes in motor power consumption. Will just design circuit with additional 2 more current sensors. We have quite a few already and just wondered if these could be substituted by a current measurement function on the chip.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.

issuefiler commented 1 year ago

Just a side question: is there any way to read the motor current from the TMC5160? Since it can limit the current allowed to the motor I guess there must be a measurement of it somewhere. Is this information somehow accessible?

CS_ACTUAL.