Library for Trinamic TMC2209 stepper modules to drive bipolar stepper motors. Ported and adapted from https://github.com/teemuatlut/TMCStepper

Dependents:   TMC2209-Test2

TMCStepper.h

Committer:
charly
Date:
2021-12-02
Revision:
2:b34e91b54373
Parent:
0:f4343071c8b1

File content as of revision 2:b34e91b54373:

#pragma once

//#define TMCDEBUG

#include "mbed.h"

#define SW_CAPABLE_PLATFORM true

//#include "TMC2130_bitfields.h"
//#include "TMC2160_bitfields.h"
//#include "TMC5130_bitfields.h"
//#include "TMC5160_bitfields.h"
#include "TMC2208_bitfields.h"
#include "TMC2209_bitfields.h"
//#include "TMC2660_bitfields.h"

#define INIT_REGISTER(REG) REG##_t REG##_register = REG##_t
//#define INIT2130_REGISTER(REG) TMC2130_n::REG##_t REG##_register = TMC2130_n::REG##_t
//#define INIT2160_REGISTER(REG) TMC2160_n::REG##_t REG##_register = TMC2160_n::REG##_t
//#define INIT5130_REGISTER(REG) TMC5130_n::REG##_t REG##_register = TMC5130_n::REG##_t
//#define INIT5160_REGISTER(REG) TMC5160_n::REG##_t REG##_register = TMC5160_n::REG##_t
//#define INIT2660_REGISTER(REG) TMC2660_n::REG##_t REG##_register = TMC2660_n::REG##_t
#define INIT2208_REGISTER(REG) TMC2208_n::REG##_t REG##_register = TMC2208_n::REG##_t
//#define INIT2224_REGISTER(REG) TMC2224_n::REG##_t REG##_register = TMC2224_n::REG##_t
#define SET_ALIAS(TYPE, DRIVER, NEW, ARG, OLD) TYPE (DRIVER::*NEW)(ARG) = &DRIVER::OLD

#define TMCSTEPPER_VERSION 0x000701 // v0.7.1

#if SW_CAPABLE_PLATFORM
    #include <BufferedSerial.h>
    #include <Stream.h>
#endif
class TMCStepper {
    public:
        uint16_t cs2rms(uint8_t CS);
        void rms_current(uint16_t mA);
        void rms_current(uint16_t mA, float mult);
        uint16_t rms_current();
        void hold_multiplier(float val) { holdMultiplier = val; }
        float hold_multiplier() { return holdMultiplier; }
        uint8_t test_connection();

        // Helper functions
        void microsteps(uint16_t ms);
        uint16_t microsteps();
        void blank_time(uint8_t value);
        uint8_t blank_time();
        void hysteresis_end(int8_t value);
        int8_t hysteresis_end();
        void hysteresis_start(uint8_t value);
        uint8_t hysteresis_start();

        // R+WC: GSTAT
        void    GSTAT(                          uint8_t input);
        uint8_t GSTAT();
        bool    reset();
        bool    drv_err();
        bool    uv_cp();

        // W: IHOLD_IRUN
        void IHOLD_IRUN(                    uint32_t input);
        uint32_t IHOLD_IRUN();
        void    ihold(                          uint8_t B);
        void    irun(                               uint8_t B);
        void    iholddelay(                 uint8_t B);
        uint8_t ihold();
        uint8_t irun();
        uint8_t iholddelay();

        // W: TPOWERDOWN
        uint8_t TPOWERDOWN();
        void TPOWERDOWN(                    uint8_t input);

        // R: TSTEP
        uint32_t TSTEP();

        // W: TPWMTHRS
        uint32_t TPWMTHRS();
        void TPWMTHRS(                      uint32_t input);

        // R: MSCNT
        uint16_t MSCNT();

        // R: MSCURACT
        uint32_t MSCURACT();
        int16_t cur_a();
        int16_t cur_b();

    protected:
        TMCStepper(float RS) : Rsense(RS) {};
        INIT_REGISTER(IHOLD_IRUN){{.sr=0}}; // 32b
        INIT_REGISTER(TPOWERDOWN){.sr=0};       // 8b
        INIT_REGISTER(TPWMTHRS){.sr=0};         // 32b

        static constexpr uint8_t TMC_READ = 0x00,
                                                        TMC_WRITE = 0x80;

        struct TSTEP_t { constexpr static uint8_t address = 0x12; };
        struct MSCNT_t { constexpr static uint8_t address = 0x6A; };

