Today we will wire up a TMC4361A-EVAL + TMC2130-EVAL combination to drive a stepper motor closed loop with an Arduino Uno. The encoder used for this test has a resolution of 10.000 cpr respective a resolution of 40.000.
Preparation
For this tutorial the Eselsbruecke got a soldered connection between +5V_USB (pin 5) to +5V_VM (pin 42) to get +5V for the encoder. You can use jumper wires as well but make sure the connection is properly.
Wiring
The wiring is very simple. You will need 9 jumper wires. To make the wiring more easy you can print out the TMC5130-EVAL_Pinning.pdf (used from a previous blog entry) and cut out the template to mount it on the connector header of the TMC4361-EVAL (As seen on illustration 4). As a reference you can use the TMC5130-Eval_v15_01_Schematic.pdf. Here you’ll find the signals that are on each pin. The configuration is documented in the comment section of the Arduino code.


Cable colors of illustration 4
+5V –> red
GND –> blue
SDO –> yellow
SDI –> orange
SCK –> white
CSN –> grey
DIO0 (DRV_ENN) –> black (Is passed thru to TMC2130-EVAL DRV_ENN pin)
DIO16 (NFREEZE) –> brown
CLK16 –> green
Arduino Code
The Arduino Code below does not need any additional libraries. The SPI library comes with the Arduino IDE. The program initializes the TMC2130 thru the TMC4361A-EVAL (cover datagram) and the TMC4361 itself. It will rotate a 200 full step motor 2 revolutions to the one and 2 revolutions to the other direction depending on the wiring of the stepper motor. Please use either the TMC4361 and TMC2130 datasheets as a reference for the different registers (Download links below).
#include <SPI.h> #include "TMC4361A_Register.h" /* The trinamic TMC4361 motor controller operates through an * SPI interface. Each datagram is sent to the device as an address byte * followed by 4 data bytes. This is 40 bits (8 bit address and 32 bit word). * Each register is specified by a one byte (MSB) address: 0 for read, 1 for * write. The MSB is transmitted first on the rising edge of SCK. * * Arduino Uno Pins Eval Board Pins * 11 MOSI 32 SPI1_SDI * 12 MISO 33 SPI1_SDO * 13 SCK 31 SPI1_SCK * 8 CS 30 SPI1_CSN * 7 DIO 8 DIO0 (DRV_ENN) * 9 DIO 23 CLK16 * 2 DIO 38 NFREEZE * GND 2 GND * +5V 5 +5V */ int chipCS = 8; const byte CLOCKOUT = 9; int enable = 7; int nFreeze = 2; void setup() { // put your setup code here, to run once: pinMode(chipCS,OUTPUT); pinMode(CLOCKOUT,OUTPUT); pinMode(enable, OUTPUT); pinMode(nFreeze, OUTPUT); digitalWrite(chipCS,HIGH); digitalWrite(enable,LOW); digitalWrite(nFreeze,HIGH); //set up Timer1 TCCR1A = bit (COM1A0); //toggle OC1A on Compare Match TCCR1B = bit (WGM12) | bit (CS10); //CTC, no prescaling OCR1A = 0; //output every cycle SPI.setBitOrder(MSBFIRST); SPI.setClockDivider(SPI_CLOCK_DIV8); SPI.setDataMode(SPI_MODE3); SPI.begin(); Serial.begin(9600); // General setup of TMC4361 Motion Controller with TMC2130 stepper driver sendData(0xCF,0x52535400); // reset squirrel sendData(0x83,0x00540022); // input filter: START and encoder pins sendData(0x84,0x8440000d); sendData(0x80,0x00007026); // direct-a, direct-bow sendData(0x90,0x00060004); // Steplength sendData(0xED,0x00000080); // Using cover datagram to write to GCONF of TMC2130: sendData(0xEC,0x00012200); // diag1=index, pushpull, direct_mode = on --> SPI mode sendData(0xED,0x00000090); // Using cover datagram to write to IHOLD_IRUN of TMC2130: sendData(0xEC,0x00051905); // IHOLD = 29, IHOLDDELAY = 5, IRUN = 25 sendData(0xED,0x00000091); // Using cover datagram to write to TPOWERDOWN of TMC2130: sendData(0xEC,0x0000000A); // TZEROWAIT = 10 sendData(0xED,0x00000094); // Using cover datagram to write to TCOOLTHRS of TMC2130: sendData(0xEC,0x000000C8); // = 200 sendData(0xED,0x00000095); // Using cover datagram to write to TCOOLTHRS of TMC2130: sendData(0xEC,0x00000032); // = 50 sendData(0xED,0x000000EE); // Using cover datagram to write to DCCTRL of TMC2130: sendData(0xEC,0x00070025); // sendData(0xED,0x000000F0); // Using cover datagram to write to PWMCONF of TMC2130: sendData(0xEC,0x000404FF); // DCCTRLSG = 5, DC_TIME = 37 sendData(0xED,0x000000EC); // Using cover datagram to write to CHOPCONF of TMC2130: sendData(0xEC,0x00010223); // sendData(0xED,0x000000ED); // Using cover datagram to write to COOLCONF of TMC2130: sendData(0xEC,0x0100a220); // OFF sendData(0xA4,0x00000000); // v = 0 sendData(0xA1,0x00000000); // xactual = 0 sendData(0xB7,0x00000000); // xtarget = 0 // Closed Loop calibration of TMC4361 Motion Controller sendData(0xD4,0x00009C40); // Encoder resolution = 40k/rev sendData(0x9C,0x00FF00FF); // CL_BETA = CL_GAMMA = 255 sendData(0xA0,0x00000004); // hold + position mode sendData(0xA4,0x00100000); // slow velocity sendData(0xDC,0x00010000); // cl_p = 1.0 sendData(0x87,0x00400000); // turn on closed loop sendData(0xB7,0x00000080); // move to full step position sendData(0x87,0x01400000); // turn on closed loop calibration sendData(0x87,0x00400000); // turn off closed loop calibration sendData(0xA4,0x00000000); // v = 0 // Setup Closed Loop Operation sendData(0xA0,0x00000006); // S-Ramp + POS Mode sendData(0xA4,0x079A8000); // VMAX = 400.000 pps sendData(0xA8,0x00000200); // AMAX sendData(0xA9,0x00000200); // DMAX sendData(0xAD,0x00000100); // bow1 sendData(0xAE,0x00000100); // bow2 sendData(0xAF,0x00000100); // bow3 sendData(0xB0,0x00000100); // bow4 sendData(0xE0,0x00250000); // emf_vmin = sendData(0xE1,0x00450000); // emf_vadd = -> emf_vmax = sendData(0xE2,0x00FFFFFF); // emf_vel0_timer sendData(0xE3,0x02000864); // enc vel filter settings sendData(0xDF,0x00000014); // cl_tolerance = 20 sendData(0xDC,0x00010000); // cl_p = 1.0 sendData(0xDA,0x000000C8); // cl_vlimit_p = 200 sendData(0xDB,0x00000032); // cl_vlimit_i = 50 sendData(0xDD,0x000003E8); // cl_vlimit_diclip = 1000 sendData(0xDE,0x00100000); // cl_vlimit = 100.000 pps sendData(0x86,0x0032f064); // cl scaling values sendData(0x98,0x00001000); // cl_upscale sendData(0x99,0x00100000); // cl_dnscale sendData(0x87,0x0A400000); // cl with gamma correction and vlimit sendData(0x85,0x00000080); // cl scaling on } void loop() { // put your main code here, to run repeatedly: sendData(0xB7,0x00019000); // XTARGET = 100.000 delay(3000); sendData(0xB7,0x00000000); // XTARGET = 0 delay(3000); } void sendData(unsigned long address, unsigned long datagram) { //TMC4361 takes 40 bit data: 8 address and 32 data delay(100); unsigned long i_datagram; digitalWrite(chipCS,LOW); delayMicroseconds(10); 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(chipCS,HIGH); Serial.print("Received: "); Serial.println(i_datagram,HEX); Serial.print(" from register: "); Serial.println(address,HEX); }
Download
The Arduino_TMC4361_TMC2130 zip file includes the pinning template, the TMC4361-EVAL schematic and the Arduino project.
Related Pages
- TMC4361A-LA
- TMC4361A-LA datasheet download
- TMC4361-EVAL
(Please note: This EVAL version has the previous TMC4361-LA on board. This version is compatible as well. The TMC4361A-EVAL will be available shortly.) - TMC2130
- TMC2130 datasheet download
- TMC2130-EVAL