TMC5130 & Encoder

Greetings

I use an Arduino Mega, a stepper motor with an ABN differential encoder as well as the driver TMC5130-BOB.
I started using the library TMCStepper.h as it should be easy to use, but i'm also able to get the data direct from the driver by accessing the registers.
Currently, my setup works (it turns when it should turn), but I'm unable to get the value from the encoder, which is important for my application.
Additional info: the TMC5130-BOB only has the connections ENCA, ENB and ENCN, therefore I ignore the differential inverted signal wires from the encoder.

Can you help me to get the encoder signal? I'm totally stuck and don't know where the issue could be.
Thank you kindly.

Here would be a part of my code so far:

// Libraries
#include <SPI.h>
#include <TMCStepper.h>

// varia parameter
const word      rtMainRate   = 2500;  // in ms
const word      rtCheckRate  = 1250;  // in ms
unsigned long   rtMainLast   = 0;    // 0-4'294'967'295 -> ca. 49 days, last runtime 
unsigned long   rtCheckLast  = 0;    // 0-4'294'967'295 -> ca. 49 days, last runtime 

// ====================================
// stepper motor stuff
// ====================================
#define motEN_pin      49      // Enable
#define motCS_pin      53      // Chip select
#define motMOSI_pin    51      // Software Master Out Slave In (MOSI)
#define motMISO_pin    50      // Software Master In Slave Out (MISO)
#define motSCK_pin     52      // Software Slave Clock (SCK)
#define motRSENSE      0.15f   // acc. to the datasheet...?
//TMC5130Stepper motDriver = TMC5130Stepper(motCS_pin, motRSENSE, motMOSI_pin, motMISO_pin, motSCK_pin);
TMC5130Stepper motDriver  = TMC5130Stepper(motCS_pin, motRSENSE);
int  motContrCount   = 5;     // counter for the circular buffer. It makes the control of the motor slow, it will only compare to the threshold if the whole circular buffer is renewed
bool motBackwardFlag = false;
int motTarget        = 0;
bool motMoving       = false;


/************************
Motor: send the commands via SPI to the driver
************************/
void motSendData(unsigned long address, unsigned long datagram) { 
	delay(50);
	uint8_t stat;
	unsigned long i_datagram;

	digitalWrite(motCS_pin,LOW);
	delay(15);
	delayMicroseconds(10);

	stat = SPI.transfer(address);

	i_datagram |= SPI.transfer((datagram >> 24) & 0xff);
	i_datagram <<= 8;
	i_datagram |= SPI.transfer((datagram >> 16) & 0xff);
	i_datagram <<= 8;
	i_datagram |= SPI.transfer((datagram >> 8) & 0xff);
	i_datagram <<= 8;
	i_datagram |= SPI.transfer((datagram) & 0xff);
	digitalWrite(motCS_pin,HIGH);
	delay(15);

	Serial.print("Received: ");
	PrintHex40(stat, i_datagram);
	Serial.print("\n");
	Serial.print(" from register: ");
	Serial.println(address,HEX);
  Serial.println();
}

int32_t motReadData(unsigned long address) { 
  delay(50);
  uint8_t stat;
  int32_t i_datagram = 0; // Store the response data here

  digitalWrite(motCS_pin,LOW);
  delay(15);

  // Send address for read operation (0x21 becomes 0x21 for reading XACTUAL, no write flag)
  stat = SPI.transfer(address & 0x7F); // Ensure the MSB is 0 for reading

  // Send dummy data (0x00) to initiate the read and capture the response
  i_datagram |= SPI.transfer(0x00) << 24;
  i_datagram |= SPI.transfer(0x00) << 16;
  i_datagram |= SPI.transfer(0x00) << 8;
  i_datagram |= SPI.transfer(0x00);

  digitalWrite(motCS_pin,HIGH);
  delay(15);

/*
  Serial.print("Received: ");
  PrintHex40(stat, i_datagram);  // Helper function to print the status and data
  Serial.print("\n");
  Serial.print(" from register: ");
  Serial.println(address, HEX);
  */

  return i_datagram;  // Return the data received
}
/************************
print the Hex40 code
************************/
void PrintHex40(uint8_t stat, uint32_t data) // prints 40-bit data in hex with leading zeroes
{
  char tmp[16];
  uint16_t LSB = data & 0xffff;
  uint16_t MSB = data >> 16;
  sprintf(tmp, "0x%.2X%.4X%.4X", stat, MSB, LSB);
  Serial.print(tmp);
}