        virtual void write(uint8_t, uint32_t) = 0;
        virtual uint32_t read(uint8_t) = 0;
        virtual void vsense(bool) = 0;
        virtual bool vsense(void) = 0;
        virtual uint32_t DRV_STATUS() = 0;
        virtual void hend(uint8_t) = 0;
        virtual uint8_t hend() = 0;
        virtual void hstrt(uint8_t) = 0;
        virtual uint8_t hstrt() = 0;
        virtual void mres(uint8_t) = 0;
        virtual uint8_t mres() = 0;
        virtual void tbl(uint8_t) = 0;
        virtual uint8_t tbl() = 0;

        const float Rsense;
        float holdMultiplier = 0.5;
};


class TMC2208Stepper : public TMCStepper {
    public:
        TMC2208Stepper(Stream * SerialPort, float RS, uint8_t addr, uint16_t mul_pin1, uint16_t mul_pin2);
        TMC2208Stepper(Stream * SerialPort, float RS) :
            TMC2208Stepper(SerialPort, RS, TMC2208_SLAVE_ADDR)
            {}
        #if SW_CAPABLE_PLATFORM
            TMC2208Stepper(PinName SW_RX_pin, PinName SW_TX_pin, float RS) :
                TMC2208Stepper(SW_RX_pin, SW_TX_pin, RS, TMC2208_SLAVE_ADDR)
                {}

            __attribute__((deprecated("Boolean argument has been deprecated and does nothing")))
            TMC2208Stepper(PinName SW_RX_pin, PinName SW_TX_pin, float RS, bool) :
                TMC2208Stepper(SW_RX_pin, SW_TX_pin, RS, TMC2208_SLAVE_ADDR)
                {};
        #else
            TMC2208Stepper(PinName, PinName, float) = delete; // Your platform does not currently support Software Serial
        #endif
        void defaults();
        void push();
        void begin();
        #if SW_CAPABLE_PLATFORM
            void beginSerial(uint32_t baudrate) __attribute__((weak));
        #else
            void beginSerial(uint32_t) = delete; // Your platform does not currently support Software Serial
        #endif
        bool isEnabled();

        // RW: GCONF
        void GCONF(uint32_t input);
        void I_scale_analog(bool B);
        void internal_Rsense(bool B);
        void en_spreadCycle(bool B);
        void shaft(bool B);
        void index_otpw(bool B);
        void index_step(bool B);
        void pdn_disable(bool B);
        void mstep_reg_select(bool B);
        void multistep_filt(bool B);
        uint32_t GCONF();
        bool I_scale_analog();
        bool internal_Rsense();
        bool en_spreadCycle();
        bool shaft();
        bool index_otpw();
        bool index_step();
        bool pdn_disable();
        bool mstep_reg_select();
        bool multistep_filt();

        // R: IFCNT
        uint8_t IFCNT();

        // W: SLAVECONF
        void SLAVECONF(uint16_t input);
        uint16_t SLAVECONF();
        void senddelay(uint8_t B);
        uint8_t senddelay();

        // W: OTP_PROG
        void OTP_PROG(uint16_t input);

        // R: OTP_READ
        uint32_t OTP_READ();

        // R: IOIN
        uint32_t IOIN();
        bool enn();
        bool ms1();
        bool ms2();
        bool diag();
        bool pdn_uart();
        bool step();
        bool sel_a();
        bool dir();
        uint8_t version();

        // RW: FACTORY_CONF
        void FACTORY_CONF(uint16_t input);
        uint16_t FACTORY_CONF();
        void fclktrim(uint8_t B);
        void ottrim(uint8_t B);
        uint8_t fclktrim();
        uint8_t ottrim();

        // W: VACTUAL
        void VACTUAL(uint32_t input);
        uint32_t VACTUAL();

        // RW: CHOPCONF
        void CHOPCONF(uint32_t input);
        void toff(uint8_t B);
        void hstrt(uint8_t B);
        void hend(uint8_t B);
        void tbl(uint8_t B);
        void vsense(bool B);
        void mres(uint8_t B);
        void intpol(bool B);
        void dedge(bool B);
        void diss2g(bool B);
        void diss2vs(bool B);
        uint32_t CHOPCONF();
        uint8_t toff();
        uint8_t hstrt();
        uint8_t hend();
        uint8_t tbl();
        bool vsense();
        uint8_t mres();
        bool intpol();
        bool dedge();
        bool diss2g();
        bool diss2vs();

        // R: DRV_STATUS
        uint32_t DRV_STATUS();
        bool otpw();
        bool ot();
        bool s2ga();
        bool s2gb();
        bool s2vsa();
        bool s2vsb();
        bool ola();
        bool olb();
        bool t120();
        bool t143();
        bool t150();
        bool t157();
        uint16_t cs_actual();
        bool stealth();
        bool stst();

