Skip to content

Commit

Permalink
Improved STMicro L64XX stepper driver support (#16452)
Browse files Browse the repository at this point in the history
  • Loading branch information
Bob-the-Kuhn authored and thinkyhead committed Jan 14, 2020
1 parent 53f1e5f commit 1ad53ce
Show file tree
Hide file tree
Showing 315 changed files with 8,826 additions and 5,587 deletions.
5 changes: 3 additions & 2 deletions Marlin/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -654,12 +654,13 @@
*
* A4988 is assumed for unspecified drivers.
*
* Options: A4988, A5984, DRV8825, LV8729, L6470, TB6560, TB6600, TMC2100,
* Options: A4988, A5984, DRV8825, LV8729, L6470, L6474, POWERSTEP01,
* TB6560, TB6600, TMC2100,
* TMC2130, TMC2130_STANDALONE, TMC2160, TMC2160_STANDALONE,
* TMC2208, TMC2208_STANDALONE, TMC2209, TMC2209_STANDALONE,
* TMC26X, TMC26X_STANDALONE, TMC2660, TMC2660_STANDALONE,
* TMC5130, TMC5130_STANDALONE, TMC5160, TMC5160_STANDALONE
* :['A4988', 'A5984', 'DRV8825', 'LV8729', 'L6470', 'TB6560', 'TB6600', 'TMC2100', 'TMC2130', 'TMC2130_STANDALONE', 'TMC2160', 'TMC2160_STANDALONE', 'TMC2208', 'TMC2208_STANDALONE', 'TMC2209', 'TMC2209_STANDALONE', 'TMC26X', 'TMC26X_STANDALONE', 'TMC2660', 'TMC2660_STANDALONE', 'TMC5130', 'TMC5130_STANDALONE', 'TMC5160', 'TMC5160_STANDALONE']
* :['A4988', 'A5984', 'DRV8825', 'LV8729', 'L6470', 'L6474', 'powerSTEP01', 'TB6560', 'TB6600', 'TMC2100', 'TMC2130', 'TMC2130_STANDALONE', 'TMC2160', 'TMC2160_STANDALONE', 'TMC2208', 'TMC2208_STANDALONE', 'TMC2209', 'TMC2209_STANDALONE', 'TMC26X', 'TMC26X_STANDALONE', 'TMC2660', 'TMC2660_STANDALONE', 'TMC5130', 'TMC5130_STANDALONE', 'TMC5160', 'TMC5160_STANDALONE']
*/
//#define X_DRIVER_TYPE A4988
//#define Y_DRIVER_TYPE A4988
Expand Down
95 changes: 57 additions & 38 deletions Marlin/Configuration_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -2217,127 +2217,146 @@

#endif // HAS_TRINAMIC

// @section L6470
// @section L64XX

/**
* L6470 Stepper Driver options
* L64XX Stepper Driver options
*
* Arduino-L6470 library (0.7.0 or higher) is required for this stepper driver.
* Arduino-L6470 library (0.8.0 or higher) is required.
* https://github.com/ameyer/Arduino-L6470
*
* Requires the following to be defined in your pins_YOUR_BOARD file
* L6470_CHAIN_SCK_PIN
* L6470_CHAIN_MISO_PIN
* L6470_CHAIN_MOSI_PIN
* L6470_CHAIN_SS_PIN
* L6470_RESET_CHAIN_PIN (optional)
* ENABLE_RESET_L64XX_CHIPS(Q) where Q is 1 to enable and 0 to reset
*/
#if HAS_DRIVER(L6470)

//#define L6470_CHITCHAT // Display additional status info
#if HAS_L64XX

#if AXIS_DRIVER_TYPE_X(L6470)
#define X_MICROSTEPS 128 // Number of microsteps (VALID: 1, 2, 4, 8, 16, 32, 128)
#define X_OVERCURRENT 2000 // (mA) Current where the driver detects an over current (VALID: 375 x (1 - 16) - 6A max - rounds down)
#define X_STALLCURRENT 1500 // (mA) Current where the driver detects a stall (VALID: 31.25 * (1-128) - 4A max - rounds down)
#define X_MAX_VOLTAGE 127 // 0-255, Maximum effective voltage seen by stepper
#define X_CHAIN_POS -1 // Position in SPI chain. (<=0 : Not in chain. 1 : Nearest MOSI)
#endif
//#define L6470_CHITCHAT // Display additional status info

#if AXIS_DRIVER_TYPE_X2(L6470)
#if AXIS_IS_L64XX(X)
#define X_MICROSTEPS 128 // Number of microsteps (VALID: 1, 2, 4, 8, 16, 32, 128) - L6474 max is 16
#define X_OVERCURRENT 2000 // (mA) Current where the driver detects an over current
// L6470 & L6474 - VALID: 375 x (1 - 16) - 6A max - rounds down
// POWERSTEP01: VALID: 1000 x (1 - 32) - 32A max - rounds down
#define X_STALLCURRENT 1500 // (mA) Current where the driver detects a stall (VALID: 31.25 * (1-128) - 4A max - rounds down)
// L6470 & L6474 - VALID: 31.25 * (1-128) - 4A max - rounds down
// POWERSTEP01: VALID: 200 x (1 - 32) - 6.4A max - rounds down
// L6474 - STALLCURRENT setting is used to set the nominal (TVAL) current
#define X_MAX_VOLTAGE 127 // 0-255, Maximum effective voltage seen by stepper - not used by L6474
#define X_CHAIN_POS 0 // Position in SPI chain, 0=Not in chain, 1=Nearest MOSI
#define X_SLEW_RATE 1 // 0-3, Slew 0 is slowest, 3 is fastest
#endif

#if AXIS_IS_L64XX(X2)
#define X2_MICROSTEPS 128
#define X2_OVERCURRENT 2000
#define X2_STALLCURRENT 1500
#define X2_MAX_VOLTAGE 127
#define X2_CHAIN_POS -1
#define X2_CHAIN_POS 0
#define X2_SLEW_RATE 1
#endif

#if AXIS_DRIVER_TYPE_Y(L6470)
#if AXIS_IS_L64XX(Y)
#define Y_MICROSTEPS 128
#define Y_OVERCURRENT 2000
#define Y_STALLCURRENT 1500
#define Y_MAX_VOLTAGE 127
#define Y_CHAIN_POS -1
#define Y_CHAIN_POS 0
#define Y_SLEW_RATE 1
#endif

#if AXIS_DRIVER_TYPE_Y2(L6470)
#if AXIS_IS_L64XX(Y2)
#define Y2_MICROSTEPS 128
#define Y2_OVERCURRENT 2000
#define Y2_STALLCURRENT 1500
#define Y2_MAX_VOLTAGE 127
#define Y2_CHAIN_POS -1
#define Y2_CHAIN_POS 0
#define Y2_SLEW_RATE 1
#endif

#if AXIS_DRIVER_TYPE_Z(L6470)
#if AXIS_IS_L64XX(Z)
#define Z_MICROSTEPS 128
#define Z_OVERCURRENT 2000
#define Z_STALLCURRENT 1500
#define Z_MAX_VOLTAGE 127
#define Z_CHAIN_POS -1
#define Z_CHAIN_POS 0
#define Z_SLEW_RATE 1
#endif

#if AXIS_DRIVER_TYPE_Z2(L6470)
#if AXIS_IS_L64XX(Z2)
#define Z2_MICROSTEPS 128
#define Z2_OVERCURRENT 2000
#define Z2_STALLCURRENT 1500
#define Z2_MAX_VOLTAGE 127
#define Z2_CHAIN_POS -1
#define Z2_CHAIN_POS 0
#define Z2_SLEW_RATE 1
#endif

#if AXIS_DRIVER_TYPE_Z3(L6470)
#if AXIS_IS_L64XX(Z3)
#define Z3_MICROSTEPS 128
#define Z3_OVERCURRENT 2000
#define Z3_STALLCURRENT 1500
#define Z3_MAX_VOLTAGE 127
#define Z3_CHAIN_POS -1
#define Z3_CHAIN_POS 0
#define Z3_SLEW_RATE 1
#endif

#if AXIS_DRIVER_TYPE_E0(L6470)
#if AXIS_IS_L64XX(E0)
#define E0_MICROSTEPS 128
#define E0_OVERCURRENT 2000
#define E0_STALLCURRENT 1500
#define E0_MAX_VOLTAGE 127
#define E0_CHAIN_POS -1
#define E0_CHAIN_POS 0
#define E0_SLEW_RATE 1
#endif

#if AXIS_DRIVER_TYPE_E1(L6470)
#if AXIS_IS_L64XX(E1)
#define E1_MICROSTEPS 128
#define E1_OVERCURRENT 2000
#define E1_STALLCURRENT 1500
#define E1_MAX_VOLTAGE 127
#define E1_CHAIN_POS -1
#define E1_CHAIN_POS 0
#define E1_SLEW_RATE 1
#endif

#if AXIS_DRIVER_TYPE_E2(L6470)
#if AXIS_IS_L64XX(E2)
#define E2_MICROSTEPS 128
#define E2_OVERCURRENT 2000
#define E2_STALLCURRENT 1500
#define E2_MAX_VOLTAGE 127
#define E2_CHAIN_POS -1
#define E2_CHAIN_POS 0
#define E2_SLEW_RATE 1
#endif

#if AXIS_DRIVER_TYPE_E3(L6470)
#if AXIS_IS_L64XX(E3)
#define E3_MICROSTEPS 128
#define E3_OVERCURRENT 2000
#define E3_STALLCURRENT 1500
#define E3_MAX_VOLTAGE 127
#define E3_CHAIN_POS -1
#define E3_CHAIN_POS 0
#define E3_SLEW_RATE 1
#endif

#if AXIS_DRIVER_TYPE_E4(L6470)
#if AXIS_IS_L64XX(E4)
#define E4_MICROSTEPS 128
#define E4_OVERCURRENT 2000
#define E4_STALLCURRENT 1500
#define E4_MAX_VOLTAGE 127
#define E4_CHAIN_POS -1
#define E4_CHAIN_POS 0
#define E4_SLEW_RATE 1
#endif

#if AXIS_DRIVER_TYPE_E5(L6470)
#if AXIS_IS_L64XX(E5)
#define E5_MICROSTEPS 128
#define E5_OVERCURRENT 2000
#define E5_STALLCURRENT 1500
#define E5_MAX_VOLTAGE 127
#define E5_CHAIN_POS -1
#define E5_CHAIN_POS 0
#define E5_SLEW_RATE 1
#endif

/**
Expand All @@ -2363,7 +2382,7 @@
//#define L6470_STOP_ON_ERROR
#endif

#endif // L6470
#endif // HAS_L64XX

/**
* TWI/I2C BUS
Expand Down
3 changes: 1 addition & 2 deletions Marlin/src/HAL/HAL_STM32/timers.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
#define hal_timer_t uint32_t
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFF // Timers can be 16 or 32 bit


#ifdef STM32F0xx

#define HAL_TIMER_RATE (F_CPU) // frequency of timer peripherals
Expand Down Expand Up @@ -63,7 +62,7 @@
#define HAL_TIMER_RATE (F_CPU/2) // frequency of timer peripherals

#ifndef STEP_TIMER
#define STEP_TIMER 6
#define STEP_TIMER 9 // STM32F401 has no TIM6, TIM7, or TIM8
#endif

#ifndef TEMP_TIMER
Expand Down
77 changes: 44 additions & 33 deletions Marlin/src/HAL/shared/HAL_spi_L6470.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,20 @@

#include "../../inc/MarlinConfig.h"

#if HAS_DRIVER(L6470)
#if HAS_L64XX

#include "Delay.h"

#include "../../core/serial.h"
#include "../../libs/L6470/L6470_Marlin.h"
#include "../../libs/L64XX/L64XX_Marlin.h"

// Make sure GCC optimizes this file.
// Note that this line triggers a bug in GCC which is fixed by casting.
// See the note below.
#pragma GCC optimize (3)

// run at ~4Mhz
uint8_t L6470_SpiTransfer_Mode_0(uint8_t b) { // using Mode 0
inline uint8_t L6470_SpiTransfer_Mode_0(uint8_t b) { // using Mode 0
for (uint8_t bits = 8; bits--;) {
WRITE(L6470_CHAIN_MOSI_PIN, b & 0x80);
b <<= 1; // little setup time
Expand All @@ -56,51 +56,75 @@ uint8_t L6470_SpiTransfer_Mode_0(uint8_t b) { // using Mode 0
return b;
}

uint8_t L6470_SpiTransfer_Mode_3(uint8_t b) { // using Mode 3
inline uint8_t L6470_SpiTransfer_Mode_3(uint8_t b) { // using Mode 3
for (uint8_t bits = 8; bits--;) {
WRITE(L6470_CHAIN_SCK_PIN, LOW);
WRITE(L6470_CHAIN_MOSI_PIN, b & 0x80);

DELAY_NS(125); // 10 cycles @ 84mhz

WRITE(L6470_CHAIN_SCK_PIN, HIGH);
DELAY_NS(125); // Need more delay for fast CPUs

b <<= 1; // little setup time
b |= (READ(L6470_CHAIN_MISO_PIN) != 0);
}

DELAY_NS(125); // 10 cycles @ 84mhz
DELAY_NS(125); // 10 cycles @ 84mhz
return b;
}

/**
* The following are weak-linked and defined as do-nothing
* functions by the L6470-Arduino library. They must be
* defined by the client (Marlin) to provide an SPI interface.
* L64XX methods for SPI init and transfer
*/
void L64XX_Marlin::spi_init() {
OUT_WRITE(L6470_CHAIN_SS_PIN, HIGH);
OUT_WRITE(L6470_CHAIN_SCK_PIN, HIGH);
OUT_WRITE(L6470_CHAIN_MOSI_PIN, HIGH);
SET_INPUT(L6470_CHAIN_MISO_PIN);

#if PIN_EXISTS(L6470_BUSY)
SET_INPUT(L6470_BUSY_PIN);
#endif

uint8_t L6470_transfer(uint8_t data, int16_t ss_pin, const uint8_t chain_position) {
OUT_WRITE(L6470_CHAIN_MOSI_PIN, HIGH);
}

uint8_t L64XX_Marlin::transfer_single(uint8_t data, int16_t ss_pin) {
// First device in chain has data sent last
extDigitalWrite(ss_pin, LOW);

DISABLE_ISRS(); // Disable interrupts during SPI transfer (can't allow partial command to chips)
const uint8_t data_out = L6470_SpiTransfer_Mode_3(data);
ENABLE_ISRS(); // Enable interrupts

extDigitalWrite(ss_pin, HIGH);
return data_out;
}

uint8_t L64XX_Marlin::transfer_chain(uint8_t data, int16_t ss_pin, uint8_t chain_position) {
uint8_t data_out = 0;

// first device in chain has data sent last
extDigitalWrite(ss_pin, LOW);

for (uint8_t i = L6470::chain[0]; (i >= 1) && !spi_abort; i--) { // stop sending data if spi_abort is active
DISABLE_ISRS(); // disable interrupts during SPI transfer (can't allow partial command to chips)
uint8_t temp = L6470_SpiTransfer_Mode_3(uint8_t(i == chain_position ? data : dSPIN_NOP));
ENABLE_ISRS(); // enable interrupts
for (uint8_t i = L64XX::chain[0]; !L64xxManager.spi_abort && i >= 1; i--) { // Send data unless aborted
DISABLE_ISRS(); // Disable interrupts during SPI transfer (can't allow partial command to chips)
const uint8_t temp = L6470_SpiTransfer_Mode_3(uint8_t(i == chain_position ? data : dSPIN_NOP));
ENABLE_ISRS(); // Enable interrupts
if (i == chain_position) data_out = temp;
}

extDigitalWrite(ss_pin, HIGH);
return data_out;
}

void L6470_transfer(uint8_t L6470_buf[], const uint8_t length) {
// first device in chain has data sent last
/**
* Platform-supplied L6470 buffer transfer method
*/
void L64XX_Marlin::transfer(uint8_t L6470_buf[], const uint8_t length) {
// First device in chain has its data sent last

if (spi_active) { // interrupted SPI transfer so need to
WRITE(L6470_CHAIN_SS_PIN, HIGH); // guarantee min high of 650nS
if (spi_active) { // Interrupted SPI transfer so need to
WRITE(L6470_CHAIN_SS_PIN, HIGH); // guarantee min high of 650ns
DELAY_US(1);
}

Expand All @@ -110,19 +134,6 @@ void L6470_transfer(uint8_t L6470_buf[], const uint8_t length) {
WRITE(L6470_CHAIN_SS_PIN, HIGH);
}

void L6470_spi_init() {
OUT_WRITE(L6470_CHAIN_SS_PIN, HIGH);
OUT_WRITE(L6470_CHAIN_SCK_PIN, HIGH);
OUT_WRITE(L6470_CHAIN_MOSI_PIN, HIGH);
SET_INPUT(L6470_CHAIN_MISO_PIN);

#if PIN_EXISTS(L6470_BUSY)
SET_INPUT(L6470_BUSY_PIN);
#endif

OUT_WRITE(L6470_CHAIN_MOSI_PIN, HIGH);
}

#pragma GCC reset_options

#endif // HAS_DRIVER(L6470)
#endif // HAS_L64XX
10 changes: 5 additions & 5 deletions Marlin/src/MarlinCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@
#include "feature/prusa_MMU2/mmu2.h"
#endif

#if HAS_DRIVER(L6470)
#include "libs/L6470/L6470_Marlin.h"
#if HAS_L64XX
#include "libs/L64XX/L64XX_Marlin.h"
#endif

const char NUL_STR[] PROGMEM = "",
Expand Down Expand Up @@ -605,7 +605,7 @@ void manage_inactivity(const bool ignore_stepper_queue/*=false*/) {
#endif

#if ENABLED(MONITOR_L6470_DRIVER_STATUS)
L6470.monitor_driver();
L64xxManager.monitor_driver();
#endif

// Limit check_axes_activity frequency to 10Hz
Expand Down Expand Up @@ -822,8 +822,8 @@ void setup() {

HAL_init();

#if HAS_DRIVER(L6470)
L6470.init(); // setup SPI and then init chips
#if HAS_L64XX
L64xxManager.init(); // Set up SPI, init drivers
#endif

#if ENABLED(MAX7219_DEBUG)
Expand Down
Loading

0 comments on commit 1ad53ce

Please sign in to comment.