void setup() {
  Serial.begin(115200); //open the serial port for communication with the PC
  while (!Serial) {}
  SPI.begin();

  pinMode(motEN_pin, OUTPUT); // motor enable
  pinMode(motCS_pin, OUTPUT); // motor chipselect
  digitalWrite(motCS_pin, HIGH); // Motor CS disabled at start
  /*
  //digitalWrite(motEN_pin, motEnableFlag); // disable motor
  SPI.begin();
  SPI.setDataMode(SPI_MODE3); // TMC5130 uses SPI mode 3
  SPI.setBitOrder(MSBFIRST);  // Most significant bit first
  SPI.setClockDivider(SPI_CLOCK_DIV16);  // Adjust clock speed as needed
  */
  // Initialize the motDriver
  motDriver.begin();
  delay(500);
  motDriver.toff(5); // Off-time setting (adjust if needed)
  motDriver.rms_current(800); // Set motor RMS current
  motDriver.microsteps(0);   // Set microsteps to 1/16

  motDriver.en_pwm_mode(false); // disable stealthChop
  motDriver.pwm_autoscale(true); // Enable auto PWM scaling
  // Set CoolStep parameters
  motDriver.TCOOLTHRS(0); // Set the CoolStep lower threshold, this is the lowest velocity when CoolStep starts to regulate
  motDriver.THIGH(0);           // Set the upper threshold velocity for switching off CoolStep
    // Optional: Fine-tune SpreadCycle parameters
  motDriver.hend(2); // Hysteresis end value
  motDriver.hstrt(3); // Hysteresis start
  // Set other motion parameters
  motDriver.a1(100);        // Initial acceleration
  motDriver.v1(500);       // Acceleration threshold velocity V1
  motDriver.AMAX(50);       // Acceleration above V1
  motDriver.VMAX(1500);    // Maximum speed
  motDriver.DMAX(70);       // Deceleration above V1
  motDriver.d1(140);        // Deceleration below V1
  motDriver.VSTOP(10);       // Stop velocity
  motDriver.RAMPMODE(0);     // Positioning mode


  /* Some default values, not sure if neccessary...
	sendData(0xA4,0x000003E8); //A1=1000
	sendData(0xA5,0x000186A0); //V1=100000
	sendData(0xA6,0x0000C350); //AMAX=50000
	sendData(0xA7,0x000186A0); //VMAX=100000
	sendData(0xAA,0x00000578); //D1=1400
	sendData(0xAB,0x00000064); //VSTOP=100
	*/
  motSendData(0xB8, 0x00000000);  // Set ENCODER_MODE to quadrature mode

  //motReadData(0x38);  // Set ENCODER_MODE to quadrature mode
  Serial.println("Motor initialized.");
  digitalWrite(motEN_pin, HIGH); // enable motor
}

void loop() {
  unsigned long rt = millis();
  if(motMoving == false && rt-rtMainLast >= rtMainRate){
    rtMainLast = rt;
    
    if(motBackwardFlag == false) motTarget += 50;
    else motTarget -= 50;
    if(motContrCount >= 10){
      motContrCount = 0;
      motBackwardFlag = !motBackwardFlag;
    }
    //Serial.print("Motor moves to target: ");
    //Serial.println(motTarget);
    //Serial.println();
    motContrCount++;
    digitalWrite(motEN_pin, LOW); // enable motor
    delay(30);
    motDriver.XTARGET(motTarget);
    motMoving = true;
    
  }

  if(rt - rtCheckLast > rtCheckRate){
    rtCheckLast = rt;
    
    int32_t motEncVal_Lib = motDriver.X_ENC();
    Serial.print("Encoder Value via Library motDriver.X_ENC(): ");
    Serial.println(motEncVal_Lib);

    int32_t motEncVal_Reg2 = motReadData(0x39);
    Serial.print("Encoder Value via motReadData(0x39): ");
    Serial.println(motEncVal_Reg2);


    Serial.print("step Value via Library motDriver.XACTUAL: ");
    Serial.println(motDriver.XACTUAL());

    int32_t motPosVal_Reg = motReadData(0x21);
    Serial.print("step Value via motReadData(0x21): ");
    Serial.println(motPosVal_Reg);
  

    //int32_t motStatus = motReadData(0x00);
    //Serial.print("GCONF status: ");
    //Serial.println(motStatus);
    
    //uint32_t drv_status = motDriver.DRV_STATUS();
    //Serial.print("DRV_STATUS: ");
    //Serial.println(drv_status, HEX);
    
    //uint32_t mtLostSteps = motDriver.LOST_STEPS();
    //Serial.print("Lost steps: ");
    //Serial.println(mtLostSteps);
    Serial.println();
  }

  if(motMoving == true && motDriver.XACTUAL() == motTarget){
    delay(30);
    digitalWrite(motEN_pin, HIGH); // disable the motor
    // Serial.println("Motor target reached --> mot disabled.");
    motMoving = false;
  }
}

