Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions src/TMCStepper.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@

#if defined(ARDUINO) && ARDUINO >= 100
#include <Arduino.h>
#include <SPI.h>
#ifndef TMC_NO_GENERIC_SPI
#include <SPI.h>
#endif
#include <Stream.h>
#elif defined(bcm2835)
#include <bcm2835.h>
Expand All @@ -36,8 +38,12 @@
#if __has_include(<Arduino.h>)
#include <Arduino.h>
#endif
#if __has_include(<SPI.h>)
#include <SPI.h>
#ifndef TMC_NO_GENERIC_SPI
#if __has_include(<SPI.h>)
#include <SPI.h>
#else
#define TMC_NO_GENERIC_SPI
#endif
#endif
#if __has_include(<Stream.h>)
#include <Stream.h>
Expand Down Expand Up @@ -76,6 +82,8 @@
#include "source/TMC2240_bitfields.h"
#include "source/TMC2660_bitfields.h"

#include "TMCStepper_fixing.h"

#include "source/TMCStepperBase.h"
#include "source/TMC2130Stepper.h"
#include "source/TMC2160Stepper.h"
Expand Down
22 changes: 22 additions & 0 deletions src/TMCStepper_SPI.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#define TMCSPI_BITORDER_LSB 0
#define TMCSPI_BITORDER_MSB 1

#define TMCSPI_CLKMODE_0 0
#define TMCSPI_CLKMODE_1 1
#define TMCSPI_CLKMODE_2 2
#define TMCSPI_CLKMODE_3 3

struct TMCSPIInterface {
virtual void begin(uint32_t maxClockFreq, int bitOrder, int clkMode) = 0;
virtual void end() = 0;
virtual uint8_t transfer(uint8_t txval) = 0;
virtual void sendRepeat(uint8_t val, uint16_t repcnt) = 0;
};

#ifndef TMC_NO_GENERIC_SPI
#define _TMC_SOFTSPI_DEFAULT false
#else
#define _TMC_SOFTSPI_DEFAULT true
#endif
107 changes: 107 additions & 0 deletions src/TMCStepper_fixing.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#pragma once

#ifndef TMC_NO_GENERIC_SPI

namespace _TMC_FIXING
{

// BEGIN https://en.cppreference.com/w/cpp/types/add_reference
namespace detail {

template <class T>
struct type_identity { using type = T; };

template <class T>
auto try_add_rvalue_reference(int) -> type_identity<T&&>;
template <class T>
auto try_add_rvalue_reference(...) -> type_identity<T>;

} // namespace detail

template <class T>
struct add_rvalue_reference : decltype(detail::try_add_rvalue_reference<T>(0)) {};

// END https://en.cppreference.com/w/cpp/types/add_reference

// BEGIN https://en.cppreference.com/w/cpp/utility/declval (inspired)
template<typename T>
struct always_false
{
enum { value = false };
};

template<typename T>
typename add_rvalue_reference<T>::type declval() {
static_assert(always_false<T>::value, "declval not allowed in an evaluated context");
}

// END https://en.cppreference.com/w/cpp/utility/declval

struct true_type {
enum { value = true };
};
struct false_type {
enum { value = false };
};

} // namespace TMC_FIXING

