Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved STMicro L64XX stepper driver support #16452

Merged
merged 6 commits into from
Jan 14, 2020
Merged
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it needed to change the value from -1 to 0 for "not in chain"? Previously, Teemu pushed for the value -1 to be used because it gives a stronger hint that the item is not in the chain, so that's the value used for TMC drivers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm OK with either.

#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