The output on the Serial is as follows:

Encoder Value via Library motDriver.X_ENC(): 0
Encoder Value via motReadData(39): 0
step Value via Library motDriver.XACTUAL: 150
step Value via motReadData(0x21): 150

edit 1: changed motReadData(39); to motReadData(0x39);, but result still the same.

To are supposed to connect them to ground rather than ignore them.

Hi Grumpy_Mike, thanks for the fast response and tip.
I conneted them to the ground now, but the output remains the same: a 0 on the encoder values.

What is missing? We normally like to see all the code.

Why are all your handy debug print statements commented out? It would be good to see what they say.

What is this all about? Are they supposed to be floating point values? If so declare them as floats and put a decimal point at the end of the value you want to assign them to. With the ATMega series of processors there is no difference between a float and a double. I have never seen the "word" definition used in the C/C++ context of Arduinos. But I am sure someone will put me right, as mainly I am a hardware guy.

One of the biggest problem here is that you seem to be writing too much code before testing.

Is this code that works or doesn't work? We like to see code with the errors in it, so some members can check it out themselves.

Normally it is good if you supply a schematic, and photo of your setup.

Hi Grumpy_Mike
Thanks again for the support.
The code now is smaller than my original as i only want to implement the encoder. The rest of the code (another script altogether) has about a 1000 lines of code, reads a load cell and RTC, log to an openlog and communicates with a Nextion display. All not relevant for the current problem and a total (working) mess, so i made an "abstract" of only the motor to get the encoder running, then implement it to the rest of the code. That's why i called it "part" of the code, i apoliogize for the missunderstanding.
The code as i posted it works, the motor makes the movements i defined, no errors and i can read the steps. No i just struggle with the encoder.

Debug statements: They gave me nothing usefull atm so i commented them out to clean up my serial output.

