Make your 3D-Printer silent with silentStepStick and stealthChop
SilentStepStick is a stepStick And Polulu compatible small stepper driver board with TMC2100, a great microstep resolution of 256 times and an interpolator so you can use it with standard step pulse engines.
It is designed and manufactured by Watterott electronic in Germany and shipped to the whole world.
Today the first protos of our new TRINAMIC RepRap Arduino Mega Shield (TRAMS) arrived – looking forward to having it operational in a few days.
TRAMS is a derivative of the popular RAMPS board and is build to work with an Arduino Mega Board. We developed a Marlin variant that uses the internal ramp controllers of TMC5130 and thus relieves the MCU from the task of generating the step pulses.
We will solve the “double step” problem all available open source printer solutions have. In addition TMC5130 comes with the absolutely silent stealthChop™ mode and will make the printer as silent as it can be.
Of course the board will be open source hardware and the firmware will be given back to the open source.
For some weeks now we are working on our TRAMS 3D-printer shield – TRAMS is a derivative of the popolar RAMPS shield for Arduino Mega Boards.
TRAMS is based on 4 TMC5130 cDriver – a Stepper motor driver with integrated ramp controller, so it offloads the AVR and reduces interrupt load to 10% of the original load.
TMC5130 comes with the same stealthChop™ feature we introduced in out TMC2100 and TMC2130, that is already known from the silentStepStick and makes the fans and mechanics the loudes part at the printer.
The firmware is integrated in the popular Marlin software and controlled by repetier host and will of course be open source as the hardware design will be.
Only a few wires including an SPI port are required to control TMC5130-EVAL with your Arduino. Here are the few steps required to get started.
Preparation
If your Arduino is a 5V type you have to resolder one resistor on the TMC5130-EVAL from position R3 to R8. This sets the logic level of the TMC5130 to +5V. While by default the resistor is soldered to the “right-hand” position, you have to move it to the “left-hand” position for 5V operation.
Wiring
The wiring is very simple. You will need 8 jumper wires. To make the wiring more easy you can print out the TMC5130-EVAL_Pinning.pdf and cut out the template to mount it on the connector header of the TMC5130-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
DRV_ENN –> black
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 TMC5130 and executes a simple move to position cycle. It will rotate a 200 full step motor 10 revolutions to the one and 10 revolutions to the other direction depending on the wiring of the stepper motor. Please use either the TMC5130 datasheet or the TMCL IDE as a reference for the different registers.
#include <SPI.h>
#include "TMC5130_registers.h"
/* The trinamic TMC5130 motor controller and driver 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 Pins Eval Board Pins
* 51 MOSI 32 SPI1_SDI
* 50 MISO 33 SPI1_SDO
* 52 SCK 31 SPI1_SCK
* 25 CS 30 SPI1_CSN
* 17 DIO 8 DIO0 (DRV_ENN)
* 11 DIO 23 CLK16
* GND 2 GND
* +5V 5 +5V
*/
int chipCS = 25;
const byte CLOCKOUT = 11;
int enable = 17;
void setup() {
// put your setup code here, to run once:
pinMode(chipCS,OUTPUT);
pinMode(CLOCKOUT,OUTPUT);
pinMode(enable, OUTPUT);
digitalWrite(chipCS,HIGH);
digitalWrite(enable,LOW);
//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);
sendData(0x80,0x00000000); //GCONF
sendData(0xEC,0x000101D5); //CHOPCONF: TOFF=5, HSTRT=5, HEND=3, TBL=2, CHM=0 (spreadcycle)
sendData(0x90,0x00070603); //IHOLD_IRUN: IHOLD=3, IRUN=10 (max.current), IHOLDDELAY=6
sendData(0x91,0x0000000A); //TPOWERDOWN=10
sendData(0xF0,0x00000000); // PWMCONF
//sendData(0xF0,0x000401C8); //PWM_CONF: AUTO=1, 2/1024 Fclk, Switch amp limit=200, grad=1
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,0x0000000A); //VSTOP=10
sendData(0xA0,0x00000000); //RAMPMODE=0
sendData(0xA1,0x00000000); //XACTUAL=0
sendData(0xAD,0x00000000); //XTARGET=0
}
void loop()
{
// put your main code here, to run repeatedly:
sendData(0xAD,0x0007D000); //XTARGET=512000 | 10 revolutions with micro step = 256
delay(20000);
sendData(0x21,0x00000000);
sendData(0xAD,0x00000000); //XTARGET=0
delay(20000);
sendData(0x21,0x00000000);
}
void sendData(unsigned long address, unsigned long datagram)
{
//TMC5130 takes 40 bit data: 8 address and 32 data
delay(100);
uint8_t stat;
unsigned long i_datagram;
digitalWrite(chipCS,LOW);
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(chipCS,HIGH);
Serial.print("Received: ");
PrintHex40(stat, i_datagram);
Serial.print("\n");
Serial.print(" from register: ");
Serial.println(address,HEX);
}
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);
}
Download
The Arduino and TMC5130 zip file includes the pinning template, the TMC5130-EVAL schematic and the Arduino project.
In this start up guide you get explained how to connect your Raspberry Pi 3 or 2 for the basic operation of the TMC5130-EVAL board. It will use the internal Motion Controller and +3V3 logic supply for the TMC5130. The wiring will be limited to the basic functionallity to communicate via SPI. The internal CLK for the TMC5130 will be used respective the CLK16 pin (Shown on figure 1) has to be tied to GND. The SPI CLK frequency of the Raspberry Pi will be set up to be 1MHz.
Preparation
With a fresh installation of Raspbian (In this tutorial Raspbian Jessy Lite – Version March 2017 – Release date 2017-03-02) first update the libraries:
sudo apt-get update
sudo apt-get dist-upgrade
This may take a while since it will upgrade all packages that are installed to the newest version if available. Furthermore it will upgrade dependencies or remove them if they have been replaced with other dependencies.
Download and install the bcm2835 library. Note XXX is a place holder for the latest version. For this guide version “1.52” was used. In this case XXX is replaced by “1.52”. You can check the latest version by scrolling to the bottom of the following page: http://www.airspayce.com/mikem/bcm2835/
wget http://www.airspayce.com/mikem/bcm2835/bcm2835-XXX.tar.gz
gunzip bcm2835-XXX.tar.gz
tar xvf bcm2835-XXX.tar
cd bcm2835-XXX
./configure
make
sudo make check // This should show you a pass message
sudo make install
Afterwards restart your PI by typing.
sudo reboot -h 0
Wiring
The wiring is very simple. You will need 8 jumper wires. As a reference you can use the TMC5130-Eval_v15_01_Schematic.pdf. You will find the signals that are on each pin.
Signal
Raspberry Pi 2
TMC5130-EVAL
+5V
+5V (2)
+5V (5)
GND
GND (39)
GND (2)
TMC5130 enable
GND (9)
DIO_0 (8)
TMC5130 CLK
GND (6)
CLK16 (23)
MOSI
SPI0 MOSI (19)
SPI1_SDI (32)
MISO
SPI0 MISO (21)
SPI1_SDO (33)
SPI CLK
SPI0 SCLK (23)
SPI1_SCK (31)
Chip select (CS)
SPI0 CS0 (24)
SPI1_CSN (30)
Please note that the TMC5130-EVAL has to be powered with the supply voltage e.g. 24V. To avoid damage only disconnect or connect a motor without supply voltage.
Raspberry Pi Code
An example code to initialize the TMC5130 is shown below. It will clear the reset flag in the GCONF register, sets example chopper configurations and sets the run and hold current for the motor. Furthermore it will set the ramping mode to velocity mode, an acceleration and a velocity. Be aware that the motor runs as soon as you execute the script.
You can download the code directly with your pi by typing:
Today we show how to connect TRINAMIC’s TMC5072-EVAL via Single Wire UART to an Arduino Mega for basic operation. The wiring is limited to the basic functionality to communicate via Single Wire UART.
Preperation
To use the 5V version of the Arduino MEGA you have to resolder Resistor from position R3 to R8. This enables 5V logic level for the TMC5072. The sense resistor by default is soldered to the right position. Please desolder and resolder to the left position.
Wiring
The wiring is very simple. You will need X jumper wires. To make the wiring easier you can connect the wire directly to the Eselsbrücke. As a reference you can use the TMC5072Eval_v10_01_Schematic.pdf. Here you 1nd the signals that are on each pin. The con1guration is documented in the comment section of the Arduino code.
Arduino Code
The Arduino Code below is based on the TMC-API package. The program initializes the TMC5072 and executes a simple move to position cycle. The sequence will rotate two 200 full stepper motors 10 revolutions to the one and 10 revolutions to the other direction depending on the wiring of the stepper motor. Please refer to the TMC5072 datasheet or the TMCL-IDE as a reference for the different registers.
TMC5072-EVAL_UART.ino
/*
* TMC5072-EVAL_UART.ino
*
* Created on: 20.02.2017
* Author: MN
*
* The Trinamic TMC5072 motor controller and driver operates through Single
* Wire UART. This is 64 bits datagram (8 sync bytes, 8 bit slave address,
* 8 bit register address and 32 bit word).
* Each register is specified by a one byte register address: with MSB = 0
* for read, MSB = 1 for write.
*
* Arduino Pins Eval Board Pins
* 18 TX1 40 SWIOP
* 19 RX1 41 SWION
* 2 DIO 38 DIO16 (SWSEL)
* 4 DIO 33 SDO/RING
* 3 DIO 8 DIO0 (DRV_ENN)
* 10 DIO 23 CLK16
* GND 2 GND
* +5V 5 +5V
*/
#include "TMC5072_register.h"
#include "CRC.h"
#define CRC8_GEN 0x07
int SWSEL = 2;
int DRV_ENN = 3;
int SDO_RING = 4;
const int CLOCKOUT = 10;
void setup() {
pinMode(SWSEL, OUTPUT);
pinMode(CLOCKOUT,OUTPUT);
pinMode(DRV_ENN, OUTPUT);
pinMode(SDO_RING, OUTPUT);
digitalWrite(DRV_ENN, LOW);
//HIGH = power stage disabled, LOW = power stage enabled
digitalWrite(SWSEL, HIGH);
//HIGH = UART mode, LOW = SPI mode
digitalWrite(SDO_RING, HIGH);
//HIGH = ring mode, LOW = normal mode
//setup timer2
TCCR2A = ((1 << WGM21) | (1 << COM2A0));
TCCR2B = (1 << CS20);
TIMSK2 = 0;
OCR2A = 0;
Serial.begin(115200);
Serial1.begin(115200);
delay(500);
uartWriteDatagram(0x00, TMC5072_SLAVECONF, 0x00000001); //SLAVEADDR to 1
delay(500);
tmc5072_initMotorDrivers();
}
void loop() {
// put your main code here, to run repeatedly:
uartRead(0x01, TMC5072_XACTUAL_1); //read out XACTUAL of motor 1
uartRead(0x01, TMC5072_XACTUAL_2); //read out XACTUAL of motor 2
uartWriteDatagram(0x01, TMC5072_XTARGET_1, 0x0007D000);
//XTARGET=512000 | 10 revolutions with micro step = 256
uartWriteDatagram(0x01, TMC5072_XTARGET_2, 0xFFF83000);
//XTARGET=-512000 | 10 revolutions with micro step = 256
delay(15000);
uartRead(0x01, TMC5072_XACTUAL_1); //read out XACTUAL of motor 1
uartRead(0x01, TMC5072_XACTUAL_2); //read out XACTUAL of motor 2
uartWriteDatagram(0x01, TMC5072_XTARGET_1, 0x00000000); //XTARGET=0
uartWriteDatagram(0x01, TMC5072_XTARGET_2, 0x00000000); //XTARGET=0
delay(15000);
}
void uartWriteDatagram(uint8_t SLAVEADDR, uint8_t registerAddress,
unsigned long datagram) {
//TMC5072 takes 64 bit data: 8 sync + reserved, 8 chip address,
//8 register address, 32 data, 8 CRC
uint8_t CRC = 0;
int temp;
unsigned char buf[8];
CRC = NextCRC(CRC, 0x05, CRC8_GEN);
CRC = NextCRC(CRC, SLAVEADDR, CRC8_GEN);
CRC = NextCRC(CRC, registerAddress|0x80, CRC8_GEN);
CRC = NextCRC(CRC, (datagram >> 24) & 0xff, CRC8_GEN);
CRC = NextCRC(CRC, (datagram >> 16) & 0xff, CRC8_GEN);
CRC = NextCRC(CRC, (datagram >> 8) & 0xff, CRC8_GEN);
CRC = NextCRC(CRC, datagram & 0xff, CRC8_GEN);
buf[0] = 0x05;
buf[1] = SLAVEADDR;
buf[2] = registerAddress|0x80;
buf[3] = (datagram >> 24) & 0xff;
buf[4] = (datagram >> 16) & 0xff;
buf[5] = (datagram >> 8) & 0xff;
buf[6] = datagram & 0xff;
buf[7] = CRC;
temp = Serial1.write(buf, 8); //write datagram
Serial1.flush(); //wait until all datas are written
Serial1.readBytes(buf, 8); //clear input buffer
}
unsigned long uartRead(uint8_t SALVEADDR, uint8_t registerAddress) {
uint8_t CRC = 0, temp;
unsigned char buf[8];
unsigned long dataBytes;
CRC = NextCRC(CRC, 0x05, CRC8_GEN);
CRC = NextCRC(CRC, SALVEADDR, CRC8_GEN);
CRC = NextCRC(CRC, registerAddress, CRC8_GEN);
buf[0] = 0x05;
buf[1] = SALVEADDR;
buf[2] = registerAddress;
buf[3] = CRC;
Serial1.write(buf, 4); //write datagram
Serial1.flush(); //wait until all datas are written
Serial1.readBytes(buf, 4); //clear input buffer
Serial1.readBytes(buf, 8);
temp = buf[2];
dataBytes = buf[3]; //bit 32...24
dataBytes <<= 8;
dataBytes |= buf[4]; //bit 23...16
dataBytes <<= 8;
dataBytes |= buf[5]; //bit 15...8
dataBytes <<= 8;
dataBytes |= buf[6]; //bit 7...0
CRC = 0;
for(int i=0;i<7;i++)
{
CRC = NextCRC(CRC, buf[i], CRC8_GEN);
}
//show received bytes
Serial.print("Received: 0x");
for(int i=0;i<8;i++)
{
char tmp[16];
sprintf(tmp, "%.2X", buf[i]);
Serial.print(tmp);
}
Serial.print("\n");
Serial.print("CRC: "); Serial.print(CRC,HEX);Serial.print(" <-> BUFFER: ");
Serial.println(buf[7],HEX);
return dataBytes;
}
void tmc5072_initMotorDrivers()
{
//2-phase configuration Motor 1
uartWriteDatagram(0x01, TMC5072_CHOPCONF_1, 0x00010135);
uartWriteDatagram(0x01, TMC5072_IHOLD_IRUN_1, 0x00071400);
//2-phase configuration Motor 2
uartWriteDatagram(0x01, TMC5072_CHOPCONF_2, 0x00010135);
uartWriteDatagram(0x01, TMC5072_IHOLD_IRUN_2, 0x00071400);
//Reset positions
uartWriteDatagram(0x01, TMC5072_RAMPMODE_1, TMC5072_MODE_POSITION);
uartWriteDatagram(0x01, TMC5072_XTARGET_1, 0);
uartWriteDatagram(0x01, TMC5072_XACTUAL_1, 0);
uartWriteDatagram(0x01, TMC5072_RAMPMODE_2, TMC5072_MODE_POSITION);
uartWriteDatagram(0x01, TMC5072_XTARGET_2, 0);
uartWriteDatagram(0x01, TMC5072_XACTUAL_2, 0);
//Standard values for speed and acceleration
uartWriteDatagram(0x01, TMC5072_VSTART_1, 1);
uartWriteDatagram(0x01, TMC5072_A1_1, 5000);
uartWriteDatagram(0x01, TMC5072_V1_1, 26843);
uartWriteDatagram(0x01, TMC5072_AMAX_1, 5000);
uartWriteDatagram(0x01, TMC5072_VMAX_1, 100000);
uartWriteDatagram(0x01, TMC5072_DMAX_1, 5000);
uartWriteDatagram(0x01, TMC5072_D1_1, 5000);
uartWriteDatagram(0x01, TMC5072_VSTOP_1, 10);
uartWriteDatagram(0x01, TMC5072_VSTART_2, 1);
uartWriteDatagram(0x01, TMC5072_A1_2, 5000);
uartWriteDatagram(0x01, TMC5072_V1_2, 26843);
uartWriteDatagram(0x01, TMC5072_AMAX_2, 5000);
uartWriteDatagram(0x01, TMC5072_VMAX_2, 100000);
uartWriteDatagram(0x01, TMC5072_DMAX_2, 5000);
uartWriteDatagram(0x01, TMC5072_D1_2, 5000);
uartWriteDatagram(0x01, TMC5072_VSTOP_2, 10);
}
/****************************************************
Projekt: TMC5130 and TMC5072 CRC calculation
Modul: CRC.h
CRC-Calculation for UART interfacing
Hinweise: Start with CRC-Register=0,
then call NextCRC for each byte to be sent
or each by received. Send CRC byte last or
check received CRC
Datum: 14.6.2011 OK
*****************************************************/
#ifndef CRC_H
#define CRC_H
#include "TypeDefs.h"
uint8 NextCRCSingle(uint8 Crc, uint8 Data, uint8 Gen, uint8 Bit);
uint8 NextCRC(uint8 Crc, uint8 Data, uint8 Gen);
#endif
CRC.cpp
/****************************************************
Projekt: TMC5130 and TMC5072 CRC calculation
Modul: CRC.cpp
CRC-Calculation for UART interfacing
Hinweise: Start with CRC-Register=0,
then call NextCRC for each byte to be sent
or each by received. Send CRC byte last or
check received CRC
Datum: 14.6.2011 OK
Geändert: crc counting direction, 17.06.2011, LL, SK
*****************************************************/
#include "CRC.h"
uint8 NextCRCSingle(uint8 Crc, uint8 Data, uint8 Gen, uint8 Bit)
{
uint8 Compare;
Compare=Data<<(7-Bit);
Compare&=0x80;
if((Crc & 0x80) ^ (Compare))
return (Crc << 1) ^ Gen;
else
return (Crc << 1);
}
uint8 NextCRC(uint8 Crc, uint8 Data, uint8 Gen)
{
uint8 Temp;
int i;
Temp=Crc;
for(i=0; i<=7; i++)
{
Temp=NextCRCSingle(Temp, Data, Gen, i);
}
return Temp;
}
TypeDefs.h
/*
* Types.h
*
* Created on: 29.09.2016
* Author: ed
*/
#ifndef API_TYPEDEFS_H
#define API_TYPEDEFS_H
// unsigned types
typedef unsigned char u8;
typedef unsigned short u16;
// typedef unsigned int u32;
typedef unsigned long long u64;
typedef unsigned char uint8;
typedef unsigned short int uint16;
typedef unsigned long int uint32;
typedef unsigned long long uint64;
#define u8_MAX (u8)255
#define u10_MAX (u16)1023
#define u12_MAX (u16)4095
#define u15_MAX (u16)32767
#define u16_MAX (u16)65535
#define u20_MAX (u32)1048575uL
#define u24_MAX (u32)16777215uL
#define u32_MAX (u32)4294967295uL
// signed types
typedef signed char s8;
typedef signed short s16;
typedef signed int s32;
typedef signed long long s64;
typedef signed char int8;
typedef signed short int int16;
typedef signed long int int32;
typedef signed long long int64;
#define s16_MAX (s16)32767
#define s16_MIN (s16)-32768
#define s24_MAX (s32)8388607
#define s24_MIN (s32)-8388608
#define s32_MAX (s32)2147483647
#define s32_MIN (s32)-2147483648
#define FALSE 0
#define TRUE 1
// parameter access
#define READ 0
#define WRITE 1
// "macros"
#define MIN(a,b) (a<b) ? (a) : (b)
#define MAX(a,b) (a>b) ? (a) : (b)
#ifndef UNUSED
#define UNUSED(x) (void)(x)
#endif
#ifndef NULL
#define NULL 0x00u
#endif
#endif /* API_TYPEDEFS_H */
There is a debate going on in the 3D printing community whether or not to use TL-Smoothers. These little modules can be added to stepper motors of 3D printers, offering recovery diodes to protect the electronic system from motor current that flows back into the system. This article discusses the use of such diodes, also known as catch diodes, flyback diodes or freewheeling diodes, and whether or not TL-Smoothers should be used in 3D printers with modern stepper drivers.
Historic use:
The idea to add recovery diodes to chopper-controlled drivers came up decades ago, when there were early (stepper motor) drivers in bipolar technology. The reason is, that bipolar devices do not automatically have internal recovery diodes: Each chopper operated motor driver (half bridge) needs so-called break-before-make operation, in order to prevent a short time short circuit between high-side and low-side device. During the so-called break-before-make (BBM) time or dead-time, both high-side and low-side devices are off. However, the inductivity of the motor coil will keep current flowing and thus it needs to flow somewhere. This is where the recovery diodes are needed – either within the driver IC, or externally. With these bipolar drivers, the external diode often has been required to protect the driver IC. It will catch motor current not only during break-before-make time, but also during times of so-called fast decay, where the motor coil feeds back energy to the power supply. Modern drivers use synchronous rectification in order to relieve the diodes and to reduce power consumption in diodes.
These bipolar drivers have been popular in the eighties and some of them are still on the market.
The first MOSFET based stepper drivers had a high MOSFET resistance due to their costly technology. They profit from the external recovery diodes, because they catch current not only during break-before-make time but also during conduction of the MOSFETs in fast-decay mode. This eliminates part of the power dissipation, and even more important a part of the power dissipation inside the IC. Reducing power dissipation allows reaching higher overall current due to reduced heating up of the driver chip itself.
Image 1: Switching diagram showing how diodes take over current with break before make time (BBM)
Effect in modern drivers:
Due to the required break-before-make (BBM) operation of each motor driver half-bridge, the intrinsic MOSFET bulk diodes become active for a short time with each switching event. Once the BBM time ends, the diodes have to recover, i.e. they go from a conducting to a non-conducting state. This recovery needs a few 10ns to roughly 150ns and some energy. As the recovery ends quite abruptly, it will cause high current spikes and inductive ringing in the interconnections with each switching event.
The external recovery diodes typically are Schottky diodes, which offer a fast and soft recovery and low forward voltage. Their recovery behavior is much better than that of the MOSFET bulk diodes. Due to the low flow voltage of the Schottky diodes, they will prevent conduction of the MOSFET bulk diodes within the driver ICs completely, and thus eliminate the recovery energy and ringing.
However, modern MOSFET drivers use improved technology which gives better recovery and also shorter, more precise BBM-times than previous older designs from the early 2000s.
There also is one additional effect which is not during actual operation: Upon hot unplugging a motor, the diodes will take over inductive currents and might save the driver from destruction.
Image 2: Diode recovery ringing, explaining ringing during reverse recovery
Actual benefits of Schottky recovery diodes
The argument to reduce power dissipation still is true with actual drivers when they are operated near their limits. However, the effect is smaller and you might not even notice the few percent difference a TL-Smoother makes in 3D printers.
The argument to improve diode recovery should be of less importance: The reason is, that MOSFET bulk diode recovery has improved a lot with modern ICs.
With a poorly designed driver IC, or poor layout, however, the current spikes caused by MOSFET driver recovery diodes could negatively influence the control part of the chip and reduce quality of the current regulation. In this case, the external diodes could also improve microstepping quality and thus printing quality. This probably is what some users see as improved printing quality with the TL-Smoothers.
For Trinamic drivers, the diodes offered on TL-Smoothers are not required and will only slightly reduce power dissipation when operating at motor currents near to the driver IC limit. In fact, when using Trinamic drivers in SpreadCycle mode, it is advised not to use recovery diodes as they negatively influence the SpreadCycle current regulation.
SpreadCycle measures both positive and negative current running through the sense resistor and uses this measurement to optimize chopper operation. Recovery diodes or TL-Smoothers allow part of the current to bypass the point of measurement, meaning SpreadCycle can’t measure the correct values. Due to this, the additional external Schottky diode from motor output to GND would negatively impact SpreadCycle operation. With StealthChop, however, there’s no negative effect of using additional recovery diodes as it measures different values.
Summed up, TL-Smoothers will only have a minor effect on the print when using state-of-the-art stepper driver ICs, so there’s no need to use them in 3D printers with Trinamic’s chips.
This start-up guide explains how to connect your Raspberry Pi 3 to the TMC5160-BOB – the breakout board of the brand new TMC5160. We’ll be using the internal Motion Controller and +3V3 logic supply for the TMC5160. The wiring will be limited to the basic functionality to communicate via SPI. The usage of the TRINAMIC’s API – TMC-API – is minimizing the software effort.
Preparation
In this tutorial we are using a fresh Raspbian Stretch System (Version November 2017 – Release date 2017-11-29) with the latest updates:
sudo apt update
sudo apt upgrade
Download and install the bcm2835 library. Note XXX is a placeholder for the latest version. For this guide version “1.52” was used. In this case, XXX is replaced by “1.52”. You can check the latest version by scrolling to the bottom of the following page: http://www.airspayce.com/mikem/bcm2835/
wget http://www.airspayce.com/mikem/bcm2835/bcm2835-XXX.tar.gz
tar zxvf bcm2835-XXX.tar
cd bcm2835-XXX
./configure
make
sudo make check
sudo make install
Create a project folder and download the latest TMC-API. Note X.XX is a placeholder for the latest version. For this guide version “3.02” was used. In this case, X.XX is replaced by “3.02”. You can check the latest version by scrolling to the bottom of the following page: https://www.trinamic.com/support/software/access-package/
The wiring is very simple. You will need 8 jumper wires. As a reference you can use the TMC5160-BOB_datasheet_Rev1.0.pdf. You will find the signals that are on each pin.
Signal
Raspberry Pi 3
TMC5160-BOB
VCC_IO
GPIO02 (3)
VCC_IO (1)
GND
GND (39)
GND (2)
SPI Chip select (CS)
SPI0 CE0 N (24)
CSN (3)
SPI CLK
SPI0 SCLK (23)
SCK (4)
MOSI
SPI0 MOSI (19)
SDI (5)
MISO
SPI0 MISO (21)
SDO (6)
TMC5160 CLK
GPIO04 (7)
CLK (8)
TMC5160 DRV_ENN
GPIO03 (5)
DRV_ENN (9)
TMC5160-BOB
Raspberry Pi 3 GPIO Header – Source: https://www.element14.com/community/docs/DOC-73950/l/raspberry-pi-3-model-b-gpio-40-pin-block-pinout
Raspberry Pi Code
An example code to initialize the TMC5160 is shown below. These files need to be placed in the same project folder as the TMC-API, in this case into ~/TMC_EXAMPLE. First, +3.3V is supplied to VCC_IO, the driver stages are enabled by pulling down DRV_ENN and the internal clock is used by pulling down CLK16. Afterwards, the TMC5160 is initialized and a simple move to position cycle is executed. The sequence will rotate a 200 full stepper motor 10 revolutions clockwise and 10 revolutions counterclockwise – depending on the wiring of the stepper motor. Please refer to the TMC5160 datasheet or the TMCL-IDE as a reference for the different registers.
You can also download the source files directly with your Pi:
cd ~/TMC_EXAMPLE
wget http://blog.trinamic.com/wp-content/uploads/2018/01/TMC5160_TMCAPI_EXAMPLE.tar.gz
tar zxvf TMC5160_TMCAPI_EXAMPLE.tar.gz
#include <stdio.h>
#include <wiringPi.h>
#include <bcm2835.h>
#include "SPI_TMC.h"
// Include the IC(s) you want to use
#include "TMC-API/tmc/ic/TMC5160/TMC5160.h"
#define MOTOR0 0 // Motor 0
void resetMotorDrivers(uint8 motor);
int main(int argc, char **argv) {
if (!bcm2835_init())
return 1;
wiringPiSetupGpio();
// Initiate SPI
bcm2835_spi_begin();
bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST); // MSB first
bcm2835_spi_setDataMode(BCM2835_SPI_MODE3); // SPI Mode 3
bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_256); // 1 MHz clock
bcm2835_spi_chipSelect(BCM2835_SPI_CS0); // define CS pin
bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW); // set CS polarity to low
/***** TMC5160-BOB Example *****/
pinMode(2, OUTPUT);
digitalWrite(2, HIGH); // Apply VCC_IO voltage to Motor 0
pinMode(3, OUTPUT);
digitalWrite(3, LOW); // Use internal clock
pinMode(4, OUTPUT);
digitalWrite(4, LOW); // Enable driver stage
resetMotorDrivers(MOTOR0);
// MULTISTEP_FILT=1, EN_PWM_MODE=1 enables stealthChop
tmc5160_writeInt(MOTOR0, TMC5160_GCONF, 0x0000000C);
// TOFF=3, HSTRT=4, HEND=1, TBL=2, CHM=0 (spreadCycle)
tmc5160_writeInt(MOTOR0, TMC5160_CHOPCONF, 0x000100C3);
// IHOLD=10, IRUN=15 (max. current), IHOLDDELAY=6
tmc5160_writeInt(MOTOR0, TMC5160_IHOLD_IRUN, 0x00080F0A);
// TPOWERDOWN=10: Delay before power down in stand still
tmc5160_writeInt(MOTOR0, TMC5160_TPOWERDOWN, 0x0000000A);
// TPWMTHRS=500
tmc5160_writeInt(MOTOR0, TMC5160_TPWMTHRS, 0x000001F4);
// Values for speed and acceleration
tmc5160_writeInt(MOTOR0, TMC5160_VSTART, 1);
tmc5160_writeInt(MOTOR0, TMC5160_A1, 5000);
tmc5160_writeInt(MOTOR0, TMC5160_V1, 26843);
tmc5160_writeInt(MOTOR0, TMC5160_AMAX, 5000);
tmc5160_writeInt(MOTOR0, TMC5160_VMAX, 100000);
tmc5160_writeInt(MOTOR0, TMC5160_DMAX, 5000);
tmc5160_writeInt(MOTOR0, TMC5160_D1, 5000);
tmc5160_writeInt(MOTOR0, TMC5160_VSTOP, 10);
tmc5160_writeInt(MOTOR0, TMC5160_RAMPMODE, TMC5160_MODE_POSITION);
while(1)
{
// put your main code here, to run repeatedly:
printf("Reply of TMC5160: 0x%08x\n", tmc5160_readInt(MOTOR0, TMC5160_XACTUAL));
tmc5160_writeInt(MOTOR0, TMC5160_XTARGET, 0x0007D000);
//XTARGET = 512000 -> 10 revolutions with micro step = 256
delay(12000);
printf("Reply of TMC5160: 0x%08x\n", tmc5160_readInt(MOTOR0, TMC5160_XACTUAL));
tmc5160_writeInt(MOTOR0, TMC5160_XTARGET, 0x00000000); //XTARGET=0
delay(12000);
}
// End SPI communication
bcm2835_spi_end();
bcm2835_close();
return 0;
}
void resetMotorDrivers(uint8 motor)
{
if(!tmc5160_readInt(MOTOR0, TMC5160_VACTUAL))
{
digitalWrite(2, LOW); // Apply VCC_IO voltage to Motor 0
delay(10);
digitalWrite(2, HIGH); // Apply VCC_IO voltage to Motor 0
delay(10);
}
}
/*
* SPI_TMC.h
*
* Created on: 12.01.2018
* Author: MN
*/
#ifndef SPI_TMC_H
#define SPI_TMC_H
#include "TMC-API/tmc/helpers/API_Header.h"
void initSPI(void);
// TMC5160 SPI wrapper
void tmc5160_writeDatagram(uint8 motor, uint8 address, uint8 x1, uint8 x2, uint8 x3, uint8 x4);
void tmc5160_writeInt(uint8 motor, uint8 address, int value);
int tmc5160_readInt(u8 motor, uint8 address);
// General SPI functions
void tmc40bit_writeInt(u8 motor, uint8 address, int value);
int tmc40bit_readInt(u8 motor, uint8 address);
#endif /* SPI_TMC_H */
#include <bcm2835.h>
#include "SPI_TMC.h"
// TMC5160 SPI wrapper
void tmc5160_writeDatagram(uint8 motor, uint8 address, uint8 x1, uint8 x2, uint8 x3, uint8 x4)
{
int value = x1;
value <<= 8;
value |= x2;
value <<= 8;
value |= x3;
value <<= 8;
value |= x4;
tmc40bit_writeInt(motor, address, value);
}
void tmc5160_writeInt(uint8 motor, uint8 address, int value)
{
tmc40bit_writeInt(motor, address, value);
}
int tmc5160_readInt(u8 motor, uint8 address)
{
tmc40bit_readInt(motor, address);
return tmc40bit_readInt(motor, address);
}
// General SPI decription
void tmc40bit_writeInt(u8 motor, uint8 address, int value)
{
char tbuf[5];
tbuf[0] = address | 0x80;
tbuf[1] = 0xFF & (value>>24);
tbuf[2] = 0xFF & (value>>16);
tbuf[3] = 0xFF & (value>>8);
tbuf[4] = 0xFF & value;
bcm2835_spi_writenb (tbuf, 5);
}
int tmc40bit_readInt(u8 motor, uint8 address)
{
char tbuf[5], rbuf[5];
int value;
// clear write bit
tbuf[0] = address & 0x7F;
bcm2835_spi_transfernb (tbuf, rbuf, 5);
value =rbuf[1];
value <<= 8;
value |= rbuf[2];
value <<= 8;
value |= rbuf[3];
value <<= 8;
value |= rbuf[4];
return value;
}
The TMC2300-IOT-REF is a completely open-source reference design for easy evaluation of the TMC2300-LA stepper motor driver IC. Whether it’s a POS device, toys, office and home automation, or mobile medical devices, Engineers can quickly prototype IoT applications running on 3.5 – 6 V batteries.
Besides the low-voltage stepper motor driver, the board features a Li-Ion cell charger via USB-C, an ESP32-PICO-D4 processor with integrated WiFi and BLE capabilities, as well as UART and USB-C for serial communication and programming. Other features including StealthChop2, StallGuard4 and CoolStep bring industrial-grade solutions to convenient, handheld devices.