        // RW: PWMCONF
        void PWMCONF(uint32_t input);
        void pwm_ofs(uint8_t B);
        void pwm_grad(uint8_t B);
        void pwm_freq(uint8_t B);
        void pwm_autoscale(bool B);
        void pwm_autograd(bool B);
        void freewheel(uint8_t B);
        void pwm_reg(uint8_t B);
        void pwm_lim(uint8_t B);
        uint32_t PWMCONF();
        uint8_t pwm_ofs();
        uint8_t pwm_grad();
        uint8_t pwm_freq();
        bool pwm_autoscale();
        bool pwm_autograd();
        uint8_t freewheel();
        uint8_t pwm_reg();
        uint8_t pwm_lim();

        // R: PWM_SCALE
        uint32_t PWM_SCALE();
        uint8_t pwm_scale_sum();
        int16_t pwm_scale_auto();

        // R: PWM_AUTO (0x72)
        uint32_t PWM_AUTO();
        uint8_t pwm_ofs_auto();
        uint8_t pwm_grad_auto();

        uint16_t bytesWritten = 0;
        float Rsense = 0.11;
        bool CRCerror = false;
    protected:
        INIT2208_REGISTER(GCONF)            {{.sr=0}};
        INIT_REGISTER(SLAVECONF)            {{.sr=0}};
        INIT_REGISTER(FACTORY_CONF)     {{.sr=0}};
        INIT2208_REGISTER(VACTUAL)      {.sr=0};
        INIT2208_REGISTER(CHOPCONF)     {{.sr=0}};
        INIT2208_REGISTER(PWMCONF)      {{.sr=0}};

        struct IFCNT_t      { constexpr static uint8_t address = 0x02; };
        struct OTP_PROG_t   { constexpr static uint8_t address = 0x04; };
        struct OTP_READ_t   { constexpr static uint8_t address = 0x05; };

        TMC2208Stepper(Stream * SerialPort, float RS, uint8_t addr);
        #if SW_CAPABLE_PLATFORM
            TMC2208Stepper(PinName SW_RX_pin, PinName SW_TX_pin, float RS, uint8_t addr);
        #endif

        Stream * HWSerial = nullptr;
        #if SW_CAPABLE_PLATFORM
            BufferedSerial * SWSerial = nullptr;
            const uint16_t RXTX_pin = 0; // Half duplex
        #endif

//        SSwitch *sswitch = nullptr;

        int available();
        void preWriteCommunication();
        void preReadCommunication();
        int16_t serial_read();
        uint8_t serial_write(const uint8_t data);
        void postWriteCommunication();
        void postReadCommunication();
        void write(uint8_t, uint32_t);
        uint32_t read(uint8_t);
        const uint8_t slave_address;
        uint8_t calcCRC(uint8_t datagram[], uint8_t len);
        static constexpr uint8_t  TMC2208_SYNC = 0x05,
                                  TMC2208_SLAVE_ADDR = 0x00;
        static constexpr uint8_t replyDelay = 2;  //ms
        static constexpr uint8_t abort_window = 5;
        static constexpr uint8_t max_retries = 2;

        uint64_t _sendDatagram(uint8_t [], const uint8_t, uint16_t);
};

class TMC2209Stepper : public TMC2208Stepper {
    public:
        TMC2209Stepper(Stream * SerialPort, float RS, uint8_t addr) :
            TMC2208Stepper(SerialPort, RS, addr) {}

        #if SW_CAPABLE_PLATFORM
            TMC2209Stepper(PinName SW_RX_pin, PinName SW_TX_pin, float RS, uint8_t addr) :
                TMC2208Stepper(SW_RX_pin, SW_TX_pin, RS, addr) {}
        #else
            TMC2209Stepper(PinName, PinName, float, uint8_t) = delete; // Your platform does not currently support Software Serial
        #endif
        void push();

        // R: IOIN
        uint32_t IOIN();
        bool enn();
        bool ms1();
        bool ms2();
        bool diag();
        bool pdn_uart();
        bool step();
        bool spread_en();
        bool dir();
        uint8_t version();

        // W: TCOOLTHRS
        uint32_t TCOOLTHRS();
        void TCOOLTHRS(uint32_t input);

        // W: SGTHRS
        void SGTHRS(uint8_t B);
        uint8_t SGTHRS();

        // R: SG_RESULT
        uint16_t SG_RESULT();

        // W: COOLCONF
        void COOLCONF(uint16_t B);
        uint16_t COOLCONF();
        void semin(uint8_t B);
        void seup(uint8_t B);
        void semax(uint8_t B);
        void sedn(uint8_t B);
        void seimin(bool B);
        uint8_t semin();
        uint8_t seup();
        uint8_t semax();
        uint8_t sedn();
        bool seimin();

    protected:
        INIT_REGISTER(TCOOLTHRS){.sr=0};
        TMC2209_n::SGTHRS_t SGTHRS_register{.sr=0};
        TMC2209_n::COOLCONF_t COOLCONF_register{{.sr=0}};
};