Those two variables (rtMainRate and rtCehckRate) are just for my timing there. I could also use int, as i will never input a value above 32k as my rate ^^
I got the different datatypes from a article and try to keep the usage of variables as slim as possible to save memory (altough I'm bad at it xD)
The rates make that the motor moves every 2.5 seconds, and i get the values each 1.25 seconds.

A foto of the setup would show a ton of jumoer wires, and beneath the mega, a stepper motor and a breadboard with the TMC5130-BOB plugged in.
A schematic have i not created yet. Can you recommend a good software for it? I use once fritzing, but did not get with it...

With the debugging serial.Prints enabled, i get those outputs:

Encoder Value via Library motDriver.X_ENC(): 0
Received: 0x0D00000000
from register: 39
Encoder Value via motReadData(0x39): 0
step Value via Library motDriver.XACTUAL: 227
Received: 0x01000000E3
from register: 21
step Value via motReadData(0x21): 227
Received: 0x05000000F9
from register: 0
GCONF status: 249
DRV_STATUS: 81080000
Lost steps: 0

Current code with some additional comments and debugging prints active

// Libraries
#include <SPI.h>
#include <TMCStepper.h>

// varia parameter
const word      rtMainRate   = 2500;  // in ms
const word      rtCheckRate  = 1250;  // in ms
unsigned long   rtMainLast   = 0;    // 0-4'294'967'295 -> ca. 49 days, last runtime 
unsigned long   rtCheckLast  = 0;    // 0-4'294'967'295 -> ca. 49 days, last runtime 

// ====================================
// stepper motor stuff
// ====================================
#define motEN_pin      49      // Enable
#define motCS_pin      53      // Chip select
#define motMOSI_pin    51      // Software Master Out Slave In (MOSI)
#define motMISO_pin    50      // Software Master In Slave Out (MISO)
#define motSCK_pin     52      // Software Slave Clock (SCK)
#define motRSENSE      0.15f   // acc. to the datasheet...?
//TMC5130Stepper motDriver = TMC5130Stepper(motCS_pin, motRSENSE, motMOSI_pin, motMISO_pin, motSCK_pin);
TMC5130Stepper motDriver  = TMC5130Stepper(motCS_pin, motRSENSE);
int  motContrCount   = 5;     // counter for the circular buffer. It makes the control of the motor slow, it will only compare to the threshold if the whole circular buffer is renewed
bool motBackwardFlag = false;
int motTarget        = 0;
bool motMoving       = false;


/************************
Motor: send the commands via SPI to the driver
************************/
void motSendData(unsigned long address, unsigned long datagram) { 
	delay(50);
	uint8_t stat;
	unsigned long i_datagram;

	digitalWrite(motCS_pin,LOW);
	delay(15);
	delayMicroseconds(10);

	stat = SPI.transfer(address);

	i_datagram |= SPI.transfer((datagram >> 24) & 0xff);
	i_datagram <<= 8;
	i_datagram |= SPI.transfer((datagram >> 16) & 0xff);
	i_datagram <<= 8;
	i_datagram |= SPI.transfer((datagram >> 8) & 0xff);
	i_datagram <<= 8;
	i_datagram |= SPI.transfer((datagram) & 0xff);
	digitalWrite(motCS_pin,HIGH);
	delay(15);

	Serial.print("Received: ");
	PrintHex40(stat, i_datagram);
	Serial.print("\n");
	Serial.print(" from register: ");
	Serial.println(address,HEX);
  Serial.println();
}

int32_t motReadData(unsigned long address) { 
  delay(50);
  uint8_t stat;
  int32_t i_datagram = 0; // Store the response data here

  digitalWrite(motCS_pin,LOW);
  delay(15);

  // Send address for read operation (0x21 becomes 0x21 for reading XACTUAL, no write flag)
  stat = SPI.transfer(address & 0x7F); // Ensure the MSB is 0 for reading

  // Send dummy data (0x00) to initiate the read and capture the response
  i_datagram |= SPI.transfer(0x00) << 24;
  i_datagram |= SPI.transfer(0x00) << 16;
  i_datagram |= SPI.transfer(0x00) << 8;
  i_datagram |= SPI.transfer(0x00);

  digitalWrite(motCS_pin,HIGH);
  delay(15);

  Serial.print("Received: ");
  PrintHex40(stat, i_datagram);  // Helper function to print the status and data
  Serial.print("\n");
  Serial.print(" from register: ");
  Serial.println(address, HEX);

  return i_datagram;  // Return the data received
}
/************************
print the Hex40 code
************************/
void PrintHex40(uint8_t stat, uint32_t data) // prints 40-bit data in hex with leading zeroes
{
  char tmp[16];
  uint16_t LSB = data & 0xffff;
  uint16_t MSB = data >> 16;
  sprintf(tmp, "0x%.2X%.4X%.4X", stat, MSB, LSB);
  Serial.print(tmp);
}

void setup() {
  Serial.begin(115200); //open the serial port for communication with the PC
  while (!Serial) {}
  SPI.begin();

  pinMode(motEN_pin, OUTPUT); // motor enable
  pinMode(motCS_pin, OUTPUT); // motor chipselect
  digitalWrite(motCS_pin, HIGH); // Motor CS disabled at start

  // Initialize the motDriver
  motDriver.begin();
  delay(500);
  motDriver.toff(5); // Off-time setting (adjust if needed)
  motDriver.rms_current(800); // Set motor RMS current
  motDriver.microsteps(0);   // Set microsteps to 1/16

  motDriver.en_pwm_mode(false); // disable stealthChop
  motDriver.pwm_autoscale(true); // Enable auto PWM scaling
  // Set CoolStep parameters
  motDriver.TCOOLTHRS(0); // Set the CoolStep lower threshold, this is the lowest velocity when CoolStep starts to regulate
  motDriver.THIGH(0);           // Set the upper threshold velocity for switching off CoolStep
    // Optional: Fine-tune SpreadCycle parameters
  motDriver.hend(2); // Hysteresis end value
  motDriver.hstrt(3); // Hysteresis start
  // Set other motion parameters
  motDriver.a1(100);        // Initial acceleration
  motDriver.v1(500);       // Acceleration threshold velocity V1
  motDriver.AMAX(50);       // Acceleration above V1
  motDriver.VMAX(1500);    // Maximum speed
  motDriver.DMAX(70);       // Deceleration above V1
  motDriver.d1(140);        // Deceleration below V1
  motDriver.VSTOP(10);       // Stop velocity
  motDriver.RAMPMODE(0);     // Positioning mode

  /* Some default values, not sure if neccessary...
	motSendData(0xA4,0x000003E8); //A1=1000
	motSendData(0xA5,0x000186A0); //V1=100000
	motSendData(0xA6,0x0000C350); //AMAX=50000
	motSendData(0xA7,0x000186A0); //VMAX=100000
	motSendData(0xAA,0x00000578); //D1=1400
	motSendData(0xAB,0x00000064); //VSTOP=100
	*/
  motSendData(0xB8, 0x00000000); 
  
  Serial.println("Motor initialized.");
  digitalWrite(motEN_pin, HIGH); // enable motor
}

void loop() {
  unsigned long rt = millis();
  if(motMoving == false && rt-rtMainLast >= rtMainRate){
    rtMainLast = rt;
    
    if(motBackwardFlag == false) motTarget += 50;
    else motTarget -= 50;
    if(motContrCount >= 10){
      motContrCount = 0;
      motBackwardFlag = !motBackwardFlag;
    }
    //Serial.print("Motor moves to target: ");
    //Serial.println(motTarget);
    //Serial.println();
    motContrCount++;
    digitalWrite(motEN_pin, LOW); // enable motor
    delay(30);
    motDriver.XTARGET(motTarget);
    motMoving = true;
    
  }

  if(rt - rtCheckLast > rtCheckRate){
    rtCheckLast = rt;
    
    // get encoder value
    int32_t motEncVal_Lib = motDriver.X_ENC();
    Serial.print("Encoder Value via Library motDriver.X_ENC(): ");
    Serial.println(motEncVal_Lib);

    int32_t motEncVal_Reg2 = motReadData(0x39);
    Serial.print("Encoder Value via motReadData(0x39): ");
    Serial.println(motEncVal_Reg2);


    // get steps
    Serial.print("step Value via Library motDriver.XACTUAL: ");
    Serial.println(motDriver.XACTUAL());

    int32_t motPosVal_Reg = motReadData(0x21);
    Serial.print("step Value via motReadData(0x21): ");
    Serial.println(motPosVal_Reg);


    // get some status
    int32_t motStatus = motReadData(0x00);
    Serial.print("GCONF status: ");
    Serial.println(motStatus);
    
    uint32_t drv_status = motDriver.DRV_STATUS();
    Serial.print("DRV_STATUS: ");
    Serial.println(drv_status, HEX);
    
    uint32_t mtLostSteps = motDriver.LOST_STEPS();
    Serial.print("Lost steps: ");
    Serial.println(mtLostSteps);
    Serial.println();
  }

  // disable motor if position (steps) is reached
  if(motMoving == true && motDriver.XACTUAL() == motTarget){
    delay(30);
    digitalWrite(motEN_pin, HIGH); // disable the motor
    // Serial.println("Motor target reached --> mot disabled.");
    motMoving = false;
  }
}

Edit 1:
Actually, the debugging lines for GCONF and DRV_STATUS return really strange values, i just don't know how to interpret this result. Somehow the communications is scrambled, or i have coding errors in my send / receive data functions. Here are the outpus from 4 cycles after 1.25 seconds each:

Encoder Value via Library motDriver.X_ENC(): 0
Received: 0xED00000000
from register: 39
Encoder Value via motReadData(0x39): 0
step Value via Library motDriver.XACTUAL: 150
Received: 0x2D00000096
from register: 21
step Value via motReadData(0x21): 150
Received: 0x2D00000096
from register: 0
GCONF status: 150
DRV_STATUS: 810800BD
Lost steps: 0

Encoder Value via Library motDriver.X_ENC(): 0
Received: 0x0D00000000
from register: 39
Encoder Value via motReadData(0x39): 0
step Value via Library motDriver.XACTUAL: 176
Received: 0x01000000B0
from register: 21
step Value via motReadData(0x21): 176
Received: 0x05000000C7
from register: 0
GCONF status: 199
DRV_STATUS: 1110000
Lost steps: 0

Encoder Value via Library motDriver.X_ENC(): 0
Received: 0x2D00000000
from register: 39
Encoder Value via motReadData(0x39): 0
step Value via Library motDriver.XACTUAL: 200
Received: 0x2D000000C8
from register: 21
step Value via motReadData(0x21): 200
Received: 0xED000000C8
from register: 0
GCONF status: 200
DRV_STATUS: 8108007E
Lost steps: 0

Encoder Value via Library motDriver.X_ENC(): 0
Received: 0x0D00000000
from register: 39
Encoder Value via motReadData(0x39): 0
step Value via Library motDriver.XACTUAL: 227
Received: 0x01000000E3
from register: 21
step Value via motReadData(0x21): 227
Received: 0x05000000F9
from register: 0
GCONF status: 249
DRV_STATUS: 81080000
Lost steps: 0

Bad idea. You shorted the inverted signal to ground. Hope you did not damage the encoder.
You need a differential signal receiver IC
Is the encoder powered with 5V?

Hi Jim-p

Well, nothing blew up so far, so i hope i don't have to replace them ^^
Jokes aside, for cases like this i connected the driver, arduino and stepper motor on a seperate breadboard. For safety and to avoid other stuff interfering in ways I cannot imagine.
But, as the output did not change in the slightest after the rewiring, i think nothing is damaged. Even if i don't know how to test it...

When i first wanted to connect the stepper / encoder to the driver, i did some research about those wires, and apparently you can ignore the inverted signal wires, but the signal may be (more) susceptible to noise. I hoped, as the the motor and driver are both from trinamic, that they are somehow compatible and there is no need for an additional IC.

Yes, the encoder and driver are powered to a 5V USB power supply, rated for 1A.
GND and Shield went to common ground, A+ to ENCA, B+ to ENCB, and Z+ to ENCN. A-, B- and Z- are floating or to ground, depending if jim-P or Grumpy_Mike is correct ^^

I also had a look at the TMCStepper library, but my skills in coding are not good enough to get a clue what I'm doing wrong.

Can you post the data sheet for the encoder and the motor, I just working in the dark.
As I said don't connect the inverted output to ground.

Hi Jim
I attached the datasheets.

QSH4218-x-10k_datasheet_rev1.50.pdf (809.5 KB)
TMC5130A_datasheet_rev1.21.pdf (2.5 MB)
TMC5130A-BOB_datasheet_rev1.00.pdf (3.8 MB)

And the wires for the unused encoder signals are floating again on the breadboard.

Encoder   5130A BOB
VCC   --> VCC_IO
GND   --> GND
A+    --> ENCA
B+    --> ENCB
N+    --> ENCN

The data type for SPI is byte so using unsigned long may be a problem.

For a read access, the data transferred back is the data from the previous read access not the current read.
So if you do two consecutive motReadData(0x39); The second one will return the data requested by the first.

I made two functions, one retuns an unsigned long, the other a signed long (int32_t). Noticed as i turned the other way and my readings of the step count were suddenly a little bit to big... it works now with the signed function, i can read the steps accuratly.

I tested it with calling the functions twice in a row, as seen below:

    // get encoder value
    int32_t motEncVal_Reg2 = motReadSignedData(0x39);
    Serial.print("Encoder Value via motReadData(0x39): ");
    Serial.println(motEncVal_Reg2);
    Serial.println();
    motEncVal_Reg2 = motReadSignedData(0x39);
    Serial.print("Encoder Value via motReadData(0x39): ");
    Serial.println(motEncVal_Reg2);
    Serial.println();

    // get steps
    int32_t motPosVal_Reg = motReadSignedData(0x21);
    Serial.print("step Value via motReadData(0x21): ");
    Serial.println(motPosVal_Reg);
    Serial.println();
    motPosVal_Reg = motReadSignedData(0x21);
    Serial.print("step Value via motReadData(0x21): ");
    Serial.println(motPosVal_Reg);
    Serial.println();

My output per check-interval is this:

Encoder Value via motReadData(0x39): 600
Encoder Value via motReadData(0x39): 0
step Value via motReadData(0x21): 0
step Value via motReadData(0x21): 600

(after 3 times 200 steps in one direction)

During running I turned the shaft by hand in the downtime of the motor, which is disabled in between the movement commands (digitalWrite(motEN_pin, HIGH); ), to check if something happens. Sadly not, i only read the step count whoch the driver assumes is correct. (Also, the step count is shown correct, no issues there).

In the meantime i tried to setup the SPI differently...

  SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE3));

