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