Skip to content
No description or website provided.
C++ C
Branch: master
Clone or download
Latest commit d1921f8 Sep 7, 2018
Type Name Latest commit message Commit time
Failed to load latest commit information.
examples Fix compile issues with the new constructor May 24, 2018
src v0.2.5 Sep 7, 2018
.gitignore Add file Apr 12, 2017
LICENSE Initial commit Apr 6, 2017 rms_current() and getCurrent() now have different roles Apr 18, 2017
keywords.txt Use a single tab field separator in keywords.txt Jul 14, 2018 v0.2.5 Sep 7, 2018


Arduino library for Trinamic TMC2208 Stepper driver

Table of contents


Visual guide (

With Watterott SilentStepStick2208 TMC2208 powered stepper drivers with UART single wire interface, first make a solder bridge across J2 near PDN_UART pin located in the middle of the driver.

To write to the driver, connect the microcontroller TX line to PDN_UART.

To allow both writing and reading with the driver, connect microcontroller RX to PDN_UART and connect microcontroller TX to RX with a 1kOhm resistor.

Image by Watterott



#define EN_PIN    13 								// LOW: Driver enabled. HIGH: Driver disabled
#define STEP_PIN  54 								// Step on rising edge

#include <TMC2208Stepper.h>							// Include library
TMC2208Stepper driver = TMC2208Stepper(&Serial);	// Create driver and use
													// HardwareSerial0 for communication

void setup() {
	Serial.begin(115200);							// Init used serial port
	while(!Serial);									// Wait for port to be ready

	// Prepare pins
	pinMode(EN_PIN, OUTPUT);

	driver.pdn_disable(1);							// Use PDN/UART pin for communication
	driver.I_scale_analog(0);						// Adjust current from the registers
	driver.rms_current(500);						// Set driver current 500mA
	driver.toff(0x2);								// Enable driver

	digitalWrite(13, LOW);							// Enable driver

void loop() {
	digitalWrite(STEP_PIN, !digitalRead(STEP_PIN)); // Step

Writing to a register

Writing to a register will update the shadow register held by the library and then push the result to the driver.

uint32_t my_ihold_irun = 0x140C; // Set IRUN to 20 (DEC) and IHOLD to 12 (DEC)

Reading from a register

Writing to a register will return a boolean value indicating whether the CRC was valid. You need to give the function an address to the 32bit variable into which the function will store the response.

uint32_t data;
Serial.println(data, BIN);

Using the functions

All functions to Read and Write and Write-only registers provide both Read and Write capabilities. If the register is Write-only, the value will be read from a shadow register held by the library. Read functions to Read registers will read the register value and then bit mask and bit shift it for you. All non-helper functions write the given bit pattern to the register.

driver.tbl(0b10); // Is the same as...
driver.tbl(2);    // And will set the blank time to 32
// Read value from register
uint8_t my_blank_time = driver.tbl();

Helper functions

Function Description
void rms_current(

Set motor RMS current
uint16_t current_rms
float hold current multiplier (default=0.5)
float sense resistor value (default=0.11)
uint16_t rms_current() Reads rms_current based on the register settings
void setCurrent(

Same as rms_current but rsense and hold current arguments
are switched. No defaults so requires all three parameters.
uint16_t getCurrent() Read back the user input value
for rms_current() or setCurrent()
void microsteps(uint16_t) [0..256] Set number of microsteps
bool checkOT() Read otpw flag from DRV_STATUS register and return the result.
Also store the result in variable held by the library.
bool getOTPW() Return the flag value set by checkOT()
void clear_otpw() Clear the flag held by the libarary


Function Description
bool GCONF(uint32_t *) Read GCONF register
void GCONF(uint32_t) Write to the GCONF register
void I_scale_analog(bool) (Reset default=1)
0: Use internal reference derived from 5VOUT
1: Use voltage supplied to VREF as current reference
void internal_Rsense(bool) (Reset default: OTP)
0: Operation with external sense resistors
1: Internal sense resistors. Use current supplied into VREF as reference
for internal sense resistor. VREF pin internally is driven to GND in this mode.
void en_spreadCycle(bool) (Reset default: OTP)
0: stealthChop PWM mode enabled (depending on velocity thresholds).
Initially switch from off to on state while in stand still, only.
1: spreadCycle mode enabled
void shaft(bool) 1: Inverse motor direction
void index_otpw(bool) 0: INDEX shows the first microstep position of sequencer
1: INDEX pin outputs overtemperature prewarning flag (otpw) instead
void index_step(bool) 0: INDEX output as selected by index_otpw
1: INDEX output shows step pulses from internal pulse generator (toggle upon each step)
void pdn_disable(bool) 0: PDN_UART controls standstill current reduction
1: PDN_UART input function disabled. Set this bit, when using the UART interface!
void mstep_reg_select(bool) 0: Microstep resolution selected by pins MS1, MS2
1: Microstep resolution selected by MSTEP register
void multistep_filt(bool) (Reset default=1)
0: No filtering of STEP pulses
1: Software pulse generator optimization enabled when fullstep
frequency > 750Hz (roughly). TSTEP shows filtered step time values when active.


Function Description
void GSTAT(uint32_t) Write to GSTAT register
bool GSTAT(uint32_t*) Read GSTAT register
void reset(bool) 1: Indicates that the IC has been reset since the last
read access to GSTAT. All registers have been cleared to reset values.
void drv_err(bool) 1: Indicates, that the driver has been shut down due to
overtemperature or short circuit detection since the last read access. Read DRV_STATUS
for details. The flag can only be cleared when all error conditions are cleared.
void uv_cp(bool) 1: Indicates an undervoltage on the charge pump. The
driver is disabled in this case. This flag is not latched and thus does not need to be cleared.


Function Description
bool IFCNT(uint32_t*) Interface transmission counter. This register becomes
incremented with each successful UART interface write access. Read out to check the serial
transmission for lost data. Read accesses do not change the content.
The counter wraps around from 255 to 0.


Function Description
void SLAVECONF(uint32_t) Write register
bool SLAVECONF(uint32_t*) Read register
void senddelay(uint8_t) SENDDELAY for read access (time until reply is sent):
0, 1: 8 bit times
2, 3: 38 bit times
4, 5: 5
8 bit times
6, 7: 78 bit times
8, 9: 9
8 bit times
10, 11: 118 bit times
12, 13: 13
8 bit times
14, 15: 15*8 bit times


Function Description
void OTP_PROG(uint32_t) OTP_PROGRAM – OTP programming Write access programs OTP
memory (one bit at a time), Read access refreshes read data from OTP after a write
Selection of OTP bit to be programmed to the selected byte
location (n=0..7: programs bit n to a logic 1)
Selection of OTP programming location (0, 1 or 2)
Set to 0xbd to enable programming. A programming time of minimum 10ms per bit is recommended (check by reading OTP_READ).


Function Description


Function Description
bool IOIN(uint32_t*) INPUT (Reads the state of all input pins available)
bool enn() ENN
bool ms1() MS1
bool ms2() MS2
bool diag() DIAG
bool pdn_uart() PDN_UART
bool step() STEP
bool sel_a() SEL_A: Driver type
1: TMC220x
0: TMC222x
bool dir() DIR
uint8_t version() VERSION: 0x20=first version of the IC
Identical numbers mean full digital compatibility.


Function Description
void FACTORY_CONF(uint32_t) Write register
bool FACTORY_CONF(uint32_t*) Read register
void fclktrim(uint8_t) 0…31: Lowest to highest clock frequency. Check at
charge pump output. The frequency span is not guaranteed, but it is tested,
that tuning to 12MHz internal clock is possible. The devices come
preset to 12MHz clock frequency by OTP programming.
void ottrim(uint8_t) %00: OT=143°C, OTPW=120°C
%01: OT=150°C, OTPW=120°C
%10: OT=150°C, OTPW=143°C
%11: OT=157°C, OTPW=143°C


Function Description
void IHOLD_IRUN(uint32_t)
bool IHOLD_IRUN(uint32_t*)
void ihold(uint8_t) (Reset default: OTP)
Standstill current (0=1/32 … 31=32/32)
In combination with stealthChop mode, setting IHOLD=0 allows to choose
freewheeling or coil short circuit (passive braking) for motor stand still.
void irun(uint8_t) (Reset default=31)
Motor run current (0=1/32 … 31=32/32)
Hint: Choose sense resistors in a way, that normal IRUN is 16 to 31 for
best microstep performance.
void iholddelay(uint8_t) (Reset default: OTP)
Controls the number of clock cycles for motor power down after standstill is
detected (stst=1) and TPOWERDOWN has expired. The smooth transition avoids
a motor jerk upon power down.
0: instant power down
1..15: Delay per current reduction step in multiple of 2^18 clocks


Function Description
void TPOWERDOWN(uint32_t) (Reset default=20)
Sets the delay time from stand still (stst) detection to motor current power down.
Time range is about 0 to 5.6 seconds.
0…((2^8)-1) * 2^18 tCLK
Attention: A minimum setting of 2 is required to allow
automatic tuning of stealthChop PWM_OFFS_AUTO.
bool TPOWERDOWN(uint32_t*)


Function Description
bool TSTEP(uint32_t*) Actual measured time between two 1/256 microsteps derived
from the step input frequency in units of 1/fCLK. Measured
value is (2^20)-1 in case of overflow or stand still.
The TSTEP related threshold uses a hysteresis of 1/16 of the compare
value to compensate for jitter in the clock or the step
frequency: (Txxx*15/16)-1 is the lower compare value for each TSTEP based comparison.
This means, that the lower switching velocity equals the
calculated setting, but the upper switching velocity is higher
as defined by the hysteresis setting.


Function Description
void TPWMTHRS(uint32_t) Sets the upper velocity for stealthChop voltage PWM mode.
- stealthChop PWM mode is enabled, if configured
When the velocity exceeds the limit set by TPWMTHRS, the driver switches to spreadCycle.

0: Disabled

bool TPWMTHRS(uint32_t*)


Function Description
void VACTUAL(uint32_t) VACTUAL allows moving the motor by UART control.
It gives the motor velocity in +-(2^23)-1 [μsteps / t]
0: Normal operation. Driver reacts to STEP input.
0: Motor moves with the velocity given by VACTUAL. Step pulses can be
monitored via INDEX output. The motor direction is controlled by the sign of VACTUAL.
bool VACTUAL(uint32_t *)


Function Description
bool MSCNT(uint32_t*) Microstep counter. Indicates actual position in the
microstep table for CUR_A. CUR_B uses an offset of 256 into the table. Reading out
MSCNT allows determination of the motor position within the electrical wave.


Function Description
bool MSCURACT(uint32_t*)
uint16_t cur_a() CUR_A (signed):
Actual microstep current for motor phase A as read from
the internal sine wave table (not scaled by current setting)
uint16_t cur_b() CUR_B (signed):
Actual microstep current for motor phase B as read from
the internal sine wave table (not scaled by current setting)


Function Description
void CHOPCONF(uint32_t)
void toff(uint8_t) off time and driver enable

Off time setting controls duration of slow decay phase
NCLK= 12 + 32*TOFF
%0000: Driver disable, all bridges off
%0001: 1 – use only with TBL ≥ 2
%0010 … %1111: 2 … 15
(Default: OTP, resp. 3 in stealthChop mode)

void hstrt(uint8_t) hysteresis start value added to HEND

%000 … %111:
Add 1, 2, …, 8 to hysteresis low value HEND
(1/512 of this setting adds to current setting)
Attention: Effective HEND+HSTRT ≤ 16.
Hint: Hysteresis decrement is done each 16 clocks
(Default: OTP, resp. 0 in stealthChop mode)

void hend(uint8_t) hysteresis low value

%0000 … %1111:
Hysteresis is -3, -2, -1, 0, 1, …, 12
(1/512 of this setting adds to current setting)
This is the hysteresis value which becomes used for the hysteresis chopper.
(Default: OTP, resp. 5 in stealthChop mode)

void tbl(uint8_t) blank time select

%00 … %11:
Set comparator blank time to 16, 24, 32 or 40 clocks
Hint: %00 or %01 is recommended for most applications
(Default: OTP)

void vsense(bool) sense resistor voltage based current scaling

0: Low sensitivity, high sense resistor voltage
1: High sensitivity, low sense resistor voltage

void mres(uint8_t) micro step resolution

Native 256 microstep setting.
%0001 … %1000:
128, 64, 32, 16, 8, 4, 2, FULLSTEP
Reduced microstep resolution.
The resolution gives the number of microstep entries per sine quarter wave.
When choosing a lower microstep resolution, the driver automatically uses
microstep positions which result in a symmetrical wave.
Number of microsteps per step pulse = 2^MRES
(Selection by pins unless disabled by GCONF. mstep_reg_select)

void intpol(bool) interpolation to 256 microsteps

1: The actual microstep resolution (MRES) becomes extrapolated to 256 microsteps
for smoothest motor operation.
(Default: 1)

void dedge(bool) enable double edge step pulses

1: Enable step impulse at each step edge to reduce step frequency requirement. This mode
is not compatible with the step filtering function (multistep_filt)

void diss2g(bool) 0: Short to GND protection is on
1: Short to GND protection is disabled
void diss2vs(bool) 0: Short protection low side is on
1: Short protection low side is disabled


Function Description
bool DRV_STATUS(uint32_t*)
bool otpw() 1: The selected overtemperature pre-warning threshold
is exceeded. The overtemperature pre-warning flag is common for both bridges.
bool ot() 1: The selected overtemperature limit has been reached.
Drivers become disabled until otpw is also cleared due to cooling down of the IC.
The overtemperature flag is common for both bridges.
bool s2ga() 1: Short to GND detected on phase A or B. The driver
becomes disabled. The flags stay active, until the driver is disabled by software (TOFF=0)
or by the ENN input. Flags are separate for both chopper modes.
bool s2gb()
bool s2vsa() 1: Short on low-side MOSFET detected on phase A or B.
The driver becomes disabled. The flags stay active, until the driver is disabled by
software (TOFF=0) or by the ENN input. Flags are separate for both chopper modes.
bool s2vsb()
bool ola() 1: Open load detected on phase A or B. Hint: This is
just an informative flag. The driver takes no action upon it. False detection may
occur in fast motion and standstill. Check during slow motion, only.
bool olb()
bool t120() 1: Temperature threshold is exceeded
bool t143()
bool t150()
bool t157()
bool stealth() 1: Driver operates in stealthChop mode
0: Driver operates in spreadCycle mode
bool stst() This flag indicates motor stand still in each operation
mode. This occurs 2^20 clocks after the last step pulse.


Function Description
void PWMCONF(uint32_t)
void pwm_ofs(uint8_t) User defined amplitude (offset)

User defined PWM amplitude offset (0-255) related to full
motor current (CS_ACTUAL=31) in stand still.
(Reset default=36)

When using automatic scaling (pwm_autoscale=1) the value is
used for initialization, only. The autoscale function starts
with PWM_SCALE_AUTO=PWM_OFS and finds the required offset
to yield the target current automatically.

PWM_OFS = 0 will disable scaling down motor current below a
motor specific lower measurement threshold. This setting should
only be used under certain conditions, i.e. when the power supply
voltage can vary up and down by a factor of two or more.
It prevents the motor going out of regulation, but it also
prevents power down below the regulation limit.

PWM_OFS > 0 allows automatic scaling to low PWM duty cycles even
below the lower regulation threshold. This allows low
(standstill) current settings based on the actual (hold)
current scale (register IHOLD_IRUN).

void pwm_grad(uint8_t) User defined amplitude gradient

Velocity dependent gradient for PWM amplitude:
This value is added to PWM_AMPL to compensate for
the velocity-dependent motor back-EMF.

With automatic scaling (pwm_autoscale=1) the value is used for
first initialization, only. Set PWM_GRAD to the application
specific value (it can be read out from PWM_GRAD_AUTO) to
speed up the automatic tuning process. An approximate value
can be stored to OTP by programming OTP_PWM_GRAD.

void pwm_freq(uint8_t) PWM frequency frequency

%00: fPWM=2/1024 fCLK
%01: fPWM=2/683 fCLK
%10: fPWM=2/512 fCLK
%11: fPWM=2/410 fCLK

void pwm_autoscale(bool) PWM automatic amplitude scaling

0: User defined feed forward PWM amplitude. The current settings IRUN
and IHOLD have no influence!
The resulting PWM amplitude (limited to 0…255) is:
PWM_OFS * ((CS_ACTUAL+1) / 32) + PWM_GRAD * 256 / TSTEP
1: Enable automatic current control (Reset default)

void pwm_autograd(bool) PWM automatic gradient adaptation

0: Fixed value for PWM_GRAD
1: Automatic tuning (only with pwm_autoscale=1)
PWM_GRAD_AUTO is initialized with PWM_GRAD and becomes
optimized automatically during motion.


1. PWM_OFS_AUTO has been automatically initialized. This requires
standstill at IRUN for >130ms in order to
a) detect standstill
b) wait > 128 chopper cycles at IRUN and
c) regulate PWM_OFS_AUTO so that -1 < PWM_SCALE_AUTO < 1

2. Motor running and
Time required for tuning PWM_GRAD

void freewheel(uint8_t) Allows different standstill modes

Stand still option when motor current setting is zero (I_HOLD=0).
%00: Normal operation
%01: Freewheeling
%10: Coil shorted using LS drivers
%11: Coil shorted using HS drivers

void pwm_reg(uint8_t) Regulation loop gradient

User defined maximum PWM amplitude change per half wave when using
pwm_autoscale=1. (1…15):
1: 0.5 increments (slowest regulation)
2: 1 increment (default with OTP2.1=1)
3: 1.5 increments
4: 2 increments

8: 4 increments (default with OTP2.1=0)
15: 7.5 increments (fastest regulation)

void pwm_lim(uint8_t) PWM automatic scale amplitude limit when switching on

Limit for PWM_SCALE_AUTO when switching back from spreadCycle to stealthChop.
This value defines the upper limit for bits 7 to 4
of the automatic current control when switching
back. It can be set to reduce the current jerk
during mode change back to stealthChop.
It does not limit PWM_GRAD or PWM_GRAD_AUTO offset.
(Default = 12)


Function Description
bool PWM_SCALE(uint32_t*)
uint8_t pwm_scale_sum() Results of stealthChop amplitude regulator. These values
can be used to monitor automatic PWM amplitude scaling (255=max. voltage).

bit 7… 0 PWM_SCALE_SUM:
Actual PWM duty cycle. This value is used for scaling
the values CUR_A and CUR_B read from the sine wave table.

bit 24… 16 PWM_SCALE_AUTO:
9 Bit signed offset added to the calculated PWM duty
cycle. This is the result of the automatic amplitude
regulation based on current measurement.

int16_t pwm_scale_auto() These automatically generated values can be read out in
order to determine a default / power up setting for PWM_GRAD and PWM_OFS.

bit 7… 0 PWM_OFS_AUTO:
Automatically determined offset value

bit 23… 16 PWM_GRAD_AUTO:
Automatically determined gradient value

Bit positions and bit masks

You can gain access to the register bit position and bit masks with

#include <TMC2208Stepper_REGDEFS.h>

Register addresses follow the patter REG_<reg_name>

Bit positions are <setting>_bp

Bit masks are <setting>_bm

uint32_t my_gconf = (1 << SHAFT_bp) & SHAFT_bm;
You can’t perform that action at this time.