TMCStepper
Library supporting Trinamic Stepper Drivers for Arduino platforms
Loading...
Searching...
No Matches
TMC2208Stepper.cpp
Go to the documentation of this file.
1
6#include "../TMCStepper.h"
7#include "TMC_MACROS.h"
8#include "SERIAL_SWITCH.h"
9
10#if defined(ARDUINO_ARCH_RP2040) && defined(RP2040_SINGLE_WIRE_UART_PIN)
11 #include <hardware/gpio.h>
12#endif
13
14// Protected
15// addr needed for TMC2209
16TMC2208Stepper::TMC2208Stepper(Stream * SerialPort, float RS, uint8_t addr) :
17 TMCStepper(RS),
18 slave_address(addr)
19 {
20 HWSerial = SerialPort;
21 defaults();
22 }
23
24TMC2208Stepper::TMC2208Stepper(Stream * SerialPort, float RS, uint8_t addr, uint16_t mul_pin1, uint16_t mul_pin2) :
25 TMC2208Stepper(SerialPort, RS)
26 {
27 SSwitch *SMulObj = new SSwitch(mul_pin1, mul_pin2, addr);
28 sswitch = SMulObj;
29 }
30
31#if TMCSTEPPER_SW_SERIAL
32 // Protected
33 // addr needed for TMC2209
34 TMC2208Stepper::TMC2208Stepper(uint16_t SW_RX_pin, uint16_t SW_TX_pin, float RS, uint8_t addr) :
35 TMCStepper(RS),
37 RXTX_pin(SW_RX_pin == SW_TX_pin ? SW_RX_pin : 0),
38 #endif
39 slave_address(addr)
40 {
41 SoftwareSerial *SWSerialObj = new SoftwareSerial(SW_RX_pin, SW_TX_pin);
42 SWSerial = SWSerialObj;
43 defaults();
44 }
45
46 void TMC2208Stepper::beginSerial(uint32_t baudrate) {
47 if (SWSerial != nullptr)
48 {
49 SWSerial->begin(baudrate);
50 SWSerial->end();
51 }
52 #if HAS_HALF_DUPLEX_MODE
53 if (RXTX_pin > 0) {
54 digitalWrite(RXTX_pin, HIGH);
55 pinMode(RXTX_pin, OUTPUT);
56 }
57 #endif
58 }
59#endif
60
62 #if TMCSTEPPER_SW_SERIAL
63 #ifndef TMC2208_BAUDRATE
64 #define TMC2208_BAUDRATE 115200
65 #endif
66 beginSerial(TMC2208_BAUDRATE);
67 #endif
68 pdn_disable(true);
69 mstep_reg_select(true);
70}
71
73 GCONF_register.i_scale_analog = 1;
74 GCONF_register.internal_rsense = 0; // OTP
75 GCONF_register.en_spreadcycle = 0; // OTP
76 GCONF_register.multistep_filt = 1; // OTP
77
78 IHOLD_IRUN_register.iholddelay = 1; // OTP
79
80 TPOWERDOWN_register.sr = 20;
81
82 //CHOPCONF_register.sr = 0x10000053;
83 CHOPCONF_register.toff = 3;
84 CHOPCONF_register.hstrt = 5;
85 CHOPCONF_register.hend = 0;
86 CHOPCONF_register.tbl = 0;
87 CHOPCONF_register.vsense = false;
88 CHOPCONF_register.mres = 0;
89 CHOPCONF_register.intpol = true;
90 CHOPCONF_register.dedge = false;
91 CHOPCONF_register.diss2g = false;
92 CHOPCONF_register.diss2vs = false;
93
94 //PWMCONF_register.sr = 0xC10D0024;
95 PWMCONF_register.pwm_ofs = 36;
96 PWMCONF_register.pwm_grad = 0;
97 PWMCONF_register.pwm_freq = 1;
98 PWMCONF_register.pwm_autoscale = true;
99 PWMCONF_register.pwm_autograd = true;
100 PWMCONF_register.freewheel = 0;
101 PWMCONF_register.pwm_reg = 1;
102 PWMCONF_register.pwm_lim = 12;
103
104 //MSLUT0_register.sr = ???;
105 //MSLUT1_register.sr = ???;
106 //MSLUT2_register.sr = ???;
107 //MSLUT3_register.sr = ???;
108 //MSLUT4_register.sr = ???;
109 //MSLUT5_register.sr = ???;
110 //MSLUT6_register.sr = ???;
111 //MSLUT7_register.sr = ???;
112 //MSLUTSTART_register.start_sin90 = 247;
113}
114
116 GCONF(GCONF_register.sr);
117 IHOLD_IRUN(IHOLD_IRUN_register.sr);
118 SLAVECONF(SLAVECONF_register.sr);
119 TPOWERDOWN(TPOWERDOWN_register.sr);
120 TPWMTHRS(TPWMTHRS_register.sr);
121 VACTUAL(VACTUAL_register.sr);
122 CHOPCONF(CHOPCONF_register.sr);
123 PWMCONF(PWMCONF_register.sr);
124}
125
126bool TMC2208Stepper::isEnabled() { return !enn() && toff(); }
127
128uint8_t TMC2208Stepper::calcCRC(uint8_t datagram[], uint8_t len) {
129 uint8_t crc = 0;
130 for (uint8_t i = 0; i < len; i++) {
131 uint8_t currentByte = datagram[i];
132 for (uint8_t j = 0; j < 8; j++) {
133 if ((crc >> 7) ^ (currentByte & 0x01)) {
134 crc = (crc << 1) ^ 0x07;
135 } else {
136 crc = (crc << 1);
137 }
138 crc &= 0xff;
139 currentByte = currentByte >> 1;
140 }
141 }
142 return crc;
143}
144
147 int out = 0;
148 #if TMCSTEPPER_SW_SERIAL
149 if (SWSerial != nullptr) {
150 out = SWSerial->available();
151 } else
152 #endif
153 if (HWSerial != nullptr) {
154 out = HWSerial->available();
155 }
156
157 return out;
158}
159
160__attribute__((weak))
162 if (HWSerial != nullptr) {
163 if (sswitch != nullptr)
164 sswitch->active();
165 }
166}
167
168__attribute__((weak))
170 #if TMCSTEPPER_SW_SERIAL
171 if (SWSerial != nullptr) {
172 SWSerial->listen();
173 } else
174 #endif
175 if (HWSerial != nullptr) {
176 if (sswitch != nullptr)
177 sswitch->active();
178 }
179}
180
181__attribute__((weak))
183 int16_t out = 0;
184 #if TMCSTEPPER_SW_SERIAL
185 if (SWSerial != nullptr) {
186 out = SWSerial->read();
187 } else
188 #endif
189 if (HWSerial != nullptr) {
190 out = HWSerial->read();
191 }
192
193 return out;
194}
195
196__attribute__((weak))
197uint8_t TMC2208Stepper::serial_write(const uint8_t data) {
198 int out = 0;;
199 #if TMCSTEPPER_SW_SERIAL
200 if (SWSerial != nullptr) {
201 return SWSerial->write(data);
202 } else
203 #endif
204 if (HWSerial != nullptr) {
205 return HWSerial->write(data);
206 }
207
208 return out;
209}
210
211__attribute__((weak))
213
214__attribute__((weak))
216 #if TMCSTEPPER_SW_SERIAL
217 if (SWSerial != nullptr) {
218 SWSerial->end();
219 }
220 #endif
221}
222
223void TMC2208Stepper::write(uint8_t addr, uint32_t regVal) {
224 uint8_t len = 7;
225 addr |= TMC_WRITE;
226 uint8_t datagram[] = {TMC2208_SYNC, slave_address, addr, (uint8_t)(regVal>>24), (uint8_t)(regVal>>16), (uint8_t)(regVal>>8), (uint8_t)(regVal>>0), 0x00};
227
228 datagram[len] = calcCRC(datagram, len);
229
231
232 for (uint8_t i = 0; i<= len; i++) {
233 bytesWritten += serial_write(datagram[i]);
234 }
236
237 delay(replyDelay);
238}
239
240#if defined(ARDUINO_ARCH_RP2040) && defined(RP2040_SINGLE_WIRE_UART_PIN)
241
242 #include <hardware/gpio.h>
243
244 // Bit-bang one 8N1 UART byte on the single-wire PDN_UART pin.
245 // Temporarily switches GPIO to SIO output for TX, then restores UART RX mode.
246 // 9 µs/bit ≈ 111 kbaud (-3.7% vs 115200) — within the ±6.25% 8N1 tolerance.
247 static void _rp2040_sw_uart_write_byte(uint8_t byte) {
248 constexpr uint32_t T = 9; // µs per bit
249 gpio_set_function(RP2040_SINGLE_WIRE_UART_PIN, GPIO_FUNC_SIO);
250 gpio_set_dir(RP2040_SINGLE_WIRE_UART_PIN, GPIO_OUT);
251 gpio_put(RP2040_SINGLE_WIRE_UART_PIN, 1); // idle HIGH before start bit
252 // Start bit
253 gpio_put(RP2040_SINGLE_WIRE_UART_PIN, 0);
254 delayMicroseconds(T);
255 // 8 data bits, LSB first
256 for (int i = 0; i < 8; i++) {
257 gpio_put(RP2040_SINGLE_WIRE_UART_PIN, (byte >> i) & 1);
258 delayMicroseconds(T);
259 }
260 // Stop bit
261 gpio_put(RP2040_SINGLE_WIRE_UART_PIN, 1);
262 delayMicroseconds(T);
263 // Restore UART1 RX function on GPIO9
264 gpio_set_function(RP2040_SINGLE_WIRE_UART_PIN, GPIO_FUNC_UART);
265 }
266
267#endif // ARDUINO_ARCH_RP2040 && RP2040_SINGLE_WIRE_UART_PIN
268
269uint64_t TMC2208Stepper::_sendDatagram(uint8_t datagram[], const uint8_t len, uint16_t timeout) {
270 // === STEP 0: flush stale RX bytes ===
271 const uint32_t _flush_t0 = micros();
272 while (available() > 0) {
273 serial_read();
274 if ((micros() - _flush_t0) > (uint32_t)timeout * 1000UL) break;
275 }
276
277 #if HAS_HALF_DUPLEX_MODE
278 if (RXTX_pin > 0) {
279 digitalWrite(RXTX_pin, HIGH);
280 pinMode(RXTX_pin, OUTPUT);
281 }
282 #endif
283
284 // === STEP 1: write request ===
285 #if defined(ARDUINO_ARCH_RP2040) && defined(RP2040_SINGLE_WIRE_UART_PIN)
286 noInterrupts();
287 for (int i = 0; i <= len; i++) _rp2040_sw_uart_write_byte(datagram[i]);
288 interrupts();
289 #else
290 for (int i = 0; i <= len; i++) serial_write(datagram[i]);
291 #endif
292
293 #if HAS_HALF_DUPLEX_MODE
294 if (RXTX_pin > 0) {
295 pinMode(RXTX_pin, INPUT_PULLUP);
296 }
297 #endif
298
299 // === STEP 2: reply delay ===
300 delay(this->replyDelay);
301
302 // === STEP 3: sync scan with micros() timeout ===
303 uint32_t _sync_t0 = micros();
304 uint32_t sync_target = (static_cast<uint32_t>(datagram[0])<<16) | 0xFF00 | datagram[2];
305 uint32_t sync = 0;
306
307 do {
308 if ((micros() - _sync_t0) > (uint32_t)timeout * 1000UL) {
309 return 0;
310 }
311
312 int16_t res = serial_read();
313 if (res < 0) continue;
314
315 sync <<= 8;
316 sync |= res & 0xFF;
317 sync &= 0xFFFFFF;
318
319 } while (sync != sync_target);
320
321 // === STEP 4: body read ===
322 uint64_t out = sync;
323 uint32_t _body_t0 = micros();
324 timeout = this->abort_window;
325
326 for (uint8_t i = 0; i < 5; i++) {
327 if ((micros() - _body_t0) > (uint32_t)timeout * 1000UL) {
328 return 0;
329 }
330
331 int16_t res = serial_read();
332 if (res < 0) continue;
333
334 out <<= 8;
335 out |= res & 0xFF;
336 }
337
338 #if HAS_HALF_DUPLEX_MODE
339 if (RXTX_pin > 0) {
340 digitalWrite(RXTX_pin, HIGH);
341 pinMode(RXTX_pin, OUTPUT);
342 }
343 #endif
344
345 while (available() > 0) serial_read(); // Flush
346
347 return out;
348}
349
350uint32_t TMC2208Stepper::read(uint8_t addr) {
351 constexpr uint8_t len = 3;
352 addr |= TMC_READ;
353 uint8_t datagram[] = {TMC2208_SYNC, slave_address, addr, 0x00};
354 datagram[len] = calcCRC(datagram, len);
355 uint64_t out = 0x00000000UL;
356
357 for (uint8_t i = 0; i < max_retries; i++) {
359 delay(3);
360 out = _sendDatagram(datagram, len, abort_window);
362
363 delay(replyDelay);
364
365 CRCerror = false;
366 uint8_t out_datagram[] = {
367 static_cast<uint8_t>(out>>56),
368 static_cast<uint8_t>(out>>48),
369 static_cast<uint8_t>(out>>40),
370 static_cast<uint8_t>(out>>32),
371 static_cast<uint8_t>(out>>24),
372 static_cast<uint8_t>(out>>16),
373 static_cast<uint8_t>(out>> 8),
374 static_cast<uint8_t>(out>> 0)
375 };
376 uint8_t crc = calcCRC(out_datagram, 7);
377 if ((crc != static_cast<uint8_t>(out)) || crc == 0 ) {
378 CRCerror = true;
379 out = 0;
380 } else {
381 break;
382 }
383 }
384
385 return out>>8;
386}
387
389
390void TMC2208Stepper::OTP_PROG(uint16_t input) {
392}
393
395
396uint16_t TMC2208Stepper::FACTORY_CONF() { return read(FACTORY_CONF_register.address); }
397void TMC2208Stepper::FACTORY_CONF(uint16_t input) {
398 FACTORY_CONF_register.sr = input;
399 write(FACTORY_CONF_register.address, FACTORY_CONF_register.sr);
400}
401void TMC2208Stepper::fclktrim(uint8_t B){ FACTORY_CONF_register.fclktrim = B; write(FACTORY_CONF_register.address, FACTORY_CONF_register.sr); }
402void TMC2208Stepper::ottrim(uint8_t B) { FACTORY_CONF_register.ottrim = B; write(FACTORY_CONF_register.address, FACTORY_CONF_register.sr); }
404uint8_t TMC2208Stepper::ottrim() { FACTORY_CONF_t r{}; r.sr = FACTORY_CONF(); return r.ottrim; }
405
406void TMC2208Stepper::VACTUAL(uint32_t input) {
407 VACTUAL_register.sr = input;
408 write(VACTUAL_register.address, VACTUAL_register.sr);
409}
411 return VACTUAL_register.sr;
412}
413
417 r.sr = PWM_SCALE();
418 return r.pwm_scale_sum;
419}
420
423 r.sr = PWM_SCALE();
424 return r.pwm_scale_auto;
425 // Not two's complement? 9nth bit determines sign
426 /*
427 uint32_t d = PWM_SCALE();
428 int16_t response = (d>>PWM_SCALE_AUTO_bp)&0xFF;
429 if (((d&PWM_SCALE_AUTO_bm) >> 24) & 0x1) return -response;
430 else return response;
431 */
432}
433
434// R: PWM_AUTO
438
439// R: MSCURACT
443 r.sr = MSCURACT();
444 int16_t value = r.cur_a;
445 if (value > 255) value -= 512;
446 return value;
447}
450 r.sr = MSCURACT();
451 int16_t value = r.cur_b;
452 if (value > 255) value -= 512;
453 return value;
454}
__attribute__((weak)) int TMC2208Stepper
#define HAS_HALF_DUPLEX_MODE
Definition TMCStepper.h:61
int available(void)
static constexpr uint8_t TMC2208_SYNC
bool mstep_reg_select()
Definition GCONF.cpp:110
uint16_t bytesWritten
void write(uint8_t, uint32_t)
static constexpr uint8_t replyDelay
static constexpr uint8_t abort_window
uint8_t pwm_grad_auto()
int16_t pwm_scale_auto()
uint32_t read(uint8_t)
uint64_t _sendDatagram(uint8_t[], const uint8_t, uint16_t)
uint8_t calcCRC(uint8_t datagram[], uint8_t len)
void postWriteCommunication()
uint32_t GCONF()
Definition GCONF.cpp:85
TMC2208Stepper(Stream *SerialPort, float RS, uint8_t addr, uint16_t mul_pin1, uint16_t mul_pin2)
uint16_t FACTORY_CONF()
void beginSerial(uint32_t)=delete
void preWriteCommunication()
void OTP_PROG(uint16_t input)
uint16_t SLAVECONF()
Definition SLAVECONF.cpp:16
uint32_t PWMCONF()
Definition PWMCONF.cpp:71
int16_t serial_read()
void preReadCommunication()
bool pdn_disable()
Definition GCONF.cpp:109
uint32_t CHOPCONF()
Definition CHOPCONF.cpp:70
uint8_t toff()
Definition CHOPCONF.cpp:86
void postReadCommunication()
const uint8_t slave_address
uint8_t pwm_scale_sum()
static constexpr uint8_t max_retries
bool enn()
Definition IOIN.cpp:45
uint8_t serial_write(const uint8_t data)
static constexpr uint8_t TMC_READ
uint32_t IHOLD_IRUN()
uint8_t TPOWERDOWN()
TMCStepper(float RS)
uint32_t TPWMTHRS()
static constexpr uint8_t TMC_WRITE
#define pinMode(PIN, MODE)
Definition rpi_bcm2835.h:13
#define digitalWrite(PIN, MODE)
Definition rpi_bcm2835.h:14
#define OUTPUT
Definition rpi_bcm2835.h:11
#define INPUT_PULLUP
Definition rpi_bcm2835.h:9
uint8_t pwm_grad_auto
static constexpr uint8_t address
uint8_t pwm_ofs_auto
static constexpr uint8_t address
uint8_t int16_t pwm_scale_auto
static constexpr uint8_t address
static constexpr uint8_t address
static constexpr uint8_t address
static constexpr uint8_t address