Library for Trinamic TMC2209 stepper modules to drive bipolar stepper motors. Ported and adapted from https://github.com/teemuatlut/TMCStepper
Diff: TMC2208Stepper.cpp
- Revision:
- 0:f4343071c8b1
- Child:
- 1:5ba0c258c4ed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TMC2208Stepper.cpp Thu Mar 18 20:50:27 2021 +0000 @@ -0,0 +1,459 @@ +#include "TMCStepper.h" +#include "TMC_MACROS.h" +//#include "SERIAL_SWITCH.h" + +// Protected +// addr needed for TMC2209 +TMC2208Stepper::TMC2208Stepper(Stream * SerialPort, float RS, uint8_t addr) : + TMCStepper(RS), + slave_address(addr) + { + HWSerial = SerialPort; + defaults(); + } + +TMC2208Stepper::TMC2208Stepper(Stream * SerialPort, float RS, uint8_t addr, uint16_t mul_pin1, uint16_t mul_pin2) : + TMC2208Stepper(SerialPort, RS) + { +// SSwitch *SMulObj = new SSwitch(mul_pin1, mul_pin2, addr); +// sswitch = SMulObj; + } + +#if SW_CAPABLE_PLATFORM + // Protected + // addr needed for TMC2209 + TMC2208Stepper::TMC2208Stepper(PinName SW_RX_pin, PinName SW_TX_pin, float RS, uint8_t addr) : + TMCStepper(RS), + RXTX_pin(SW_RX_pin == SW_TX_pin ? SW_RX_pin : 0), + slave_address(addr) + { + BufferedSerial *SWSerialObj = new BufferedSerial(SW_TX_pin, SW_RX_pin); + SWSerial = SWSerialObj; + defaults(); + } + + void TMC2208Stepper::beginSerial(uint32_t baudrate) { + if (SWSerial != nullptr) + { + //SWSerial->begin(baudrate); + //SWSerial->end(); + SWSerial->set_baud(baudrate); + SWSerial->set_format( + /* bits */ 8, + /* parity */ BufferedSerial::None, + /* stop bit */ 1 + ); + SWSerial->set_blocking(true); + } +// #if defined(ARDUINO_ARCH_AVR) +// if (RXTX_pin > 0) { +// digitalWrite(RXTX_pin, HIGH); +// pinMode(RXTX_pin, OUTPUT); +// } +// #endif + } +#endif + +void TMC2208Stepper::begin() { + #if SW_CAPABLE_PLATFORM + beginSerial(115200); + //beginSerial(9600); + #endif + pdn_disable(true); + mstep_reg_select(true); + //Wait to initialize + wait_us(replyDelay*1000); + +} + +void TMC2208Stepper::defaults() { + GCONF_register.i_scale_analog = 1; + GCONF_register.internal_rsense = 0; // OTP + GCONF_register.en_spreadcycle = 0; // OTP + GCONF_register.multistep_filt = 1; // OTP + IHOLD_IRUN_register.iholddelay = 1; // OTP + TPOWERDOWN_register.sr = 20; + CHOPCONF_register.sr = 0x10000053; + PWMCONF_register.sr = 0xC10D0024; + //MSLUT0_register.sr = ???; + //MSLUT1_register.sr = ???; + //MSLUT2_register.sr = ???; + //MSLUT3_register.sr = ???; + //MSLUT4_register.sr = ???; + //MSLUT5_register.sr = ???; + //MSLUT6_register.sr = ???; + //MSLUT7_register.sr = ???; + //MSLUTSTART_register.start_sin90 = 247; +} + +void TMC2208Stepper::push() { + GCONF(GCONF_register.sr); + IHOLD_IRUN(IHOLD_IRUN_register.sr); + SLAVECONF(SLAVECONF_register.sr); + TPOWERDOWN(TPOWERDOWN_register.sr); + TPWMTHRS(TPWMTHRS_register.sr); + VACTUAL(VACTUAL_register.sr); + CHOPCONF(CHOPCONF_register.sr); + PWMCONF(PWMCONF_register.sr); +} + +bool TMC2208Stepper::isEnabled() { return !enn() && toff(); } + +uint8_t TMC2208Stepper::calcCRC(uint8_t datagram[], uint8_t len) { + uint8_t crc = 0; + for (uint8_t i = 0; i < len; i++) { + uint8_t currentByte = datagram[i]; + for (uint8_t j = 0; j < 8; j++) { + if ((crc >> 7) ^ (currentByte & 0x01)) { + crc = (crc << 1) ^ 0x07; + } else { + crc = (crc << 1); + } + crc &= 0xff; + currentByte = currentByte >> 1; + } + } + return crc; +} + +__attribute__((weak)) +int TMC2208Stepper::available() { + int out = 0; + #if SW_CAPABLE_PLATFORM + if (SWSerial != nullptr) { +// out = SWSerial->available(); +out = 1; + } else + #endif + if (HWSerial != nullptr) { +// out = HWSerial->available(); +out = 1; + } + + return out; +} + +__attribute__((weak)) +void TMC2208Stepper::preWriteCommunication() { + if (HWSerial != nullptr) { +// if (sswitch != nullptr) +// sswitch->active(); + } +} + +__attribute__((weak)) +void TMC2208Stepper::preReadCommunication() { + #if SW_CAPABLE_PLATFORM + if (SWSerial != nullptr) { +// SWSerial->listen(); + } else + #endif + if (HWSerial != nullptr) { +// if (sswitch != nullptr) +// sswitch->active(); + } +} + +__attribute__((weak)) +int16_t TMC2208Stepper::serial_read() { + int16_t out = 0; + int16_t count = 0; + + #if SW_CAPABLE_PLATFORM + if (SWSerial != nullptr) { +// out = SWSerial->read(); + count = SWSerial->read(&out, 1); // read one character +// if (SWSerial->readable()) { +// SWSerial->read(&out, 1); // read one character +// } + + } else + #endif + if (HWSerial != nullptr) { +// out = HWSerial->read(); + HWSerial->read(&out, 1); // read one character + } + if (count >= 1) { +// printf("<%02X|",out); + return out; + } else { + return -1; + } +} + +__attribute__((weak)) +uint8_t TMC2208Stepper::serial_write(const uint8_t data) { + int out = 0; + #if SW_CAPABLE_PLATFORM + if (SWSerial != nullptr) { +// printf(">%02X|",data); + return SWSerial->write(&data,1); + } else + #endif + if (HWSerial != nullptr) { + return HWSerial->write(&data,1); + } + + return out; +} + +__attribute__((weak)) +void TMC2208Stepper::postWriteCommunication() {} + +__attribute__((weak)) +void TMC2208Stepper::postReadCommunication() { + #if SW_CAPABLE_PLATFORM +// if (SWSerial != nullptr) { +// SWSerial->end(); +// } + #endif +} + +void TMC2208Stepper::write(uint8_t addr, uint32_t regVal) { + uint8_t len = 7; + addr |= TMC_WRITE; + 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}; + + datagram[len] = calcCRC(datagram, len); + + preWriteCommunication(); + + for(uint8_t i=0; i<=len; i++) { + bytesWritten += serial_write(datagram[i]); + } + postWriteCommunication(); + + //delay(replyDelay); + wait_us(replyDelay*1000); +} + +uint64_t TMC2208Stepper::_sendDatagram(uint8_t datagram[], const uint8_t len, uint16_t timeout) { + +// while (available() > 0) serial_read(); // Flush + SWSerial->sync(); +/* uint8_t dummy; + while (SWSerial->readable()) { + SWSerial->read(&dummy, 1); // read one character + } +*/ +/* uint8_t dummy; + while (SWSerial->read(&dummy, 1) >= 0) { + ; + } +*/ + + #if defined(ARDUINO_ARCH_AVR) + if (RXTX_pin > 0) { + digitalWrite(RXTX_pin, HIGH); + pinMode(RXTX_pin, OUTPUT); + } + #endif + + for(int i=0; i<=len; i++) serial_write(datagram[i]); + + #if defined(ARDUINO_ARCH_AVR) + if (RXTX_pin > 0) { + pinMode(RXTX_pin, INPUT_PULLUP); + } + #endif + + //delay(this->replyDelay); + wait_us(this->replyDelay*1000); + + // scan for the rx frame and read it + +// uint32_t ms = millis(); + uint32_t sync_target = (static_cast<uint32_t>(datagram[0])<<16) | 0xFF00 | datagram[2]; + uint32_t sync = 0; + + + do { +/* uint32_t ms2 = millis(); + if (ms2 != ms) { + // 1ms tick + ms = ms2; + timeout--; + } + if (!timeout) return 0; +*/ + int16_t res = serial_read(); + if (res < 0) continue; + + sync <<= 8; + sync |= res & 0xFF; + sync &= 0xFFFFFF; + + } while (sync != sync_target); + + uint64_t out = sync; + // ms = millis(); + // timeout = this->abort_window; + + for(uint8_t i=0; i<5;) { +/* uint32_t ms2 = millis(); + if (ms2 != ms) { + // 1ms tick + ms = ms2; + timeout--; + } + if (!timeout) return 0; +*/ + int16_t res = serial_read(); + if (res < 0) continue; + + out <<= 8; + out |= res & 0xFF; + + i++; + } + + #if defined(ARDUINO_ARCH_AVR) + if (RXTX_pin > 0) { + digitalWrite(RXTX_pin, HIGH); + pinMode(RXTX_pin, OUTPUT); + } + #endif + +// while (available() > 0) serial_read(); // Flush + SWSerial->sync(); + + return out; + + +} + +uint32_t TMC2208Stepper::read(uint8_t addr) { + constexpr uint8_t len = 3; + addr |= TMC_READ; + uint8_t datagram[] = {TMC2208_SYNC, slave_address, addr, 0x00}; + datagram[len] = calcCRC(datagram, len); + uint64_t out = 0x00000000UL; + + for (uint8_t i = 0; i < max_retries; i++) { + preReadCommunication(); + out = _sendDatagram(datagram, len, abort_window); + postReadCommunication(); + +// delay(replyDelay); +// wait_us(replyDelay*1000); + + CRCerror = false; + uint8_t out_datagram[] = { + static_cast<uint8_t>(out>>56), + static_cast<uint8_t>(out>>48), + static_cast<uint8_t>(out>>40), + static_cast<uint8_t>(out>>32), + static_cast<uint8_t>(out>>24), + static_cast<uint8_t>(out>>16), + static_cast<uint8_t>(out>> 8), + static_cast<uint8_t>(out>> 0) + }; + uint8_t crc = calcCRC(out_datagram, 7); + if ((crc != static_cast<uint8_t>(out)) || crc == 0 ) { + CRCerror = true; + out = 0; + } else { + break; + } + } + + return out>>8; +} + +uint8_t TMC2208Stepper::IFCNT() { + return read(IFCNT_t::address); +} + +void TMC2208Stepper::SLAVECONF(uint16_t input) { + SLAVECONF_register.sr = input&0xF00; + write(SLAVECONF_register.address, SLAVECONF_register.sr); +} +uint16_t TMC2208Stepper::SLAVECONF() { + return SLAVECONF_register.sr; +} +void TMC2208Stepper::senddelay(uint8_t B) { SLAVECONF_register.senddelay = B; write(SLAVECONF_register.address, SLAVECONF_register.sr); } +uint8_t TMC2208Stepper::senddelay() { return SLAVECONF_register.senddelay; } + +void TMC2208Stepper::OTP_PROG(uint16_t input) { + write(OTP_PROG_t::address, input); +} + +uint32_t TMC2208Stepper::OTP_READ() { + return read(OTP_READ_t::address); +} + +uint32_t TMC2208Stepper::IOIN() { + return read(TMC2208_n::IOIN_t::address); +} +bool TMC2208Stepper::enn() { TMC2208_n::IOIN_t r{0}; r.sr = IOIN(); return r.enn; } +bool TMC2208Stepper::ms1() { TMC2208_n::IOIN_t r{0}; r.sr = IOIN(); return r.ms1; } +bool TMC2208Stepper::ms2() { TMC2208_n::IOIN_t r{0}; r.sr = IOIN(); return r.ms2; } +bool TMC2208Stepper::diag() { TMC2208_n::IOIN_t r{0}; r.sr = IOIN(); return r.diag; } +bool TMC2208Stepper::pdn_uart() { TMC2208_n::IOIN_t r{0}; r.sr = IOIN(); return r.pdn_uart; } +bool TMC2208Stepper::step() { TMC2208_n::IOIN_t r{0}; r.sr = IOIN(); return r.step; } +bool TMC2208Stepper::sel_a() { TMC2208_n::IOIN_t r{0}; r.sr = IOIN(); return r.sel_a; } +bool TMC2208Stepper::dir() { TMC2208_n::IOIN_t r{0}; r.sr = IOIN(); return r.dir; } +uint8_t TMC2208Stepper::version() { TMC2208_n::IOIN_t r{0}; r.sr = IOIN(); return r.version; } + +/* +uint32_t TMC2224Stepper::IOIN() { + return read(TMC2224_n::IOIN_t::address); +} +bool TMC2224Stepper::enn() { TMC2224_n::IOIN_t r{0}; r.sr = IOIN(); return r.enn; } +bool TMC2224Stepper::ms1() { TMC2224_n::IOIN_t r{0}; r.sr = IOIN(); return r.ms1; } +bool TMC2224Stepper::ms2() { TMC2224_n::IOIN_t r{0}; r.sr = IOIN(); return r.ms2; } +bool TMC2224Stepper::pdn_uart() { TMC2224_n::IOIN_t r{0}; r.sr = IOIN(); return r.pdn_uart; } +bool TMC2224Stepper::spread() { TMC2224_n::IOIN_t r{0}; r.sr = IOIN(); return r.spread; } +bool TMC2224Stepper::step() { TMC2224_n::IOIN_t r{0}; r.sr = IOIN(); return r.step; } +bool TMC2224Stepper::sel_a() { TMC2224_n::IOIN_t r{0}; r.sr = IOIN(); return r.sel_a; } +bool TMC2224Stepper::dir() { TMC2224_n::IOIN_t r{0}; r.sr = IOIN(); return r.dir; } +uint8_t TMC2224Stepper::version() { TMC2224_n::IOIN_t r{0}; r.sr = IOIN(); return r.version; } +*/ +uint16_t TMC2208Stepper::FACTORY_CONF() { + return read(FACTORY_CONF_register.address); +} +void TMC2208Stepper::FACTORY_CONF(uint16_t input) { + FACTORY_CONF_register.sr = input; + write(FACTORY_CONF_register.address, FACTORY_CONF_register.sr); +} +void TMC2208Stepper::fclktrim(uint8_t B){ FACTORY_CONF_register.fclktrim = B; write(FACTORY_CONF_register.address, FACTORY_CONF_register.sr); } +void TMC2208Stepper::ottrim(uint8_t B) { FACTORY_CONF_register.ottrim = B; write(FACTORY_CONF_register.address, FACTORY_CONF_register.sr); } +uint8_t TMC2208Stepper::fclktrim() { FACTORY_CONF_t r{0}; r.sr = FACTORY_CONF(); return r.fclktrim; } +uint8_t TMC2208Stepper::ottrim() { FACTORY_CONF_t r{0}; r.sr = FACTORY_CONF(); return r.ottrim; } + +void TMC2208Stepper::VACTUAL(uint32_t input) { + VACTUAL_register.sr = input; + write(VACTUAL_register.address, VACTUAL_register.sr); +} +uint32_t TMC2208Stepper::VACTUAL() { + return VACTUAL_register.sr; +} + +uint32_t TMC2208Stepper::PWM_SCALE() { + return read(TMC2208_n::PWM_SCALE_t::address); +} +uint8_t TMC2208Stepper::pwm_scale_sum() { + TMC2208_n::PWM_SCALE_t r{0}; + r.sr = PWM_SCALE(); + return r.pwm_scale_sum; +} + +int16_t TMC2208Stepper::pwm_scale_auto() { + TMC2208_n::PWM_SCALE_t r{0}; + r.sr = PWM_SCALE(); + return r.pwm_scale_auto; + // Not two's complement? 9nth bit determines sign + /* + uint32_t d = PWM_SCALE(); + int16_t response = (d>>PWM_SCALE_AUTO_bp)&0xFF; + if (((d&PWM_SCALE_AUTO_bm) >> 24) & 0x1) return -response; + else return response; + */ +} + +// R: PWM_AUTO +uint32_t TMC2208Stepper::PWM_AUTO() { + return read(PWM_AUTO_t::address); +} +uint8_t TMC2208Stepper::pwm_ofs_auto() { PWM_AUTO_t r{0}; r.sr = PWM_AUTO(); return r.pwm_ofs_auto; } +uint8_t TMC2208Stepper::pwm_grad_auto() { PWM_AUTO_t r{0}; r.sr = PWM_AUTO(); return r.pwm_grad_auto; } \ No newline at end of file