// Since we don't have C++20 we need to do some ugly hacks to ensure compat.
// https://stackoverflow.com/questions/63253287/using-sfinae-to-detect-method-with-gcc
// Did you know that ATMEL AVR does not support standard C++ headers???
#define __DEF_HAS_METH( methName ) \
template<typename T> \
struct ___has_##methName \
{ \
template<typename C> \
static constexpr auto test(...) -> _TMC_FIXING::false_type; \
template<typename C> \
static constexpr auto test(int) \
-> decltype(static_cast<void>(_TMC_FIXING::declval<C>().methName(0)), _TMC_FIXING::true_type()); \
using result_type = decltype(test<T>(0)); \
static const bool value = result_type::value; \
}
#define __HAS_METH( className, methName ) \
( ___has_##methName <className>::value )

__DEF_HAS_METH( setMISO );
__DEF_HAS_METH( setMOSI );
__DEF_HAS_METH( setSCLK );

#define SPI_SET_PIN_HELPER( pinDescName ) \
template <bool hasPin> \
struct _spiInitHelper_##pinDescName \
{}; \
template <> \
struct _spiInitHelper_##pinDescName <true> \
{ \
template <typename SPIClassT> \
static void spiSet##pinDescName( SPIClassT& spi, uint16_t pin ) { spi.set##pinDescName( pin ); } \
}; \
template <> \
struct _spiInitHelper_##pinDescName <false> \
{ \
template <typename SPIClassT> \
static void spiSet##pinDescName( SPIClassT& spi, uint16_t pin ) {} \
}

SPI_SET_PIN_HELPER( MISO );
SPI_SET_PIN_HELPER( MOSI );
SPI_SET_PIN_HELPER( SCLK );

#define SPI_INIT_PIN( spi, pinDescName, val ) _spiInitHelper_##pinDescName <__HAS_METH(SPIClass, set##pinDescName)> ::spiSet##pinDescName( spi, val )

// Speciality of the ESP32 platform.
#ifdef ESP_PLATFORM
// https://github.com/espressif/arduino-esp32/blob/master/libraries/SPI/src/SPI.cpp SPIClass::begin method.
#define SPI_BEGIN( spi, sck, miso, mosi ) ( spi.begin( sck, miso, mosi ) )
#else
// Other platforms.
#define SPI_BEGIN( spi, sck, miso, mosi ) \
{ SPI_INIT_PIN( spi, MISO, miso ); \
SPI_INIT_PIN( SPI, MOSI, mosi ); \
SPI_INIT_PIN( SPI, SCLK, sck ); \
spi.begin(); }
#endif

#endif // TMC_NO_GENERIC_SPI
100 changes: 87 additions & 13 deletions src/source/TMC2130Stepper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,84 @@
int8_t TMC2130Stepper::chain_length = 0;
uint32_t TMC2130Stepper::spi_speed = 16000000/8;

TMC2130Stepper::TMC2130Stepper(uint16_t pinCS, float RS, int8_t link) :
TMC2130Stepper::TMC2130Stepper(uint16_t pinCS, float RS, int8_t link_index) :
TMCStepper(RS),
_pinCS(pinCS),
_pinMISO(0),
_pinMOSI(0),
_pinSCK(0),
_has_pins(false),
TMC_SW_SPI(nullptr),
_spiMan(nullptr),
link_index(link_index)
{
defaults();

if (link_index > chain_length)
chain_length = link_index;
}

TMC2130Stepper::TMC2130Stepper(uint16_t pinCS, uint16_t pinMOSI, uint16_t pinMISO, uint16_t pinSCK, int8_t link, bool softSPI) :
TMCStepper(default_RS),
_pinCS(pinCS),
_pinMISO(pinMISO),
_pinMOSI(pinMOSI),
_pinSCK(pinSCK),
_has_pins(true),
_spiMan(nullptr),
link_index(link)
{
if (softSPI)
{
SW_SPIClass *SW_SPI_Obj = new SW_SPIClass(pinMOSI, pinMISO, pinSCK);
TMC_SW_SPI = SW_SPI_Obj;
}
else
{
TMC_SW_SPI = nullptr;
}
defaults();

if (link > chain_length)
chain_length = link;
}

TMC2130Stepper::TMC2130Stepper(uint16_t pinCS, uint16_t pinMOSI, uint16_t pinMISO, uint16_t pinSCK, int8_t link) :
TMCStepper(default_RS),
TMC2130Stepper::TMC2130Stepper(uint16_t pinCS, float RS, uint16_t pinMOSI, uint16_t pinMISO, uint16_t pinSCK, int8_t link, bool softSPI) :
TMCStepper(RS),
_pinCS(pinCS),
_pinMISO(pinMISO),
_pinMOSI(pinMOSI),
_pinSCK(pinSCK),
_has_pins(true),
_spiMan(nullptr),
link_index(link)
{
SW_SPIClass *SW_SPI_Obj = new SW_SPIClass(pinMOSI, pinMISO, pinSCK);
TMC_SW_SPI = SW_SPI_Obj;
if (softSPI)
{
SW_SPIClass *SW_SPI_Obj = new SW_SPIClass(pinMOSI, pinMISO, pinSCK);
TMC_SW_SPI = SW_SPI_Obj;
}
else
{
TMC_SW_SPI = nullptr;
}
defaults();

if (link > chain_length)
chain_length = link;
}

TMC2130Stepper::TMC2130Stepper(uint16_t pinCS, float RS, uint16_t pinMOSI, uint16_t pinMISO, uint16_t pinSCK, int8_t link) :
TMC2130Stepper::TMC2130Stepper(uint16_t pinCS, float RS, TMCSPIInterface *spiMan, int8_t link) :
TMCStepper(RS),
_pinCS(pinCS),
_pinMISO(0),
_pinMOSI(0),
_pinSCK(0),
_has_pins(false),
TMC_SW_SPI(nullptr),
_spiMan(spiMan),
link_index(link)
{
SW_SPIClass *SW_SPI_Obj = new SW_SPIClass(pinMOSI, pinMISO, pinSCK);
TMC_SW_SPI = SW_SPI_Obj;
defaults();

if (link > chain_length)
Expand Down Expand Up @@ -78,32 +125,59 @@ void TMC2130Stepper::switchCSpin(bool state) {

__attribute__((weak))
void TMC2130Stepper::beginTransaction() {
if (TMC_SW_SPI == nullptr) {
if (_spiMan) {
_spiMan->begin(spi_speed, TMCSPI_BITORDER_MSB, TMCSPI_CLKMODE_3);
}
#ifndef TMC_NO_GENERIC_SPI
else if (TMC_SW_SPI == nullptr) {
if (_has_pins)
{
SPI_BEGIN( SPI, _pinSCK, _pinMISO, _pinMOSI );
}
else
SPI.begin();
SPI.beginTransaction(SPISettings(spi_speed, MSBFIRST, SPI_MODE3));
}
#endif
}
__attribute__((weak))
void TMC2130Stepper::endTransaction() {
if (TMC_SW_SPI == nullptr) {
if (_spiMan) {
_spiMan->end();
}
#ifndef TMC_NO_GENERIC_SPI
else if (TMC_SW_SPI == nullptr) {
SPI.endTransaction();
SPI.end();
}
#endif
}

__attribute__((weak))
uint8_t TMC2130Stepper::transfer(const uint8_t data) {
uint8_t out = 0;
if (TMC_SW_SPI != nullptr) {
if (_spiMan) {
out = _spiMan->transfer(data);
}
else if (TMC_SW_SPI != nullptr) {
out = TMC_SW_SPI->transfer(data);
}
#ifndef TMC_NO_GENERIC_SPI
else {
out = SPI.transfer(data);
}
#endif
return out;
}

void TMC2130Stepper::transferEmptyBytes(const uint8_t n) {
for (uint8_t i = 0; i < n; i++) {
transfer(0x00);
if (_spiMan) {
_spiMan->sendRepeat(0, n);
}
else {
for (uint8_t i = 0; i < n; i++) {
transfer(0x00);
}
}
}

Expand Down
12 changes: 10 additions & 2 deletions src/source/TMC2130Stepper.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@
*/
#pragma once

#include "TMCStepper_SPI.h"

#define INIT2130_REGISTER(REG) TMC2130_n::REG##_t REG##_register{}

class TMC2130Stepper : public TMCStepper {
public:
TMC2130Stepper(uint16_t pinCS, float RS = default_RS, int8_t link_index = -1);
TMC2130Stepper(uint16_t pinCS, uint16_t pinMOSI, uint16_t pinMISO, uint16_t pinSCK, int8_t link_index = -1);
TMC2130Stepper(uint16_t pinCS, float RS, uint16_t pinMOSI, uint16_t pinMISO, uint16_t pinSCK, int8_t link_index = -1);
TMC2130Stepper(uint16_t pinCS, uint16_t pinMOSI, uint16_t pinMISO, uint16_t pinSCK, int8_t link_index = -1, bool softSPI = _TMC_SOFTSPI_DEFAULT);
TMC2130Stepper(uint16_t pinCS, float RS, uint16_t pinMOSI, uint16_t pinMISO, uint16_t pinSCK, int8_t link_index = -1, bool softSPI = _TMC_SOFTSPI_DEFAULT);
TMC2130Stepper(uint16_t pinCS, float RS, TMCSPIInterface *spiMan, int8_t link_index = -1);
void begin();
void defaults();
void setSPISpeed(uint32_t speed);
Expand Down Expand Up @@ -228,6 +231,11 @@ class TMC2130Stepper : public TMCStepper {

static uint32_t spi_speed; // Default 2MHz
const uint16_t _pinCS;
const uint16_t _pinMISO;
const uint16_t _pinMOSI;
const uint16_t _pinSCK;
const TMCSPIInterface *_spiMan;
const bool _has_pins;
SW_SPIClass * TMC_SW_SPI = nullptr;
static constexpr float default_RS = 0.11;

Expand Down
11 changes: 6 additions & 5 deletions src/source/TMC2160Stepper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
#include "../TMCStepper.h"
#include "TMC_MACROS.h"

TMC2160Stepper::TMC2160Stepper(uint16_t pinCS, float RS, int8_t link) : TMC2130Stepper(pinCS, RS, link)
TMC2160Stepper::TMC2160Stepper(uint16_t pinCS, float RS, int8_t link_index) :
TMC2130Stepper(pinCS, RS, link_index)
{ defaults(); }
TMC2160Stepper::TMC2160Stepper(uint16_t pinCS, float RS, uint16_t pinMOSI, uint16_t pinMISO, uint16_t pinSCK, int8_t link) :
TMC2130Stepper(pinCS, RS, pinMOSI, pinMISO, pinSCK, link)
TMC2160Stepper::TMC2160Stepper(uint16_t pinCS, float RS, uint16_t pinMOSI, uint16_t pinMISO, uint16_t pinSCK, int8_t link, bool softSPI) :
TMC2130Stepper(pinCS, RS, pinMOSI, pinMISO, pinSCK, link, softSPI)
{ defaults(); }
TMC2160Stepper::TMC2160Stepper(uint16_t pinCS, uint16_t pinMOSI, uint16_t pinMISO, uint16_t pinSCK, int8_t link) :
TMC2130Stepper(pinCS, default_RS, pinMOSI, pinMISO, pinSCK, link)
TMC2160Stepper::TMC2160Stepper(uint16_t pinCS, uint16_t pinMOSI, uint16_t pinMISO, uint16_t pinSCK, int8_t link, bool softSPI) :
TMC2130Stepper(pinCS, default_RS, pinMOSI, pinMISO, pinSCK, link, softSPI)
{ defaults(); }

void TMC2160Stepper::begin() {
Expand Down
4 changes: 2 additions & 2 deletions src/source/TMC2160Stepper.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
class TMC2160Stepper : public TMC2130Stepper {
public:
TMC2160Stepper(uint16_t pinCS, float RS = default_RS, int8_t link_index = -1);
TMC2160Stepper(uint16_t pinCS, uint16_t pinMOSI, uint16_t pinMISO, uint16_t pinSCK, int8_t link_index = -1);
TMC2160Stepper(uint16_t pinCS, float RS, uint16_t pinMOSI, uint16_t pinMISO, uint16_t pinSCK, int8_t link_index = -1);
TMC2160Stepper(uint16_t pinCS, uint16_t pinMOSI, uint16_t pinMISO, uint16_t pinSCK, int8_t link_index = -1, bool softSPI = _TMC_SOFTSPI_DEFAULT);
TMC2160Stepper(uint16_t pinCS, float RS, uint16_t pinMOSI, uint16_t pinMISO, uint16_t pinSCK, int8_t link_index = -1, bool softSPI = _TMC_SOFTSPI_DEFAULT);
void begin();
void defaults();
void push();
Expand Down
Loading