This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

DRV8711: Increasing torque to Stepper Motor

Part Number: DRV8711
Other Parts Discussed in Thread: ENERGIA, MSP430G2553,

Hi,

I've written code to drive a 4 Amp stepper motor.  I'm using an MSP430 launchpad with a boost-drv8711.  Everything is working well, except it doesn't have enough torque for my application.  This same motor is being driven by another motor controller in the same application without difficulty.  With the boost-drv8711 i'm seeing about 0.2 amps RMS being driven to the motor, but the motor is capable of 4Amps.  What techniques can I use to increase torque.  I've played around with various settings in the 8711 register and nothing seems to change anything.  I've copied the code that writes the settings I'm currently writing to the registers for reference.

Thanks

Matt

_____________________________________________________________________________

#define CCW_16_Enable 0x25
#define CW_16_Enable 0x27
#define CCW_16_Disable 0x24
#define CW_16_Disable 0x26

//CTRL Register defaults
unsigned char CTRLdataHi, CTRLdataLo;
CTRLdataHi = 0x0F; //was C before. F changes isgain to 40 for more torque
CTRLdataLo = CW_16_Disable; //1/16 disabled
WriteSPI(CTRLdataHi, CTRLdataLo);

//TORQUE defaults
unsigned char TORQUEHi, TORQUELo;
TORQUEHi = 0x13;
TORQUELo = 0x1F;
WriteSPI(TORQUEHi, TORQUELo);

//OFF defaults
unsigned char OFFHi, OFFLo;
OFFHi = 0x20; //Internal Indexer
//OFFHi = 0x21; //Bypass Indexer
OFFLo = 0xA0;
WriteSPI(OFFHi, OFFLo);

//BLANK defaults
unsigned char BLNKHi, BLNKLo;
BLNKHi = 0x31;
BLNKLo = 0xF0;
WriteSPI(BLNKHi, BLNKLo);

//DECAY defaults
unsigned char DECAYHi, DECAYLo;
DECAYHi = 0x41;
DECAYLo = 0x10;
WriteSPI(DECAYHi, DECAYLo);

//STALL defaults
unsigned char STALLHi, STALLLo;
STALLHi = 0x53;
STALLLo = 0xFF;
WriteSPI(STALLHi, STALLLo);

//DRIVE defaults
unsigned char DRIVEHi, DRIVELo;
DRIVEHi = 0x6F; //400mA peak sink 200mA peak source
DRIVELo = 0x5F;
WriteSPI(DRIVEHi, DRIVELo);