...but it had no influence on the result.

Does seem like the problem is with the encoder.
Do you have an oscilloscope to check the signals?

Don't have one right now, but i will grab one from the other lab on monday. Good idea to have a look, thanks ^^

For now you could connect an LED and a 1K resistor to one of the inverted outputs maybe A- and see if it goes ON/OFF when you spin the motor.

I used an oscilloscope to analyse the signal of the ABZ wires, all give plausible signals: peaks in 5 V, slower frequency at the start and end of a movement, the Z (N) gives one spike per rotation. Same for the inversed wires. Additionally, i checked all the connections again and let them check by a friend, nothing seems to be wrong. I also used the "inversed" configuration, (A-, B- and Z-) but same result.
I still assume it is an issue with the code...

So the encoder seems to be OK.
I've never used that IC and I won't pretend I know how to use it or the TMC library.
I did see that analogdevices does have code for accessing the registers.

Hi Jim

Thanks for the link to the library. I had a look, but i found nothing usefull there.

Nevertheless, I finally got it running.
Now, what was the issue? The init of the motor, as I suspected.
For other with maybe the same issue, here is the solution. In the arduino setup, I added the following lines:

  motSendData(0xB8, 0x00000400);  // ENCMODE: Set enc_sel_decimal to a 1
  motSendData(0xBA, 0x00000032);  // ENC_CONST of 0.005 ()

