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

[2.0.x] Add L6470 SPI daisy chain support #12895

Merged
merged 16 commits into from
Jan 24, 2019
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 75 additions & 16 deletions Marlin/Configuration_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1509,62 +1509,121 @@
/**
* L6470 Stepper Driver options
*
* The Arduino-L6470 library is required for this stepper driver.
* Arduino-L6470 library (0.7.0 or higher) is required for this stepper driver.
* 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)
*/
#if HAS_DRIVER(L6470)

#define X_MICROSTEPS 16 // number of microsteps
#define X_OVERCURRENT 2000 // maxc current in mA. If the current goes over this value, the driver will switch off
#define X_STALLCURRENT 1500 // current in mA where the driver will detect a stall
#define X_MICROSTEPS 128 // number of microsteps (VALID: 1, 2, 4, 8, 16, 32, 128 & 128)
#define X_OVERCURRENT 2000 // current in mA where the driver will detect an over current (VALID: 375 x (1 - 16) - 6A max - rounds down)
#define X_STALLCURRENT 1500 // current in mA where the driver will detect a stall (VALID: 31.25 * (1-128) - 4A max - rounds down)
#define X_MAX_VOLTAGE 127 // 0-255, max effective voltage seen by stepper
#define X_CHAIN_POS 0 // position in SPI chain, 0 - not in chain, 1- nearest MOSI

#define X2_MICROSTEPS 16
#define X2_MICROSTEPS 128
#define X2_OVERCURRENT 2000
#define X2_STALLCURRENT 1500
#define X2_MAX_VOLTAGE 127
#define X2_CHAIN_POS 0

#define Y_MICROSTEPS 16
#define Y_MICROSTEPS 128
#define Y_OVERCURRENT 2000
#define Y_STALLCURRENT 1500
#define Y_MAX_VOLTAGE 127
#define Y_CHAIN_POS 0

#define Y2_MICROSTEPS 16
#define Y2_MICROSTEPS 128
#define Y2_OVERCURRENT 2000
#define Y2_STALLCURRENT 1500
#define Y2_MAX_VOLTAGE 127
#define Y2_CHAIN_POS 0

#define Z_MICROSTEPS 16
#define Z_MICROSTEPS 128
#define Z_OVERCURRENT 2000
#define Z_STALLCURRENT 1500
#define Z_MAX_VOLTAGE 127
#define Z_CHAIN_POS 0

#define Z2_MICROSTEPS 16
#define Z2_MICROSTEPS 128
#define Z2_OVERCURRENT 2000
#define Z2_STALLCURRENT 1500
#define Z2_MAX_VOLTAGE 127
#define Z2_CHAIN_POS 0

#define Z3_MICROSTEPS 16
#define Z3_MICROSTEPS 128
#define Z3_OVERCURRENT 2000
#define Z3_STALLCURRENT 1500
#define Z3_MAX_VOLTAGE 127
#define Z3_CHAIN_POS 0

#define E0_MICROSTEPS 16
#define E0_MICROSTEPS 128
#define E0_OVERCURRENT 2000
#define E0_STALLCURRENT 1500
#define E0_MAX_VOLTAGE 127
#define E0_CHAIN_POS 0

#define E1_MICROSTEPS 16
#define E1_MICROSTEPS 128
#define E1_OVERCURRENT 2000
#define E1_STALLCURRENT 1500
#define E1_MAX_VOLTAGE 127
#define E1_CHAIN_POS 0

#define E2_MICROSTEPS 16
#define E2_MICROSTEPS 128
#define E2_OVERCURRENT 2000
#define E2_STALLCURRENT 1500
#define E2_MAX_VOLTAGE 127
#define E2_CHAIN_POS 0

#define E3_MICROSTEPS 16
#define E3_MICROSTEPS 128
#define E3_OVERCURRENT 2000
#define E3_STALLCURRENT 1500
#define E3_MAX_VOLTAGE 127
#define E3_CHAIN_POS 0

#define E4_MICROSTEPS 16
#define E4_MICROSTEPS 128
#define E4_OVERCURRENT 2000
#define E4_STALLCURRENT 1500
#define E4_MAX_VOLTAGE 127
#define E4_CHAIN_POS 0

#define E5_MICROSTEPS 16
#define E5_MICROSTEPS 128
#define E5_OVERCURRENT 2000
#define E5_STALLCURRENT 1500
#define E5_MAX_VOLTAGE 127
#define E5_CHAIN_POS 0


/**
* Monitor L6470 drivers for error conditions like over temperature and over current.
* In the case of over temperature Marlin can decrease the drive until the error condition clears.
* Other detected conditions can be used to stop the current print.
* Relevant g-codes:
* M906 - I1/2/3/4/5 Set or get motor drive level using axis codes X, Y, Z, E. Report values if no axis codes given.
* I not present or I0 or I1 - X, Y, Z or E0
* I2 - X2, Y2, Z2 or E1
* I3 - Z3 or E3
* I4 - E4
* I5 - E5
* M916 - Increase drive level until get thermal warning
* M917 - Find minimum current thresholds
* M918 - Increase speed until max or error
* M122 S0/1 - Report driver parameters
*/
//#define MONITOR_L6470_DRIVER_STATUS