//STATUS defaults
unsigned char STATUSHi, STATUSLo;
STATUSHi = 0x70;
STATUSLo = 0x00;
result = WriteSPI(STATUSHi, STATUSLo);

  • Hi Matt,

    Do you have a scope capture of the current waveform with the STEP pin?
    What is the step rate?
    What is the current sense resistor and system voltage?

    It appears your settings may be incorrect. Assuming you have not changed the sense resistor from 50mOhm, the current should be limited to approximately 166mA. To reach 4A, the TORQUE value should be increased and the gain decreased per equation (2) of the datasheet.

    An example would be setting the ISGAIN to 00 (Gain of 5) and the TORQUE to 0x5D (93 Decimal) . There are other combinations of GAIN and TORQUE that can approach the same results.
  • Hi Rick,

    Thanks for your reply. I've tried messing with ISGAIN and TORQUE. It has successfully increased the torque of the motor, but it's introduced a couple other problems.
    1. The motor movement is not always smooth, it seems to stutter occasionally.
    2. The 8711 quickly faults out sometime immediately, sometime in a few seconds of running and under no load.

    Obviously it would be helpful to understand the reason for the fault from the status register, but I haven't been able to read the state of any registers. I always get a return of 0. I'll copy the code below I'm using to read the status of the registers, I use function getCurrentRegisters. In summary, I'm looking for help in understanding how to eliminate the new problems 1 and 2 listed about and/or how to read the status register so I have direction to resolve the problem.

    Thanks!
    Matt
    ______________________________________________________
    unsigned int WriteSPI(unsigned char dataHi, unsigned char dataLo)
    {
    unsigned int resultHigh;
    unsigned int resultLow;
    unsigned int finalResult;

    digitalWrite(chipSelect,HIGH);
    resultHigh = SPI.transfer(dataHi);
    resultLow = SPI.transfer(dataLo);
    digitalWrite(chipSelect,LOW);
    finalResult = resultHigh << 8;
    finalResult = finalResult & resultLow;

    delay(10);

    return finalResult;

    }


    void getCurrentRegisters()
    {
    Serial.print("\n-----------------------------------------------\n");
    Serial.print("CTRL register ");
    Serial.print(WriteSPI(0x80, 0x00),HEX);
    Serial.print("\n");

    Serial.print("TORQUE register ");
    Serial.print(WriteSPI(0x90, 0x00),HEX);
    Serial.print("\n");

    Serial.print("OFF register ");
    Serial.print(WriteSPI(0xA0, 0x00),HEX);
    Serial.print("\n");

    Serial.print("BLANK register ");
    Serial.print(WriteSPI(0xB0, 0x00),HEX);
    Serial.print("\n");

    Serial.print("DECAY register ");
    Serial.print(WriteSPI(0xC0, 0x00),HEX);
    Serial.print("\n");

    Serial.print("STALL register ");
    Serial.print(WriteSPI(0xD0, 0x00),HEX);
    Serial.print("\n");

    Serial.print("DRIVE register ");
    Serial.print(WriteSPI(0xE0, 0x00),HEX);
    Serial.print("\n");

    Serial.print("STATUS register ");
    Serial.print(WriteSPI(0xF0, 0x00),HEX);
    Serial.print("\n-----------------------------------------------\n");
    }
  • Hi Matt,

    Can you capture a read of a register prior to trying to operate the motor? The DRIVE register is a good example because the default value has 1's and 0's.
  • Hi Rick,

    Yes, I try to read the registers before operating the motor. Here's a copy of all my code. This has been written for energia. You'll notice that getCurrentRegisters(); is called in setup().

    Despite that, 0 is returned.

    thx
    Matt


    #include<SPI.h>

    #include<msp430G2553.h>
    #include "HardwareSerial.h"
    #include<driverlib.h>
    int chipSelect = 11;
    int DIR = 13;
    int Direction = 1;
    #define BUTTON BIT3
    int MODE = 1;
    int Brake = 12;
    int sensorValue;
    int PULSE_TIME = 100;
    int CYCLE_TIME = 3*PULSE_TIME;
    #define CCW_16_Enable 0x25
    #define CW_16_Enable 0x27
    #define CCW_16_Disable 0x24
    #define CW_16_Disable 0x26
    #define CCW_2_Enable 0xd
    #define CW_2_Enable 0xf
    #define CCW_2_Disable 0xc
    #define CW_2_Disable 0xe
    void setup()
    {


    // put your setup code here, to run once:
    pinMode(P1_6,OUTPUT); // make the LED pins outputs
    pinMode(P1_0,OUTPUT);
    pinMode(Brake, OUTPUT);
    digitalWrite(P1_6,LOW);
    digitalWrite(P1_0,LOW);
    pinMode(chipSelect,OUTPUT);
    digitalWrite(chipSelect,HIGH);
    pinMode(DIR,INPUT_PULLUP);
    Serial.begin(9600);
    Serial.println("bla");
    pinMode(5,INPUT_PULLUP);
    SPI.begin();
    pinMode(6, OUTPUT); //Sleep mode
    pinMode(9, OUTPUT); //Step
    pinMode(8, OUTPUT); //reset
    digitalWrite(6, HIGH); //Sleep
    digitalWrite(10, HIGH);//Direction
    digitalWrite(8, LOW);//reset
    Initialize();
    delay(1);
    Serial.println(TACCTL0,BIN);
    Serial.println("Done");
    getCurrentRegisters();
    // Configuration word
    // Bits 15-10: Unused
    // Bits 9-8: TASSEL. Clock source select: set to SMCLK (16MHz)
    //00 TACLK
    //01 ACLK Aux. Clock
    //10 SMCLK Sub-main clock
    //11 INCLK
    //SET to SMCLK below
    // Bits 7-6: ID Bits Input divider: set to 8
    // Bits 5-4: Mode control: Count up to TACCRO and reset
    // 00 Stop The timer is halted.
    // 01 Up The timer repeatedly counts from zero to the value of TACCR0. THIS ONE SET
    // 10 Continuous The timer repeatedly counts from zero to 0FFFFh.
    // 11 Up/down The timer repeatedly counts from zero up to the value of TACCR0 and back down to zero.

    // Bit 3: Unused
    // Bits 2: TACLR : set to initially clear timer system
    // Bit 1: Enable interrupts from TA0
    // Bit 0: Interrupt (pending) flag : set to zero (initially)
    TA0CTL=0b0000001011010000; // Timer_A control 0x0160h
    TACCR0=3000; // Timer_A capture/compare 0. to generate a 1ms timebase @ 16MHz with a divisor of 8



    //TACCTL0 = BIT4;// 0x162=TACCTL0 Timer_A capture/compare control 0
    //BIT0 CCIFG Capture/compare interupt flag
    // 0 No interupt pending
    // 1 Interrupt pending
    }
    void loop()
    {
    sensorValue = analogRead(2); //Potentiometer

    unsigned char CTRLdataHi, CTRLdataLo;
    bool runningFlag = 0;
    //Serial.print("Sensor Value: ");
    //Serial.println(sensorValue);

    //Perform Accellerations

    if (digitalRead(5) == LOW)
    {

    if (TACCR0 > CYCLE_TIME)//400 and 2000
    {
    TACCTL0 ^= 1 << 4; //Toggle Capture/Compare interrupt enable CCIE
    //TACCR0 = TACCR0-1;
    TACCTL0 ^= 1 << 4; //Toggle Capture/Compare interrupt enable CCIE
    }

    /*
    if (runningFlag == 0) //if not running enable motor
    {

    CTRLdataHi = 0x0C; //control register
    CTRLdataLo = CW_16_Enable;
    WriteSPI(CTRLdataHi, CTRLdataLo);
    runningFlag = 1;
    delay(100);

    }
    */
    if (digitalRead(DIR) == LOW)
    {

    Serial.println("CW");
    switch (MODE)
    {

    case 1: //register method. This one tested successfully.
    CTRLdataHi = 0x0C;
    CTRLdataLo = CCW_16_Enable; //1/16
    WriteSPI(CTRLdataHi, CTRLdataLo);

    case 2: //direction pin method.
    pinMode(10, OUTPUT);
    if (Direction == 1)
    {
    digitalWrite(10,0);
    }
    else
    {
    digitalWrite(10,1);
    }
    }

    }
    else
    {
    Serial.println("CCW");
    CTRLdataHi = 0x0C;
    CTRLdataLo = CW_16_Enable; //1/2
    WriteSPI(CTRLdataHi, CTRLdataLo);
    }
    TACCTL0 = BIT4;

    }
    else if (digitalRead(5) == HIGH) //Stop motor movement interupt stop.
    {
    TACCTL0 = 0;
    TACCR0=3000;
    /* CTRLdataHi = 0x0C; //control register
    CTRLdataLo = CW_16_Disable;
    WriteSPI(CTRLdataHi, CTRLdataLo);
    runningFlag = 0;
    */

    }
    // put your main code here, to run repeatedly:

    }
    // The address function that follows this vector statement is placed in the specified location Interrupt Vector table
    #pragma vector=TIMER0_A0_VECTOR // (0x0012) 0xFFF2 Timer0_A CC0
    __interrupt void timerA0ISR(void)
    {


    TACCTL0 ^= 1 << 4; //Toggle Capture/Compare interrupt enable CCIE
    digitalWrite(9,HIGH);
    delayMicroseconds(PULSE_TIME);
    digitalWrite(9,LOW);

    if (TACCR0 > CYCLE_TIME)//400 and 2000
    {
    TACCR0 = TACCR0-8;
    }
    TACCTL0 ^= 1 << 4; //Toggle Capture/Compare interrupt enable CCIE

    }


    unsigned int WriteSPI(unsigned char dataHi, unsigned char dataLo)
    {
    unsigned int resultHigh;
    unsigned int resultLow;
    unsigned int finalResult;

    digitalWrite(chipSelect,HIGH);
    resultHigh = SPI.transfer(dataHi);
    resultLow = SPI.transfer(dataLo);
    digitalWrite(chipSelect,LOW);
    finalResult = resultHigh << 8;
    finalResult = finalResult & resultLow;

    delay(10);

    return finalResult;

    }
    void Initialize()
    {
    int result;
    //CTRL Register defaults
    unsigned char CTRLdataHi, CTRLdataLo;
    CTRLdataHi = 0x0F; //was C before. F changes isgain to 40 for more torque
    //CTRLdataLo = 0x2F; //1/32 enabled
    //CTRLdataLo = 0x27; //1/16 enabled
    CTRLdataLo = CW_16_Disable; //1/16 disabled
    //CTRLdataLo = 0x47; //1/256 enabled
    //CTRLdataLo = 0x00;
    WriteSPI(CTRLdataHi, CTRLdataLo);

    //TORQUE defaults
    unsigned char TORQUEHi, TORQUELo;
    TORQUEHi = 0x13;
    TORQUELo = 0x5D;
    //TORQUELo = 0x1F;
    WriteSPI(TORQUEHi, TORQUELo);

    //OFF defaults
    unsigned char OFFHi, OFFLo;
    OFFHi = 0x20; //Internal Indexer
    //OFFHi = 0x21; //Bypass Indexer
    OFFLo = 0xA0;
    WriteSPI(OFFHi, OFFLo);

    //BLANK defaults
    unsigned char BLNKHi, BLNKLo;
    BLNKHi = 0x31;
    BLNKLo = 0xFF;
    WriteSPI(BLNKHi, BLNKLo);

    //DECAY defaults
    unsigned char DECAYHi, DECAYLo;
    DECAYHi = 0x41;
    DECAYLo = 0x10;
    WriteSPI(DECAYHi, DECAYLo);

    //STALL defaults
    unsigned char STALLHi, STALLLo;
    STALLHi = 0x53;
    STALLLo = 0xFF;
    WriteSPI(STALLHi, STALLLo);

    //DRIVE defaults
    unsigned char DRIVEHi, DRIVELo;
    DRIVEHi = 0x6F; //400mA peak sink 200mA peak source
    DRIVELo = 0x5C;
    WriteSPI(DRIVEHi, DRIVELo);

    //STATUS defaults
    unsigned char STATUSHi, STATUSLo;
    STATUSHi = 0x70;
    STATUSLo = 0x00;
    result = WriteSPI(STATUSHi, STATUSLo);
    result = WriteSPI(STATUSHi, STATUSLo);
    Serial.print("Status: ");
    Serial.println(result,HEX);
    digitalWrite(chipSelect,LOW);
    }

    void getCurrentRegisters()
    {
    Serial.print("\n-----------------------------------------------\n");
    Serial.print("CTRL register ");
    Serial.print(WriteSPI(0x80, 0x00),HEX);
    Serial.print("\n");

    Serial.print("TORQUE register ");
    Serial.print(WriteSPI(0x90, 0x00),HEX);
    Serial.print("\n");

    Serial.print("OFF register ");
    Serial.print(WriteSPI(0xA0, 0x00),HEX);
    Serial.print("\n");

    Serial.print("BLANK register ");
    Serial.print(WriteSPI(0xB0, 0x00),HEX);
    Serial.print("\n");

    Serial.print("DECAY register ");
    Serial.print(WriteSPI(0xC0, 0x00),HEX);
    Serial.print("\n");

    Serial.print("STALL register ");
    Serial.print(WriteSPI(0xD0, 0x00),HEX);
    Serial.print("\n");

    Serial.print("DRIVE register ");
    Serial.print(WriteSPI(0xE0, 0x00),HEX);
    Serial.print("\n");

    Serial.print("STATUS register ");
    Serial.print(WriteSPI(0xF0, 0x00),HEX);
    Serial.print("\n-----------------------------------------------\n");
    }
  • Hi Matt,

    A scope capture of the SPI transaction will be easier to debug. This will help determine what is sent to the DRV8711 and how the DRV8711 is responding.
  • Hi Rick,

    Here's what I captured with the scope.  This is a read of the status register.  You'll notice:

    Clock: BLUE

    SDO: RED

    SDI: BROWN

    CS: GREEN

    The SDO high voltage seems low.  Perhaps this is why I'm not receiving anything other than zero.  I do have the SDO pin on the msp430 configured with an internal pull up.  Any ideas why I'm getting such low voltages.  Do I need an external pull up?

    On to the original problem, why is the drive faulting.  From the trace I see Bit 3 and Bit 7 high indicating that there's a Channel A predriver fault and Latched Stall Detect is active.  I'm not sure how to configure the predriver.  I have experimented with IDRIVEN and IDRIVEP.  Setting these values to their minimums have helped some, but I continue to get faults and stuttering in the motor rotation.  I do have OCPDEG to 8uS.

    Any thoughts on:

    1.  Why SDO voltages are so long

    2. How to solve intermittent predriver fault.

    thx

    Matt