The motSendData function does the following:

void motSendData(unsigned long address, unsigned long datagram) { 
    // c/p from somewhere in the net, it works so far
	unsigned long i_datagram;
	digitalWrite(motCS_pin,LOW);
	delay(25);
	SPI.transfer(address);
	i_datagram |= SPI.transfer((datagram >> 24) & 0xff);
	i_datagram <<= 8;
	i_datagram |= SPI.transfer((datagram >> 16) & 0xff);
	i_datagram <<= 8;
	i_datagram |= SPI.transfer((datagram >> 8) & 0xff);
	i_datagram <<= 8;
	i_datagram |= SPI.transfer((datagram) & 0xff);
	digitalWrite(motCS_pin,HIGH);
	delay(15);
}

In this function, first the register is given according to the datasheet, then the desired value.
The fist line in the setup i added is for the ENCMODE. There i had to set the 10th bit to a 1 to set the next value, enc_sel_decimal, correctly.

ENCMODE is in register 0x38. As defined in the datasheet, when i want to WRITE to a register, 0x80 has to be added to the register adress, therefore it is 0xB8 instead of 0x38. And the 10th bit to 1 is 0x00000400 in hex.

Afterwards, i set ENC_CONST to 0.005. This defines the scaling of the encoder.
The value is calculated with this formula:
[Steps of the motor per revolution] * [used microsteps] / [encoder resolution]
In my case:

  • 200 steps per revolution
  • 1 for microsteps as i dont use it currently
  • 40'000 lines as per encoder datasheet

...results in a value of 0.005. To write values with fractions, the following system is used: ENC_CONST = 0x0000.0x0000 = Factor.Fraction. The fraction is multiplied by 10'000 when the 10th bit in ENCMODE is set to a 1, as we did just above.
Example: 25.6 = 0x00191770 (25 dec = 19 hex, 0.6*10'000 dec = 1770 hex)
Therefore, in my case of 0.005, i have to write 0xBA00000032 (as 0.005 * 10'000 = 50 dec = 32 hex).

With this set, the encoder shows the same value as the amount of steps executed. If I rorate the motor by hand, the encoder will show the exact value and will not be in sync with the steps anymore. If i want to increase the resolution of the encoder, i can increase the facor in ENC_CONST. For example, i want 2 encoder values per 1 step, therefore 400 per full revolution, I use 0.01 as ENC_CONST, therefore send the command 0xBA00000064 to the TMC5130 driver.

I hope this helps anyone struggling with this encoder issue. Thanks again to grumpy-mike and jim-p for their support.

1 Like

Glad you figured it out
Have a nice day!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.