#if ENABLED(MONITOR_L6470_DRIVER_STATUS)
#define KVAL_HOLD_STEP_DOWN 1
//#define L6470_STOP_ON_ERROR
#endif

#define L6470_CHITCHAT // enable display of additional status info

#endif // L6470

Expand Down
144 changes: 144 additions & 0 deletions Marlin/src/HAL/shared/HAL_spi_L6470.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/**
* Marlin 3D Printer Firmware
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

/**
* Software L6470 SPI functions originally from Arduino Sd2Card Library
* Copyright (C) 2009 by William Greiman
*/

// --------------------------------------------------------------------------
// Includes
// --------------------------------------------------------------------------

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

#if HAS_DRIVER(L6470)

#include "Delay.h"

// --------------------------------------------------------------------------
// Public Variables
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// Public functions
// --------------------------------------------------------------------------

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

// --------------------------------------------------------------------------
// Software L6470 SPI
// --------------------------------------------------------------------------

// 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
for (uint8_t bits = 8; bits--;) {
WRITE(L6470_CHAIN_MOSI_PIN, b & 0x80);
b <<= 1; // little setup time

WRITE(L6470_CHAIN_SCK_PIN, HIGH);
DELAY_NS(125); // 10 cycles @ 84mhz

b |= (READ(L6470_CHAIN_MISO_PIN) != 0);

WRITE(L6470_CHAIN_SCK_PIN, LOW);
DELAY_NS(125); // 10 cycles @ 84mhz
}
return b;
}

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);

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

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.
*/

uint8_t L6470_transfer(uint8_t data, int _SSPin, const uint8_t chain_position) {
uint8_t data_out = 0;

// first device in chain has data sent last
digitalWrite(_SSPin, 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
if (i == chain_position) data_out = temp;
}

digitalWrite(_SSPin, HIGH);
return data_out;
}

void L6470_transfer(uint8_t L6470_buf[], const uint8_t length) {
// first device in chain has data sent last

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

WRITE(L6470_CHAIN_SS_PIN, LOW);
for (uint8_t i = length; i >= 1; i--)
L6470_SpiTransfer_Mode_3(uint8_t(L6470_buf[i]));
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)
56 changes: 38 additions & 18 deletions Marlin/src/Marlin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@

#include "HAL/shared/Delay.h"

#include "module/stepper_indirection.h"

#ifdef ARDUINO
#include <pins_arduino.h>
#endif
Expand Down Expand Up @@ -158,6 +160,10 @@
#include "lcd/extensible_ui/ui_api.h"
#endif

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

bool Running = true;

#if ENABLED(TEMPERATURE_UNITS_SUPPORT)
Expand Down Expand Up @@ -341,28 +347,34 @@ void manage_inactivity(const bool ignore_stepper_queue/*=false*/) {
#endif

if (stepper_inactive_time) {
static bool already_shutdown_steppers; // = false
if (planner.has_blocks_queued())
gcode.previous_move_ms = ms; // reset_stepper_timeout to keep steppers powered
else if (MOVE_AWAY_TEST && !ignore_stepper_queue && ELAPSED(ms, gcode.previous_move_ms + stepper_inactive_time)) {
#if ENABLED(DISABLE_INACTIVE_X)
disable_X();
#endif
#if ENABLED(DISABLE_INACTIVE_Y)
disable_Y();
#endif
#if ENABLED(DISABLE_INACTIVE_Z)
disable_Z();
#endif
#if ENABLED(DISABLE_INACTIVE_E)
disable_e_steppers();
#endif
#if HAS_LCD_MENU && ENABLED(AUTO_BED_LEVELING_UBL)
if (ubl.lcd_map_control) {
ubl.lcd_map_control = false;
ui.defer_status_screen(false);
}
#endif
if (!already_shutdown_steppers) {
already_shutdown_steppers = true; // L6470 SPI will consume 99% of free time without this
#if ENABLED(DISABLE_INACTIVE_X)
disable_X();
#endif
#if ENABLED(DISABLE_INACTIVE_Y)
disable_Y();
#endif
#if ENABLED(DISABLE_INACTIVE_Z)
disable_Z();
#endif
#if ENABLED(DISABLE_INACTIVE_E)
disable_e_steppers();
#endif
#if HAS_LCD_MENU && ENABLED(AUTO_BED_LEVELING_UBL)
if (ubl.lcd_map_control) {
ubl.lcd_map_control = false;
ui.defer_status_screen(false);
}
#endif
}
}
else
already_shutdown_steppers = false;
}

#if PIN_EXISTS(CHDK) // Check if pin should be set to LOW (after M240 set it HIGH)
Expand Down Expand Up @@ -516,6 +528,10 @@ void manage_inactivity(const bool ignore_stepper_queue/*=false*/) {
monitor_tmc_driver();
#endif

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

// Limit check_axes_activity frequency to 10Hz
static millis_t next_check_axes_ms = 0;
if (ELAPSED(ms, next_check_axes_ms)) {
Expand Down Expand Up @@ -680,6 +696,10 @@ void setup() {
HAL_init();
#endif

#if HAS_DRIVER(L6470)
L6470.init(); // setup SPI and then init chips
#endif

#if ENABLED(MAX7219_DEBUG)
max7219.init();
#endif
Expand Down
Loading