Improved STMicro L64XX stepper driver support (#16452)
parent
53f1e5ff5b
commit
1ad53cee1f
@ -1,793 +0,0 @@
|
|||||||
/**
|
|
||||||
* Marlin 3D Printer Firmware
|
|
||||||
* Copyright (c) 2019 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/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The monitor_driver routines are a close copy of the TMC code
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "../../inc/MarlinConfig.h"
|
|
||||||
|
|
||||||
#if HAS_DRIVER(L6470)
|
|
||||||
|
|
||||||
#include "L6470_Marlin.h"
|
|
||||||
|
|
||||||
L6470_Marlin L6470;
|
|
||||||
|
|
||||||
#include "../../module/stepper/indirection.h"
|
|
||||||
#include "../../module/planner.h"
|
|
||||||
#include "../../gcode/gcode.h"
|
|
||||||
|
|
||||||
#define DEBUG_OUT ENABLED(L6470_CHITCHAT)
|
|
||||||
#include "../../core/debug_out.h"
|
|
||||||
|
|
||||||
uint8_t L6470_Marlin::dir_commands[MAX_L6470]; // array to hold direction command for each driver
|
|
||||||
|
|
||||||
char L6470_Marlin::index_to_axis[MAX_L6470][3] = { "X ", "Y ", "Z ", "X2", "Y2", "Z2", "Z3", "E0", "E1", "E2", "E3", "E4", "E5" };
|
|
||||||
|
|
||||||
bool L6470_Marlin::index_to_dir[MAX_L6470] = {
|
|
||||||
INVERT_X_DIR , // 0 X
|
|
||||||
INVERT_Y_DIR , // 1 Y
|
|
||||||
INVERT_Z_DIR , // 2 Z
|
|
||||||
#if ENABLED(X_DUAL_STEPPER_DRIVERS)
|
|
||||||
INVERT_X_DIR ^ INVERT_X2_VS_X_DIR , // 3 X2
|
|
||||||
#else
|
|
||||||
INVERT_X_DIR , // 3 X2
|
|
||||||
#endif
|
|
||||||
#if ENABLED(Y_DUAL_STEPPER_DRIVERS)
|
|
||||||
INVERT_Y_DIR ^ INVERT_Y2_VS_Y_DIR , // 4 Y2
|
|
||||||
#else
|
|
||||||
INVERT_Y_DIR , // 4 Y2
|
|
||||||
#endif
|
|
||||||
INVERT_Z_DIR , // 5 Z2
|
|
||||||
INVERT_Z_DIR , // 6 Z3
|
|
||||||
INVERT_E0_DIR , // 7 E0
|
|
||||||
INVERT_E1_DIR , // 8 E1
|
|
||||||
INVERT_E2_DIR , // 9 E2
|
|
||||||
INVERT_E3_DIR , //10 E3
|
|
||||||
INVERT_E4_DIR , //11 E4
|
|
||||||
INVERT_E5_DIR , //12 E5
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8_t L6470_Marlin::axis_xref[MAX_L6470] = {
|
|
||||||
AxisEnum(X_AXIS), // X
|
|
||||||
AxisEnum(Y_AXIS), // Y
|
|
||||||
AxisEnum(Z_AXIS), // Z
|
|
||||||
AxisEnum(X_AXIS), // X2
|
|
||||||
AxisEnum(Y_AXIS), // Y2
|
|
||||||
AxisEnum(Z_AXIS), // Z2
|
|
||||||
AxisEnum(Z_AXIS), // Z3
|
|
||||||
AxisEnum(E_AXIS), // E0
|
|
||||||
AxisEnum(E_AXIS), // E1
|
|
||||||
AxisEnum(E_AXIS), // E2
|
|
||||||
AxisEnum(E_AXIS), // E3
|
|
||||||
AxisEnum(E_AXIS), // E4
|
|
||||||
AxisEnum(E_AXIS) // E5
|
|
||||||
};
|
|
||||||
|
|
||||||
volatile bool L6470_Marlin::spi_abort = false;
|
|
||||||
bool L6470_Marlin::spi_active = false;
|
|
||||||
|
|
||||||
void L6470_Marlin::populate_chain_array() {
|
|
||||||
|
|
||||||
#define _L6470_INIT_SPI(Q) do{ stepper##Q.set_chain_info(Q, Q##_CHAIN_POS); }while(0)
|
|
||||||
|
|
||||||
#if AXIS_DRIVER_TYPE_X(L6470)
|
|
||||||
_L6470_INIT_SPI(X);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_X2(L6470)
|
|
||||||
_L6470_INIT_SPI(X2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Y(L6470)
|
|
||||||
_L6470_INIT_SPI(Y);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Y2(L6470)
|
|
||||||
_L6470_INIT_SPI(Y2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z(L6470)
|
|
||||||
_L6470_INIT_SPI(Z);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z2(L6470)
|
|
||||||
_L6470_INIT_SPI(Z2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z3(L6470)
|
|
||||||
_L6470_INIT_SPI(Z3);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E0(L6470)
|
|
||||||
_L6470_INIT_SPI(E0);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E1(L6470)
|
|
||||||
_L6470_INIT_SPI(E1);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E2(L6470)
|
|
||||||
_L6470_INIT_SPI(E2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E3(L6470)
|
|
||||||
_L6470_INIT_SPI(E3);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E4(L6470)
|
|
||||||
_L6470_INIT_SPI(E4);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E5(L6470)
|
|
||||||
_L6470_INIT_SPI(E5);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void L6470_Marlin::init() { // Set up SPI and then init chips
|
|
||||||
#if PIN_EXISTS(L6470_RESET_CHAIN)
|
|
||||||
OUT_WRITE(L6470_RESET_CHAIN_PIN, LOW); // hardware reset of drivers
|
|
||||||
delay(1);
|
|
||||||
OUT_WRITE(L6470_RESET_CHAIN_PIN, HIGH);
|
|
||||||
delay(1); // need about 650uS for the chip to fully start up
|
|
||||||
#endif
|
|
||||||
populate_chain_array(); // Set up array to control where in the SPI transfer sequence a particular stepper's data goes
|
|
||||||
L6470_spi_init(); // Set up L6470 soft SPI pins
|
|
||||||
init_to_defaults(); // init the chips
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t L6470_Marlin::get_status(const uint8_t axis) {
|
|
||||||
|
|
||||||
#define GET_L6470_STATUS(Q) stepper##Q.getStatus()
|
|
||||||
|
|
||||||
switch (axis) {
|
|
||||||
#if AXIS_DRIVER_TYPE_X(L6470)
|
|
||||||
case 0: return GET_L6470_STATUS(X);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Y(L6470)
|
|
||||||
case 1: return GET_L6470_STATUS(Y);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z(L6470)
|
|
||||||
case 2: return GET_L6470_STATUS(Z);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_X2(L6470)
|
|
||||||
case 3: return GET_L6470_STATUS(X2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Y2(L6470)
|
|
||||||
case 4: return GET_L6470_STATUS(Y2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z2(L6470)
|
|
||||||
case 5: return GET_L6470_STATUS(Z2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z3(L6470)
|
|
||||||
case 6: return GET_L6470_STATUS(Z3);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E0(L6470)
|
|
||||||
case 7: return GET_L6470_STATUS(E0);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E1(L6470)
|
|
||||||
case 8: return GET_L6470_STATUS(E1);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E2(L6470)
|
|
||||||
case 9: return GET_L6470_STATUS(E2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E3(L6470)
|
|
||||||
case 10: return GET_L6470_STATUS(E3);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E4(L6470)
|
|
||||||
case 11: return GET_L6470_STATUS(E4);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E5(L6470)
|
|
||||||
case 12: return GET_L6470_STATUS(E5);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0; // Not needed but kills a compiler warning
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t L6470_Marlin::get_param(uint8_t axis, uint8_t param) {
|
|
||||||
|
|
||||||
#define GET_L6470_PARAM(Q) L6470_GETPARAM(param,Q)
|
|
||||||
|
|
||||||
switch (axis) {
|
|
||||||
#if AXIS_DRIVER_TYPE_X(L6470)
|
|
||||||
case 0: return GET_L6470_PARAM(X);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Y(L6470)
|
|
||||||
case 1: return GET_L6470_PARAM(Y);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z(L6470)
|
|
||||||
case 2: return GET_L6470_PARAM(Z);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_X2(L6470)
|
|
||||||
case 3: return GET_L6470_PARAM(X2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Y2(L6470)
|
|
||||||
case 4: return GET_L6470_PARAM(Y2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z2(L6470)
|
|
||||||
case 5: return GET_L6470_PARAM(Z2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z3(L6470)
|
|
||||||
case 6: return GET_L6470_PARAM(Z3);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E0(L6470)
|
|
||||||
case 7: return GET_L6470_PARAM(E0);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E1(L6470)
|
|
||||||
case 8: return GET_L6470_PARAM(E1);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E2(L6470)
|
|
||||||
case 9: return GET_L6470_PARAM(E2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E3(L6470)
|
|
||||||
case 10: return GET_L6470_PARAM(E3);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E4(L6470)
|
|
||||||
case 11: return GET_L6470_PARAM(E4);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E5(L6470)
|
|
||||||
case 12: return GET_L6470_PARAM(E5);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0 ; // not needed but kills a compiler warning
|
|
||||||
}
|
|
||||||
|
|
||||||
void L6470_Marlin::set_param(uint8_t axis, uint8_t param, uint32_t value) {
|
|
||||||
|
|
||||||
#define SET_L6470_PARAM(Q) stepper##Q.SetParam(param, value)
|
|
||||||
|
|
||||||
switch (axis) {
|
|
||||||
#if AXIS_DRIVER_TYPE_X(L6470)
|
|
||||||
case 0: SET_L6470_PARAM(X);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Y(L6470)
|
|
||||||
case 1: SET_L6470_PARAM(Y);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z(L6470)
|
|
||||||
case 2: SET_L6470_PARAM(Z);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_X2(L6470)
|
|
||||||
case 3: SET_L6470_PARAM(X2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Y2(L6470)
|
|
||||||
case 4: SET_L6470_PARAM(Y2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z2(L6470)
|
|
||||||
case 5: SET_L6470_PARAM(Z2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z3(L6470)
|
|
||||||
case 6: SET_L6470_PARAM(Z3);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E0(L6470)
|
|
||||||
case 7: SET_L6470_PARAM(E0);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E1(L6470)
|
|
||||||
case 8: SET_L6470_PARAM(E1);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E2(L6470)
|
|
||||||
case 9: SET_L6470_PARAM(E2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E3(L6470)
|
|
||||||
case 10: SET_L6470_PARAM(E3);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E4(L6470)
|
|
||||||
case 11: SET_L6470_PARAM(E4);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E5(L6470)
|
|
||||||
case 12: SET_L6470_PARAM(E5);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void echo_min_max(const char a, const float &min, const float &max) {
|
|
||||||
DEBUG_CHAR(' '); DEBUG_CHAR(a);
|
|
||||||
DEBUG_ECHOPAIR(" min = ", min);
|
|
||||||
DEBUG_ECHOLNPAIR(" max = ", max);
|
|
||||||
}
|
|
||||||
inline void echo_oct_used(const float &oct, const bool stall) {
|
|
||||||
DEBUG_ECHOPAIR("over_current_threshold used : ", oct);
|
|
||||||
serialprintPGM(stall ? PSTR(" (Stall") : PSTR(" (OCD"));
|
|
||||||
DEBUG_ECHOLNPGM(" threshold)");
|
|
||||||
}
|
|
||||||
inline void err_out_of_bounds() { DEBUG_ECHOLNPGM("ERROR - motion out of bounds"); }
|
|
||||||
|
|
||||||
bool L6470_Marlin::get_user_input(uint8_t &driver_count, uint8_t axis_index[3], char axis_mon[3][3],
|
|
||||||
float &position_max, float &position_min, float &final_feedrate, uint8_t &kval_hold,
|
|
||||||
bool over_current_flag, uint8_t &OCD_TH_val, uint8_t &STALL_TH_val, uint16_t &over_current_threshold
|
|
||||||
) {
|
|
||||||
// Return TRUE if the calling routine needs to abort/kill
|
|
||||||
|
|
||||||
uint16_t displacement = 0; // " = 0" to eliminate compiler warning
|
|
||||||
uint8_t j; // general purpose counter
|
|
||||||
|
|
||||||
if (!all_axes_homed()) {
|
|
||||||
DEBUG_ECHOLNPGM("ERROR - home all before running this command");
|
|
||||||
//return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOOP_XYZE(i) if (uint16_t _displacement = parser.intval(axis_codes[i])) {
|
|
||||||
displacement = _displacement;
|
|
||||||
uint8_t axis_offset = parser.byteval('J');
|
|
||||||
axis_mon[0][0] = axis_codes[i]; // axis ASCII value (target character)
|
|
||||||
if (axis_offset >= 2 || axis_mon[0][0] == 'E') // Single axis, E0, or E1
|
|
||||||
axis_mon[0][1] = axis_offset + '0';
|
|
||||||
else if (axis_offset == 0) { // one or more axes
|
|
||||||
uint8_t driver_count_local = 0; // can't use "driver_count" directly as a subscript because it's passed by reference
|
|
||||||
for (j = 0; j < MAX_L6470; j++) // see how many drivers on this axis
|
|
||||||
if (axis_mon[0][0] == index_to_axis[j][0]) {
|
|
||||||
axis_mon[driver_count_local][0] = axis_mon[0][0];
|
|
||||||
axis_mon[driver_count_local][1] = index_to_axis[j][1];
|
|
||||||
axis_mon[driver_count_local][2] = index_to_axis[j][2]; // append end of string
|
|
||||||
axis_index[driver_count_local] = j; // set axis index
|
|
||||||
driver_count_local++;
|
|
||||||
}
|
|
||||||
driver_count = driver_count_local;
|
|
||||||
}
|
|
||||||
break; // only take first axis found
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Position calcs & checks
|
|
||||||
//
|
|
||||||
|
|
||||||
const xyze_pos_t center = {
|
|
||||||
LOGICAL_X_POSITION(current_position.x),
|
|
||||||
LOGICAL_Y_POSITION(current_position.y),
|
|
||||||
LOGICAL_Z_POSITION(current_position.z),
|
|
||||||
current_position.e
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (axis_mon[0][0]) {
|
|
||||||
default: position_max = position_min = 0; break;
|
|
||||||
|
|
||||||
case 'X': {
|
|
||||||
position_min = center.x - displacement;
|
|
||||||
position_max = center.x + displacement;
|
|
||||||
echo_min_max('X', position_min, position_max);
|
|
||||||
if (false
|
|
||||||
#ifdef X_MIN_POS
|
|
||||||
|| position_min < (X_MIN_POS)
|
|
||||||
#endif
|
|
||||||
#ifdef X_MAX_POS
|
|
||||||
|| position_max > (X_MAX_POS)
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
err_out_of_bounds();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case 'Y': {
|
|
||||||
position_min = center.y - displacement;
|
|
||||||
position_max = center.y + displacement;
|
|
||||||
echo_min_max('Y', position_min, position_max);
|
|
||||||
if (false
|
|
||||||
#ifdef Y_MIN_POS
|
|
||||||
|| position_min < (Y_MIN_POS)
|
|
||||||
#endif
|
|
||||||
#ifdef Y_MAX_POS
|
|
||||||
|| position_max > (Y_MAX_POS)
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
err_out_of_bounds();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case 'Z': {
|
|
||||||
position_min = center.z - displacement;
|
|
||||||
position_max = center.z + displacement;
|
|
||||||
echo_min_max('Z', position_min, position_max);
|
|
||||||
if (false
|
|
||||||
#ifdef Z_MIN_POS
|
|
||||||
|| position_min < (Z_MIN_POS)
|
|
||||||
#endif
|
|
||||||
#ifdef Z_MAX_POS
|
|
||||||
|| position_max > (Z_MAX_POS)
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
err_out_of_bounds();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case 'E': {
|
|
||||||
position_min = center.e - displacement;
|
|
||||||
position_max = center.e + displacement;
|
|
||||||
echo_min_max('E', position_min, position_max);
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Work on the drivers
|
|
||||||
//
|
|
||||||
for (uint8_t k = 0; k < driver_count; k++) {
|
|
||||||
bool not_found = true;
|
|
||||||
for (j = 1; j <= L6470::chain[0]; j++) {
|
|
||||||
const char * const ind_axis = index_to_axis[L6470::chain[j]];
|
|
||||||
if (ind_axis[0] == axis_mon[k][0] && ind_axis[1] == axis_mon[k][1]) { // See if a L6470 driver
|
|
||||||
not_found = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (not_found) {
|
|
||||||
driver_count = k;
|
|
||||||
axis_mon[k][0] = ' '; // mark this entry invalid
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (driver_count == 0) {
|
|
||||||
DEBUG_ECHOLNPGM("ERROR - not a L6470 axis");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_ECHOPGM("Monitoring:");
|
|
||||||
for (j = 0; j < driver_count; j++) DEBUG_ECHOPAIR(" ", axis_mon[j]);
|
|
||||||
L6470_EOL();
|
|
||||||
|
|
||||||
// now have a list of driver(s) to monitor
|
|
||||||
|
|
||||||
//
|
|
||||||
// kVAL_HOLD checks & settings
|
|
||||||
//
|
|
||||||
|
|
||||||
kval_hold = parser.byteval('K');
|
|
||||||
if (kval_hold) {
|
|
||||||
DEBUG_ECHOLNPAIR("kval_hold = ", kval_hold);
|
|
||||||
for (j = 0; j < driver_count; j++)
|
|
||||||
set_param(axis_index[j], L6470_KVAL_HOLD, kval_hold);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// only print the KVAL_HOLD from one of the drivers
|
|
||||||
kval_hold = get_param(axis_index[0], L6470_KVAL_HOLD);
|
|
||||||
DEBUG_ECHOLNPAIR("KVAL_HOLD = ", kval_hold);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Overcurrent checks & settings
|
|
||||||
//
|
|
||||||
|
|
||||||
if (over_current_flag) {
|
|
||||||
|
|
||||||
uint8_t OCD_TH_val_local = 0, // compiler thinks OCD_TH_val is unused if use it directly
|
|
||||||
STALL_TH_val_local = 0; // just in case ...
|
|
||||||
|
|
||||||
over_current_threshold = parser.intval('I');
|
|
||||||
|
|
||||||
if (over_current_threshold) {
|
|
||||||
|
|
||||||
OCD_TH_val_local = over_current_threshold/375;
|
|
||||||
LIMIT(OCD_TH_val_local, 0, 15);
|
|
||||||
STALL_TH_val_local = over_current_threshold/31.25;
|
|
||||||
LIMIT(STALL_TH_val_local, 0, 127);
|
|
||||||
uint16_t OCD_TH_actual = (OCD_TH_val_local + 1) * 375,
|
|
||||||
STALL_TH_actual = (STALL_TH_val_local + 1) * 31.25;
|
|
||||||
if (OCD_TH_actual < STALL_TH_actual) {
|
|
||||||
OCD_TH_val_local++;
|
|
||||||
OCD_TH_actual = (OCD_TH_val_local + 1) * 375;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_ECHOLNPAIR("over_current_threshold specified: ", over_current_threshold);
|
|
||||||
echo_oct_used(STALL_TH_actual, true);
|
|
||||||
echo_oct_used(OCD_TH_actual, false);
|
|
||||||
|
|
||||||
#define SET_OVER_CURRENT(Q) do { stepper##Q.SetParam(L6470_STALL_TH, STALL_TH_val_local); stepper##Q.SetParam(L6470_OCD_TH, OCD_TH_val_local);} while (0)
|
|
||||||
|
|
||||||
for (j = 0; j < driver_count; j++) {
|
|
||||||
set_param(axis_index[j], L6470_STALL_TH, STALL_TH_val_local);
|
|
||||||
set_param(axis_index[j], L6470_OCD_TH, OCD_TH_val_local);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// only get & print the OVER_CURRENT values from one of the drivers
|
|
||||||
STALL_TH_val_local = get_param(axis_index[0], L6470_STALL_TH);
|
|
||||||
OCD_TH_val_local = get_param(axis_index[0], L6470_OCD_TH);
|
|
||||||
|
|
||||||
echo_oct_used((STALL_TH_val_local + 1) * 31.25, true);
|
|
||||||
echo_oct_used((OCD_TH_val_local + 1) * 375, false);
|
|
||||||
} // over_current_threshold
|
|
||||||
|
|
||||||
for (j = 0; j < driver_count; j++) { // set all drivers on axis the same
|
|
||||||
set_param(axis_index[j], L6470_STALL_TH, STALL_TH_val_local);
|
|
||||||
set_param(axis_index[j], L6470_OCD_TH, OCD_TH_val_local);
|
|
||||||
}
|
|
||||||
|
|
||||||
OCD_TH_val = OCD_TH_val_local; // force compiler to update the main routine's copy
|
|
||||||
STALL_TH_val = STALL_TH_val_local; // force compiler to update the main routine's copy
|
|
||||||
} // end of overcurrent
|
|
||||||
|
|
||||||
//
|
|
||||||
// Feedrate
|
|
||||||
//
|
|
||||||
|
|
||||||
final_feedrate = parser.floatval('F');
|
|
||||||
if (final_feedrate == 0) {
|
|
||||||
static constexpr float default_max_feedrate[] = DEFAULT_MAX_FEEDRATE;
|
|
||||||
const uint8_t num_feedrates = COUNT(default_max_feedrate);
|
|
||||||
for (j = 0; j < num_feedrates; j++) {
|
|
||||||
if (axis_codes[j] == axis_mon[0][0]) {
|
|
||||||
final_feedrate = default_max_feedrate[j];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (j == 3 && num_feedrates > 4) { // have more than one extruder feedrate
|
|
||||||
uint8_t extruder_num = axis_mon[0][1] - '0';
|
|
||||||
if (j <= num_feedrates - extruder_num) // have a feedrate specifically for this extruder
|
|
||||||
final_feedrate = default_max_feedrate[j + extruder_num];
|
|
||||||
else
|
|
||||||
final_feedrate = default_max_feedrate[3]; // use E0 feedrate for this extruder
|
|
||||||
}
|
|
||||||
final_feedrate *= 60; // convert to mm/minute
|
|
||||||
} // end of feedrate
|
|
||||||
|
|
||||||
return false; // FALSE indicates no user input problems
|
|
||||||
}
|
|
||||||
|
|
||||||
#if ENABLED(L6470_CHITCHAT)
|
|
||||||
inline void echo_yes_no(const bool yes) { serialprintPGM(yes ? PSTR("YES") : PSTR("NO ")); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void L6470_Marlin::say_axis(const uint8_t axis, const bool label/*=true*/) {
|
|
||||||
if (label) SERIAL_ECHOPGM("AXIS:");
|
|
||||||
SERIAL_CHAR(' ', index_to_axis[axis][0], index_to_axis[axis][1], ' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
void L6470_Marlin::error_status_decode(const uint16_t status, const uint8_t axis) { // assumes status bits have been inverted
|
|
||||||
#if ENABLED(L6470_CHITCHAT)
|
|
||||||
char temp_buf[10];
|
|
||||||
say_axis(axis);
|
|
||||||
sprintf_P(temp_buf, PSTR(" %4x "), status);
|
|
||||||
DEBUG_ECHO(temp_buf);
|
|
||||||
print_bin(status);
|
|
||||||
DEBUG_ECHOPGM(" THERMAL: ");
|
|
||||||
serialprintPGM((status & STATUS_TH_SD) ? PSTR("SHUTDOWN") : (status & STATUS_TH_WRN) ? PSTR("WARNING ") : PSTR("OK "));
|
|
||||||
DEBUG_ECHOPGM(" OVERCURRENT: ");
|
|
||||||
echo_yes_no(status & STATUS_OCD);
|
|
||||||
DEBUG_ECHOPGM(" STALL: ");
|
|
||||||
echo_yes_no(status & (STATUS_STEP_LOSS_A | STATUS_STEP_LOSS_B));
|
|
||||||
L6470_EOL();
|
|
||||||
#else
|
|
||||||
UNUSED(status); UNUSED(axis);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
////
|
|
||||||
//// MONITOR_L6470_DRIVER_STATUS routines
|
|
||||||
////
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#if ENABLED(MONITOR_L6470_DRIVER_STATUS)
|
|
||||||
|
|
||||||
struct L6470_driver_data {
|
|
||||||
uint8_t driver_index;
|
|
||||||
uint32_t driver_status;
|
|
||||||
bool is_otw;
|
|
||||||
uint8_t otw_counter;
|
|
||||||
bool is_ot;
|
|
||||||
bool is_hi_Z;
|
|
||||||
uint8_t com_counter;
|
|
||||||
};
|
|
||||||
|
|
||||||
L6470_driver_data driver_L6470_data[] = {
|
|
||||||
#if AXIS_DRIVER_TYPE_X(L6470)
|
|
||||||
{ 0, 0, 0, 0, 0, 0, 0 },
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Y(L6470)
|
|
||||||
{ 1, 0, 0, 0, 0, 0, 0 },
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z(L6470)
|
|
||||||
{ 2, 0, 0, 0, 0, 0, 0 },
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_X2(L6470)
|
|
||||||
{ 3, 0, 0, 0, 0, 0, 0 },
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Y2(L6470)
|
|
||||||
{ 4, 0, 0, 0, 0, 0, 0 },
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z2(L6470)
|
|
||||||
{ 5, 0, 0, 0, 0, 0, 0 },
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z3(L6470)
|
|
||||||
{ 6, 0, 0, 0, 0, 0, 0 },
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E0(L6470)
|
|
||||||
{ 7, 0, 0, 0, 0, 0, 0 },
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E1(L6470)
|
|
||||||
{ 8, 0, 0, 0, 0, 0, 0 },
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E2(L6470)
|
|
||||||
{ 9, 0, 0, 0, 0, 0, 0 },
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E3(L6470)
|
|
||||||
{ 10, 0, 0, 0, 0, 0, 0 },
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E4(L6470)
|
|
||||||
{ 11, 0, 0, 0, 0, 0, 0 },
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E5(L6470)
|
|
||||||
{ 12, 0, 0, 0, 0, 0, 0 }
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void append_stepper_err(char * &p, const uint8_t stepper_index, const char * const err=nullptr) {
|
|
||||||
p += sprintf_P(p, PSTR("Stepper %c%c "), char(index_to_axis[stepper_index][0]), char(index_to_axis[stepper_index][1]));
|
|
||||||
if (err) p += sprintf_P(p, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
void L6470_monitor_update(uint8_t stepper_index, uint16_t status) {
|
|
||||||
if (spi_abort) return; // don't do anything if set_directions() has occurred
|
|
||||||
uint8_t kval_hold;
|
|
||||||
char temp_buf[120];
|
|
||||||
char* p = &temp_buf[0];
|
|
||||||
uint8_t j;
|
|
||||||
for (j = 0; j < L6470::chain[0]; j++) // find the table for this stepper
|
|
||||||
if (driver_L6470_data[j].driver_index == stepper_index) break;
|
|
||||||
|
|
||||||
driver_L6470_data[j].driver_status = status;
|
|
||||||
uint16_t _status = ~status; // all error bits are active low
|
|
||||||
|
|
||||||
if (status == 0 || status == 0xFFFF) { // com problem
|
|
||||||
if (driver_L6470_data[j].com_counter == 0) { // warn user when it first happens
|
|
||||||
driver_L6470_data[j].com_counter++;
|
|
||||||
append_stepper_err(p, stepper_index, PSTR(" - communications lost\n"));
|
|
||||||
DEBUG_ECHO(temp_buf);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
driver_L6470_data[j].com_counter++;
|
|
||||||
if (driver_L6470_data[j].com_counter > 240) { // remind of com problem about every 2 minutes
|
|
||||||
driver_L6470_data[j].com_counter = 1;
|
|
||||||
append_stepper_err(p, stepper_index, PSTR(" - still no communications\n"));
|
|
||||||
DEBUG_ECHO(temp_buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (driver_L6470_data[j].com_counter) { // comms re-established
|
|
||||||
driver_L6470_data[j].com_counter = 0;
|
|
||||||
append_stepper_err(p, stepper_index, PSTR(" - communications re-established\n.. setting all drivers to default values\n"));
|
|
||||||
DEBUG_ECHO(temp_buf);
|
|
||||||
init_to_defaults();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// no com problems - do the usual checks
|
|
||||||
if (_status & L6470_ERROR_MASK) {
|
|
||||||
append_stepper_err(p, stepper_index);
|
|
||||||
|
|
||||||
if (status & STATUS_HIZ) { // the driver has shut down HiZ is active high
|
|
||||||
driver_L6470_data[j].is_hi_Z = true;
|
|
||||||
p += sprintf_P(p, PSTR("%cIS SHUT DOWN"), ' ');
|
|
||||||
// if (_status & STATUS_TH_SD) { // strange - TH_SD never seems to go active, must be implied by the HiZ and TH_WRN
|
|
||||||
if (_status & STATUS_TH_WRN) { // over current shutdown
|
|
||||||
p += sprintf_P(p, PSTR("%cdue to over temperature"), ' ');
|
|
||||||
driver_L6470_data[j].is_ot = true;
|
|
||||||
kval_hold = get_param(stepper_index, L6470_KVAL_HOLD) - 2 * KVAL_HOLD_STEP_DOWN;
|
|
||||||
set_param(stepper_index, L6470_KVAL_HOLD, kval_hold); // reduce KVAL_HOLD
|
|
||||||
p += sprintf_P(p, PSTR(" - KVAL_HOLD reduced by %d to %d"), 2 * KVAL_HOLD_STEP_DOWN, kval_hold); // let user know
|
|
||||||
}
|
|
||||||
else
|
|
||||||
driver_L6470_data[j].is_ot = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
driver_L6470_data[j].is_hi_Z = false;
|
|
||||||
|
|
||||||
if (_status & STATUS_TH_WRN) { // have an over temperature warning
|
|
||||||
driver_L6470_data[j].is_otw = true;
|
|
||||||
driver_L6470_data[j].otw_counter++;
|
|
||||||
kval_hold = get_param(stepper_index, L6470_KVAL_HOLD);
|
|
||||||
if (driver_L6470_data[j].otw_counter > 4) { // otw present for 2 - 2.5 seconds, reduce KVAL_HOLD
|
|
||||||
kval_hold -= KVAL_HOLD_STEP_DOWN;
|
|
||||||
set_param(stepper_index, L6470_KVAL_HOLD, kval_hold); // reduce KVAL_HOLD
|
|
||||||
p += sprintf_P(p, PSTR(" - KVAL_HOLD reduced by %d to %d"), KVAL_HOLD_STEP_DOWN, kval_hold); // let user know
|
|
||||||
driver_L6470_data[j].otw_counter = 0;
|
|
||||||
driver_L6470_data[j].is_otw = true;
|
|
||||||
}
|
|
||||||
else if (driver_L6470_data[j].otw_counter)
|
|
||||||
p += sprintf_P(p, PSTR("%c- thermal warning"), ' '); // warn user
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef L6470_STOP_ON_ERROR
|
|
||||||
if (_status & (STATUS_UVLO | STATUS_TH_WRN | STATUS_TH_SD))
|
|
||||||
kill(temp_buf);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if ENABLED(L6470_CHITCHAT)
|
|
||||||
|
|
||||||
if (_status & STATUS_OCD)
|
|
||||||
p += sprintf_P(p, PSTR("%c over current"), ' ');
|
|
||||||
|
|
||||||
if (_status & (STATUS_STEP_LOSS_A | STATUS_STEP_LOSS_B))
|
|
||||||
p += sprintf_P(p, PSTR("%c stall"), ' ');
|
|
||||||
|
|
||||||
if (_status & STATUS_UVLO)
|
|
||||||
p += sprintf_P(p, PSTR("%c under voltage lock out"), ' ');
|
|
||||||
|
|
||||||
p += sprintf_P(p, PSTR("%c\n"), ' ');
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DEBUG_ECHOLN(temp_buf); // print the error message
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
driver_L6470_data[j].is_ot = false;
|
|
||||||
driver_L6470_data[j].otw_counter = 0; //clear out warning indicators
|
|
||||||
driver_L6470_data[j].is_otw = false;
|
|
||||||
|
|
||||||
} // end usual checks
|
|
||||||
} // comms established but have errors
|
|
||||||
} // comms re-established
|
|
||||||
} // end L6470_monitor_update()
|
|
||||||
|
|
||||||
#define MONITOR_L6470_DRIVE(Q) L6470_monitor_update(Q, stepper##Q.getStatus())
|
|
||||||
|
|
||||||
void L6470_Marlin::monitor_driver() {
|
|
||||||
static millis_t next_cOT = 0;
|
|
||||||
if (ELAPSED(millis(), next_cOT)) {
|
|
||||||
next_cOT = millis() + 500;
|
|
||||||
|
|
||||||
spi_active = true; // let set_directions() know we're in the middle of a series of SPI transfers
|
|
||||||
|
|
||||||
#if AXIS_DRIVER_TYPE_X(L6470)
|
|
||||||
MONITOR_L6470_DRIVE(X);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Y(L6470)
|
|
||||||
MONITOR_L6470_DRIVE(Y);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z(L6470)
|
|
||||||
MONITOR_L6470_DRIVE(Z);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_X2(L6470)
|
|
||||||
MONITOR_L6470_DRIVE(X2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Y2(L6470)
|
|
||||||
MONITOR_L6470_DRIVE(Y2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z2(L6470)
|
|
||||||
MONITOR_L6470_DRIVE(Z2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z3(L6470)
|
|
||||||
MONITOR_L6470_DRIVE(Z3);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E0(L6470)
|
|
||||||
MONITOR_L6470_DRIVE(E0);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E1(L6470)
|
|
||||||
MONITOR_L6470_DRIVE(E1);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E2(L6470)
|
|
||||||
MONITOR_L6470_DRIVE(E2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E3(L6470)
|
|
||||||
MONITOR_L6470_DRIVE(E3);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E4(L6470)
|
|
||||||
MONITOR_L6470_DRIVE(E4);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E5(L6470)
|
|
||||||
MONITOR_L6470_DRIVE(E5);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ENABLED(L6470_DEBUG)
|
|
||||||
if (report_L6470_status) L6470_EOL();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
spi_active = false; // done with all SPI transfers - clear handshake flags
|
|
||||||
spi_abort = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // MONITOR_L6470_DRIVER_STATUS
|
|
||||||
|
|
||||||
#endif // HAS_DRIVER(L6470)
|
|
@ -1,72 +0,0 @@
|
|||||||
/**
|
|
||||||
* Marlin 3D Printer Firmware
|
|
||||||
* Copyright (c) 2019 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/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../../inc/MarlinConfig.h"
|
|
||||||
|
|
||||||
#include <L6470.h>
|
|
||||||
|
|
||||||
#define L6470_GETPARAM(P,Q) stepper##Q.GetParam(P)
|
|
||||||
|
|
||||||
enum L6470_driver_enum : unsigned char { X, Y, Z, X2, Y2, Z2, Z3, E0, E1, E2, E3, E4, E5, MAX_L6470 };
|
|
||||||
|
|
||||||
#define L6470_ERROR_MASK (STATUS_UVLO | STATUS_TH_WRN | STATUS_TH_SD | STATUS_OCD | STATUS_STEP_LOSS_A | STATUS_STEP_LOSS_B)
|
|
||||||
#define dSPIN_STEP_CLOCK_FWD dSPIN_STEP_CLOCK
|
|
||||||
#define dSPIN_STEP_CLOCK_REV dSPIN_STEP_CLOCK+1
|
|
||||||
|
|
||||||
class L6470_Marlin {
|
|
||||||
public:
|
|
||||||
static bool index_to_dir[MAX_L6470];
|
|
||||||
static uint8_t axis_xref[MAX_L6470];
|
|
||||||
static char index_to_axis[MAX_L6470][3];
|
|
||||||
static uint8_t dir_commands[MAX_L6470];
|
|
||||||
|
|
||||||
// Flags to guarantee graceful switch if stepper interrupts L6470 SPI transfer
|
|
||||||
static volatile bool spi_abort;
|
|
||||||
static bool spi_active;
|
|
||||||
|
|
||||||
L6470_Marlin() {}
|
|
||||||
|
|
||||||
static uint16_t get_status(const uint8_t axis);
|
|
||||||
|
|
||||||
static uint32_t get_param(uint8_t axis, uint8_t param);
|
|
||||||
|
|
||||||
static void set_param(uint8_t axis, uint8_t param, uint32_t value);
|
|
||||||
|
|
||||||
static bool get_user_input(uint8_t &driver_count, uint8_t axis_index[3], char axis_mon[3][3],
|
|
||||||
float &position_max, float &position_min, float &final_feedrate, uint8_t &kval_hold,
|
|
||||||
bool over_current_flag, uint8_t &OCD_TH_val, uint8_t &STALL_TH_val, uint16_t &over_current_threshold);
|
|
||||||
|
|
||||||
static void error_status_decode(const uint16_t status, const uint8_t axis);
|
|
||||||
|
|
||||||
static void monitor_driver();
|
|
||||||
|
|
||||||
static void init();
|
|
||||||
static void init_to_defaults();
|
|
||||||
|
|
||||||
static void say_axis(const uint8_t axis, const bool label=true);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void populate_chain_array();
|
|
||||||
};
|
|
||||||
|
|
||||||
extern L6470_Marlin L6470;
|
|
@ -0,0 +1,892 @@
|
|||||||
|
/**
|
||||||
|
* Marlin 3D Printer Firmware
|
||||||
|
* Copyright (c) 2019 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The monitor_driver routines are a close copy of the TMC code
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../../inc/MarlinConfig.h"
|
||||||
|
|
||||||
|
#if HAS_L64XX
|
||||||
|
|
||||||
|
#include "L64XX_Marlin.h"
|
||||||
|
|
||||||
|
L64XX_Marlin L64xxManager;
|
||||||
|
|
||||||
|
#include "../../module/stepper/indirection.h"
|
||||||
|
#include "../../gcode/gcode.h"
|
||||||
|
#include "../../module/planner.h"
|
||||||
|
#include "../../HAL/shared/Delay.h"
|
||||||
|
|
||||||
|
void echo_yes_no(const bool yes) { serialprintPGM(yes ? PSTR(" YES") : PSTR(" NO ")); }
|
||||||
|
|
||||||
|
char L64XX_Marlin::index_to_axis[MAX_L6470][3] = { "X ", "Y ", "Z ", "X2", "Y2", "Z2", "Z3", "E0", "E1", "E2", "E3", "E4", "E5" };
|
||||||
|
|
||||||
|
#define DEBUG_OUT ENABLED(L6470_CHITCHAT)
|
||||||
|
#include "../../core/debug_out.h"
|
||||||
|
|
||||||
|
uint8_t L64XX_Marlin::dir_commands[MAX_L6470]; // array to hold direction command for each driver
|
||||||
|
|
||||||
|
uint8_t L64XX_Marlin::index_to_dir[MAX_L6470] = { (INVERT_X_DIR) , // 0 X
|
||||||
|
(INVERT_Y_DIR) , // 1 Y
|
||||||
|
(INVERT_Z_DIR) , // 2 Z
|
||||||
|
#if ENABLED(X_DUAL_STEPPER_DRIVERS)
|
||||||
|
(INVERT_X_DIR) ^ (INVERT_X2_VS_X_DIR) , // 3 X2
|
||||||
|
#else
|
||||||
|
(INVERT_X_DIR) , // 3 X2
|
||||||
|
#endif
|
||||||
|
#if ENABLED(Y_DUAL_STEPPER_DRIVERS)
|
||||||
|
(INVERT_Y_DIR) ^ (INVERT_Y2_VS_Y_DIR) , // 4 Y2
|
||||||
|
#else
|
||||||
|
(INVERT_Y_DIR) , // 4 Y2
|
||||||
|
#endif
|
||||||
|
(INVERT_Z_DIR) , // 5 Z2
|
||||||
|
(INVERT_Z_DIR) , // 6 Z3
|
||||||
|
(INVERT_E0_DIR) , // 7 E0
|
||||||
|
(INVERT_E1_DIR) , // 8 E1
|
||||||
|
(INVERT_E2_DIR) , // 9 E2
|
||||||
|
(INVERT_E3_DIR) , // 10 E3
|
||||||
|
(INVERT_E4_DIR) , // 11 E4
|
||||||
|
(INVERT_E5_DIR) , // 12 E5
|
||||||
|
};
|
||||||
|
|
||||||
|
volatile uint8_t L64XX_Marlin::spi_abort = false;
|
||||||
|
uint8_t L64XX_Marlin::spi_active = false;
|
||||||
|
|
||||||
|
L64XX_Marlin::L64XX_shadow_t L64XX_Marlin::shadow;
|
||||||
|
|
||||||
|
//uint32_t UVLO_ADC = 0x0400; // ADC undervoltage event
|
||||||
|
|
||||||
|
void L6470_populate_chain_array() {
|
||||||
|
|
||||||
|
#define _L6470_INIT_SPI(Q) do{ stepper##Q.set_chain_info(Q, Q##_CHAIN_POS); }while(0)
|
||||||
|
|
||||||
|
#if AXIS_IS_L64XX(X)
|
||||||
|
_L6470_INIT_SPI(X);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(X2)
|
||||||
|
_L6470_INIT_SPI(X2);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Y)
|
||||||
|
_L6470_INIT_SPI(Y);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Y2)
|
||||||
|
_L6470_INIT_SPI(Y2);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z)
|
||||||
|
_L6470_INIT_SPI(Z);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z2)
|
||||||
|
_L6470_INIT_SPI(Z2);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z3)
|
||||||
|
_L6470_INIT_SPI(Z3);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E0)
|
||||||
|
_L6470_INIT_SPI(E0);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E1)
|
||||||
|
_L6470_INIT_SPI(E1);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E2)
|
||||||
|
_L6470_INIT_SPI(E2);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E3)
|
||||||
|
_L6470_INIT_SPI(E3);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E4)
|
||||||
|
_L6470_INIT_SPI(E4);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E5)
|
||||||
|
_L6470_INIT_SPI(E5);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some status bit positions & definitions differ per driver.
|
||||||
|
* Copy info to known locations to simplfy check/display logic.
|
||||||
|
* 1. Copy stepper status
|
||||||
|
* 2. Copy status bit definitions
|
||||||
|
* 3. Copy status layout
|
||||||
|
* 4. Make all error bits active low (as needed)
|
||||||
|
*/
|
||||||
|
uint16_t L64XX_Marlin::get_stepper_status(L64XX &st) {
|
||||||
|
shadow.STATUS_AXIS_RAW = st.getStatus();
|
||||||
|
shadow.STATUS_AXIS = shadow.STATUS_AXIS_RAW;
|
||||||
|
shadow.STATUS_AXIS_LAYOUT = st.L6470_status_layout;
|
||||||
|
shadow.AXIS_OCD_TH_MAX = st.OCD_TH_MAX;
|
||||||
|
shadow.AXIS_STALL_TH_MAX = st.STALL_TH_MAX;
|
||||||
|
shadow.AXIS_OCD_CURRENT_CONSTANT_INV = st.OCD_CURRENT_CONSTANT_INV;
|
||||||
|
shadow.AXIS_STALL_CURRENT_CONSTANT_INV = st.STALL_CURRENT_CONSTANT_INV;
|
||||||
|
shadow.L6470_AXIS_CONFIG = st.L64XX_CONFIG;
|
||||||
|
shadow.L6470_AXIS_STATUS = st.L64XX_STATUS;
|
||||||
|
shadow.STATUS_AXIS_OCD = st.STATUS_OCD;
|
||||||
|
shadow.STATUS_AXIS_SCK_MOD = st.STATUS_SCK_MOD;
|
||||||
|
shadow.STATUS_AXIS_STEP_LOSS_A = st.STATUS_STEP_LOSS_A;
|
||||||
|
shadow.STATUS_AXIS_STEP_LOSS_B = st.STATUS_STEP_LOSS_B;
|
||||||
|
shadow.STATUS_AXIS_TH_SD = st.STATUS_TH_SD;
|
||||||
|
shadow.STATUS_AXIS_TH_WRN = st.STATUS_TH_WRN;
|
||||||
|
shadow.STATUS_AXIS_UVLO = st.STATUS_UVLO;
|
||||||
|
shadow.STATUS_AXIS_WRONG_CMD = st.STATUS_WRONG_CMD;
|
||||||
|
shadow.STATUS_AXIS_CMD_ERR = st.STATUS_CMD_ERR;
|
||||||
|
shadow.STATUS_AXIS_NOTPERF_CMD = st.STATUS_NOTPERF_CMD;
|
||||||
|
|
||||||
|
switch (shadow.STATUS_AXIS_LAYOUT) {
|
||||||
|
case L6470_STATUS_LAYOUT: { // L6470
|
||||||
|
shadow.L6470_ERROR_MASK = shadow.STATUS_AXIS_UVLO | shadow.STATUS_AXIS_TH_WRN | shadow.STATUS_AXIS_TH_SD | shadow.STATUS_AXIS_OCD | shadow.STATUS_AXIS_STEP_LOSS_A | shadow.STATUS_AXIS_STEP_LOSS_B;
|
||||||
|
shadow.STATUS_AXIS ^= (shadow.STATUS_AXIS_WRONG_CMD | shadow.STATUS_AXIS_NOTPERF_CMD); // invert just error bits that are active high
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case L6474_STATUS_LAYOUT: { // L6474
|
||||||
|
shadow.L6470_ERROR_MASK = shadow.STATUS_AXIS_UVLO | shadow.STATUS_AXIS_TH_WRN | shadow.STATUS_AXIS_TH_SD | shadow.STATUS_AXIS_OCD ;
|
||||||
|
shadow.STATUS_AXIS ^= (shadow.STATUS_AXIS_WRONG_CMD | shadow.STATUS_AXIS_NOTPERF_CMD); // invert just error bits that are active high
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case L6480_STATUS_LAYOUT: { // L6480 & powerSTEP01
|
||||||
|
shadow.L6470_ERROR_MASK = shadow.STATUS_AXIS_UVLO | shadow.STATUS_AXIS_TH_WRN | shadow.STATUS_AXIS_TH_SD | shadow.STATUS_AXIS_OCD | shadow.STATUS_AXIS_STEP_LOSS_A | shadow.STATUS_AXIS_STEP_LOSS_B;
|
||||||
|
shadow.STATUS_AXIS ^= (shadow.STATUS_AXIS_CMD_ERR | shadow.STATUS_AXIS_TH_WRN | shadow.STATUS_AXIS_TH_SD); // invert just error bits that are active high
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return shadow.STATUS_AXIS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void L64XX_Marlin::init() { // Set up SPI and then init chips
|
||||||
|
ENABLE_RESET_L64XX_CHIPS(LOW); // hardware reset of drivers
|
||||||
|
DELAY_US(100);
|
||||||
|
ENABLE_RESET_L64XX_CHIPS(HIGH);
|
||||||
|
DELAY_US(1000); // need about 650µs for the chip(s) to fully start up
|
||||||
|
L6470_populate_chain_array(); // Set up array to control where in the SPI transfer sequence a particular stepper's data goes
|
||||||
|
|
||||||
|
spi_init(); // Since L64XX SPI pins are unset we must init SPI here
|
||||||
|
|
||||||
|
init_to_defaults(); // init the chips
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t L64XX_Marlin::get_status(const L64XX_axis_t axis) {
|
||||||
|
|
||||||
|
#define STATUS_L6470(Q) get_stepper_status(stepper##Q)
|
||||||
|
|
||||||
|
switch (axis) {
|
||||||
|
default: break;
|
||||||
|
#if AXIS_IS_L64XX(X)
|
||||||
|
case X : return STATUS_L6470(X);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Y)
|
||||||
|
case Y : return STATUS_L6470(Y);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z)
|
||||||
|
case Z : return STATUS_L6470(Z);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(X2)
|
||||||
|
case X2: return STATUS_L6470(X2);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Y2)
|
||||||
|
case Y2: return STATUS_L6470(Y2);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z2)
|
||||||
|
case Z2: return STATUS_L6470(Z2);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z3)
|
||||||
|
case Z3: return STATUS_L6470(Z3);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E0)
|
||||||
|
case E0: return STATUS_L6470(E0);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E1)
|
||||||
|
case E1: return STATUS_L6470(E1);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E2)
|
||||||
|
case E2: return STATUS_L6470(E2);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E3)
|
||||||
|
case E3: return STATUS_L6470(E3);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E4)
|
||||||
|
case E4: return STATUS_L6470(E4);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E5)
|
||||||
|
case E5: return STATUS_L6470(E5);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // Not needed but kills a compiler warning
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t L64XX_Marlin::get_param(const L64XX_axis_t axis, const uint8_t param) {
|
||||||
|
|
||||||
|
#define GET_L6470_PARAM(Q) L6470_GETPARAM(param, Q)
|
||||||
|
|
||||||
|
switch (axis) {
|
||||||
|
default: break;
|
||||||
|
#if AXIS_IS_L64XX(X)
|
||||||
|
case X : return GET_L6470_PARAM(X);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Y)
|
||||||
|
case Y : return GET_L6470_PARAM(Y);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z)
|
||||||
|
case Z : return GET_L6470_PARAM(Z);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(X2)
|
||||||
|
case X2: return GET_L6470_PARAM(X2);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Y2)
|
||||||
|
case Y2: return GET_L6470_PARAM(Y2);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z2)
|
||||||
|
case Z2: return GET_L6470_PARAM(Z2);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z3)
|
||||||
|
case Z3: return GET_L6470_PARAM(Z3);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E0)
|
||||||
|
case E0: return GET_L6470_PARAM(E0);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E1)
|
||||||
|
case E1: return GET_L6470_PARAM(E1);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E2)
|
||||||
|
case E2: return GET_L6470_PARAM(E2);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E3)
|
||||||
|
case E3: return GET_L6470_PARAM(E3);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E4)
|
||||||
|
case E4: return GET_L6470_PARAM(E4);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E5)
|
||||||
|
case E5: return GET_L6470_PARAM(E5);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // not needed but kills a compiler warning
|
||||||
|
}
|
||||||
|
|
||||||
|
void L64XX_Marlin::set_param(const L64XX_axis_t axis, const uint8_t param, const uint32_t value) {
|
||||||
|
|
||||||
|
#define SET_L6470_PARAM(Q) stepper##Q.SetParam(param, value)
|
||||||
|
|
||||||
|
switch (axis) {
|
||||||
|
default: break;
|
||||||
|
#if AXIS_IS_L64XX(X)
|
||||||
|
case X : SET_L6470_PARAM(X); break;
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Y)
|
||||||
|
case Y : SET_L6470_PARAM(Y); break;
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z)
|
||||||
|
case Z : SET_L6470_PARAM(Z); break;
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(X2)
|
||||||
|
case X2: SET_L6470_PARAM(X2); break;
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Y2)
|
||||||
|
case Y2: SET_L6470_PARAM(Y2); break;
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z2)
|
||||||
|
case Z2: SET_L6470_PARAM(Z2); break;
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z3)
|
||||||
|
case Z3: SET_L6470_PARAM(Z3); break;
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E0)
|
||||||
|
case E0: SET_L6470_PARAM(E0); break;
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E1)
|
||||||
|
case E1: SET_L6470_PARAM(E1); break;
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E2)
|
||||||
|
case E2: SET_L6470_PARAM(E2); break;
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E3)
|
||||||
|
case E3: SET_L6470_PARAM(E3); break;
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E4)
|
||||||
|
case E4: SET_L6470_PARAM(E4); break;
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E5)
|
||||||
|
case E5: SET_L6470_PARAM(E5); break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void echo_min_max(const char a, const float &min, const float &max) {
|
||||||
|
DEBUG_CHAR(' '); DEBUG_CHAR(a);
|
||||||
|
DEBUG_ECHOPAIR(" min = ", min);
|
||||||
|
DEBUG_ECHOLNPAIR(" max = ", max);
|
||||||
|
}
|
||||||
|
inline void echo_oct_used(const float &oct, const uint8_t stall) {
|
||||||
|
DEBUG_ECHOPAIR("over_current_threshold used : ", oct);
|
||||||
|
serialprintPGM(stall ? PSTR(" (Stall") : PSTR(" (OCD"));
|
||||||
|
DEBUG_ECHOLNPGM(" threshold)");
|
||||||
|
}
|
||||||
|
inline void err_out_of_bounds() { DEBUG_ECHOLNPGM("Test aborted - motion out of bounds"); }
|
||||||
|
|
||||||
|
uint8_t L64XX_Marlin::get_user_input(uint8_t &driver_count, L64XX_axis_t axis_index[3], char axis_mon[3][3],
|
||||||
|
float &position_max, float &position_min, float &final_feedrate, uint8_t &kval_hold,
|
||||||
|
uint8_t over_current_flag, uint8_t &OCD_TH_val, uint8_t &STALL_TH_val, uint16_t &over_current_threshold
|
||||||
|
) {
|
||||||
|
// Return TRUE if the calling routine needs to abort/kill
|
||||||
|
|
||||||
|
uint16_t displacement = 0; // " = 0" to eliminate compiler warning
|
||||||
|
uint8_t j; // general purpose counter
|
||||||
|
|
||||||
|
if (!all_axes_homed()) {
|
||||||
|
DEBUG_ECHOLNPGM("Test aborted - home all before running this command");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t found_displacement = false;
|
||||||
|
LOOP_XYZE(i) if (uint16_t _displacement = parser.intval(axis_codes[i])) {
|
||||||
|
found_displacement = true;
|
||||||
|
displacement = _displacement;
|
||||||
|
uint8_t axis_offset = parser.byteval('J');
|
||||||
|
axis_mon[0][0] = axis_codes[i]; // axis ASCII value (target character)
|
||||||
|
uint8_t driver_count_local = 0; // Can't use "driver_count" directly as a subscript because it's passed by reference
|
||||||
|
if (axis_offset >= 2 || axis_mon[0][0] == 'E') { // Single axis, E0, or E1
|
||||||
|
axis_mon[0][1] = axis_offset + '0';
|
||||||
|
for (j = 0; j < MAX_L6470; j++) { // See how many drivers on this axis
|
||||||
|
const char * const str = index_to_axis[j];
|
||||||
|
if (axis_mon[0][0] == str[0]) {
|
||||||
|
char * const mon = axis_mon[driver_count_local];
|
||||||
|
mon[0] = str[0];
|
||||||
|
mon[1] = str[1];
|
||||||
|
mon[2] = str[2]; // append end of string
|
||||||
|
axis_index[driver_count_local] = (L64XX_axis_t)j; // set axis index
|
||||||
|
driver_count_local++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (axis_offset == 0) { // One or more axes
|
||||||
|
for (j = 0; j < MAX_L6470; j++) { // See how many drivers on this axis
|
||||||
|
const char * const str = index_to_axis[j];
|
||||||
|
if (axis_mon[0][0] == str[0]) {
|
||||||
|
char * const mon = axis_mon[driver_count_local];
|
||||||
|
mon[0] = str[0];
|
||||||
|
mon[1] = str[1];
|
||||||
|
mon[2] = str[2]; // append end of string
|
||||||
|
axis_index[driver_count_local] = (L64XX_axis_t)j; // set axis index
|
||||||
|
driver_count_local++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
driver_count = driver_count_local;
|
||||||
|
}
|
||||||
|
break; // only take first axis found
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found_displacement) {
|
||||||
|
DEBUG_ECHOLNPGM("Test aborted - AXIS with displacement is required");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Position calcs & checks
|
||||||
|
//
|
||||||
|
|
||||||
|
const float X_center = LOGICAL_X_POSITION(current_position.x),
|
||||||
|
Y_center = LOGICAL_Y_POSITION(current_position.y),
|
||||||
|
Z_center = LOGICAL_Z_POSITION(current_position.z),
|
||||||
|
E_center = current_position.e;
|
||||||
|
|
||||||
|
switch (axis_mon[0][0]) {
|
||||||
|
default: position_max = position_min = 0; break;
|
||||||
|
|
||||||
|
case 'X': {
|
||||||
|
position_min = X_center - displacement;
|
||||||
|
position_max = X_center + displacement;
|
||||||
|
echo_min_max('X', position_min, position_max);
|
||||||
|
if (false
|
||||||
|
#ifdef X_MIN_POS
|
||||||
|
|| position_min < (X_MIN_POS)
|
||||||
|
#endif
|
||||||
|
#ifdef X_MAX_POS
|
||||||
|
|| position_max > (X_MAX_POS)
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
err_out_of_bounds();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 'Y': {
|
||||||
|
position_min = Y_center - displacement;
|
||||||
|
position_max = Y_center + displacement;
|
||||||
|
echo_min_max('Y', position_min, position_max);
|
||||||
|
if (false
|
||||||
|
#ifdef Y_MIN_POS
|
||||||
|
|| position_min < (Y_MIN_POS)
|
||||||
|
#endif
|
||||||
|
#ifdef Y_MAX_POS
|
||||||
|
|| position_max > (Y_MAX_POS)
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
err_out_of_bounds();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 'Z': {
|
||||||
|
position_min = Z_center - displacement;
|
||||||
|
position_max = Z_center + displacement;
|
||||||
|
echo_min_max('Z', position_min, position_max);
|
||||||
|
if (false
|
||||||
|
#ifdef Z_MIN_POS
|
||||||
|
|| position_min < (Z_MIN_POS)
|
||||||
|
#endif
|
||||||
|
#ifdef Z_MAX_POS
|
||||||
|
|| position_max > (Z_MAX_POS)
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
err_out_of_bounds();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 'E': {
|
||||||
|
position_min = E_center - displacement;
|
||||||
|
position_max = E_center + displacement;
|
||||||
|
echo_min_max('E', position_min, position_max);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Work on the drivers
|
||||||
|
//
|
||||||
|
|
||||||
|
for (uint8_t k = 0; k < driver_count; k++) {
|
||||||
|
uint8_t not_found = true;
|
||||||
|
for (j = 1; j <= L64XX::chain[0]; j++) {
|
||||||
|
const char * const ind_axis = index_to_axis[L64XX::chain[j]];
|
||||||
|
if (ind_axis[0] == axis_mon[k][0] && ind_axis[1] == axis_mon[k][1]) { // See if a L6470 driver
|
||||||
|
not_found = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (not_found) {
|
||||||
|
driver_count = k;
|
||||||
|
axis_mon[k][0] = ' '; // mark this entry invalid
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (driver_count == 0) {
|
||||||
|
DEBUG_ECHOLNPGM("Test aborted - not a L6470 axis");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_ECHOPGM("Monitoring:");
|
||||||
|
for (j = 0; j < driver_count; j++) DEBUG_ECHOPAIR(" ", axis_mon[j]);
|
||||||
|
DEBUG_EOL();
|
||||||
|
|
||||||
|
// now have a list of driver(s) to monitor
|
||||||
|
|
||||||
|
//
|
||||||
|
// TVAL & kVAL_HOLD checks & settings
|
||||||
|
//
|
||||||
|
const L64XX_shadow_t &sh = shadow;
|
||||||
|
get_status(axis_index[0]); // populate shadow array
|
||||||
|
|
||||||
|
if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT) { // L6474 - use TVAL
|
||||||
|
uint16_t TVAL_current = parser.ushortval('T');
|
||||||
|
if (TVAL_current) {
|
||||||
|
uint8_t TVAL_count = (TVAL_current / sh.AXIS_STALL_CURRENT_CONSTANT_INV) - 1;
|
||||||
|
LIMIT(TVAL_count, 0, sh.AXIS_STALL_TH_MAX);
|
||||||
|
for (j = 0; j < driver_count; j++)
|
||||||
|
set_param(axis_index[j], L6474_TVAL, TVAL_count);
|
||||||
|
}
|
||||||
|
// only print the tval from one of the drivers
|
||||||
|
kval_hold = get_param(axis_index[0], L6474_TVAL);
|
||||||
|
DEBUG_ECHOLNPAIR("TVAL current (mA) = ", (kval_hold + 1) * sh.AXIS_STALL_CURRENT_CONSTANT_INV);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
kval_hold = parser.byteval('K');
|
||||||
|
if (kval_hold) {
|
||||||
|
DEBUG_ECHOLNPAIR("kval_hold = ", kval_hold);
|
||||||
|
for (j = 0; j < driver_count; j++)
|
||||||
|
set_param(axis_index[j], L6470_KVAL_HOLD, kval_hold);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// only print the KVAL_HOLD from one of the drivers
|
||||||
|
kval_hold = get_param(axis_index[0], L6470_KVAL_HOLD);
|
||||||
|
DEBUG_ECHOLNPAIR("KVAL_HOLD = ", kval_hold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Overcurrent checks & settings
|
||||||
|
//
|
||||||
|
|
||||||
|
if (over_current_flag) {
|
||||||
|
|
||||||
|
uint8_t OCD_TH_val_local = 0, // compiler thinks OCD_TH_val is unused if use it directly
|
||||||
|
STALL_TH_val_local = 0; // just in case ...
|
||||||
|
|
||||||
|
over_current_threshold = parser.intval('I');
|
||||||
|
|
||||||
|
if (over_current_threshold) {
|
||||||
|
|
||||||
|
OCD_TH_val_local = over_current_threshold/375;
|
||||||
|
LIMIT(OCD_TH_val_local, 0, 15);
|
||||||
|
STALL_TH_val_local = over_current_threshold/31.25;
|
||||||
|
LIMIT(STALL_TH_val_local, 0, 127);
|
||||||
|
uint16_t OCD_TH_actual = (OCD_TH_val_local + 1) * 375,
|
||||||
|
STALL_TH_actual = (STALL_TH_val_local + 1) * 31.25;
|
||||||
|
if (OCD_TH_actual < STALL_TH_actual) {
|
||||||
|
OCD_TH_val_local++;
|
||||||
|
OCD_TH_actual = (OCD_TH_val_local + 1) * 375;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_ECHOLNPAIR("over_current_threshold specified: ", over_current_threshold);
|
||||||
|
if (!(sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT)) echo_oct_used((STALL_TH_val_local + 1) * 31.25, true);
|
||||||
|
echo_oct_used((OCD_TH_val_local + 1) * 375, false);
|
||||||
|
|
||||||
|
#define SET_OVER_CURRENT(Q) do { stepper##Q.SetParam(L6470_STALL_TH, STALL_TH_val_local); stepper##Q.SetParam(L6470_OCD_TH, OCD_TH_val_local);} while (0)
|
||||||
|
|
||||||
|
for (j = 0; j < driver_count; j++) {
|
||||||
|
set_param(axis_index[j], L6470_STALL_TH, STALL_TH_val_local);
|
||||||
|
set_param(axis_index[j], L6470_OCD_TH, OCD_TH_val_local);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// only get & print the OVER_CURRENT values from one of the drivers
|
||||||
|
STALL_TH_val_local = get_param(axis_index[0], L6470_STALL_TH);
|
||||||
|
OCD_TH_val_local = get_param(axis_index[0], L6470_OCD_TH);
|
||||||
|
|
||||||
|
if (!(sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT)) echo_oct_used((STALL_TH_val_local + 1) * 31.25, true);
|
||||||
|
echo_oct_used((OCD_TH_val_local + 1) * 375, false);
|
||||||
|
} // over_current_threshold
|
||||||
|
|
||||||
|
for (j = 0; j < driver_count; j++) { // set all drivers on axis the same
|
||||||
|
set_param(axis_index[j], L6470_STALL_TH, STALL_TH_val_local);
|
||||||
|
set_param(axis_index[j], L6470_OCD_TH, OCD_TH_val_local);
|
||||||
|
}
|
||||||
|
|
||||||
|
OCD_TH_val = OCD_TH_val_local; // force compiler to update the main routine's copy
|
||||||
|
STALL_TH_val = STALL_TH_val_local; // force compiler to update the main routine's copy
|
||||||
|
} // end of overcurrent
|
||||||
|
|
||||||
|
//
|
||||||
|
// Feedrate
|
||||||
|
//
|
||||||
|
|
||||||
|
final_feedrate = parser.floatval('F');
|
||||||
|
if (final_feedrate == 0) {
|
||||||
|
static constexpr float default_max_feedrate[] = DEFAULT_MAX_FEEDRATE;
|
||||||
|
const uint8_t num_feedrates = COUNT(default_max_feedrate);
|
||||||
|
for (j = 0; j < num_feedrates; j++) {
|
||||||
|
if (axis_codes[j] == axis_mon[0][0]) {
|
||||||
|
final_feedrate = default_max_feedrate[j];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j == 3 && num_feedrates > 4) { // have more than one extruder feedrate
|
||||||
|
uint8_t extruder_num = axis_mon[0][1] - '0';
|
||||||
|
if (j <= num_feedrates - extruder_num) // have a feedrate specifically for this extruder
|
||||||
|
final_feedrate = default_max_feedrate[j + extruder_num];
|
||||||
|
else
|
||||||
|
final_feedrate = default_max_feedrate[3]; // use E0 feedrate for this extruder
|
||||||
|
}
|
||||||
|
final_feedrate *= 60; // convert to mm/minute
|
||||||
|
} // end of feedrate
|
||||||
|
|
||||||
|
return false; // FALSE indicates no user input problems
|
||||||
|
}
|
||||||
|
|
||||||
|
void L64XX_Marlin::say_axis(const L64XX_axis_t axis, const uint8_t label/*=true*/) {
|
||||||
|
if (label) SERIAL_ECHOPGM("AXIS:");
|
||||||
|
const char * const str = L64xxManager.index_to_axis[axis];
|
||||||
|
SERIAL_CHAR(' ', str[0], str[1], ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLED(L6470_CHITCHAT)
|
||||||
|
|
||||||
|
// Assumes status bits have been inverted
|
||||||
|
void L64XX_Marlin::error_status_decode(const uint16_t status, const L64XX_axis_t axis,
|
||||||
|
const uint16_t _status_axis_th_sd, const uint16_t _status_axis_th_wrn,
|
||||||
|
const uint16_t _status_axis_step_loss_a, const uint16_t _status_axis_step_loss_b,
|
||||||
|
const uint16_t _status_axis_ocd, const uint8_t _status_axis_layout
|
||||||
|
) {
|
||||||
|
say_axis(axis);
|
||||||
|
DEBUG_ECHOPGM(" THERMAL: ");
|
||||||
|
serialprintPGM((status & _status_axis_th_sd) ? PSTR("SHUTDOWN") : (status & _status_axis_th_wrn) ? PSTR("WARNING ") : PSTR("OK "));
|
||||||
|
DEBUG_ECHOPGM(" OVERCURRENT: ");
|
||||||
|
echo_yes_no((status & _status_axis_ocd) != 0);
|
||||||
|
if (!(_status_axis_layout == L6474_STATUS_LAYOUT)) { // L6474 doesn't have these bits
|
||||||
|
DEBUG_ECHOPGM(" STALL: ");
|
||||||
|
echo_yes_no((status & (_status_axis_step_loss_a | _status_axis_step_loss_b)) != 0);
|
||||||
|
}
|
||||||
|
DEBUG_EOL();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
////
|
||||||
|
//// MONITOR_L6470_DRIVER_STATUS routines
|
||||||
|
////
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#if ENABLED(MONITOR_L6470_DRIVER_STATUS)
|
||||||
|
|
||||||
|
bool L64XX_Marlin::monitor_paused = false; // Flag to skip monitor during M122, M906, M916, M917, M918, etc.
|
||||||
|
|
||||||
|
struct L6470_driver_data {
|
||||||
|
uint8_t driver_index;
|
||||||
|
uint32_t driver_status;
|
||||||
|
uint8_t is_otw;
|
||||||
|
uint8_t otw_counter;
|
||||||
|
uint8_t is_ot;
|
||||||
|
uint8_t is_hi_Z;
|
||||||
|
uint8_t com_counter;
|
||||||
|
};
|
||||||
|
|
||||||
|
L6470_driver_data driver_L6470_data[] = {
|
||||||
|
#if AXIS_IS_L64XX(X)
|
||||||
|
{ 0, 0, 0, 0, 0, 0, 0 },
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Y)
|
||||||
|
{ 1, 0, 0, 0, 0, 0, 0 },
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z)
|
||||||
|
{ 2, 0, 0, 0, 0, 0, 0 },
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(X2)
|
||||||
|
{ 3, 0, 0, 0, 0, 0, 0 },
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Y2)
|
||||||
|
{ 4, 0, 0, 0, 0, 0, 0 },
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z2)
|
||||||
|
{ 5, 0, 0, 0, 0, 0, 0 },
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z3)
|
||||||
|
{ 6, 0, 0, 0, 0, 0, 0 },
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E0)
|
||||||
|
{ 7, 0, 0, 0, 0, 0, 0 },
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E1)
|
||||||
|
{ 8, 0, 0, 0, 0, 0, 0 },
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E2)
|
||||||
|
{ 9, 0, 0, 0, 0, 0, 0 },
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E3)
|
||||||
|
{ 10, 0, 0, 0, 0, 0, 0 },
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E4)
|
||||||
|
{ 11, 0, 0, 0, 0, 0, 0 },
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E5)
|
||||||
|
{ 12, 0, 0, 0, 0, 0, 0 }
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
void L64XX_Marlin::append_stepper_err(char* &p, const uint8_t stepper_index, const char * const err/*=nullptr*/) {
|
||||||
|
p += sprintf_P(p, PSTR("Stepper %c%c "), index_to_axis[stepper_index][0], index_to_axis[stepper_index][1]);
|
||||||
|
if (err) p += sprintf_P(p, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
void L64XX_Marlin::monitor_update(L64XX_axis_t stepper_index) {
|
||||||
|
if (spi_abort) return; // don't do anything if set_directions() has occurred
|
||||||
|
const L64XX_shadow_t &sh = shadow;
|
||||||
|
get_status(stepper_index); // get stepper status and details
|
||||||
|
uint16_t status = sh.STATUS_AXIS;
|
||||||
|
uint8_t kval_hold, tval;
|
||||||
|
char temp_buf[120], *p = temp_buf;
|
||||||
|
uint8_t j;
|
||||||
|
for (j = 0; j < L64XX::chain[0]; j++) // find the table for this stepper
|
||||||
|
if (driver_L6470_data[j].driver_index == stepper_index) break;
|
||||||
|
|
||||||
|
driver_L6470_data[j].driver_status = status;
|
||||||
|
uint16_t _status = ~status; // all error bits are active low
|
||||||
|
|
||||||
|
if (status == 0 || status == 0xFFFF) { // com problem
|
||||||
|
if (driver_L6470_data[j].com_counter == 0) { // warn user when it first happens
|
||||||
|
driver_L6470_data[j].com_counter++;
|
||||||
|
append_stepper_err(p, stepper_index, PSTR(" - communications lost\n"));
|
||||||
|
DEBUG_ECHO(temp_buf);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
driver_L6470_data[j].com_counter++;
|
||||||
|
if (driver_L6470_data[j].com_counter > 240) { // remind of com problem about every 2 minutes
|
||||||
|
driver_L6470_data[j].com_counter = 1;
|
||||||
|
append_stepper_err(p, stepper_index, PSTR(" - still no communications\n"));
|
||||||
|
DEBUG_ECHO(temp_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (driver_L6470_data[j].com_counter) { // comms re-established
|
||||||
|
driver_L6470_data[j].com_counter = 0;
|
||||||
|
append_stepper_err(p, stepper_index, PSTR(" - communications re-established\n.. setting all drivers to default values\n"));
|
||||||
|
DEBUG_ECHO(temp_buf);
|
||||||
|
init_to_defaults();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// no com problems - do the usual checks
|
||||||
|
if (_status & sh.L6470_ERROR_MASK) {
|
||||||
|
append_stepper_err(p, stepper_index);
|
||||||
|
|
||||||
|
if (status & STATUS_HIZ) { // The driver has shut down. HiZ is active high
|
||||||
|
driver_L6470_data[j].is_hi_Z = true;
|
||||||
|
p += sprintf_P(p, PSTR("%cIS SHUT DOWN"), ' ');
|
||||||
|
//if (_status & sh.STATUS_AXIS_TH_SD) { // strange - TH_SD never seems to go active, must be implied by the HiZ and TH_WRN
|
||||||
|
if (_status & sh.STATUS_AXIS_TH_WRN) { // over current shutdown
|
||||||
|
p += sprintf_P(p, PSTR("%cdue to over temperature"), ' ');
|
||||||
|
driver_L6470_data[j].is_ot = true;
|
||||||
|
if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT) { // L6474
|
||||||
|
tval = get_param(stepper_index, L6474_TVAL) - 2 * KVAL_HOLD_STEP_DOWN;
|
||||||
|
set_param(stepper_index, L6474_TVAL, tval); // reduce TVAL
|
||||||
|
p += sprintf_P(p, PSTR(" - TVAL reduced by %d to %d mA"), uint16_t (2 * KVAL_HOLD_STEP_DOWN * sh.AXIS_STALL_CURRENT_CONSTANT_INV), uint16_t ((tval + 1) * sh.AXIS_STALL_CURRENT_CONSTANT_INV)); // let user know
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
kval_hold = get_param(stepper_index, L6470_KVAL_HOLD) - 2 * KVAL_HOLD_STEP_DOWN;
|
||||||
|
set_param(stepper_index, L6470_KVAL_HOLD, kval_hold); // reduce KVAL_HOLD
|
||||||
|
p += sprintf_P(p, PSTR(" - KVAL_HOLD reduced by %d to %d"), 2 * KVAL_HOLD_STEP_DOWN, kval_hold); // let user know
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
driver_L6470_data[j].is_ot = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
driver_L6470_data[j].is_hi_Z = false;
|
||||||
|
|
||||||
|
if (_status & sh.STATUS_AXIS_TH_WRN) { // have an over temperature warning
|
||||||
|
driver_L6470_data[j].is_otw = true;
|
||||||
|
driver_L6470_data[j].otw_counter++;
|
||||||
|
kval_hold = get_param(stepper_index, L6470_KVAL_HOLD);
|
||||||
|
if (driver_L6470_data[j].otw_counter > 4) { // otw present for 2 - 2.5 seconds, reduce KVAL_HOLD
|
||||||
|
driver_L6470_data[j].otw_counter = 0;
|
||||||
|
driver_L6470_data[j].is_otw = true;
|
||||||
|
if (sh.STATUS_AXIS_LAYOUT == L6474_STATUS_LAYOUT) { // L6474
|
||||||
|
tval = get_param(stepper_index, L6474_TVAL) - KVAL_HOLD_STEP_DOWN;
|
||||||
|
set_param(stepper_index, L6474_TVAL, tval); // reduce TVAL
|
||||||
|
p += sprintf_P(p, PSTR(" - TVAL reduced by %d to %d mA"), uint16_t (KVAL_HOLD_STEP_DOWN * sh.AXIS_STALL_CURRENT_CONSTANT_INV), uint16_t ((tval + 1) * sh.AXIS_STALL_CURRENT_CONSTANT_INV)); // let user know
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
kval_hold = get_param(stepper_index, L6470_KVAL_HOLD) - KVAL_HOLD_STEP_DOWN;
|
||||||
|
set_param(stepper_index, L6470_KVAL_HOLD, kval_hold); // reduce KVAL_HOLD
|
||||||
|
p += sprintf_P(p, PSTR(" - KVAL_HOLD reduced by %d to %d"), KVAL_HOLD_STEP_DOWN, kval_hold); // let user know
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (driver_L6470_data[j].otw_counter)
|
||||||
|
p += sprintf_P(p, PSTR("%c- thermal warning"), ' '); // warn user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLED(L6470_STOP_ON_ERROR)
|
||||||
|
if (_status & (sh.STATUS_AXIS_UVLO | sh.STATUS_AXIS_TH_WRN | sh.STATUS_AXIS_TH_SD))
|
||||||
|
kill(temp_buf);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ENABLED(L6470_CHITCHAT)
|
||||||
|
if (_status & sh.STATUS_AXIS_OCD)
|
||||||
|
p += sprintf_P(p, PSTR("%c over current"), ' ');
|
||||||
|
|
||||||
|
if (_status & (sh.STATUS_AXIS_STEP_LOSS_A | sh.STATUS_AXIS_STEP_LOSS_B))
|
||||||
|
p += sprintf_P(p, PSTR("%c stall"), ' ');
|
||||||
|
|
||||||
|
if (_status & sh.STATUS_AXIS_UVLO)
|
||||||
|
p += sprintf_P(p, PSTR("%c under voltage lock out"), ' ');
|
||||||
|
|
||||||
|
p += sprintf_P(p, PSTR("%c\n"), ' ');
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DEBUG_ECHOLN(temp_buf); // print the error message
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
driver_L6470_data[j].is_ot = false;
|
||||||
|
driver_L6470_data[j].otw_counter = 0; //clear out warning indicators
|
||||||
|
driver_L6470_data[j].is_otw = false;
|
||||||
|
} // end usual checks
|
||||||
|
|
||||||
|
} // comms established but have errors
|
||||||
|
} // comms re-established
|
||||||
|
} // end monitor_update()
|
||||||
|
|
||||||
|
|
||||||
|
void L64XX_Marlin::monitor_driver() {
|
||||||
|
static millis_t next_cOT = 0;
|
||||||
|
if (ELAPSED(millis(), next_cOT)) {
|
||||||
|
next_cOT = millis() + 500;
|
||||||
|
|
||||||
|
if (!monitor_paused) { // Skip during M122, M906, M916, M917 or M918 (could steal status result from test)
|
||||||
|
|
||||||
|
spi_active = true; // Tell set_directions() a series of SPI transfers is underway
|
||||||
|
|
||||||
|
#if AXIS_IS_L64XX(X)
|
||||||
|
monitor_update(X);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Y)
|
||||||
|
monitor_update(Y);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z)
|
||||||
|
monitor_update(Z);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(X2)
|
||||||
|
monitor_update(X2);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Y2)
|
||||||
|
monitor_update(Y2);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z2)
|
||||||
|
monitor_update(Z2);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z3)
|
||||||
|
monitor_update(Z3);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E0)
|
||||||
|
monitor_update(E0);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E1)
|
||||||
|
monitor_update(E1);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E2)
|
||||||
|
monitor_update(E2);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E3)
|
||||||
|
monitor_update(E3);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E4)
|
||||||
|
monitor_update(E4);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E5)
|
||||||
|
monitor_update(E5);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ENABLED(L6470_DEBUG)
|
||||||
|
if (report_L6470_status) DEBUG_EOL();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
spi_active = false; // done with all SPI transfers - clear handshake flags
|
||||||
|
spi_abort = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MONITOR_L6470_DRIVER_STATUS
|
||||||
|
|
||||||
|
#endif // HAS_L64XX
|
@ -0,0 +1,141 @@
|
|||||||
|
/**
|
||||||
|
* Marlin 3D Printer Firmware
|
||||||
|
* Copyright (c) 2019 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../../inc/MarlinConfig.h"
|
||||||
|
|
||||||
|
#include <L6470.h>
|
||||||
|
#if !(L6470_LIBRARY_VERSION >= 0x000800)
|
||||||
|
#error 'L6470_LIBRARY_VERSION 0x000800 or later required'
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define L6470_GETPARAM(P,Q) stepper##Q.GetParam(P)
|
||||||
|
|
||||||
|
#define MAX_L6470 (7 + MAX_EXTRUDERS) // Maximum number of axes in Marlin
|
||||||
|
|
||||||
|
#define dSPIN_STEP_CLOCK 0x58
|
||||||
|
#define dSPIN_STEP_CLOCK_FWD dSPIN_STEP_CLOCK
|
||||||
|
#define dSPIN_STEP_CLOCK_REV dSPIN_STEP_CLOCK+1
|
||||||
|
#define HAS_L64XX_EXTRUDER (AXIS_IS_L64XX(E0) || AXIS_IS_L64XX(E1) || AXIS_IS_L64XX(E2) || AXIS_IS_L64XX(E3) || AXIS_IS_L64XX(E4) || AXIS_IS_L64XX(E5))
|
||||||
|
|
||||||
|
typedef enum : uint8_t { X, Y, Z, X2, Y2, Z2, Z3, E0, E1, E2, E3, E4, E5 } L64XX_axis_t;
|
||||||
|
|
||||||
|
class L64XX_Marlin : public L64XXHelper {
|
||||||
|
public:
|
||||||
|
static char index_to_axis[MAX_L6470][3];
|
||||||
|
|
||||||
|
static uint8_t index_to_dir[MAX_L6470];
|
||||||
|
static uint8_t dir_commands[MAX_L6470];
|
||||||
|
|
||||||
|
// Flags to guarantee graceful switch if stepper interrupts L6470 SPI transfer
|
||||||
|
static volatile uint8_t spi_abort;
|
||||||
|
static uint8_t spi_active;
|
||||||
|
|
||||||
|
L64XX_Marlin() {}
|
||||||
|
|
||||||
|
static void init();
|
||||||
|
static void init_to_defaults();
|
||||||
|
|
||||||
|
static uint16_t get_stepper_status(L64XX &st);
|
||||||
|
|
||||||
|
static uint16_t get_status(const L64XX_axis_t axis);
|
||||||
|
|
||||||
|
static uint32_t get_param(const L64XX_axis_t axis, const uint8_t param);
|
||||||
|
|
||||||
|
static void set_param(const L64XX_axis_t axis, const uint8_t param, const uint32_t value);
|
||||||
|
|
||||||
|
//static void send_command(const L64XX_axis_t axis, uint8_t command);
|
||||||
|
|
||||||
|
static uint8_t get_user_input(uint8_t &driver_count, L64XX_axis_t axis_index[3], char axis_mon[3][3],
|
||||||
|
float &position_max, float &position_min, float &final_feedrate, uint8_t &kval_hold,
|
||||||
|
uint8_t over_current_flag, uint8_t &OCD_TH_val, uint8_t &STALL_TH_val, uint16_t &over_current_threshold);
|
||||||
|
|
||||||
|
static void transfer(uint8_t L6470_buf[], const uint8_t length);
|
||||||
|
|
||||||
|
//static char* index_to_axis(const uint8_t index);
|
||||||
|
static void say_axis(const L64XX_axis_t axis, const uint8_t label=true);
|
||||||
|
#if ENABLED(L6470_CHITCHAT)
|
||||||
|
static void error_status_decode(
|
||||||
|
const uint16_t status, const L64XX_axis_t axis,
|
||||||
|
const uint16_t _status_axis_th_sd, const uint16_t _status_axis_th_wrn,
|
||||||
|
const uint16_t _status_axis_step_loss_a, const uint16_t _status_axis_step_loss_b,
|
||||||
|
const uint16_t _status_axis_ocd, const uint8_t _status_axis_layout
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
FORCE_INLINE static void error_status_decode(
|
||||||
|
const uint16_t, const L64XX_axis_t,
|
||||||
|
const uint16_t, const uint16_t,
|
||||||
|
const uint16_t, const uint16_t,
|
||||||
|
const uint16_t, const uint8_t
|
||||||
|
){}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ~40 bytes SRAM to simplify status decode routines
|
||||||
|
typedef struct {
|
||||||
|
uint8_t STATUS_AXIS_LAYOUT; // Copy of L6470_status_layout
|
||||||
|
uint8_t AXIS_OCD_TH_MAX; // Size of OCD_TH field
|
||||||
|
uint8_t AXIS_STALL_TH_MAX; // Size of STALL_TH field
|
||||||
|
float AXIS_OCD_CURRENT_CONSTANT_INV; // mA per count
|
||||||
|
float AXIS_STALL_CURRENT_CONSTANT_INV; // mA per count
|
||||||
|
uint8_t L6470_AXIS_CONFIG, // Address of the CONFIG register
|
||||||
|
L6470_AXIS_STATUS; // Address of the STATUS register
|
||||||
|
uint16_t L6470_ERROR_MASK, // STATUS_UVLO | STATUS_TH_WRN | STATUS_TH_SD | STATUS_OCD | STATUS_STEP_LOSS_A | STATUS_STEP_LOSS_B
|
||||||
|
L6474_ERROR_MASK, // STATUS_UVLO | STATUS_TH_WRN | STATUS_TH_SD | STATUS_OCD
|
||||||
|
STATUS_AXIS_RAW, // Copy of status register contents
|
||||||
|
STATUS_AXIS, // Copy of status register contents but with all error bits active low
|
||||||
|
STATUS_AXIS_OCD, // Overcurrent detected bit position
|
||||||
|
STATUS_AXIS_SCK_MOD, // Step clock mode is active bit position
|
||||||
|
STATUS_AXIS_STEP_LOSS_A, // Stall detected on A bridge bit position
|
||||||
|
STATUS_AXIS_STEP_LOSS_B, // Stall detected on B bridge bit position
|
||||||
|
STATUS_AXIS_TH_SD, // Thermal shutdown bit position
|
||||||
|
STATUS_AXIS_TH_WRN, // Thermal warning bit position
|
||||||
|
STATUS_AXIS_UVLO, // Undervoltage lockout is active bit position
|
||||||
|
STATUS_AXIS_WRONG_CMD, // Last command not valid bit position
|
||||||
|
STATUS_AXIS_CMD_ERR, // Command error bit position
|
||||||
|
STATUS_AXIS_NOTPERF_CMD; // Last command not performed bit position
|
||||||
|
} L64XX_shadow_t;
|
||||||
|
|
||||||
|
static L64XX_shadow_t shadow;
|
||||||
|
|
||||||
|
#if ENABLED(MONITOR_L6470_DRIVER_STATUS)
|
||||||
|
static bool monitor_paused;
|
||||||
|
static inline void pause_monitor(const bool p) { monitor_paused = p; }
|
||||||
|
static void monitor_update(L64XX_axis_t stepper_index);
|
||||||
|
static void monitor_driver();
|
||||||
|
#else
|
||||||
|
static inline void pause_monitor(const bool) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//protected:
|
||||||
|
// L64XXHelper methods
|
||||||
|
static void spi_init();
|
||||||
|
static uint8_t transfer_single(uint8_t data, int16_t ss_pin);
|
||||||
|
static uint8_t transfer_chain(uint8_t data, int16_t ss_pin, uint8_t chain_position);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void append_stepper_err(char* &p, const uint8_t stepper_index, const char * const err=nullptr);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
void echo_yes_no(const bool yes);
|
||||||
|
|
||||||
|
extern L64XX_Marlin L64xxManager;
|
@ -1,143 +0,0 @@
|
|||||||
/**
|
|
||||||
* Marlin 3D Printer Firmware
|
|
||||||
* Copyright (c) 2019 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/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* stepper/L6470.cpp
|
|
||||||
* Stepper driver indirection for L6470 drivers
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "../../inc/MarlinConfig.h"
|
|
||||||
|
|
||||||
#if HAS_DRIVER(L6470)
|
|
||||||
|
|
||||||
#include "L6470.h"
|
|
||||||
|
|
||||||
#define _L6470_DEFINE(ST) L6470 stepper##ST((const int)L6470_CHAIN_SS_PIN)
|
|
||||||
|
|
||||||
// L6470 Stepper objects
|
|
||||||
#if AXIS_DRIVER_TYPE_X(L6470)
|
|
||||||
_L6470_DEFINE(X);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_X2(L6470)
|
|
||||||
_L6470_DEFINE(X2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Y(L6470)
|
|
||||||
_L6470_DEFINE(Y);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Y2(L6470)
|
|
||||||
_L6470_DEFINE(Y2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z(L6470)
|
|
||||||
_L6470_DEFINE(Z);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z2(L6470)
|
|
||||||
_L6470_DEFINE(Z2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z3(L6470)
|
|
||||||
_L6470_DEFINE(Z3);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E0(L6470)
|
|
||||||
_L6470_DEFINE(E0);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E1(L6470)
|
|
||||||
_L6470_DEFINE(E1);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E2(L6470)
|
|
||||||
_L6470_DEFINE(E2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E3(L6470)
|
|
||||||
_L6470_DEFINE(E3);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E4(L6470)
|
|
||||||
_L6470_DEFINE(E4);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E5(L6470)
|
|
||||||
_L6470_DEFINE(E5);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// not using L6470 library's init command because it
|
|
||||||
// briefly sends power to the steppers
|
|
||||||
|
|
||||||
#define _L6470_INIT_CHIP(Q) do{ \
|
|
||||||
stepper##Q.resetDev(); \
|
|
||||||
stepper##Q.softFree(); \
|
|
||||||
stepper##Q.SetParam(L6470_CONFIG, CONFIG_PWM_DIV_1 \
|
|
||||||
| CONFIG_PWM_MUL_2 \
|
|
||||||
| CONFIG_SR_290V_us \
|
|
||||||
| CONFIG_OC_SD_DISABLE \
|
|
||||||
| CONFIG_VS_COMP_DISABLE \
|
|
||||||
| CONFIG_SW_HARD_STOP \
|
|
||||||
| CONFIG_INT_16MHZ); \
|
|
||||||
stepper##Q.SetParam(L6470_KVAL_RUN, 0xFF); \
|
|
||||||
stepper##Q.SetParam(L6470_KVAL_ACC, 0xFF); \
|
|
||||||
stepper##Q.SetParam(L6470_KVAL_DEC, 0xFF); \
|
|
||||||
stepper##Q.setMicroSteps(Q##_MICROSTEPS); \
|
|
||||||
stepper##Q.setOverCurrent(Q##_OVERCURRENT); \
|
|
||||||
stepper##Q.setStallCurrent(Q##_STALLCURRENT); \
|
|
||||||
stepper##Q.SetParam(L6470_KVAL_HOLD, Q##_MAX_VOLTAGE); \
|
|
||||||
stepper##Q.SetParam(L6470_ABS_POS, 0); \
|
|
||||||
stepper##Q.getStatus(); \
|
|
||||||
}while(0)
|
|
||||||
|
|
||||||
void L6470_Marlin::init_to_defaults() {
|
|
||||||
#if AXIS_DRIVER_TYPE_X(L6470)
|
|
||||||
_L6470_INIT_CHIP(X);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_X2(L6470)
|
|
||||||
_L6470_INIT_CHIP(X2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Y(L6470)
|
|
||||||
_L6470_INIT_CHIP(Y);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Y2(L6470)
|
|
||||||
_L6470_INIT_CHIP(Y2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z(L6470)
|
|
||||||
_L6470_INIT_CHIP(Z);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z2(L6470)
|
|
||||||
_L6470_INIT_CHIP(Z2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_Z3(L6470)
|
|
||||||
_L6470_INIT_CHIP(Z3);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E0(L6470)
|
|
||||||
_L6470_INIT_CHIP(E0);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E1(L6470)
|
|
||||||
_L6470_INIT_CHIP(E1);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E2(L6470)
|
|
||||||
_L6470_INIT_CHIP(E2);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E3(L6470)
|
|
||||||
_L6470_INIT_CHIP(E3);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E4(L6470)
|
|
||||||
_L6470_INIT_CHIP(E4);
|
|
||||||
#endif
|
|
||||||
#if AXIS_DRIVER_TYPE_E5(L6470)
|
|
||||||
_L6470_INIT_CHIP(E5);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // L6470
|
|
@ -1,176 +0,0 @@
|
|||||||
/**
|
|
||||||
* Marlin 3D Printer Firmware
|
|
||||||
* Copyright (c) 2019 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/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
/**
|
|
||||||
* stepper/L6470.h
|
|
||||||
* Stepper driver indirection for L6470 drivers
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "../../inc/MarlinConfig.h"
|
|
||||||
#include "../../libs/L6470/L6470_Marlin.h"
|
|
||||||
|
|
||||||
// L6470 has STEP on normal pins, but DIR/ENABLE via SPI
|
|
||||||
#define L6470_WRITE_DIR_COMMAND(STATE,Q) do{ L6470_dir_commands[Q] = (STATE ? dSPIN_STEP_CLOCK_REV : dSPIN_STEP_CLOCK_FWD); }while(0)
|
|
||||||
|
|
||||||
// X Stepper
|
|
||||||
#if AXIS_DRIVER_TYPE_X(L6470)
|
|
||||||
extern L6470 stepperX;
|
|
||||||
#define X_ENABLE_INIT NOOP
|
|
||||||
#define X_ENABLE_WRITE(STATE) NOOP
|
|
||||||
#define X_ENABLE_READ() (stepperX.getStatus() & STATUS_HIZ)
|
|
||||||
#define X_DIR_INIT NOOP
|
|
||||||
#define X_DIR_WRITE(STATE) L6470_WRITE_DIR_COMMAND(STATE,X)
|
|
||||||
#define X_DIR_READ() (stepperX.getStatus() & STATUS_DIR)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Y Stepper
|
|
||||||
#if AXIS_DRIVER_TYPE_Y(L6470)
|
|
||||||
extern L6470 stepperY;
|
|
||||||
#define Y_ENABLE_INIT NOOP
|
|
||||||
#define Y_ENABLE_WRITE(STATE) NOOP
|
|
||||||
#define Y_ENABLE_READ() (stepperY.getStatus() & STATUS_HIZ)
|
|
||||||
#define Y_DIR_INIT NOOP
|
|
||||||
#define Y_DIR_WRITE(STATE) L6470_WRITE_DIR_COMMAND(STATE,Y)
|
|
||||||
#define Y_DIR_READ() (stepperY.getStatus() & STATUS_DIR)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Z Stepper
|
|
||||||
#if AXIS_DRIVER_TYPE_Z(L6470)
|
|
||||||
extern L6470 stepperZ;
|
|
||||||
#define Z_ENABLE_INIT NOOP
|
|
||||||
#define Z_ENABLE_WRITE(STATE) NOOP
|
|
||||||
#define Z_ENABLE_READ() (stepperZ.getStatus() & STATUS_HIZ)
|
|
||||||
#define Z_DIR_INIT NOOP
|
|
||||||
#define Z_DIR_WRITE(STATE) L6470_WRITE_DIR_COMMAND(STATE,Z)
|
|
||||||
#define Z_DIR_READ() (stepperZ.getStatus() & STATUS_DIR)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// X2 Stepper
|
|
||||||
#if HAS_X2_ENABLE && AXIS_DRIVER_TYPE_X2(L6470)
|
|
||||||
extern L6470 stepperX2;
|
|
||||||
#define X2_ENABLE_INIT NOOP
|
|
||||||
#define X2_ENABLE_WRITE(STATE) NOOP
|
|
||||||
#define X2_ENABLE_READ() (stepperX2.getStatus() & STATUS_HIZ)
|
|
||||||
#define X2_DIR_INIT NOOP
|
|
||||||
#define X2_DIR_WRITE(STATE) L6470_WRITE_DIR_COMMAND(STATE,X2)
|
|
||||||
#define X2_DIR_READ() (stepperX2.getStatus() & STATUS_DIR)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Y2 Stepper
|
|
||||||
#if HAS_Y2_ENABLE && AXIS_DRIVER_TYPE_Y2(L6470)
|
|
||||||
extern L6470 stepperY2;
|
|
||||||
#define Y2_ENABLE_INIT NOOP
|
|
||||||
#define Y2_ENABLE_WRITE(STATE) NOOP
|
|
||||||
#define Y2_ENABLE_READ() (stepperY2.getStatus() & STATUS_HIZ)
|
|
||||||
#define Y2_DIR_INIT NOOP
|
|
||||||
#define Y2_DIR_WRITE(STATE) L6470_WRITE_DIR_COMMAND(STATE,Y2)
|
|
||||||
#define Y2_DIR_READ() (stepperY2.getStatus() & STATUS_DIR)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Z2 Stepper
|
|
||||||
#if HAS_Z2_ENABLE && AXIS_DRIVER_TYPE_Z2(L6470)
|
|
||||||
extern L6470 stepperZ2;
|
|
||||||
#define Z2_ENABLE_INIT NOOP
|
|
||||||
#define Z2_ENABLE_WRITE(STATE) NOOP
|
|
||||||
#define Z2_ENABLE_READ() (stepperZ2.getStatus() & STATUS_HIZ)
|
|
||||||
#define Z2_DIR_INIT NOOP
|
|
||||||
#define Z2_DIR_WRITE(STATE) L6470_WRITE_DIR_COMMAND(STATE,Z2)
|
|
||||||
#define Z2_DIR_READ() (stepperZ2.getStatus() & STATUS_DIR)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Z3 Stepper
|
|
||||||
#if HAS_Z3_ENABLE && AXIS_DRIVER_TYPE_Z3(L6470)
|
|
||||||
extern L6470 stepperZ3;
|
|
||||||
#define Z3_ENABLE_INIT NOOP
|
|
||||||
#define Z3_ENABLE_WRITE(STATE) NOOP
|
|
||||||
#define Z3_ENABLE_READ() (stepperZ3.getStatus() & STATUS_HIZ)
|
|
||||||
#define Z3_DIR_INIT NOOP
|
|
||||||
#define Z3_DIR_WRITE(STATE) L6470_WRITE_DIR_COMMAND(STATE,Z3)
|
|
||||||
#define Z3_DIR_READ() (stepperZ3.getStatus() & STATUS_DIR)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// E0 Stepper
|
|
||||||
#if AXIS_DRIVER_TYPE_E0(L6470)
|
|
||||||
extern L6470 stepperE0;
|
|
||||||
#define E0_ENABLE_INIT NOOP
|
|
||||||
#define E0_ENABLE_WRITE(STATE) NOOP
|
|
||||||
#define E0_ENABLE_READ() (stepperE0.getStatus() & STATUS_HIZ)
|
|
||||||
#define E0_DIR_INIT NOOP
|
|
||||||
#define E0_DIR_WRITE(STATE) L6470_WRITE_DIR_COMMAND(STATE,E0)
|
|
||||||
#define E0_DIR_READ() (stepperE0.getStatus() & STATUS_DIR)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// E1 Stepper
|
|
||||||
#if AXIS_DRIVER_TYPE_E1(L6470)
|
|
||||||
extern L6470 stepperE1;
|
|
||||||
#define E1_ENABLE_INIT NOOP
|
|
||||||
#define E1_ENABLE_WRITE(STATE) NOOP
|
|
||||||
#define E1_ENABLE_READ() (stepperE1.getStatus() & STATUS_HIZ)
|
|
||||||
#define E1_DIR_INIT NOOP
|
|
||||||
#define E1_DIR_WRITE(STATE) L6470_WRITE_DIR_COMMAND(STATE,E1)
|
|
||||||
#define E1_DIR_READ() (stepperE1.getStatus() & STATUS_DIR)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// E2 Stepper
|
|
||||||
#if AXIS_DRIVER_TYPE_E2(L6470)
|
|
||||||
extern L6470 stepperE2;
|
|
||||||
#define E2_ENABLE_INIT NOOP
|
|
||||||
#define E2_ENABLE_WRITE(STATE) NOOP
|
|
||||||
#define E2_ENABLE_READ() (stepperE2.getStatus() & STATUS_HIZ)
|
|
||||||
#define E2_DIR_INIT NOOP
|
|
||||||
#define E2_DIR_WRITE(STATE) L6470_WRITE_DIR_COMMAND(STATE,E2)
|
|
||||||
#define E2_DIR_READ() (stepperE2.getStatus() & STATUS_DIR)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// E3 Stepper
|
|
||||||
#if AXIS_DRIVER_TYPE_E3(L6470)
|
|
||||||
extern L6470 stepperE3;
|
|
||||||
#define E3_ENABLE_INIT NOOP
|
|
||||||
#define E3_ENABLE_WRITE(STATE) NOOP
|
|
||||||
#define E3_ENABLE_READ() (stepperE3.getStatus() & STATUS_HIZ)
|
|
||||||
#define E3_DIR_INIT NOOP
|
|
||||||
#define E3_DIR_WRITE(STATE) L6470_WRITE_DIR_COMMAND(STATE,E3)
|
|
||||||
#define E3_DIR_READ() (stepperE3.getStatus() & STATUS_DIR)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// E4 Stepper
|
|
||||||
#if AXIS_DRIVER_TYPE_E4(L6470)
|
|
||||||
extern L6470 stepperE4;
|
|
||||||
#define E4_ENABLE_INIT NOOP
|
|
||||||
#define E4_ENABLE_WRITE(STATE) NOOP
|
|
||||||
#define E4_ENABLE_READ() (stepperE4.getStatus() & STATUS_HIZ)
|
|
||||||
#define E4_DIR_INIT NOOP
|
|
||||||
#define E4_DIR_WRITE(STATE) L6470_WRITE_DIR_COMMAND(STATE,E4)
|
|
||||||
#define E4_DIR_READ() (stepperE4.getStatus() & STATUS_DIR)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// E5 Stepper
|
|
||||||
#if AXIS_DRIVER_TYPE_E5(L6470)
|
|
||||||
extern L6470 stepperE5;
|
|
||||||
#define E5_ENABLE_INIT NOOP
|
|
||||||
#define E5_ENABLE_WRITE(STATE) NOOP
|
|
||||||
#define E5_ENABLE_READ() (stepperE5.getStatus() & STATUS_HIZ)
|
|
||||||
#define E5_DIR_INIT NOOP
|
|
||||||
#define E5_DIR_WRITE(STATE) L6470_WRITE_DIR_COMMAND(STATE,E5)
|
|
||||||
#define E5_DIR_READ() (stepperE5.getStatus() & STATUS_DIR)
|
|
||||||
#endif
|
|
@ -0,0 +1,210 @@
|
|||||||
|
/**
|
||||||
|
* Marlin 3D Printer Firmware
|
||||||
|
* Copyright (c) 2019 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stepper/L64xx.cpp
|
||||||
|
* Stepper driver indirection for L64XX drivers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../../inc/MarlinConfig.h"
|
||||||
|
|
||||||
|
#if HAS_L64XX
|
||||||
|
|
||||||
|
#include "L64xx.h"
|
||||||
|
|
||||||
|
#if AXIS_IS_L64XX(X)
|
||||||
|
L64XX_CLASS(X) stepperX(L6470_CHAIN_SS_PIN);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(X2)
|
||||||
|
L64XX_CLASS(X2) stepperX2(L6470_CHAIN_SS_PIN);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Y)
|
||||||
|
L64XX_CLASS(Y) stepperY(L6470_CHAIN_SS_PIN);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Y2)
|
||||||
|
L64XX_CLASS(Y2) stepperY2(L6470_CHAIN_SS_PIN);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z)
|
||||||
|
L64XX_CLASS(Z) stepperZ(L6470_CHAIN_SS_PIN);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z2)
|
||||||
|
L64XX_CLASS(Z2) stepperZ2(L6470_CHAIN_SS_PIN);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z3)
|
||||||
|
L64XX_CLASS(Z3) stepperZ3(L6470_CHAIN_SS_PIN);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E0)
|
||||||
|
L64XX_CLASS(E0) stepperE0(L6470_CHAIN_SS_PIN);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E1)
|
||||||
|
L64XX_CLASS(E1) stepperE1(L6470_CHAIN_SS_PIN);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E2)
|
||||||
|
L64XX_CLASS(E2) stepperE2(L6470_CHAIN_SS_PIN);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E3)
|
||||||
|
L64XX_CLASS(E3) stepperE3(L6470_CHAIN_SS_PIN);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E4)
|
||||||
|
L64XX_CLASS(E4) stepperE4(L6470_CHAIN_SS_PIN);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E5)
|
||||||
|
L64XX_CLASS(E5) stepperE5(L6470_CHAIN_SS_PIN);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Not using L64XX class init method because it
|
||||||
|
// briefly sends power to the steppers
|
||||||
|
|
||||||
|
inline void L6470_init_chip(L64XX &st, const int ms, const int oc, const int sc, const int mv, const int slew_rate) {
|
||||||
|
st.set_handlers(L64xxManager.spi_init, L64xxManager.transfer_single, L64xxManager.transfer_chain); // specify which external SPI routines to use
|
||||||
|
switch (st.L6470_status_layout) {
|
||||||
|
case L6470_STATUS_LAYOUT: {
|
||||||
|
st.resetDev();
|
||||||
|
st.softFree();
|
||||||
|
st.SetParam(st.L64XX_CONFIG, CONFIG_PWM_DIV_1 | CONFIG_PWM_MUL_2 | CONFIG_OC_SD_DISABLE | CONFIG_VS_COMP_DISABLE | CONFIG_SW_HARD_STOP | CONFIG_INT_16MHZ);
|
||||||
|
st.SetParam(L6470_KVAL_RUN, 0xFF);
|
||||||
|
st.SetParam(L6470_KVAL_ACC, 0xFF);
|
||||||
|
st.SetParam(L6470_KVAL_DEC, 0xFF);
|
||||||
|
st.setMicroSteps(ms);
|
||||||
|
st.setOverCurrent(oc);
|
||||||
|
st.setStallCurrent(sc);
|
||||||
|
st.SetParam(L6470_KVAL_HOLD, mv);
|
||||||
|
st.SetParam(L6470_ABS_POS, 0);
|
||||||
|
uint32_t config_temp = st.GetParam(st.L64XX_CONFIG);
|
||||||
|
config_temp &= ~CONFIG_POW_SR;
|
||||||
|
switch (slew_rate) {
|
||||||
|
case 0: st.SetParam(st.L64XX_CONFIG, config_temp | CONFIG_SR_75V_us); break;
|
||||||
|
default:
|
||||||
|
case 1: st.SetParam(st.L64XX_CONFIG, config_temp | CONFIG_SR_110V_us); break;
|
||||||
|
case 3:
|
||||||
|
case 2: st.SetParam(st.L64XX_CONFIG, config_temp | CONFIG_SR_260V_us); break;
|
||||||
|
}
|
||||||
|
st.getStatus();
|
||||||
|
st.getStatus();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case L6474_STATUS_LAYOUT: {
|
||||||
|
st.free();
|
||||||
|
//st.SetParam(st.L64XX_CONFIG, CONFIG_PWM_DIV_1 | CONFIG_PWM_MUL_2 | CONFIG_OC_SD_DISABLE | CONFIG_VS_COMP_DISABLE | CONFIG_SW_HARD_STOP | CONFIG_INT_16MHZ);
|
||||||
|
//st.SetParam(L6474_TVAL, 0xFF);
|
||||||
|
st.setMicroSteps(ms);
|
||||||
|
st.setOverCurrent(oc);
|
||||||
|
st.setTVALCurrent(sc);
|
||||||
|
st.SetParam(L6470_ABS_POS, 0);
|
||||||
|
uint32_t config_temp = st.GetParam(st.L64XX_CONFIG);
|
||||||
|
config_temp &= ~CONFIG_POW_SR & ~CONFIG_EN_TQREG; // clear out slew rate and set current to be controlled by TVAL register
|
||||||
|
switch (slew_rate) {
|
||||||
|
case 0: st.SetParam(st.L64XX_CONFIG, config_temp | CONFIG_SR_75V_us); break;
|
||||||
|
default:
|
||||||
|
case 1: st.SetParam(st.L64XX_CONFIG, config_temp | CONFIG_SR_110V_us); break;
|
||||||
|
case 3:
|
||||||
|
case 2: st.SetParam(st.L64XX_CONFIG, config_temp | CONFIG_SR_260V_us); break;
|
||||||
|
//case 0: st.SetParam(st.L64XX_CONFIG, 0x2E88 | CONFIG_EN_TQREG | CONFIG_SR_75V_us); break;
|
||||||
|
//default:
|
||||||
|
//case 1: st.SetParam(st.L64XX_CONFIG, 0x2E88 | CONFIG_EN_TQREG | CONFIG_SR_110V_us); break;
|
||||||
|
//case 3:
|
||||||
|
//case 2: st.SetParam(st.L64XX_CONFIG, 0x2E88 | CONFIG_EN_TQREG | CONFIG_SR_260V_us); break;
|
||||||
|
|
||||||
|
//case 0: st.SetParam(st.L64XX_CONFIG, 0x2E88 ); break;
|
||||||
|
//default:
|
||||||
|
//case 1: st.SetParam(st.L64XX_CONFIG, 0x2E88 ); break;
|
||||||
|
//case 3:
|
||||||
|
//case 2: st.SetParam(st.L64XX_CONFIG, 0x2E88 ); break;
|
||||||
|
}
|
||||||
|
st.getStatus();
|
||||||
|
st.getStatus();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case L6480_STATUS_LAYOUT: {
|
||||||
|
st.resetDev();
|
||||||
|
st.softFree();
|
||||||
|
st.SetParam(st.L64XX_CONFIG, CONFIG_PWM_DIV_1 | CONFIG_PWM_MUL_2 | CONFIG_OC_SD_DISABLE | CONFIG_VS_COMP_DISABLE | CONFIG_SW_HARD_STOP | CONFIG_INT_16MHZ);
|
||||||
|
st.SetParam(L6470_KVAL_RUN, 0xFF);
|
||||||
|
st.SetParam(L6470_KVAL_ACC, 0xFF);
|
||||||
|
st.SetParam(L6470_KVAL_DEC, 0xFF);
|
||||||
|
st.setMicroSteps(ms);
|
||||||
|
st.setOverCurrent(oc);
|
||||||
|
st.setStallCurrent(sc);
|
||||||
|
st.SetParam(+-L6470_KVAL_HOLD, mv);
|
||||||
|
st.SetParam(L6470_ABS_POS, 0);
|
||||||
|
st.SetParam(st.L64XX_CONFIG,(st.GetParam(st.L64XX_CONFIG) | PWR_VCC_7_5V));
|
||||||
|
st.getStatus(); // must clear out status bits before can set slew rate
|
||||||
|
st.getStatus();
|
||||||
|
switch (slew_rate) {
|
||||||
|
case 0: st.SetParam(L6470_GATECFG1, CONFIG1_SR_220V_us); st.SetParam(L6470_GATECFG2, CONFIG2_SR_220V_us); break;
|
||||||
|
default:
|
||||||
|
case 1: st.SetParam(L6470_GATECFG1, CONFIG1_SR_400V_us); st.SetParam(L6470_GATECFG2, CONFIG2_SR_400V_us); break;
|
||||||
|
case 2: st.SetParam(L6470_GATECFG1, CONFIG1_SR_520V_us); st.SetParam(L6470_GATECFG2, CONFIG2_SR_520V_us); break;
|
||||||
|
case 3: st.SetParam(L6470_GATECFG1, CONFIG1_SR_980V_us); st.SetParam(L6470_GATECFG2, CONFIG2_SR_980V_us); break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define L6470_INIT_CHIP(Q) L6470_init_chip(stepper##Q, Q##_MICROSTEPS, Q##_OVERCURRENT, Q##_STALLCURRENT, Q##_MAX_VOLTAGE, Q##_SLEW_RATE)
|
||||||
|
|
||||||
|
void L64XX_Marlin::init_to_defaults() {
|
||||||
|
#if AXIS_IS_L64XX(X)
|
||||||
|
L6470_INIT_CHIP(X);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(X2)
|
||||||
|
L6470_INIT_CHIP(X2);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Y)
|
||||||
|
L6470_INIT_CHIP(Y);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Y2)
|
||||||
|
L6470_INIT_CHIP(Y2);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z)
|
||||||
|
L6470_INIT_CHIP(Z);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z2)
|
||||||
|
L6470_INIT_CHIP(Z2);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(Z3)
|
||||||
|
L6470_INIT_CHIP(Z3);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E0)
|
||||||
|
L6470_INIT_CHIP(E0);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E1)
|
||||||
|
L6470_INIT_CHIP(E1);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E2)
|
||||||
|
L6470_INIT_CHIP(E2);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E3)
|
||||||
|
L6470_INIT_CHIP(E3);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E4)
|
||||||
|
L6470_INIT_CHIP(E4);
|
||||||
|
#endif
|
||||||
|
#if AXIS_IS_L64XX(E5)
|
||||||
|
L6470_INIT_CHIP(E5);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // HAS_L64XX
|
@ -0,0 +1,263 @@
|
|||||||
|
/**
|
||||||
|
* Marlin 3D Printer Firmware
|
||||||
|
* Copyright (c) 2019 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stepper/L64xx.h
|
||||||
|
* Stepper driver indirection for L64XX drivers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../../inc/MarlinConfig.h"
|
||||||
|
#include "../../libs/L64XX/L64XX_Marlin.h"
|
||||||
|
|
||||||
|
// Convert option names to L64XX classes
|
||||||
|
#define CLASS_L6470 L6470
|
||||||
|
#define CLASS_L6474 L6474
|
||||||
|
#define CLASS_POWERSTEP01 powerSTEP01
|
||||||
|
|
||||||
|
#define __L64XX_CLASS(TYPE) CLASS_##TYPE
|
||||||
|
#define _L64XX_CLASS(TYPE) __L64XX_CLASS(TYPE)
|
||||||
|
#define L64XX_CLASS(ST) _L64XX_CLASS(ST##_DRIVER_TYPE)
|
||||||
|
|
||||||
|
#define L6474_DIR_WRITE(A,STATE) do{ L64xxManager.dir_commands[A] = dSPIN_L6474_ENABLE; WRITE(A##_DIR_PIN, STATE); }while(0)
|
||||||
|
#define L64XX_DIR_WRITE(A,STATE) do{ L64xxManager.dir_commands[A] = (STATE) ? dSPIN_STEP_CLOCK_REV : dSPIN_STEP_CLOCK_FWD; }while(0)
|
||||||
|
|
||||||
|
// X Stepper
|
||||||
|
#if AXIS_IS_L64XX(X)
|
||||||
|
extern L64XX_CLASS(X) stepperX;
|
||||||
|
#define X_ENABLE_INIT NOOP
|
||||||
|
#define X_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperX.free())
|
||||||
|
#define X_ENABLE_READ (stepperX.getStatus() & STATUS_HIZ)
|
||||||
|
#if AXIS_DRIVER_TYPE_X(L6474)
|
||||||
|
#define X_DIR_INIT SET_OUTPUT(X_DIR_PIN)
|
||||||
|
#define X_DIR_WRITE(STATE) L6474_DIR_WRITE(X, STATE)
|
||||||
|
#define X_DIR_READ READ(X_DIR_PIN)
|
||||||
|
#else
|
||||||
|
#define X_DIR_INIT NOOP
|
||||||
|
#define X_DIR_WRITE(STATE) L64XX_DIR_WRITE(X, STATE)
|
||||||
|
#define X_DIR_READ (stepper##X.getStatus() & STATUS_DIR);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Y Stepper
|
||||||
|
#if AXIS_IS_L64XX(Y)
|
||||||
|
extern L64XX_CLASS(Y) stepperY;
|
||||||
|
#define Y_ENABLE_INIT NOOP
|
||||||
|
#define Y_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperY.free())
|
||||||
|
#define Y_ENABLE_READ (stepperY.getStatus() & STATUS_HIZ)
|
||||||
|
#if AXIS_DRIVER_TYPE_Y(L6474)
|
||||||
|
#define Y_DIR_INIT SET_OUTPUT(Y_DIR_PIN)
|
||||||
|
#define Y_DIR_WRITE(STATE) L6474_DIR_WRITE(Y, STATE)
|
||||||
|
#define Y_DIR_READ READ(Y_DIR_PIN)
|
||||||
|
#else
|
||||||
|
#define Y_DIR_INIT NOOP
|
||||||
|
#define Y_DIR_WRITE(STATE) L64XX_DIR_WRITE(Y, STATE)
|
||||||
|
#define Y_DIR_READ (stepper##Y.getStatus() & STATUS_DIR);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Z Stepper
|
||||||
|
#if AXIS_IS_L64XX(Z)
|
||||||
|
extern L64XX_CLASS(Z) stepperZ;
|
||||||
|
#define Z_ENABLE_INIT NOOP
|
||||||
|
#define Z_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperZ.free())
|
||||||
|
#define Z_ENABLE_READ (stepperZ.getStatus() & STATUS_HIZ)
|
||||||
|
#if AXIS_DRIVER_TYPE_Z(L6474)
|
||||||
|
#define Z_DIR_INIT SET_OUTPUT(Z_DIR_PIN)
|
||||||
|
#define Z_DIR_WRITE(STATE) L6474_DIR_WRITE(Z, STATE)
|
||||||
|
#define Z_DIR_READ READ(Z_DIR_PIN)
|
||||||
|
#else
|
||||||
|
#define Z_DIR_INIT NOOP
|
||||||
|
#define Z_DIR_WRITE(STATE) L64XX_DIR_WRITE(Z, STATE)
|
||||||
|
#define Z_DIR_READ (stepper##Z.getStatus() & STATUS_DIR);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// X2 Stepper
|
||||||
|
#if HAS_X2_ENABLE && AXIS_IS_L64XX(X2)
|
||||||
|
extern L64XX_CLASS(X2) stepperX2;
|
||||||
|
#define X2_ENABLE_INIT NOOP
|
||||||
|
#define X2_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperX2.free())
|
||||||
|
#define X2_ENABLE_READ (stepperX2.getStatus() & STATUS_HIZ)
|
||||||
|
#if AXIS_DRIVER_TYPE_X2(L6474)
|
||||||
|
#define X2_DIR_INIT SET_OUTPUT(X2_DIR_PIN)
|
||||||
|
#define X2_DIR_WRITE(STATE) L6474_DIR_WRITE(X2, STATE)
|
||||||
|
#define X2_DIR_READ READ(X2_DIR_PIN)
|
||||||
|
#else
|
||||||
|
#define X2_DIR_INIT NOOP
|
||||||
|
#define X2_DIR_WRITE(STATE) L64XX_DIR_WRITE(X2, STATE)
|
||||||
|
#define X2_DIR_READ (stepper##X2.getStatus() & STATUS_DIR);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Y2 Stepper
|
||||||
|
#if HAS_Y2_ENABLE && AXIS_IS_L64XX(Y2)
|
||||||
|
extern L64XX_CLASS(Y2) stepperY2;
|
||||||
|
#define Y2_ENABLE_INIT NOOP
|
||||||
|
#define Y2_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperY2.free())
|
||||||
|
#define Y2_ENABLE_READ (stepperY2.getStatus() & STATUS_HIZ)
|
||||||
|
#if AXIS_DRIVER_TYPE_Y2(L6474)
|
||||||
|
#define Y2_DIR_INIT SET_OUTPUT(Y2_DIR_PIN)
|
||||||
|
#define Y2_DIR_WRITE(STATE) L6474_DIR_WRITE(Y2, STATE)
|
||||||
|
#define Y2_DIR_READ READ(Y2_DIR_PIN)
|
||||||
|
#else
|
||||||
|
#define Y2_DIR_INIT NOOP
|
||||||
|
#define Y2_DIR_WRITE(STATE) L64XX_DIR_WRITE(Y2, STATE)
|
||||||
|
#define Y2_DIR_READ (stepper##Y2.getStatus() & STATUS_DIR);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Z2 Stepper
|
||||||
|
#if HAS_Z2_ENABLE && AXIS_IS_L64XX(Z2)
|
||||||
|
extern L64XX_CLASS(Z2) stepperZ2;
|
||||||
|
#define Z2_ENABLE_INIT NOOP
|
||||||
|
#define Z2_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperZ2.free())
|
||||||
|
#define Z2_ENABLE_READ (stepperZ2.getStatus() & STATUS_HIZ)
|
||||||
|
#if AXIS_DRIVER_TYPE_Z2(L6474)
|
||||||
|
#define Z2_DIR_INIT SET_OUTPUT(Z2_DIR_PIN)
|
||||||
|
#define Z2_DIR_WRITE(STATE) L6474_DIR_WRITE(Z2, STATE)
|
||||||
|
#define Z2_DIR_READ READ(Z2_DIR_PIN)
|
||||||
|
#else
|
||||||
|
#define Z2_DIR_INIT NOOP
|
||||||
|
#define Z2_DIR_WRITE(STATE) L64XX_DIR_WRITE(Z2, STATE)
|
||||||
|
#define Z2_DIR_READ (stepper##Z2.getStatus() & STATUS_DIR);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Z3 Stepper
|
||||||
|
#if HAS_Z3_ENABLE && AXIS_IS_L64XX(Z3)
|
||||||
|
extern L64XX_CLASS(Z3) stepperZ3;
|
||||||
|
#define Z3_ENABLE_INIT NOOP
|
||||||
|
#define Z3_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperZ3.free())
|
||||||
|
#define Z3_ENABLE_READ (stepperZ3.getStatus() & STATUS_HIZ)
|
||||||
|
#if AXIS_DRIVER_TYPE_Z3(L6474)
|
||||||
|
#define Z3_DIR_INIT SET_OUTPUT(Z3_DIR_PIN)
|
||||||
|
#define Z3_DIR_WRITE(STATE) L6474_DIR_WRITE(Z3, STATE)
|
||||||
|
#define Z3_DIR_READ READ(Z3_DIR_PIN)
|
||||||
|
#else
|
||||||
|
#define Z3_DIR_INIT NOOP
|
||||||
|
#define Z3_DIR_WRITE(STATE) L64XX_DIR_WRITE(Z3, STATE)
|
||||||
|
#define Z3_DIR_READ (stepper##Z3.getStatus() & STATUS_DIR);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// E0 Stepper
|
||||||
|
#if AXIS_IS_L64XX(E0)
|
||||||
|
extern L64XX_CLASS(E0) stepperE0;
|
||||||
|
#define E0_ENABLE_INIT NOOP
|
||||||
|
#define E0_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperE0.free())
|
||||||
|
#define E0_ENABLE_READ (stepperE0.getStatus() & STATUS_HIZ)
|
||||||
|
#if AXIS_DRIVER_TYPE_E0(L6474)
|
||||||
|
#define E0_DIR_INIT SET_OUTPUT(E0_DIR_PIN)
|
||||||
|
#define E0_DIR_WRITE(STATE) L6474_DIR_WRITE(E0, STATE)
|
||||||
|
#define E0_DIR_READ READ(E0_DIR_PIN)
|
||||||
|
#else
|
||||||
|
#define E0_DIR_INIT NOOP
|
||||||
|
#define E0_DIR_WRITE(STATE) L64XX_DIR_WRITE(E0, STATE)
|
||||||
|
#define E0_DIR_READ (stepper##E0.getStatus() & STATUS_DIR);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// E1 Stepper
|
||||||
|
#if AXIS_IS_L64XX(E1)
|
||||||
|
extern L64XX_CLASS(E1) stepperE1;
|
||||||
|
#define E1_ENABLE_INIT NOOP
|
||||||
|
#define E1_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperE1.free())
|
||||||
|
#define E1_ENABLE_READ (stepperE1.getStatus() & STATUS_HIZ)
|
||||||
|
#if AXIS_DRIVER_TYPE_E1(L6474)
|
||||||
|
#define E1_DIR_INIT SET_OUTPUT(E1_DIR_PIN)
|
||||||
|
#define E1_DIR_WRITE(STATE) L6474_DIR_WRITE(E1, STATE)
|
||||||
|
#define E1_DIR_READ READ(E1_DIR_PIN)
|
||||||
|
#else
|
||||||
|
#define E1_DIR_INIT NOOP
|
||||||
|
#define E1_DIR_WRITE(STATE) L64XX_DIR_WRITE(E1, STATE)
|
||||||
|
#define E1_DIR_READ (stepper##E1.getStatus() & STATUS_DIR);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// E2 Stepper
|
||||||
|
#if AXIS_IS_L64XX(E2)
|
||||||
|
extern L64XX_CLASS(E2) stepperE2;
|
||||||
|
#define E2_ENABLE_INIT NOOP
|
||||||
|
#define E2_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperE2.free())
|
||||||
|
#define E2_ENABLE_READ (stepperE2.getStatus() & STATUS_HIZ)
|
||||||
|
#if AXIS_DRIVER_TYPE_E2(L6474)
|
||||||
|
#define E2_DIR_INIT SET_OUTPUT(E2_DIR_PIN)
|
||||||
|
#define E2_DIR_WRITE(STATE) L6474_DIR_WRITE(E2, STATE)
|
||||||
|
#define E2_DIR_READ READ(E2_DIR_PIN)
|
||||||
|
#else
|
||||||
|
#define E2_DIR_INIT NOOP
|
||||||
|
#define E2_DIR_WRITE(STATE) L64XX_DIR_WRITE(E2, STATE)
|
||||||
|
#define E2_DIR_READ (stepper##E2.getStatus() & STATUS_DIR);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// E3 Stepper
|
||||||
|
#if AXIS_IS_L64XX(E3)
|
||||||
|
extern L64XX_CLASS(E3) stepperE3;
|
||||||
|
#define E3_ENABLE_INIT NOOP
|
||||||
|
#define E3_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperE3.free())
|
||||||
|
#define E3_ENABLE_READ (stepperE3.getStatus() & STATUS_HIZ)
|
||||||
|
#if AXIS_DRIVER_TYPE_E3(L6474)
|
||||||
|
#define E3_DIR_INIT SET_OUTPUT(E3_DIR_PIN)
|
||||||
|
#define E3_DIR_WRITE(STATE) L6474_DIR_WRITE(E3, STATE)
|
||||||
|
#define E3_DIR_READ READ(E3_DIR_PIN)
|
||||||
|
#else
|
||||||
|
#define E3_DIR_INIT NOOP
|
||||||
|
#define E3_DIR_WRITE(STATE) L64XX_DIR_WRITE(E3, STATE)
|
||||||
|
#define E3_DIR_READ (stepper##E3.getStatus() & STATUS_DIR);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// E4 Stepper
|
||||||
|
#if AXIS_IS_L64XX(E4)
|
||||||
|
extern L64XX_CLASS(E4) stepperE4;
|
||||||
|
#define E4_ENABLE_INIT NOOP
|
||||||
|
#define E4_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperE4.free())
|
||||||
|
#define E4_ENABLE_READ (stepperE4.getStatus() & STATUS_HIZ)
|
||||||
|
#if AXIS_DRIVER_TYPE_E4(L6474)
|
||||||
|
#define E4_DIR_INIT SET_OUTPUT(E4_DIR_PIN)
|
||||||
|
#define E4_DIR_WRITE(STATE) L6474_DIR_WRITE(E4, STATE)
|
||||||
|
#define E4_DIR_READ READ(E4_DIR_PIN)
|
||||||
|
#else
|
||||||
|
#define E4_DIR_INIT NOOP
|
||||||
|
#define E4_DIR_WRITE(STATE) L64XX_DIR_WRITE(E4, STATE)
|
||||||
|
#define E4_DIR_READ (stepper##E4.getStatus() & STATUS_DIR);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// E5 Stepper
|
||||||
|
#if AXIS_IS_L64XX(E5)
|
||||||
|
extern L64XX_CLASS(E5) stepperE5;
|
||||||
|
#define E5_ENABLE_INIT NOOP
|
||||||
|
#define E5_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperE5.free())
|
||||||
|
#define E5_ENABLE_READ (stepperE5.getStatus() & STATUS_HIZ)
|
||||||
|
#if AXIS_DRIVER_TYPE_E5(L6474)
|
||||||
|
#define E5_DIR_INIT SET_OUTPUT(E5_DIR_PIN)
|
||||||
|
#define E5_DIR_WRITE(STATE) L6474_DIR_WRITE(E5, STATE)
|
||||||
|
#define E5_DIR_READ READ(E5_DIR_PIN)
|
||||||
|
#else
|
||||||
|
#define E5_DIR_INIT NOOP
|
||||||
|
#define E5_DIR_WRITE(STATE) L64XX_DIR_WRITE(E5, STATE)
|
||||||
|
#define E5_DIR_READ (stepper##E5.getStatus() & STATUS_DIR);
|
||||||
|
#endif
|
||||||
|
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue