update code base to Marlin 2.0.9.2

This commit is contained in:
Stefan Kalscheuer
2021-10-03 18:57:12 +02:00
parent b9d7ba838e
commit 7077da3591
2617 changed files with 332093 additions and 103438 deletions

File diff suppressed because it is too large Load Diff

84
Marlin/src/module/delta.cpp Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
@@ -34,7 +34,7 @@
// For homing:
#include "planner.h"
#include "endstops.h"
#include "../lcd/ultralcd.h"
#include "../lcd/marlinui.h"
#include "../MarlinCore.h"
#if HAS_BED_PROBE
@@ -54,11 +54,12 @@ float delta_height;
abc_float_t delta_endstop_adj{0};
float delta_radius,
delta_diagonal_rod,
delta_segments_per_second;
segments_per_second;
abc_float_t delta_tower_angle_trim;
xy_float_t delta_tower[ABC];
abc_float_t delta_diagonal_rod_2_tower;
float delta_clip_start_height = Z_MAX_POS;
abc_float_t delta_diagonal_rod_trim;
float delta_safe_distance_from_top();
@@ -67,43 +68,20 @@ float delta_safe_distance_from_top();
* settings have been changed (e.g., by M665).
*/
void recalc_delta_settings() {
constexpr abc_float_t trt = DELTA_RADIUS_TRIM_TOWER,
drt = DELTA_DIAGONAL_ROD_TRIM_TOWER;
constexpr abc_float_t trt = DELTA_RADIUS_TRIM_TOWER;
delta_tower[A_AXIS].set(cos(RADIANS(210 + delta_tower_angle_trim.a)) * (delta_radius + trt.a), // front left tower
sin(RADIANS(210 + delta_tower_angle_trim.a)) * (delta_radius + trt.a));
delta_tower[B_AXIS].set(cos(RADIANS(330 + delta_tower_angle_trim.b)) * (delta_radius + trt.b), // front right tower
sin(RADIANS(330 + delta_tower_angle_trim.b)) * (delta_radius + trt.b));
delta_tower[C_AXIS].set(cos(RADIANS( 90 + delta_tower_angle_trim.c)) * (delta_radius + trt.c), // back middle tower
sin(RADIANS( 90 + delta_tower_angle_trim.c)) * (delta_radius + trt.c));
delta_diagonal_rod_2_tower.set(sq(delta_diagonal_rod + drt.a),
sq(delta_diagonal_rod + drt.b),
sq(delta_diagonal_rod + drt.c));
delta_diagonal_rod_2_tower.set(sq(delta_diagonal_rod + delta_diagonal_rod_trim.a),
sq(delta_diagonal_rod + delta_diagonal_rod_trim.b),
sq(delta_diagonal_rod + delta_diagonal_rod_trim.c));
update_software_endstops(Z_AXIS);
set_all_unhomed();
}
/**
* Get a safe radius for calibration
*/
#if EITHER(DELTA_AUTO_CALIBRATION, DELTA_CALIBRATION_MENU)
#if ENABLED(DELTA_AUTO_CALIBRATION)
float calibration_radius_factor = 1;
#endif
float delta_calibration_radius() {
return calibration_radius_factor * (
#if HAS_BED_PROBE
FLOOR((DELTA_PRINTABLE_RADIUS) - _MAX(HYPOT(probe.offset_xy.x, probe.offset_xy.y), MIN_PROBE_EDGE))
#else
DELTA_PRINTABLE_RADIUS
#endif
);
}
#endif
/**
* Delta Inverse Kinematics
*
@@ -121,8 +99,8 @@ void recalc_delta_settings() {
*/
#define DELTA_DEBUG(VAR) do { \
SERIAL_ECHOLNPAIR_P(PSTR("Cartesian X"), VAR.x, SP_Y_STR, VAR.y, SP_Z_STR, VAR.z); \
SERIAL_ECHOLNPAIR("Delta A", delta.a, " B", delta.b, " C", delta.c); \
SERIAL_ECHOLNPGM_P(PSTR("Cartesian X"), VAR.x, SP_Y_STR, VAR.y, SP_Z_STR, VAR.z); \
SERIAL_ECHOLNPGM_P(PSTR("Delta A"), delta.a, SP_B_STR, delta.b, SP_C_STR, delta.c); \
}while(0)
void inverse_kinematics(const xyz_pos_t &raw) {
@@ -177,7 +155,7 @@ float delta_safe_distance_from_top() {
*
* The result is stored in the cartes[] array.
*/
void forward_kinematics_DELTA(const float &z1, const float &z2, const float &z3) {
void forward_kinematics(const_float_t z1, const_float_t z2, const_float_t z3) {
// Create a vector in old coordinates along x axis of new coordinate
const float p12[3] = { delta_tower[B_AXIS].x - delta_tower[A_AXIS].x, delta_tower[B_AXIS].y - delta_tower[A_AXIS].y, z2 - z1 },
@@ -233,7 +211,8 @@ void forward_kinematics_DELTA(const float &z1, const float &z2, const float &z3)
* This is like quick_home_xy() but for 3 towers.
*/
void home_delta() {
if (DEBUGGING(LEVELING)) DEBUG_POS(">>> home_delta", current_position);
DEBUG_SECTION(log_home_delta, "home_delta", DEBUGGING(LEVELING));
// Init the current position of all carriages to 0,0,0
current_position.reset();
destination.reset();
@@ -241,27 +220,28 @@ void home_delta() {
// Disable stealthChop if used. Enable diag1 pin on driver.
#if ENABLED(SENSORLESS_HOMING)
sensorless_t stealth_states {
tmc_enable_stallguard(stepperX),
tmc_enable_stallguard(stepperY),
tmc_enable_stallguard(stepperZ)
};
TERN_(X_SENSORLESS, sensorless_t stealth_states_x = start_sensorless_homing_per_axis(X_AXIS));
TERN_(Y_SENSORLESS, sensorless_t stealth_states_y = start_sensorless_homing_per_axis(Y_AXIS));
TERN_(Z_SENSORLESS, sensorless_t stealth_states_z = start_sensorless_homing_per_axis(Z_AXIS));
TERN_(I_SENSORLESS, sensorless_t stealth_states_i = start_sensorless_homing_per_axis(I_AXIS));
TERN_(J_SENSORLESS, sensorless_t stealth_states_j = start_sensorless_homing_per_axis(J_AXIS));
TERN_(K_SENSORLESS, sensorless_t stealth_states_k = start_sensorless_homing_per_axis(K_AXIS));
#endif
// Move all carriages together linearly until an endstop is hit.
current_position.z = (delta_height + 10
#if HAS_BED_PROBE
- probe.offset.z
#endif
);
current_position.z = DIFF_TERN(HAS_BED_PROBE, delta_height + 10, probe.offset.z);
line_to_current_position(homing_feedrate(Z_AXIS));
planner.synchronize();
TERN_(HAS_DELTA_SENSORLESS_PROBING, endstops.report_states());
// Re-enable stealthChop if used. Disable diag1 pin on driver.
#if ENABLED(SENSORLESS_HOMING)
tmc_disable_stallguard(stepperX, stealth_states.x);
tmc_disable_stallguard(stepperY, stealth_states.y);
tmc_disable_stallguard(stepperZ, stealth_states.z);
#if ENABLED(SENSORLESS_HOMING) && DISABLED(ENDSTOPS_ALWAYS_ON_DEFAULT)
TERN_(X_SENSORLESS, end_sensorless_homing_per_axis(X_AXIS, stealth_states_x));
TERN_(Y_SENSORLESS, end_sensorless_homing_per_axis(Y_AXIS, stealth_states_y));
TERN_(Z_SENSORLESS, end_sensorless_homing_per_axis(Z_AXIS, stealth_states_z));
TERN_(I_SENSORLESS, end_sensorless_homing_per_axis(I_AXIS, stealth_states_i));
TERN_(J_SENSORLESS, end_sensorless_homing_per_axis(J_AXIS, stealth_states_j));
TERN_(K_SENSORLESS, end_sensorless_homing_per_axis(K_AXIS, stealth_states_k));
#endif
endstops.validate_homing_move();
@@ -276,19 +256,17 @@ void home_delta() {
// Do this here all at once for Delta, because
// XYZ isn't ABC. Applying this per-tower would
// give the impression that they are the same.
LOOP_XYZ(i) set_axis_is_at_home((AxisEnum)i);
LOOP_ABC(i) set_axis_is_at_home((AxisEnum)i);
sync_plan_position();
#if DISABLED(DELTA_HOME_TO_SAFE_ZONE) && defined(HOMING_BACKOFF_MM)
constexpr xyz_float_t endstop_backoff = HOMING_BACKOFF_MM;
#if DISABLED(DELTA_HOME_TO_SAFE_ZONE) && defined(HOMING_BACKOFF_POST_MM)
constexpr xyz_float_t endstop_backoff = HOMING_BACKOFF_POST_MM;
if (endstop_backoff.z) {
current_position.z -= ABS(endstop_backoff.z) * Z_HOME_DIR;
line_to_current_position(homing_feedrate(Z_AXIS));
}
#endif
if (DEBUGGING(LEVELING)) DEBUG_POS("<<< home_delta", current_position);
}
#endif // DELTA

24
Marlin/src/module/delta.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -32,11 +32,12 @@ extern float delta_height;
extern abc_float_t delta_endstop_adj;
extern float delta_radius,
delta_diagonal_rod,
delta_segments_per_second;
segments_per_second;
extern abc_float_t delta_tower_angle_trim;
extern xy_float_t delta_tower[ABC];
extern abc_float_t delta_diagonal_rod_2_tower;
extern float delta_clip_start_height;
extern abc_float_t delta_diagonal_rod_trim;
/**
* Recalculate factors used for delta kinematics whenever
@@ -44,19 +45,6 @@ extern float delta_clip_start_height;
*/
void recalc_delta_settings();
/**
* Get a safe radius for calibration
*/
#if ENABLED(DELTA_AUTO_CALIBRATION)
extern float calibration_radius_factor;
#else
constexpr float calibration_radius_factor = 1;
#endif
#if EITHER(DELTA_AUTO_CALIBRATION, DELTA_CALIBRATION_MENU)
float delta_calibration_radius();
#endif
/**
* Delta Inverse Kinematics
*
@@ -119,10 +107,10 @@ float delta_safe_distance_from_top();
*
* The result is stored in the cartes[] array.
*/
void forward_kinematics_DELTA(const float &z1, const float &z2, const float &z3);
void forward_kinematics(const_float_t z1, const_float_t z2, const_float_t z3);
FORCE_INLINE void forward_kinematics_DELTA(const abc_float_t &point) {
forward_kinematics_DELTA(point.a, point.b, point.c);
FORCE_INLINE void forward_kinematics(const abc_float_t &point) {
forward_kinematics(point.a, point.b, point.c);
}
void home_delta();

696
Marlin/src/module/endstops.cpp Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
@@ -27,10 +27,9 @@
#include "endstops.h"
#include "stepper.h"
#include "../MarlinCore.h"
#include "../sd/cardreader.h"
#include "temperature.h"
#include "../lcd/ultralcd.h"
#include "../lcd/marlinui.h"
#if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
#include HAL_PATH(../HAL, endstop_interrupts.h)
@@ -48,17 +47,21 @@
#include "../feature/joystick.h"
#endif
#if HAS_BED_PROBE
#include "probe.h"
#endif
Endstops endstops;
// private:
bool Endstops::enabled, Endstops::enabled_globally; // Initialized by settings.load()
volatile uint8_t Endstops::hit_state;
Endstops::esbits_t Endstops::live_state = 0;
volatile Endstops::endstop_mask_t Endstops::hit_state;
Endstops::endstop_mask_t Endstops::live_state = 0;
#if ENDSTOP_NOISE_THRESHOLD
Endstops::esbits_t Endstops::validated_live_state;
Endstops::endstop_mask_t Endstops::validated_live_state;
uint8_t Endstops::endstop_poll_count;
#endif
@@ -256,6 +259,66 @@ void Endstops::init() {
#endif
#endif
#if HAS_I_MIN
#if ENABLED(ENDSTOPPULLUP_IMIN)
SET_INPUT_PULLUP(I_MIN_PIN);
#elif ENABLED(ENDSTOPPULLDOWN_IMIN)
SET_INPUT_PULLDOWN(I_MIN_PIN);
#else
SET_INPUT(I_MIN_PIN);
#endif
#endif
#if HAS_I_MAX
#if ENABLED(ENDSTOPPULLUP_IMAX)
SET_INPUT_PULLUP(I_MAX_PIN);
#elif ENABLED(ENDSTOPPULLDOWN_IMAX)
SET_INPUT_PULLDOWN(I_MAX_PIN);
#else
SET_INPUT(I_MAX_PIN);
#endif
#endif
#if HAS_J_MIN
#if ENABLED(ENDSTOPPULLUP_JMIN)
SET_INPUT_PULLUP(J_MIN_PIN);
#elif ENABLED(ENDSTOPPULLDOWN_IMIN)
SET_INPUT_PULLDOWN(J_MIN_PIN);
#else
SET_INPUT(J_MIN_PIN);
#endif
#endif
#if HAS_J_MAX
#if ENABLED(ENDSTOPPULLUP_JMAX)
SET_INPUT_PULLUP(J_MAX_PIN);
#elif ENABLED(ENDSTOPPULLDOWN_JMAX)
SET_INPUT_PULLDOWN(J_MAX_PIN);
#else
SET_INPUT(J_MAX_PIN);
#endif
#endif
#if HAS_K_MIN
#if ENABLED(ENDSTOPPULLUP_KMIN)
SET_INPUT_PULLUP(K_MIN_PIN);
#elif ENABLED(ENDSTOPPULLDOWN_KMIN)
SET_INPUT_PULLDOWN(K_MIN_PIN);
#else
SET_INPUT(K_MIN_PIN);
#endif
#endif
#if HAS_K_MAX
#if ENABLED(ENDSTOPPULLUP_KMAX)
SET_INPUT_PULLUP(K_MAX_PIN);
#elif ENABLED(ENDSTOPPULLDOWN_KMIN)
SET_INPUT_PULLDOWN(K_MAX_PIN);
#else
SET_INPUT(K_MAX_PIN);
#endif
#endif
#if PIN_EXISTS(CALIBRATION)
#if ENABLED(CALIBRATION_PIN_PULLUP)
SET_INPUT_PULLUP(CALIBRATION_PIN);
@@ -266,7 +329,7 @@ void Endstops::init() {
#endif
#endif
#if HAS_CUSTOM_PROBE_PIN
#if USES_Z_MIN_PROBE_PIN
#if ENABLED(ENDSTOPPULLUP_ZMIN_PROBE)
SET_INPUT_PULLUP(Z_MIN_PROBE_PIN);
#elif ENABLED(ENDSTOPPULLDOWN_ZMIN_PROBE)
@@ -276,27 +339,23 @@ void Endstops::init() {
#endif
#endif
#if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
setup_endstop_interrupts();
#if ENABLED(PROBE_ACTIVATION_SWITCH)
SET_INPUT(PROBE_ACTIVATION_SWITCH_PIN);
#endif
TERN_(PROBE_TARE, probe.tare());
TERN_(ENDSTOP_INTERRUPTS_FEATURE, setup_endstop_interrupts());
// Enable endstops
enable_globally(
#if ENABLED(ENDSTOPS_ALWAYS_ON_DEFAULT)
true
#else
false
#endif
);
enable_globally(ENABLED(ENDSTOPS_ALWAYS_ON_DEFAULT));
} // Endstops::init
// Called at ~1KHz from Temperature ISR: Poll endstop state if required
void Endstops::poll() {
#if ENABLED(PINS_DEBUGGING)
run_monitor(); // report changes in endstop status
#endif
TERN_(PINS_DEBUGGING, run_monitor()); // Report changes in endstop status
#if DISABLED(ENDSTOP_INTERRUPTS_FEATURE)
update();
@@ -325,7 +384,7 @@ void Endstops::not_homing() {
// If the last move failed to trigger an endstop, call kill
void Endstops::validate_homing_move() {
if (trigger_state()) hit_on_purpose();
else kill(GET_TEXT(MSG_LCD_HOMING_FAILED));
else kill(GET_TEXT(MSG_KILL_HOMING_FAILED));
}
#endif
@@ -341,14 +400,9 @@ void Endstops::not_homing() {
void Endstops::resync() {
if (!abort_enabled()) return; // If endstops/probes are disabled the loop below can hang
#if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
update();
#else
safe_delay(2); // Wait for Temperature ISR to run at least once (runs at 1KHz)
#endif
#if ENDSTOP_NOISE_THRESHOLD
while (endstop_poll_count) safe_delay(1);
#endif
// Wait for Temperature ISR to run at least once (runs at 1KHz)
TERN(ENDSTOP_INTERRUPTS_FEATURE, update(), safe_delay(2));
while (TERN0(ENDSTOP_NOISE_THRESHOLD, endstop_poll_count)) safe_delay(1);
}
#if ENABLED(PINS_DEBUGGING)
@@ -362,48 +416,60 @@ void Endstops::resync() {
#endif
void Endstops::event_handler() {
static uint8_t prev_hit_state; // = 0
static endstop_mask_t prev_hit_state; // = 0
if (hit_state == prev_hit_state) return;
prev_hit_state = hit_state;
if (hit_state) {
#if HAS_SPI_LCD
char chrX = ' ', chrY = ' ', chrZ = ' ', chrP = ' ';
#if HAS_STATUS_MESSAGE
char LINEAR_AXIS_LIST(chrX = ' ', chrY = ' ', chrZ = ' ', chrI = ' ', chrJ = ' ', chrK = ' '),
chrP = ' ';
#define _SET_STOP_CHAR(A,C) (chr## A = C)
#else
#define _SET_STOP_CHAR(A,C) ;
#define _SET_STOP_CHAR(A,C) NOOP
#endif
#define _ENDSTOP_HIT_ECHO(A,C) do{ \
SERIAL_ECHOPAIR(" " STRINGIFY(A) ":", planner.triggered_position_mm(_AXIS(A))); \
_SET_STOP_CHAR(A,C); }while(0)
SERIAL_ECHOPGM(" " STRINGIFY(A) ":", planner.triggered_position_mm(_AXIS(A))); _SET_STOP_CHAR(A,C); }while(0)
#define _ENDSTOP_HIT_TEST(A,C) \
if (TEST(hit_state, A ##_MIN) || TEST(hit_state, A ##_MAX)) \
if (TERN0(HAS_##A##_MIN, TEST(hit_state, A##_MIN)) || TERN0(HAS_##A##_MAX, TEST(hit_state, A##_MAX))) \
_ENDSTOP_HIT_ECHO(A,C)
#define ENDSTOP_HIT_TEST_X() _ENDSTOP_HIT_TEST(X,'X')
#define ENDSTOP_HIT_TEST_Y() _ENDSTOP_HIT_TEST(Y,'Y')
#define ENDSTOP_HIT_TEST_Z() _ENDSTOP_HIT_TEST(Z,'Z')
#define ENDSTOP_HIT_TEST_I() _ENDSTOP_HIT_TEST(I,'I')
#define ENDSTOP_HIT_TEST_J() _ENDSTOP_HIT_TEST(J,'J')
#define ENDSTOP_HIT_TEST_K() _ENDSTOP_HIT_TEST(K,'K')
SERIAL_ECHO_START();
SERIAL_ECHOPGM(STR_ENDSTOPS_HIT);
ENDSTOP_HIT_TEST_X();
ENDSTOP_HIT_TEST_Y();
ENDSTOP_HIT_TEST_Z();
LINEAR_AXIS_CODE(
ENDSTOP_HIT_TEST_X(),
ENDSTOP_HIT_TEST_Y(),
ENDSTOP_HIT_TEST_Z(),
_ENDSTOP_HIT_TEST(I,'I'),
_ENDSTOP_HIT_TEST(J,'J'),
_ENDSTOP_HIT_TEST(K,'K')
);
#if HAS_CUSTOM_PROBE_PIN
#if USES_Z_MIN_PROBE_PIN
#define P_AXIS Z_AXIS
if (TEST(hit_state, Z_MIN_PROBE)) _ENDSTOP_HIT_ECHO(P, 'P');
#endif
SERIAL_EOL();
#if HAS_SPI_LCD
ui.status_printf_P(0, PSTR(S_FMT " %c %c %c %c"), GET_TEXT(MSG_LCD_ENDSTOPS), chrX, chrY, chrZ, chrP);
#endif
TERN_(HAS_STATUS_MESSAGE,
ui.status_printf_P(0,
PSTR(S_FMT GANG_N_1(LINEAR_AXES, " %c") " %c"),
GET_TEXT(MSG_LCD_ENDSTOPS),
LINEAR_AXIS_LIST(chrX, chrY, chrZ, chrI, chrJ, chrK), chrP
)
);
#if BOTH(SD_ABORT_ON_ENDSTOP_HIT, SDSUPPORT)
if (planner.abort_on_endstop_hit) {
card.endFilePrint();
card.abortFilePrintNow();
quickstop_stepper();
thermalManager.disable_all_heaters();
print_job_timer.stop();
@@ -412,17 +478,23 @@ void Endstops::event_handler() {
}
}
#if GCC_VERSION <= 50000
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
static void print_es_state(const bool is_hit, PGM_P const label=nullptr) {
if (label) serialprintPGM(label);
if (label) SERIAL_ECHOPGM_P(label);
SERIAL_ECHOPGM(": ");
serialprintPGM(is_hit ? PSTR(STR_ENDSTOP_HIT) : PSTR(STR_ENDSTOP_OPEN));
SERIAL_EOL();
SERIAL_ECHOLNPGM_P(is_hit ? PSTR(STR_ENDSTOP_HIT) : PSTR(STR_ENDSTOP_OPEN));
}
#if GCC_VERSION <= 50000
#pragma GCC diagnostic pop
#endif
void _O2 Endstops::report_states() {
#if ENABLED(BLTOUCH)
bltouch._set_SW_mode();
#endif
TERN_(BLTOUCH, bltouch._set_SW_mode());
SERIAL_ECHOLNPGM(STR_M119_REPORT);
#define ES_REPORT(S) print_es_state(READ(S##_PIN) != S##_ENDSTOP_INVERTING, PSTR(STR_##S))
#if HAS_X_MIN
@@ -473,43 +545,66 @@ void _O2 Endstops::report_states() {
#if HAS_Z4_MAX
ES_REPORT(Z4_MAX);
#endif
#if HAS_CUSTOM_PROBE_PIN
print_es_state(READ(Z_MIN_PROBE_PIN) != Z_MIN_PROBE_ENDSTOP_INVERTING, PSTR(STR_Z_PROBE));
#if HAS_I_MIN
ES_REPORT(I_MIN);
#endif
#if HAS_FILAMENT_SENSOR
#if NUM_RUNOUT_SENSORS == 1
print_es_state(READ(FIL_RUNOUT_PIN) != FIL_RUNOUT_INVERTING, PSTR(STR_FILAMENT_RUNOUT_SENSOR));
#else
#define _CASE_RUNOUT(N) case N: pin = FIL_RUNOUT##N##_PIN; break;
LOOP_S_LE_N(i, 1, NUM_RUNOUT_SENSORS) {
pin_t pin;
switch (i) {
default: continue;
REPEAT_S(1, INCREMENT(NUM_RUNOUT_SENSORS), _CASE_RUNOUT)
}
SERIAL_ECHOPGM(STR_FILAMENT_RUNOUT_SENSOR);
if (i > 1) SERIAL_CHAR(' ', '0' + i);
print_es_state(extDigitalRead(pin) != FIL_RUNOUT_INVERTING);
#if HAS_I_MAX
ES_REPORT(I_MAX);
#endif
#if HAS_J_MIN
ES_REPORT(J_MIN);
#endif
#if HAS_J_MAX
ES_REPORT(J_MAX);
#endif
#if HAS_K_MIN
ES_REPORT(K_MIN);
#endif
#if HAS_K_MAX
ES_REPORT(K_MAX);
#endif
#if BOTH(MARLIN_DEV_MODE, PROBE_ACTIVATION_SWITCH)
print_es_state(probe_switch_activated(), PSTR(STR_PROBE_EN));
#endif
#if USES_Z_MIN_PROBE_PIN
print_es_state(PROBE_TRIGGERED(), PSTR(STR_Z_PROBE));
#endif
#if MULTI_FILAMENT_SENSOR
#define _CASE_RUNOUT(N) case N: pin = FIL_RUNOUT##N##_PIN; state = FIL_RUNOUT##N##_STATE; break;
LOOP_S_LE_N(i, 1, NUM_RUNOUT_SENSORS) {
pin_t pin;
uint8_t state;
switch (i) {
default: continue;
REPEAT_1(NUM_RUNOUT_SENSORS, _CASE_RUNOUT)
}
#undef _CASE_RUNOUT
#endif
#endif
#if ENABLED(BLTOUCH)
bltouch._reset_SW_mode();
SERIAL_ECHOPGM(STR_FILAMENT);
if (i > 1) SERIAL_CHAR(' ', '0' + i);
print_es_state(extDigitalRead(pin) != state);
}
#undef _CASE_RUNOUT
#elif HAS_FILAMENT_SENSOR
print_es_state(READ(FIL_RUNOUT1_PIN) != FIL_RUNOUT1_STATE, PSTR(STR_FILAMENT));
#endif
#if ENABLED(JOYSTICK_DEBUG)
joystick.report();
#endif
TERN_(BLTOUCH, bltouch._reset_SW_mode());
TERN_(JOYSTICK_DEBUG, joystick.report());
} // Endstops::report_states
// The following routines are called from an ISR context. It could be the temperature ISR, the
// endstop ISR or the Stepper ISR.
#define _ENDSTOP(AXIS, MINMAX) AXIS ##_## MINMAX
#define _ENDSTOP_PIN(AXIS, MINMAX) AXIS ##_## MINMAX ##_PIN
#define _ENDSTOP_INVERTING(AXIS, MINMAX) AXIS ##_## MINMAX ##_ENDSTOP_INVERTING
#if HAS_DELTA_SENSORLESS_PROBING
#define __ENDSTOP(AXIS, ...) AXIS ##_MAX
#define _ENDSTOP_PIN(AXIS, ...) AXIS ##_MAX_PIN
#define _ENDSTOP_INVERTING(AXIS, ...) AXIS ##_MAX_ENDSTOP_INVERTING
#else
#define __ENDSTOP(AXIS, MINMAX) AXIS ##_## MINMAX
#define _ENDSTOP_PIN(AXIS, MINMAX) AXIS ##_## MINMAX ##_PIN
#define _ENDSTOP_INVERTING(AXIS, MINMAX) AXIS ##_## MINMAX ##_ENDSTOP_INVERTING
#endif
#define _ENDSTOP(AXIS, MINMAX) __ENDSTOP(AXIS, MINMAX)
// Check endstops - Could be called from Temperature ISR!
void Endstops::update() {
@@ -521,28 +616,23 @@ void Endstops::update() {
#define UPDATE_ENDSTOP_BIT(AXIS, MINMAX) SET_BIT_TO(live_state, _ENDSTOP(AXIS, MINMAX), (READ(_ENDSTOP_PIN(AXIS, MINMAX)) != _ENDSTOP_INVERTING(AXIS, MINMAX)))
#define COPY_LIVE_STATE(SRC_BIT, DST_BIT) SET_BIT_TO(live_state, DST_BIT, TEST(live_state, SRC_BIT))
#if ENABLED(G38_PROBE_TARGET) && PIN_EXISTS(Z_MIN_PROBE) && !(CORE_IS_XY || CORE_IS_XZ)
// If G38 command is active check Z_MIN_PROBE for ALL movement
if (G38_move) UPDATE_ENDSTOP_BIT(Z, MIN_PROBE);
#if ENABLED(G38_PROBE_TARGET) && NONE(CORE_IS_XY, CORE_IS_XZ, MARKFORGED_XY)
#define HAS_G38_PROBE 1
// For G38 moves check the probe's pin for ALL movement
if (G38_move) UPDATE_ENDSTOP_BIT(Z, TERN(USES_Z_MIN_PROBE_PIN, MIN_PROBE, MIN));
#endif
// With Dual X, endstops are only checked in the homing direction for the active extruder
#if ENABLED(DUAL_X_CARRIAGE)
#define E0_ACTIVE stepper.movement_extruder() == 0
#define X_MIN_TEST() ((X_HOME_DIR < 0 && E0_ACTIVE) || (X2_HOME_DIR < 0 && !E0_ACTIVE))
#define X_MAX_TEST() ((X_HOME_DIR > 0 && E0_ACTIVE) || (X2_HOME_DIR > 0 && !E0_ACTIVE))
#else
#define X_MIN_TEST() true
#define X_MAX_TEST() true
#endif
#define X_MIN_TEST() TERN1(DUAL_X_CARRIAGE, TERN0(X_HOME_TO_MIN, stepper.last_moved_extruder == 0) || TERN0(X2_HOME_TO_MIN, stepper.last_moved_extruder != 0))
#define X_MAX_TEST() TERN1(DUAL_X_CARRIAGE, TERN0(X_HOME_TO_MAX, stepper.last_moved_extruder == 0) || TERN0(X2_HOME_TO_MAX, stepper.last_moved_extruder != 0))
// Use HEAD for core axes, AXIS for others
#if CORE_IS_XY || CORE_IS_XZ
#if ANY(CORE_IS_XY, CORE_IS_XZ, MARKFORGED_XY)
#define X_AXIS_HEAD X_HEAD
#else
#define X_AXIS_HEAD X_AXIS
#endif
#if CORE_IS_XY || CORE_IS_YZ
#if ANY(CORE_IS_XY, CORE_IS_YZ, MARKFORGED_XY)
#define Y_AXIS_HEAD Y_HEAD
#else
#define Y_AXIS_HEAD Y_AXIS
@@ -553,6 +643,10 @@ void Endstops::update() {
#define Z_AXIS_HEAD Z_AXIS
#endif
#define I_AXIS_HEAD I_AXIS
#define J_AXIS_HEAD J_AXIS
#define K_AXIS_HEAD K_AXIS
/**
* Check and update endstops
*/
@@ -600,7 +694,7 @@ void Endstops::update() {
#endif
#endif
#if HAS_Z_MIN && !Z_SPI_SENSORLESS
#if HAS_Z_MIN && NONE(Z_SPI_SENSORLESS, Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN)
UPDATE_ENDSTOP_BIT(Z, MIN);
#if ENABLED(Z_MULTI_ENDSTOPS)
#if HAS_Z2_MIN
@@ -625,9 +719,10 @@ void Endstops::update() {
#endif
#endif
// When closing the gap check the enabled probe
#if HAS_CUSTOM_PROBE_PIN
UPDATE_ENDSTOP_BIT(Z, MIN_PROBE);
#if HAS_BED_PROBE
// When closing the gap check the enabled probe
if (probe_switch_activated())
UPDATE_ENDSTOP_BIT(Z, TERN(USES_Z_MIN_PROBE_PIN, MIN_PROBE, MIN));
#endif
#if HAS_Z_MAX && !Z_SPI_SENSORLESS
@@ -653,12 +748,90 @@ void Endstops::update() {
COPY_LIVE_STATE(Z_MAX, Z4_MAX);
#endif
#endif
#elif !HAS_CUSTOM_PROBE_PIN || Z_MAX_PIN != Z_MIN_PROBE_PIN
#elif TERN1(USES_Z_MIN_PROBE_PIN, Z_MAX_PIN != Z_MIN_PROBE_PIN)
// If this pin isn't the bed probe it's the Z endstop
UPDATE_ENDSTOP_BIT(Z, MAX);
#endif
#endif
#if HAS_I_MIN && !I_SPI_SENSORLESS
#if ENABLED(I_DUAL_ENDSTOPS)
UPDATE_ENDSTOP_BIT(I, MIN);
#if HAS_I2_MIN
UPDATE_ENDSTOP_BIT(I2, MAX);
#else
COPY_LIVE_STATE(I_MIN, I2_MIN);
#endif
#else
UPDATE_ENDSTOP_BIT(I, MIN);
#endif
#endif
#if HAS_I_MAX && !I_SPI_SENSORLESS
#if ENABLED(I_DUAL_ENDSTOPS)
UPDATE_ENDSTOP_BIT(I, MAX);
#if HAS_I2_MAX
UPDATE_ENDSTOP_BIT(I2, MAX);
#else
COPY_LIVE_STATE(I_MAX, I2_MAX);
#endif
#else
UPDATE_ENDSTOP_BIT(I, MAX);
#endif
#endif
#if HAS_J_MIN && !J_SPI_SENSORLESS
#if ENABLED(J_DUAL_ENDSTOPS)
UPDATE_ENDSTOP_BIT(J, MIN);
#if HAS_J2_MIN
UPDATE_ENDSTOP_BIT(J2, MIN);
#else
COPY_LIVE_STATE(J_MIN, J2_MIN);
#endif
#else
UPDATE_ENDSTOP_BIT(J, MIN);
#endif
#endif
#if HAS_J_MAX && !J_SPI_SENSORLESS
#if ENABLED(J_DUAL_ENDSTOPS)
UPDATE_ENDSTOP_BIT(J, MAX);
#if HAS_J2_MAX
UPDATE_ENDSTOP_BIT(J2, MAX);
#else
COPY_LIVE_STATE(J_MAX, J2_MAX);
#endif
#else
UPDATE_ENDSTOP_BIT(J, MAX);
#endif
#endif
#if HAS_K_MIN && !K_SPI_SENSORLESS
#if ENABLED(K_DUAL_ENDSTOPS)
UPDATE_ENDSTOP_BIT(K, MIN);
#if HAS_K2_MIN
UPDATE_ENDSTOP_BIT(K2, MIN);
#else
COPY_LIVE_STATE(K_MIN, K2_MIN);
#endif
#else
UPDATE_ENDSTOP_BIT(K, MIN);
#endif
#endif
#if HAS_K_MAX && !K_SPI_SENSORLESS
#if ENABLED(K_DUAL_ENDSTOPS)
UPDATE_ENDSTOP_BIT(K, MAX);
#if HAS_K2_MAX
UPDATE_ENDSTOP_BIT(K2, MAX);
#else
COPY_LIVE_STATE(K_MAX, K2_MAX);
#endif
#else
UPDATE_ENDSTOP_BIT(K, MAX);
#endif
#endif
#if ENDSTOP_NOISE_THRESHOLD
/**
@@ -671,7 +844,7 @@ void Endstops::update() {
* still exist. The only way to reduce them further is to increase the number of samples.
* To reduce the chance to 1% (1/128th) requires 7 samples (adding 7ms of delay).
*/
static esbits_t old_live_state;
static endstop_mask_t old_live_state;
if (old_live_state != live_state) {
endstop_poll_count = ENDSTOP_NOISE_THRESHOLD;
old_live_state = live_state;
@@ -697,12 +870,21 @@ void Endstops::update() {
} \
}while(0)
// Core Sensorless Homing needs to test an Extra Pin
#define CORE_DIAG(QQ,A,MM) (CORE_IS_##QQ && A##_SENSORLESS && !A##_SPI_SENSORLESS && HAS_##A##_##MM)
#define PROCESS_CORE_ENDSTOP(A1,M1,A2,M2) do { \
if (TEST_ENDSTOP(_ENDSTOP(A1,M1))) { \
_ENDSTOP_HIT(A2,M2); \
planner.endstop_triggered(_AXIS(A2)); \
} \
}while(0)
// Call the endstop triggered routine for dual endstops
#define PROCESS_DUAL_ENDSTOP(A, MINMAX) do { \
const byte dual_hit = TEST_ENDSTOP(_ENDSTOP(A, MINMAX)) | (TEST_ENDSTOP(_ENDSTOP(A##2, MINMAX)) << 1); \
if (dual_hit) { \
_ENDSTOP_HIT(A, MINMAX); \
/* if not performing home or if both endstops were trigged during homing... */ \
/* if not performing home or if both endstops were triggered during homing... */ \
if (!stepper.separate_multi_axis || dual_hit == 0b11) \
planner.endstop_triggered(_AXIS(A)); \
} \
@@ -712,7 +894,7 @@ void Endstops::update() {
const byte triple_hit = TEST_ENDSTOP(_ENDSTOP(A, MINMAX)) | (TEST_ENDSTOP(_ENDSTOP(A##2, MINMAX)) << 1) | (TEST_ENDSTOP(_ENDSTOP(A##3, MINMAX)) << 2); \
if (triple_hit) { \
_ENDSTOP_HIT(A, MINMAX); \
/* if not performing home or if both endstops were trigged during homing... */ \
/* if not performing home or if both endstops were triggered during homing... */ \
if (!stepper.separate_multi_axis || triple_hit == 0b111) \
planner.endstop_triggered(_AXIS(A)); \
} \
@@ -722,7 +904,7 @@ void Endstops::update() {
const byte quad_hit = TEST_ENDSTOP(_ENDSTOP(A, MINMAX)) | (TEST_ENDSTOP(_ENDSTOP(A##2, MINMAX)) << 1) | (TEST_ENDSTOP(_ENDSTOP(A##3, MINMAX)) << 2) | (TEST_ENDSTOP(_ENDSTOP(A##4, MINMAX)) << 3); \
if (quad_hit) { \
_ENDSTOP_HIT(A, MINMAX); \
/* if not performing home or if both endstops were trigged during homing... */ \
/* if not performing home or if both endstops were triggered during homing... */ \
if (!stepper.separate_multi_axis || quad_hit == 0b1111) \
planner.endstop_triggered(_AXIS(A)); \
} \
@@ -750,117 +932,249 @@ void Endstops::update() {
#define PROCESS_ENDSTOP_Z(MINMAX) PROCESS_DUAL_ENDSTOP(Z, MINMAX)
#endif
#if ENABLED(G38_PROBE_TARGET) && PIN_EXISTS(Z_MIN_PROBE) && !(CORE_IS_XY || CORE_IS_XZ)
#if ENABLED(G38_PROBE_AWAY)
#define _G38_OPEN_STATE (G38_move >= 4)
#else
#define _G38_OPEN_STATE LOW
#endif
// If G38 command is active check Z_MIN_PROBE for ALL movement
if (G38_move && TEST_ENDSTOP(_ENDSTOP(Z, MIN_PROBE)) != _G38_OPEN_STATE) {
if (stepper.axis_is_moving(X_AXIS)) { _ENDSTOP_HIT(X, MIN); planner.endstop_triggered(X_AXIS); }
else if (stepper.axis_is_moving(Y_AXIS)) { _ENDSTOP_HIT(Y, MIN); planner.endstop_triggered(Y_AXIS); }
else if (stepper.axis_is_moving(Z_AXIS)) { _ENDSTOP_HIT(Z, MIN); planner.endstop_triggered(Z_AXIS); }
#if HAS_G38_PROBE
#define _G38_OPEN_STATE TERN(G38_PROBE_AWAY, (G38_move >= 4), LOW)
// For G38 moves check the probe's pin for ALL movement
if (G38_move && TEST_ENDSTOP(_ENDSTOP(Z, TERN(USES_Z_MIN_PROBE_PIN, MIN_PROBE, MIN))) != _G38_OPEN_STATE) {
if (stepper.axis_is_moving(X_AXIS)) { _ENDSTOP_HIT(X, TERN(X_HOME_TO_MIN, MIN, MAX)); planner.endstop_triggered(X_AXIS); }
#if HAS_Y_AXIS
else if (stepper.axis_is_moving(Y_AXIS)) { _ENDSTOP_HIT(Y, TERN(Y_HOME_TO_MIN, MIN, MAX)); planner.endstop_triggered(Y_AXIS); }
#endif
#if HAS_Z_AXIS
else if (stepper.axis_is_moving(Z_AXIS)) { _ENDSTOP_HIT(Z, TERN(Z_HOME_TO_MIN, MIN, MAX)); planner.endstop_triggered(Z_AXIS); }
#endif
G38_did_trigger = true;
}
#endif
// Now, we must signal, after validation, if an endstop limit is pressed or not
// Signal, after validation, if an endstop limit is pressed or not
if (stepper.axis_is_moving(X_AXIS)) {
if (stepper.motor_direction(X_AXIS_HEAD)) { // -direction
#if HAS_X_MIN || (X_SPI_SENSORLESS && X_HOME_DIR < 0)
#if HAS_X_MIN || (X_SPI_SENSORLESS && X_HOME_TO_MIN)
PROCESS_ENDSTOP_X(MIN);
#if CORE_DIAG(XY, Y, MIN)
PROCESS_CORE_ENDSTOP(Y,MIN,X,MIN);
#elif CORE_DIAG(XY, Y, MAX)
PROCESS_CORE_ENDSTOP(Y,MAX,X,MIN);
#elif CORE_DIAG(XZ, Z, MIN)
PROCESS_CORE_ENDSTOP(Z,MIN,X,MIN);
#elif CORE_DIAG(XZ, Z, MAX)
PROCESS_CORE_ENDSTOP(Z,MAX,X,MIN);
#endif
#endif
}
else { // +direction
#if HAS_X_MAX || (X_SPI_SENSORLESS && X_HOME_DIR > 0)
#if HAS_X_MAX || (X_SPI_SENSORLESS && X_HOME_TO_MAX)
PROCESS_ENDSTOP_X(MAX);
#endif
}
}
if (stepper.axis_is_moving(Y_AXIS)) {
if (stepper.motor_direction(Y_AXIS_HEAD)) { // -direction
#if HAS_Y_MIN || (Y_SPI_SENSORLESS && Y_HOME_DIR < 0)
PROCESS_ENDSTOP_Y(MIN);
#endif
}
else { // +direction
#if HAS_Y_MAX || (Y_SPI_SENSORLESS && Y_HOME_DIR > 0)
PROCESS_ENDSTOP_Y(MAX);
#endif
}
}
if (stepper.axis_is_moving(Z_AXIS)) {
if (stepper.motor_direction(Z_AXIS_HEAD)) { // Z -direction. Gantry down, bed up.
#if HAS_Z_MIN || (Z_SPI_SENSORLESS && Z_HOME_DIR < 0)
if (true
#if ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN)
&& z_probe_enabled
#elif HAS_CUSTOM_PROBE_PIN
&& !z_probe_enabled
#endif
) PROCESS_ENDSTOP_Z(MIN);
#endif
// When closing the gap check the enabled probe
#if HAS_CUSTOM_PROBE_PIN
if (z_probe_enabled) PROCESS_ENDSTOP(Z, MIN_PROBE);
#endif
}
else { // Z +direction. Gantry up, bed down.
#if HAS_Z_MAX || (Z_SPI_SENSORLESS && Z_HOME_DIR > 0)
#if ENABLED(Z_MULTI_ENDSTOPS)
PROCESS_ENDSTOP_Z(MAX);
#elif !HAS_CUSTOM_PROBE_PIN || Z_MAX_PIN != Z_MIN_PROBE_PIN // No probe or probe is Z_MIN || Probe is not Z_MAX
PROCESS_ENDSTOP(Z, MAX);
#if CORE_DIAG(XY, Y, MIN)
PROCESS_CORE_ENDSTOP(Y,MIN,X,MAX);
#elif CORE_DIAG(XY, Y, MAX)
PROCESS_CORE_ENDSTOP(Y,MAX,X,MAX);
#elif CORE_DIAG(XZ, Z, MIN)
PROCESS_CORE_ENDSTOP(Z,MIN,X,MAX);
#elif CORE_DIAG(XZ, Z, MAX)
PROCESS_CORE_ENDSTOP(Z,MAX,X,MAX);
#endif
#endif
}
}
#if HAS_Y_AXIS
if (stepper.axis_is_moving(Y_AXIS)) {
if (stepper.motor_direction(Y_AXIS_HEAD)) { // -direction
#if HAS_Y_MIN || (Y_SPI_SENSORLESS && Y_HOME_TO_MIN)
PROCESS_ENDSTOP_Y(MIN);
#if CORE_DIAG(XY, X, MIN)
PROCESS_CORE_ENDSTOP(X,MIN,Y,MIN);
#elif CORE_DIAG(XY, X, MAX)
PROCESS_CORE_ENDSTOP(X,MAX,Y,MIN);
#elif CORE_DIAG(YZ, Z, MIN)
PROCESS_CORE_ENDSTOP(Z,MIN,Y,MIN);
#elif CORE_DIAG(YZ, Z, MAX)
PROCESS_CORE_ENDSTOP(Z,MAX,Y,MIN);
#endif
#endif
}
else { // +direction
#if HAS_Y_MAX || (Y_SPI_SENSORLESS && Y_HOME_TO_MAX)
PROCESS_ENDSTOP_Y(MAX);
#if CORE_DIAG(XY, X, MIN)
PROCESS_CORE_ENDSTOP(X,MIN,Y,MAX);
#elif CORE_DIAG(XY, X, MAX)
PROCESS_CORE_ENDSTOP(X,MAX,Y,MAX);
#elif CORE_DIAG(YZ, Z, MIN)
PROCESS_CORE_ENDSTOP(Z,MIN,Y,MAX);
#elif CORE_DIAG(YZ, Z, MAX)
PROCESS_CORE_ENDSTOP(Z,MAX,Y,MAX);
#endif
#endif
}
}
#endif
#if HAS_Z_AXIS
if (stepper.axis_is_moving(Z_AXIS)) {
if (stepper.motor_direction(Z_AXIS_HEAD)) { // Z -direction. Gantry down, bed up.
#if HAS_Z_MIN || (Z_SPI_SENSORLESS && Z_HOME_TO_MIN)
if ( TERN1(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN, z_probe_enabled)
&& TERN1(USES_Z_MIN_PROBE_PIN, !z_probe_enabled)
) PROCESS_ENDSTOP_Z(MIN);
#if CORE_DIAG(XZ, X, MIN)
PROCESS_CORE_ENDSTOP(X,MIN,Z,MIN);
#elif CORE_DIAG(XZ, X, MAX)
PROCESS_CORE_ENDSTOP(X,MAX,Z,MIN);
#elif CORE_DIAG(YZ, Y, MIN)
PROCESS_CORE_ENDSTOP(Y,MIN,Z,MIN);
#elif CORE_DIAG(YZ, Y, MAX)
PROCESS_CORE_ENDSTOP(Y,MAX,Z,MIN);
#endif
#endif
// When closing the gap check the enabled probe
#if USES_Z_MIN_PROBE_PIN
if (z_probe_enabled) PROCESS_ENDSTOP(Z, MIN_PROBE);
#endif
}
else { // Z +direction. Gantry up, bed down.
#if HAS_Z_MAX || (Z_SPI_SENSORLESS && Z_HOME_TO_MAX)
#if ENABLED(Z_MULTI_ENDSTOPS)
PROCESS_ENDSTOP_Z(MAX);
#elif TERN1(USES_Z_MIN_PROBE_PIN, Z_MAX_PIN != Z_MIN_PROBE_PIN) // No probe or probe is Z_MIN || Probe is not Z_MAX
PROCESS_ENDSTOP(Z, MAX);
#endif
#if CORE_DIAG(XZ, X, MIN)
PROCESS_CORE_ENDSTOP(X,MIN,Z,MAX);
#elif CORE_DIAG(XZ, X, MAX)
PROCESS_CORE_ENDSTOP(X,MAX,Z,MAX);
#elif CORE_DIAG(YZ, Y, MIN)
PROCESS_CORE_ENDSTOP(Y,MIN,Z,MAX);
#elif CORE_DIAG(YZ, Y, MAX)
PROCESS_CORE_ENDSTOP(Y,MAX,Z,MAX);
#endif
#endif
}
}
#endif
#if LINEAR_AXES >= 4
if (stepper.axis_is_moving(I_AXIS)) {
if (stepper.motor_direction(I_AXIS_HEAD)) { // -direction
#if HAS_I_MIN || (I_SPI_SENSORLESS && I_HOME_TO_MIN)
PROCESS_ENDSTOP(I, MIN);
#endif
}
else { // +direction
#if HAS_I_MAX || (I_SPI_SENSORLESS && I_HOME_TO_MAX)
PROCESS_ENDSTOP(I, MAX);
#endif
}
}
#endif
#if LINEAR_AXES >= 5
if (stepper.axis_is_moving(J_AXIS)) {
if (stepper.motor_direction(J_AXIS_HEAD)) { // -direction
#if HAS_J_MIN || (J_SPI_SENSORLESS && J_HOME_TO_MIN)
PROCESS_ENDSTOP(J, MIN);
#endif
}
else { // +direction
#if HAS_J_MAX || (J_SPI_SENSORLESS && J_HOME_TO_MAX)
PROCESS_ENDSTOP(J, MAX);
#endif
}
}
#endif
#if LINEAR_AXES >= 6
if (stepper.axis_is_moving(K_AXIS)) {
if (stepper.motor_direction(K_AXIS_HEAD)) { // -direction
#if HAS_K_MIN || (K_SPI_SENSORLESS && K_HOME_TO_MIN)
PROCESS_ENDSTOP(K, MIN);
#endif
}
else { // +direction
#if HAS_K_MAX || (K_SPI_SENSORLESS && K_HOME_TO_MAX)
PROCESS_ENDSTOP(K, MAX);
#endif
}
}
#endif
} // Endstops::update()
#if ENABLED(SPI_ENDSTOPS)
#define X_STOP (X_HOME_DIR < 0 ? X_MIN : X_MAX)
#define Y_STOP (Y_HOME_DIR < 0 ? Y_MIN : Y_MAX)
#define Z_STOP (Z_HOME_DIR < 0 ? Z_MIN : Z_MAX)
bool Endstops::tmc_spi_homing_check() {
bool hit = false;
#if X_SPI_SENSORLESS
if (tmc_spi_homing.x && stepperX.test_stall_status()) {
SBI(live_state, X_STOP);
if (tmc_spi_homing.x && (stepperX.test_stall_status()
#if ANY(CORE_IS_XY, MARKFORGED_XY) && Y_SPI_SENSORLESS
|| stepperY.test_stall_status()
#elif CORE_IS_XZ && Z_SPI_SENSORLESS
|| stepperZ.test_stall_status()
#endif
)) {
SBI(live_state, X_ENDSTOP);
hit = true;
}
#endif
#if Y_SPI_SENSORLESS
if (tmc_spi_homing.y && stepperY.test_stall_status()) {
SBI(live_state, Y_STOP);
if (tmc_spi_homing.y && (stepperY.test_stall_status()
#if ANY(CORE_IS_XY, MARKFORGED_XY) && X_SPI_SENSORLESS
|| stepperX.test_stall_status()
#elif CORE_IS_YZ && Z_SPI_SENSORLESS
|| stepperZ.test_stall_status()
#endif
)) {
SBI(live_state, Y_ENDSTOP);
hit = true;
}
#endif
#if Z_SPI_SENSORLESS
if (tmc_spi_homing.z && stepperZ.test_stall_status()) {
SBI(live_state, Z_STOP);
if (tmc_spi_homing.z && (stepperZ.test_stall_status()
#if CORE_IS_XZ && X_SPI_SENSORLESS
|| stepperX.test_stall_status()
#elif CORE_IS_YZ && Y_SPI_SENSORLESS
|| stepperY.test_stall_status()
#endif
)) {
SBI(live_state, Z_ENDSTOP);
hit = true;
}
#endif
#if I_SPI_SENSORLESS
if (tmc_spi_homing.i && stepperI.test_stall_status()) {
SBI(live_state, I_ENDSTOP);
hit = true;
}
#endif
#if J_SPI_SENSORLESS
if (tmc_spi_homing.j && stepperJ.test_stall_status()) {
SBI(live_state, J_ENDSTOP);
hit = true;
}
#endif
#if K_SPI_SENSORLESS
if (tmc_spi_homing.k && stepperK.test_stall_status()) {
SBI(live_state, K_ENDSTOP);
hit = true;
}
#endif
if (TERN0(ENDSTOP_INTERRUPTS_FEATURE, hit)) update();
return hit;
}
void Endstops::clear_endstop_state() {
#if X_SPI_SENSORLESS
CBI(live_state, X_STOP);
#endif
#if Y_SPI_SENSORLESS
CBI(live_state, Y_STOP);
#endif
#if Z_SPI_SENSORLESS
CBI(live_state, Z_STOP);
#endif
TERN_(X_SPI_SENSORLESS, CBI(live_state, X_ENDSTOP));
TERN_(Y_SPI_SENSORLESS, CBI(live_state, Y_ENDSTOP));
TERN_(Z_SPI_SENSORLESS, CBI(live_state, Z_ENDSTOP));
TERN_(I_SPI_SENSORLESS, CBI(live_state, I_ENDSTOP));
TERN_(J_SPI_SENSORLESS, CBI(live_state, J_ENDSTOP));
TERN_(K_SPI_SENSORLESS, CBI(live_state, K_ENDSTOP));
}
#endif // SPI_ENDSTOPS
@@ -937,9 +1251,27 @@ void Endstops::update() {
#if HAS_Z4_MAX
ES_GET_STATE(Z4_MAX);
#endif
#if HAS_I_MAX
ES_GET_STATE(I_MAX);
#endif
#if HAS_I_MIN
ES_GET_STATE(I_MIN);
#endif
#if HAS_J_MAX
ES_GET_STATE(J_MAX);
#endif
#if HAS_J_MIN
ES_GET_STATE(J_MIN);
#endif
#if HAS_K_MAX
ES_GET_STATE(K_MAX);
#endif
#if HAS_K_MIN
ES_GET_STATE(K_MIN);
#endif
uint16_t endstop_change = live_state_local ^ old_live_state_local;
#define ES_REPORT_CHANGE(S) if (TEST(endstop_change, S)) SERIAL_ECHOPAIR(" " STRINGIFY(S) ":", TEST(live_state_local, S))
#define ES_REPORT_CHANGE(S) if (TEST(endstop_change, S)) SERIAL_ECHOPGM(" " STRINGIFY(S) ":", TEST(live_state_local, S))
if (endstop_change) {
#if HAS_X_MIN
@@ -993,6 +1325,24 @@ void Endstops::update() {
#if HAS_Z4_MAX
ES_REPORT_CHANGE(Z4_MAX);
#endif
#if HAS_I_MIN
ES_REPORT_CHANGE(I_MIN);
#endif
#if HAS_I_MAX
ES_REPORT_CHANGE(I_MAX);
#endif
#if HAS_J_MIN
ES_REPORT_CHANGE(J_MIN);
#endif
#if HAS_J_MAX
ES_REPORT_CHANGE(J_MAX);
#endif
#if HAS_K_MIN
ES_REPORT_CHANGE(K_MIN);
#endif
#if HAS_K_MAX
ES_REPORT_CHANGE(K_MAX);
#endif
SERIAL_ECHOLNPGM("\n");
analogWrite(pin_t(LED_PIN), local_LED_status);
local_LED_status ^= 255;

130
Marlin/src/module/endstops.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -28,46 +28,96 @@
#include "../inc/MarlinConfig.h"
#include <stdint.h>
#define __ES_ITEM(N) N,
#define _ES_ITEM(K,N) TERN_(K,DEFER4(__ES_ITEM)(N))
enum EndstopEnum : char {
X_MIN, Y_MIN, Z_MIN, Z_MIN_PROBE,
X_MAX, Y_MAX, Z_MAX,
X2_MIN, X2_MAX,
Y2_MIN, Y2_MAX,
Z2_MIN, Z2_MAX,
Z3_MIN, Z3_MAX,
Z4_MIN, Z4_MAX
// Common XYZ (ABC) endstops. Defined according to USE_[XYZ](MIN|MAX)_PLUG settings.
_ES_ITEM(HAS_X_MIN, X_MIN)
_ES_ITEM(HAS_X_MAX, X_MAX)
_ES_ITEM(HAS_Y_MIN, Y_MIN)
_ES_ITEM(HAS_Y_MAX, Y_MAX)
_ES_ITEM(HAS_Z_MIN, Z_MIN)
_ES_ITEM(HAS_Z_MAX, Z_MAX)
_ES_ITEM(HAS_I_MIN, I_MIN)
_ES_ITEM(HAS_I_MAX, I_MAX)
_ES_ITEM(HAS_J_MIN, J_MIN)
_ES_ITEM(HAS_J_MAX, J_MAX)
_ES_ITEM(HAS_K_MIN, K_MIN)
_ES_ITEM(HAS_K_MAX, K_MAX)
// Extra Endstops for XYZ
_ES_ITEM(HAS_X2_MIN, X2_MIN)
_ES_ITEM(HAS_X2_MAX, X2_MAX)
_ES_ITEM(HAS_Y2_MIN, Y2_MIN)
_ES_ITEM(HAS_Y2_MAX, Y2_MAX)
_ES_ITEM(HAS_Z2_MIN, Z2_MIN)
_ES_ITEM(HAS_Z2_MAX, Z2_MAX)
_ES_ITEM(HAS_Z3_MIN, Z3_MIN)
_ES_ITEM(HAS_Z3_MAX, Z3_MAX)
_ES_ITEM(HAS_Z4_MIN, Z4_MIN)
_ES_ITEM(HAS_Z4_MAX, Z4_MAX)
// Bed Probe state is distinct or shared with Z_MIN (i.e., when the probe is the only Z endstop)
#if !HAS_DELTA_SENSORLESS_PROBING
_ES_ITEM(HAS_BED_PROBE, Z_MIN_PROBE IF_DISABLED(USES_Z_MIN_PROBE_PIN, = Z_MIN))
#endif
// The total number of states
NUM_ENDSTOP_STATES
// Endstops can be either MIN or MAX but not both
#if HAS_X_MIN || HAS_X_MAX
, X_ENDSTOP = TERN(X_HOME_TO_MAX, X_MAX, X_MIN)
#endif
#if HAS_Y_MIN || HAS_Y_MAX
, Y_ENDSTOP = TERN(Y_HOME_TO_MAX, Y_MAX, Y_MIN)
#endif
#if HAS_Z_MIN || HAS_Z_MAX || HOMING_Z_WITH_PROBE
, Z_ENDSTOP = TERN(Z_HOME_TO_MAX, Z_MAX, TERN(HOMING_Z_WITH_PROBE, Z_MIN_PROBE, Z_MIN))
#endif
#if HAS_I_MIN || HAS_I_MAX
, I_ENDSTOP = TERN(I_HOME_TO_MAX, I_MAX, I_MIN)
#endif
#if HAS_J_MIN || HAS_J_MAX
, J_ENDSTOP = TERN(J_HOME_TO_MAX, J_MAX, J_MIN)
#endif
#if HAS_K_MIN || HAS_K_MAX
, K_ENDSTOP = TERN(K_HOME_TO_MAX, K_MAX, K_MIN)
#endif
};
#undef __ES_ITEM
#undef _ES_ITEM
class Endstops {
public:
#if HAS_EXTRA_ENDSTOPS
typedef uint16_t esbits_t;
#if ENABLED(X_DUAL_ENDSTOPS)
static float x2_endstop_adj;
#endif
#if ENABLED(Y_DUAL_ENDSTOPS)
static float y2_endstop_adj;
#endif
#if ENABLED(Z_MULTI_ENDSTOPS)
static float z2_endstop_adj;
#endif
#if ENABLED(Z_MULTI_ENDSTOPS) && NUM_Z_STEPPER_DRIVERS >= 3
static float z3_endstop_adj;
#endif
#if ENABLED(Z_MULTI_ENDSTOPS) && NUM_Z_STEPPER_DRIVERS >= 4
static float z4_endstop_adj;
#endif
#else
typedef uint8_t esbits_t;
typedef IF<(NUM_ENDSTOP_STATES > 8), uint16_t, uint8_t>::type endstop_mask_t;
#if ENABLED(X_DUAL_ENDSTOPS)
static float x2_endstop_adj;
#endif
#if ENABLED(Y_DUAL_ENDSTOPS)
static float y2_endstop_adj;
#endif
#if ENABLED(Z_MULTI_ENDSTOPS)
static float z2_endstop_adj;
#endif
#if ENABLED(Z_MULTI_ENDSTOPS) && NUM_Z_STEPPER_DRIVERS >= 3
static float z3_endstop_adj;
#endif
#if ENABLED(Z_MULTI_ENDSTOPS) && NUM_Z_STEPPER_DRIVERS >= 4
static float z4_endstop_adj;
#endif
private:
static bool enabled, enabled_globally;
static esbits_t live_state;
static volatile uint8_t hit_state; // Use X_MIN, Y_MIN, Z_MIN and Z_MIN_PROBE as BIT index
static endstop_mask_t live_state;
static volatile endstop_mask_t hit_state; // Use X_MIN, Y_MIN, Z_MIN and Z_MIN_PROBE as BIT index
#if ENDSTOP_NOISE_THRESHOLD
static esbits_t validated_live_state;
static endstop_mask_t validated_live_state;
static uint8_t endstop_poll_count; // Countdown from threshold for polling
#endif
@@ -83,11 +133,7 @@ class Endstops {
* Are endstops or the probe set to abort the move?
*/
FORCE_INLINE static bool abort_enabled() {
return (enabled
#if HAS_BED_PROBE
|| z_probe_enabled
#endif
);
return enabled || TERN0(HAS_BED_PROBE, z_probe_enabled);
}
static inline bool global_enabled() { return enabled_globally; }
@@ -107,12 +153,12 @@ class Endstops {
/**
* Get Endstop hit state.
*/
FORCE_INLINE static uint8_t trigger_state() { return hit_state; }
FORCE_INLINE static endstop_mask_t trigger_state() { return hit_state; }
/**
* Get current endstops state
*/
FORCE_INLINE static esbits_t state() {
FORCE_INLINE static endstop_mask_t state() {
return
#if ENDSTOP_NOISE_THRESHOLD
validated_live_state
@@ -122,6 +168,14 @@ class Endstops {
;
}
static inline bool probe_switch_activated() {
return (true
#if ENABLED(PROBE_ACTIVATION_SWITCH)
&& READ(PROBE_ACTIVATION_SWITCH_PIN) == PROBE_ACTIVATION_SWITCH_STATE
#endif
);
}
/**
* Report endstop hits to serial. Called from loop().
*/
@@ -170,7 +224,7 @@ class Endstops {
typedef struct {
union {
bool any;
struct { bool x:1, y:1, z:1; };
struct { bool LINEAR_AXIS_LIST(x:1, y:1, z:1, i:1, j:1, k:1); };
};
} tmc_spi_homing_t;
static tmc_spi_homing_t tmc_spi_homing;

2118
Marlin/src/module/motion.cpp Executable file → Normal file

File diff suppressed because it is too large Load Diff

454
Marlin/src/module/motion.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -34,25 +34,6 @@
#include "scara.h"
#endif
// Axis homed and known-position states
extern uint8_t axis_homed, axis_known_position;
constexpr uint8_t xyz_bits = _BV(X_AXIS) | _BV(Y_AXIS) | _BV(Z_AXIS);
FORCE_INLINE bool no_axes_homed() { return !axis_homed; }
FORCE_INLINE bool all_axes_homed() { return (axis_homed & xyz_bits) == xyz_bits; }
FORCE_INLINE bool all_axes_known() { return (axis_known_position & xyz_bits) == xyz_bits; }
FORCE_INLINE void set_all_unhomed() { axis_homed = 0; }
FORCE_INLINE void set_all_unknown() { axis_known_position = 0; }
FORCE_INLINE bool homing_needed() {
return !(
#if ENABLED(HOME_AFTER_DEACTIVATE)
all_axes_known()
#else
all_axes_homed()
#endif
);
}
// Error margin to work around float imprecision
constexpr float fslop = 0.0001;
@@ -63,8 +44,8 @@ extern xyze_pos_t current_position, // High-level current tool position
// G60/G61 Position Save and Return
#if SAVED_POSITIONS
extern uint8_t saved_slots[(SAVED_POSITIONS + 7) >> 3];
extern xyz_pos_t stored_position[SAVED_POSITIONS];
extern uint8_t saved_slots[(SAVED_POSITIONS + 7) >> 3]; // TODO: Add support for LINEAR_AXES >= 4
extern xyze_pos_t stored_position[SAVED_POSITIONS];
#endif
// Scratch space for a cartesian result
@@ -72,39 +53,57 @@ extern xyz_pos_t cartes;
// Until kinematics.cpp is created, declare this here
#if IS_KINEMATIC
extern abc_pos_t delta;
extern abce_pos_t delta;
#endif
#if HAS_ABL_NOT_UBL
extern float xy_probe_feedrate_mm_s;
extern feedRate_t xy_probe_feedrate_mm_s;
#define XY_PROBE_FEEDRATE_MM_S xy_probe_feedrate_mm_s
#elif defined(XY_PROBE_SPEED)
#define XY_PROBE_FEEDRATE_MM_S MMM_TO_MMS(XY_PROBE_SPEED)
#elif defined(XY_PROBE_FEEDRATE)
#define XY_PROBE_FEEDRATE_MM_S MMM_TO_MMS(XY_PROBE_FEEDRATE)
#else
#define XY_PROBE_FEEDRATE_MM_S PLANNER_XY_FEEDRATE()
#endif
#if ENABLED(Z_SAFE_HOMING)
constexpr xy_float_t safe_homing_xy = { Z_SAFE_HOMING_X_POINT, Z_SAFE_HOMING_Y_POINT };
#if HAS_BED_PROBE
constexpr feedRate_t z_probe_fast_mm_s = MMM_TO_MMS(Z_PROBE_FEEDRATE_FAST);
#endif
/**
* Feed rates are often configured with mm/m
* but the planner and stepper like mm/s units.
*/
extern const feedRate_t homing_feedrate_mm_s[XYZ];
FORCE_INLINE feedRate_t homing_feedrate(const AxisEnum a) { return pgm_read_float(&homing_feedrate_mm_s[a]); }
constexpr xyz_feedrate_t homing_feedrate_mm_m = HOMING_FEEDRATE_MM_M;
FORCE_INLINE feedRate_t homing_feedrate(const AxisEnum a) {
float v = TERN0(HAS_Z_AXIS, homing_feedrate_mm_m.z);
#if DISABLED(DELTA)
LINEAR_AXIS_CODE(
if (a == X_AXIS) v = homing_feedrate_mm_m.x,
else if (a == Y_AXIS) v = homing_feedrate_mm_m.y,
else if (a == Z_AXIS) v = homing_feedrate_mm_m.z,
else if (a == I_AXIS) v = homing_feedrate_mm_m.i,
else if (a == J_AXIS) v = homing_feedrate_mm_m.j,
else if (a == K_AXIS) v = homing_feedrate_mm_m.k
);
#endif
return MMM_TO_MMS(v);
}
feedRate_t get_homing_bump_feedrate(const AxisEnum axis);
/**
* The default feedrate for many moves, set by the most recent move
*/
extern feedRate_t feedrate_mm_s;
/**
* Feedrate scaling
* Feedrate scaling is applied to all G0/G1, G2/G3, and G5 moves
*/
extern int16_t feedrate_percentage;
#define MMS_SCALED(V) ((V) * 0.01f * feedrate_percentage)
// The active extruder (tool). Set with T<extruder> command.
#if EXTRUDERS > 1
#if HAS_MULTI_EXTRUDER
extern uint8_t active_extruder;
#else
constexpr uint8_t active_extruder = 0;
@@ -114,24 +113,35 @@ extern int16_t feedrate_percentage;
extern float e_move_accumulator;
#endif
FORCE_INLINE float pgm_read_any(const float *p) { return pgm_read_float(p); }
FORCE_INLINE signed char pgm_read_any(const signed char *p) { return pgm_read_byte(p); }
#ifdef __IMXRT1062__
#define DEFS_PROGMEM
#else
#define DEFS_PROGMEM PROGMEM
#endif
inline float pgm_read_any(const float *p) { return TERN(__IMXRT1062__, *p, pgm_read_float(p)); }
inline int8_t pgm_read_any(const int8_t *p) { return TERN(__IMXRT1062__, *p, pgm_read_byte(p)); }
#define XYZ_DEFS(T, NAME, OPT) \
extern const XYZval<T> NAME##_P; \
FORCE_INLINE T NAME(AxisEnum axis) { return pgm_read_any(&NAME##_P[axis]); }
inline T NAME(const AxisEnum axis) { \
static const XYZval<T> NAME##_P DEFS_PROGMEM = LINEAR_AXIS_ARRAY(X_##OPT, Y_##OPT, Z_##OPT, I_##OPT, J_##OPT, K_##OPT); \
return pgm_read_any(&NAME##_P[axis]); \
}
XYZ_DEFS(float, base_min_pos, MIN_POS);
XYZ_DEFS(float, base_max_pos, MAX_POS);
XYZ_DEFS(float, base_home_pos, HOME_POS);
XYZ_DEFS(float, max_length, MAX_LENGTH);
XYZ_DEFS(float, home_bump_mm, HOME_BUMP_MM);
XYZ_DEFS(signed char, home_dir, HOME_DIR);
XYZ_DEFS(int8_t, home_dir, HOME_DIR);
inline float home_bump_mm(const AxisEnum axis) {
static const xyz_pos_t home_bump_mm_P DEFS_PROGMEM = HOMING_BUMP_MM;
return pgm_read_any(&home_bump_mm_P[axis]);
}
#if HAS_WORKSPACE_OFFSET
void update_workspace_offset(const AxisEnum axis);
#else
#define update_workspace_offset(x) NOOP
inline void update_workspace_offset(const AxisEnum) {}
#endif
#if HAS_HOTEND_OFFSET
@@ -143,67 +153,167 @@ XYZ_DEFS(signed char, home_dir, HOME_DIR);
constexpr xyz_pos_t hotend_offset[1] = { { 0 } };
#endif
typedef struct { xyz_pos_t min, max; } axis_limits_t;
#if HAS_SOFTWARE_ENDSTOPS
extern bool soft_endstops_enabled;
extern axis_limits_t soft_endstop;
typedef struct {
bool _enabled, _loose;
bool enabled() { return _enabled && !_loose; }
xyz_pos_t min, max;
void get_manual_axis_limits(const AxisEnum axis, float &amin, float &amax) {
amin = -100000; amax = 100000; // "No limits"
#if HAS_SOFTWARE_ENDSTOPS
if (enabled()) switch (axis) {
case X_AXIS:
TERN_(MIN_SOFTWARE_ENDSTOP_X, amin = min.x);
TERN_(MAX_SOFTWARE_ENDSTOP_X, amax = max.x);
break;
#if HAS_Y_AXIS
case Y_AXIS:
TERN_(MIN_SOFTWARE_ENDSTOP_Y, amin = min.y);
TERN_(MAX_SOFTWARE_ENDSTOP_Y, amax = max.y);
break;
#endif
#if HAS_Z_AXIS
case Z_AXIS:
TERN_(MIN_SOFTWARE_ENDSTOP_Z, amin = min.z);
TERN_(MAX_SOFTWARE_ENDSTOP_Z, amax = max.z);
break;
#endif
#if LINEAR_AXES >= 4
case I_AXIS:
TERN_(MIN_SOFTWARE_ENDSTOP_I, amin = min.i);
TERN_(MIN_SOFTWARE_ENDSTOP_I, amax = max.i);
break;
#endif
#if LINEAR_AXES >= 5
case J_AXIS:
TERN_(MIN_SOFTWARE_ENDSTOP_J, amin = min.j);
TERN_(MIN_SOFTWARE_ENDSTOP_J, amax = max.j);
break;
#endif
#if LINEAR_AXES >= 6
case K_AXIS:
TERN_(MIN_SOFTWARE_ENDSTOP_K, amin = min.k);
TERN_(MIN_SOFTWARE_ENDSTOP_K, amax = max.k);
break;
#endif
default: break;
}
#endif
}
} soft_endstops_t;
extern soft_endstops_t soft_endstop;
void apply_motion_limits(xyz_pos_t &target);
void update_software_endstops(const AxisEnum axis
#if HAS_HOTEND_OFFSET
, const uint8_t old_tool_index=0, const uint8_t new_tool_index=0
#endif
);
#else
constexpr bool soft_endstops_enabled = false;
//constexpr axis_limits_t soft_endstop = {
// { X_MIN_POS, Y_MIN_POS, Z_MIN_POS },
// { X_MAX_POS, Y_MAX_POS, Z_MAX_POS } };
#define apply_motion_limits(V) NOOP
#define SET_SOFT_ENDSTOP_LOOSE(loose) (soft_endstop._loose = loose)
#else // !HAS_SOFTWARE_ENDSTOPS
typedef struct {
bool enabled() { return false; }
void get_manual_axis_limits(const AxisEnum axis, float &amin, float &amax) {
// No limits
amin = current_position[axis] - 1000;
amax = current_position[axis] + 1000;
}
} soft_endstops_t;
extern soft_endstops_t soft_endstop;
#define apply_motion_limits(V) NOOP
#define update_software_endstops(...) NOOP
#endif
#define SET_SOFT_ENDSTOP_LOOSE(V) NOOP
#endif // !HAS_SOFTWARE_ENDSTOPS
void report_real_position();
void report_current_position();
void report_current_position_projected();
#if ENABLED(AUTO_REPORT_POSITION)
#include "../libs/autoreport.h"
struct PositionReport { static void report() { report_current_position_projected(); } };
extern AutoReporter<PositionReport> position_auto_reporter;
#endif
#if EITHER(FULL_REPORT_TO_HOST_FEATURE, REALTIME_REPORTING_COMMANDS)
#define HAS_GRBL_STATE 1
/**
* Machine states for GRBL or TinyG
*/
enum M_StateEnum : uint8_t {
M_INIT = 0, // 0 machine is initializing
M_RESET, // 1 machine is ready for use
M_ALARM, // 2 machine is in alarm state (soft shut down)
M_IDLE, // 3 program stop or no more blocks (M0, M1, M60)
M_END, // 4 program end via M2, M30
M_RUNNING, // 5 motion is running
M_HOLD, // 6 motion is holding
M_PROBE, // 7 probe cycle active
M_CYCLING, // 8 machine is running (cycling)
M_HOMING, // 9 machine is homing
M_JOGGING, // 10 machine is jogging
M_ERROR // 11 machine is in hard alarm state (shut down)
};
extern M_StateEnum M_State_grbl;
M_StateEnum grbl_state_for_marlin_state();
void report_current_grblstate_moving();
void report_current_position_moving();
#if ENABLED(FULL_REPORT_TO_HOST_FEATURE)
inline void set_and_report_grblstate(const M_StateEnum state) {
M_State_grbl = state;
report_current_grblstate_moving();
}
#endif
#if ENABLED(REALTIME_REPORTING_COMMANDS)
void quickpause_stepper();
void quickresume_stepper();
#endif
#endif
void get_cartesian_from_steppers();
void set_current_from_steppers_for_axis(const AxisEnum axis);
void quickstop_stepper();
/**
* sync_plan_position
*
* Set the planner/stepper positions directly from current_position with
* no kinematic translation. Used for homing axes and cartesian/core syncing.
*/
void sync_plan_position();
void sync_plan_position_e();
#if HAS_EXTRUDERS
void sync_plan_position_e();
#endif
/**
* Move the planner to the current position from wherever it last moved
* (or from wherever it has been told it is located).
*/
void line_to_current_position(const feedRate_t &fr_mm_s=feedrate_mm_s);
void line_to_current_position(const_feedRate_t fr_mm_s=feedrate_mm_s);
#if EXTRUDERS
void unscaled_e_move(const float &length, const feedRate_t &fr_mm_s);
#if HAS_EXTRUDERS
void unscaled_e_move(const_float_t length, const_feedRate_t fr_mm_s);
#endif
void prepare_line_to_destination();
void _internal_move_to_destination(const feedRate_t &fr_mm_s=0.0f
#if IS_KINEMATIC
, const bool is_fast=false
#endif
);
void _internal_move_to_destination(const_feedRate_t fr_mm_s=0.0f OPTARG(IS_KINEMATIC, const bool is_fast=false));
inline void prepare_internal_move_to_destination(const feedRate_t &fr_mm_s=0.0f) {
inline void prepare_internal_move_to_destination(const_feedRate_t fr_mm_s=0.0f) {
_internal_move_to_destination(fr_mm_s);
}
#if IS_KINEMATIC
void prepare_fast_move_to_destination(const feedRate_t &scaled_fr_mm_s=MMS_SCALED(feedrate_mm_s));
void prepare_fast_move_to_destination(const_feedRate_t scaled_fr_mm_s=MMS_SCALED(feedrate_mm_s));
inline void prepare_internal_fast_move_to_destination(const feedRate_t &fr_mm_s=0.0f) {
inline void prepare_internal_fast_move_to_destination(const_feedRate_t fr_mm_s=0.0f) {
_internal_move_to_destination(fr_mm_s, true);
}
#endif
@@ -211,46 +321,114 @@ inline void prepare_internal_move_to_destination(const feedRate_t &fr_mm_s=0.0f)
/**
* Blocking movement and shorthand functions
*/
void do_blocking_move_to(const float rx, const float ry, const float rz, const feedRate_t &fr_mm_s=0.0f);
void do_blocking_move_to(const xy_pos_t &raw, const feedRate_t &fr_mm_s=0.0f);
void do_blocking_move_to(const xyz_pos_t &raw, const feedRate_t &fr_mm_s=0.0f);
void do_blocking_move_to(const xyze_pos_t &raw, const feedRate_t &fr_mm_s=0.0f);
void do_blocking_move_to(LINEAR_AXIS_ARGS(const float), const_feedRate_t fr_mm_s=0.0f);
void do_blocking_move_to(const xy_pos_t &raw, const_feedRate_t fr_mm_s=0.0f);
void do_blocking_move_to(const xyz_pos_t &raw, const_feedRate_t fr_mm_s=0.0f);
void do_blocking_move_to(const xyze_pos_t &raw, const_feedRate_t fr_mm_s=0.0f);
void do_blocking_move_to_x(const float &rx, const feedRate_t &fr_mm_s=0.0f);
void do_blocking_move_to_y(const float &ry, const feedRate_t &fr_mm_s=0.0f);
void do_blocking_move_to_z(const float &rz, const feedRate_t &fr_mm_s=0.0f);
void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s=0.0f);
#if HAS_Y_AXIS
void do_blocking_move_to_y(const_float_t ry, const_feedRate_t fr_mm_s=0.0f);
#endif
#if HAS_Z_AXIS
void do_blocking_move_to_z(const_float_t rz, const_feedRate_t fr_mm_s=0.0f);
#endif
#if LINEAR_AXES >= 4
void do_blocking_move_to_i(const_float_t ri, const_feedRate_t fr_mm_s=0.0f);
void do_blocking_move_to_xyz_i(const xyze_pos_t &raw, const_float_t i, const_feedRate_t fr_mm_s=0.0f);
#endif
#if LINEAR_AXES >= 5
void do_blocking_move_to_j(const_float_t rj, const_feedRate_t fr_mm_s=0.0f);
void do_blocking_move_to_xyzi_j(const xyze_pos_t &raw, const_float_t j, const_feedRate_t fr_mm_s=0.0f);
#endif
#if LINEAR_AXES >= 6
void do_blocking_move_to_k(const_float_t rk, const_feedRate_t fr_mm_s=0.0f);
void do_blocking_move_to_xyzij_k(const xyze_pos_t &raw, const_float_t k, const_feedRate_t fr_mm_s=0.0f);
#endif
void do_blocking_move_to_xy(const float &rx, const float &ry, const feedRate_t &fr_mm_s=0.0f);
void do_blocking_move_to_xy(const xy_pos_t &raw, const feedRate_t &fr_mm_s=0.0f);
FORCE_INLINE void do_blocking_move_to_xy(const xyz_pos_t &raw, const feedRate_t &fr_mm_s=0.0f) { do_blocking_move_to_xy(xy_pos_t(raw), fr_mm_s); }
FORCE_INLINE void do_blocking_move_to_xy(const xyze_pos_t &raw, const feedRate_t &fr_mm_s=0.0f) { do_blocking_move_to_xy(xy_pos_t(raw), fr_mm_s); }
#if HAS_Y_AXIS
void do_blocking_move_to_xy(const_float_t rx, const_float_t ry, const_feedRate_t fr_mm_s=0.0f);
void do_blocking_move_to_xy(const xy_pos_t &raw, const_feedRate_t fr_mm_s=0.0f);
FORCE_INLINE void do_blocking_move_to_xy(const xyz_pos_t &raw, const_feedRate_t fr_mm_s=0.0f) { do_blocking_move_to_xy(xy_pos_t(raw), fr_mm_s); }
FORCE_INLINE void do_blocking_move_to_xy(const xyze_pos_t &raw, const_feedRate_t fr_mm_s=0.0f) { do_blocking_move_to_xy(xy_pos_t(raw), fr_mm_s); }
#endif
void do_blocking_move_to_xy_z(const xy_pos_t &raw, const float &z, const feedRate_t &fr_mm_s=0.0f);
FORCE_INLINE void do_blocking_move_to_xy_z(const xyz_pos_t &raw, const float &z, const feedRate_t &fr_mm_s=0.0f) { do_blocking_move_to_xy_z(xy_pos_t(raw), z, fr_mm_s); }
FORCE_INLINE void do_blocking_move_to_xy_z(const xyze_pos_t &raw, const float &z, const feedRate_t &fr_mm_s=0.0f) { do_blocking_move_to_xy_z(xy_pos_t(raw), z, fr_mm_s); }
#if HAS_Z_AXIS
void do_blocking_move_to_xy_z(const xy_pos_t &raw, const_float_t z, const_feedRate_t fr_mm_s=0.0f);
FORCE_INLINE void do_blocking_move_to_xy_z(const xyz_pos_t &raw, const_float_t z, const_feedRate_t fr_mm_s=0.0f) { do_blocking_move_to_xy_z(xy_pos_t(raw), z, fr_mm_s); }
FORCE_INLINE void do_blocking_move_to_xy_z(const xyze_pos_t &raw, const_float_t z, const_feedRate_t fr_mm_s=0.0f) { do_blocking_move_to_xy_z(xy_pos_t(raw), z, fr_mm_s); }
#endif
void remember_feedrate_and_scaling();
void remember_feedrate_scaling_off();
void restore_feedrate_and_scaling();
//
// Homing
//
#if HAS_Z_AXIS
void do_z_clearance(const_float_t zclear, const bool lower_allowed=false);
#else
inline void do_z_clearance(float, bool=false) {}
#endif
uint8_t axes_need_homing(uint8_t axis_bits=0x07);
bool axis_unhomed_error(uint8_t axis_bits=0x07);
/**
* Homing and Trusted Axes
*/
typedef IF<(LINEAR_AXES > 8), uint16_t, uint8_t>::type linear_axis_bits_t;
constexpr linear_axis_bits_t linear_bits = _BV(LINEAR_AXES) - 1;
void set_axis_is_at_home(const AxisEnum axis);
#if HAS_ENDSTOPS
/**
* axis_homed
* Flags that each linear axis was homed.
* XYZ on cartesian, ABC on delta, ABZ on SCARA.
*
* axis_trusted
* Flags that the position is trusted in each linear axis. Set when homed.
* Cleared whenever a stepper powers off, potentially losing its position.
*/
extern linear_axis_bits_t axis_homed, axis_trusted;
void homeaxis(const AxisEnum axis);
void set_axis_never_homed(const AxisEnum axis);
linear_axis_bits_t axes_should_home(linear_axis_bits_t axis_bits=linear_bits);
bool homing_needed_error(linear_axis_bits_t axis_bits=linear_bits);
inline void set_axis_unhomed(const AxisEnum axis) { CBI(axis_homed, axis); }
inline void set_axis_untrusted(const AxisEnum axis) { CBI(axis_trusted, axis); }
inline void set_all_unhomed() { axis_homed = axis_trusted = 0; }
inline void set_axis_homed(const AxisEnum axis) { SBI(axis_homed, axis); }
inline void set_axis_trusted(const AxisEnum axis) { SBI(axis_trusted, axis); }
inline void set_all_homed() { axis_homed = axis_trusted = linear_bits; }
#else
constexpr linear_axis_bits_t axis_homed = linear_bits, axis_trusted = linear_bits; // Zero-endstop machines are always homed and trusted
inline void homeaxis(const AxisEnum axis) {}
inline void set_axis_never_homed(const AxisEnum) {}
inline linear_axis_bits_t axes_should_home(linear_axis_bits_t=linear_bits) { return false; }
inline bool homing_needed_error(linear_axis_bits_t=linear_bits) { return false; }
inline void set_axis_unhomed(const AxisEnum axis) {}
inline void set_axis_untrusted(const AxisEnum axis) {}
inline void set_all_unhomed() {}
inline void set_axis_homed(const AxisEnum axis) {}
inline void set_axis_trusted(const AxisEnum axis) {}
inline void set_all_homed() {}
#endif
inline bool axis_was_homed(const AxisEnum axis) { return TEST(axis_homed, axis); }
inline bool axis_is_trusted(const AxisEnum axis) { return TEST(axis_trusted, axis); }
inline bool axis_should_home(const AxisEnum axis) { return (axes_should_home() & _BV(axis)) != 0; }
inline bool no_axes_homed() { return !axis_homed; }
inline bool all_axes_homed() { return linear_bits == (axis_homed & linear_bits); }
inline bool homing_needed() { return !all_axes_homed(); }
inline bool all_axes_trusted() { return linear_bits == (axis_trusted & linear_bits); }
void home_if_needed(const bool keeplev=false);
#if ENABLED(NO_MOTION_BEFORE_HOMING)
#define MOTION_CONDITIONS (IsRunning() && !axis_unhomed_error())
#define MOTION_CONDITIONS (IsRunning() && !homing_needed_error())
#else
#define MOTION_CONDITIONS IsRunning()
#endif
void set_axis_is_at_home(const AxisEnum axis);
void set_axis_not_trusted(const AxisEnum axis);
void homeaxis(const AxisEnum axis);
#define BABYSTEP_ALLOWED() ((ENABLED(BABYSTEP_WITHOUT_HOMING) || all_axes_trusted()) && (ENABLED(BABYSTEP_ALWAYS_AVAILABLE) || printer_busy()))
/**
* Workspace offsets
@@ -289,16 +467,31 @@ void homeaxis(const AxisEnum axis);
FORCE_INLINE void toNative(xyze_pos_t&) {}
#endif
#define LOGICAL_X_POSITION(POS) NATIVE_TO_LOGICAL(POS, X_AXIS)
#define LOGICAL_Y_POSITION(POS) NATIVE_TO_LOGICAL(POS, Y_AXIS)
#define LOGICAL_Z_POSITION(POS) NATIVE_TO_LOGICAL(POS, Z_AXIS)
#define RAW_X_POSITION(POS) LOGICAL_TO_NATIVE(POS, X_AXIS)
#define RAW_Y_POSITION(POS) LOGICAL_TO_NATIVE(POS, Y_AXIS)
#define RAW_Z_POSITION(POS) LOGICAL_TO_NATIVE(POS, Z_AXIS)
#if HAS_Y_AXIS
#define LOGICAL_Y_POSITION(POS) NATIVE_TO_LOGICAL(POS, Y_AXIS)
#define RAW_Y_POSITION(POS) LOGICAL_TO_NATIVE(POS, Y_AXIS)
#endif
#if HAS_Z_AXIS
#define LOGICAL_Z_POSITION(POS) NATIVE_TO_LOGICAL(POS, Z_AXIS)
#define RAW_Z_POSITION(POS) LOGICAL_TO_NATIVE(POS, Z_AXIS)
#endif
#if LINEAR_AXES >= 4
#define LOGICAL_I_POSITION(POS) NATIVE_TO_LOGICAL(POS, I_AXIS)
#define RAW_I_POSITION(POS) LOGICAL_TO_NATIVE(POS, I_AXIS)
#endif
#if LINEAR_AXES >= 5
#define LOGICAL_J_POSITION(POS) NATIVE_TO_LOGICAL(POS, J_AXIS)
#define RAW_J_POSITION(POS) LOGICAL_TO_NATIVE(POS, J_AXIS)
#endif
#if LINEAR_AXES >= 6
#define LOGICAL_K_POSITION(POS) NATIVE_TO_LOGICAL(POS, K_AXIS)
#define RAW_K_POSITION(POS) LOGICAL_TO_NATIVE(POS, K_AXIS)
#endif
/**
* position_is_reachable family of functions
*/
#if IS_KINEMATIC // (DELTA or SCARA)
#if HAS_SCARA_OFFSET
@@ -306,10 +499,31 @@ void homeaxis(const AxisEnum axis);
#endif
// Return true if the given point is within the printable area
inline bool position_is_reachable(const float &rx, const float &ry, const float inset=0) {
inline bool position_is_reachable(const_float_t rx, const_float_t ry, const float inset=0) {
#if ENABLED(DELTA)
return HYPOT2(rx, ry) <= sq(DELTA_PRINTABLE_RADIUS - inset + fslop);
#elif ENABLED(POLARGRAPH)
const float x1 = rx - (X_MIN_POS), x2 = (X_MAX_POS) - rx, y = ry - (Y_MAX_POS),
a = HYPOT(x1, y), b = HYPOT(x2, y);
return a < (POLARGRAPH_MAX_BELT_LEN) + 1
&& b < (POLARGRAPH_MAX_BELT_LEN) + 1
&& (a + b) > _MIN(X_BED_SIZE, Y_BED_SIZE);
#elif ENABLED(AXEL_TPARA)
const float R2 = HYPOT2(rx - TPARA_OFFSET_X, ry - TPARA_OFFSET_Y);
return (
R2 <= sq(L1 + L2) - inset
#if MIDDLE_DEAD_ZONE_R > 0
&& R2 >= sq(float(MIDDLE_DEAD_ZONE_R))
#endif
);
#elif IS_SCARA
const float R2 = HYPOT2(rx - SCARA_OFFSET_X, ry - SCARA_OFFSET_Y);
return (
R2 <= sq(L1 + L2) - inset
@@ -317,6 +531,7 @@ void homeaxis(const AxisEnum axis);
&& R2 >= sq(float(MIDDLE_DEAD_ZONE_R))
#endif
);
#endif
}
@@ -327,15 +542,15 @@ void homeaxis(const AxisEnum axis);
#else // CARTESIAN
// Return true if the given position is within the machine bounds.
inline bool position_is_reachable(const float &rx, const float &ry) {
if (!WITHIN(ry, Y_MIN_POS - fslop, Y_MAX_POS + fslop)) return false;
inline bool position_is_reachable(const_float_t rx, const_float_t ry) {
if (!COORDINATE_OKAY(ry, Y_MIN_POS - fslop, Y_MAX_POS + fslop)) return false;
#if ENABLED(DUAL_X_CARRIAGE)
if (active_extruder)
return WITHIN(rx, X2_MIN_POS - fslop, X2_MAX_POS + fslop);
return COORDINATE_OKAY(rx, X2_MIN_POS - fslop, X2_MAX_POS + fslop);
else
return WITHIN(rx, X1_MIN_POS - fslop, X1_MAX_POS + fslop);
return COORDINATE_OKAY(rx, X1_MIN_POS - fslop, X1_MAX_POS + fslop);
#else
return WITHIN(rx, X_MIN_POS - fslop, X_MAX_POS + fslop);
return COORDINATE_OKAY(rx, X_MIN_POS - fslop, X_MAX_POS + fslop);
#endif
}
inline bool position_is_reachable(const xy_pos_t &pos) { return position_is_reachable(pos.x, pos.y); }
@@ -346,11 +561,7 @@ void homeaxis(const AxisEnum axis);
* Duplication mode
*/
#if HAS_DUPLICATION_MODE
extern bool extruder_duplication_enabled, // Used in Dual X mode 2
mirrored_duplication_mode; // Used in Dual X mode 3
#if ENABLED(MULTI_NOZZLE_DUPLICATION)
extern uint8_t duplication_e_mask;
#endif
extern bool extruder_duplication_enabled; // Used in Dual X mode 2
#endif
/**
@@ -366,29 +577,42 @@ void homeaxis(const AxisEnum axis);
};
extern DualXMode dual_x_carriage_mode;
extern float inactive_extruder_x_pos, // Used in mode 0 & 1
duplicate_extruder_x_offset; // Used in mode 2 & 3
extern xyz_pos_t raised_parked_position; // Used in mode 1
extern bool active_extruder_parked; // Used in mode 1, 2 & 3
extern millis_t delayed_move_time; // Used in mode 1
extern int16_t duplicate_extruder_temp_offset; // Used in mode 2 & 3
extern float inactive_extruder_x, // Used in mode 0 & 1
duplicate_extruder_x_offset; // Used in mode 2 & 3
extern xyz_pos_t raised_parked_position; // Used in mode 1
extern bool active_extruder_parked; // Used in mode 1, 2 & 3
extern millis_t delayed_move_time; // Used in mode 1
extern celsius_t duplicate_extruder_temp_offset; // Used in mode 2 & 3
extern bool idex_mirrored_mode; // Used in mode 3
FORCE_INLINE bool dxc_is_duplicating() { return dual_x_carriage_mode >= DXC_DUPLICATION_MODE; }
FORCE_INLINE bool idex_is_duplicating() { return dual_x_carriage_mode >= DXC_DUPLICATION_MODE; }
float x_home_pos(const int extruder);
float x_home_pos(const uint8_t extruder);
FORCE_INLINE int x_home_dir(const uint8_t extruder) { return extruder ? X2_HOME_DIR : X_HOME_DIR; }
#define TOOL_X_HOME_DIR(T) ((T) ? X2_HOME_DIR : X_HOME_DIR)
void set_duplication_enabled(const bool dupe, const int8_t tool_index=-1);
void idex_set_mirrored_mode(const bool mirr);
void idex_set_parked(const bool park=true);
#else
#if ENABLED(MULTI_NOZZLE_DUPLICATION)
extern uint8_t duplication_e_mask;
enum DualXMode : char { DXC_DUPLICATION_MODE = 2 };
FORCE_INLINE void set_duplication_enabled(const bool dupe) { extruder_duplication_enabled = dupe; }
#endif
FORCE_INLINE int x_home_dir(const uint8_t) { return home_dir(X_AXIS); }
#define TOOL_X_HOME_DIR(T) X_HOME_DIR
#endif
#if HAS_M206_COMMAND
void set_home_offset(const AxisEnum axis, const float v);
#endif
#if USE_SENSORLESS
struct sensorless_t;
sensorless_t start_sensorless_homing_per_axis(const AxisEnum axis);
void end_sensorless_homing_per_axis(const AxisEnum axis, sensorless_t enable_stealth);
#endif

1793
Marlin/src/module/planner.cpp Executable file → Normal file

File diff suppressed because it is too large Load Diff

532
Marlin/src/module/planner.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -32,11 +32,24 @@
#include "../MarlinCore.h"
#if ENABLED(JD_HANDLE_SMALL_SEGMENTS)
// Enable this option for perfect accuracy but maximum
// computation. Should be fine on ARM processors.
//#define JD_USE_MATH_ACOS
// Disable this option to save 120 bytes of PROGMEM,
// but incur increased computation and a reduction
// in accuracy.
#define JD_USE_LOOKUP_TABLE
#endif
#include "motion.h"
#include "../gcode/queue.h"
#if ENABLED(DELTA)
#include "delta.h"
#elif ENABLED(POLARGRAPH)
#include "polargraph.h"
#endif
#if ABL_PLANAR
@@ -52,16 +65,25 @@
#endif
#if HAS_CUTTER
#include "../feature/spindle_laser.h"
#include "../feature/spindle_laser_types.h"
#endif
#if ENABLED(DIRECT_STEPPING)
#include "../feature/direct_stepping.h"
#define IS_PAGE(B) TEST(B->flag, BLOCK_BIT_IS_PAGE)
#else
#define IS_PAGE(B) false
#endif
// Feedrate for manual moves
#ifdef MANUAL_FEEDRATE
constexpr xyze_feedrate_t _mf = MANUAL_FEEDRATE,
manual_feedrate_mm_s { _mf.x / 60.0f, _mf.y / 60.0f, _mf.z / 60.0f, _mf.e / 60.0f };
manual_feedrate_mm_s = LOGICAL_AXIS_ARRAY(_mf.e / 60.0f,
_mf.x / 60.0f, _mf.y / 60.0f, _mf.z / 60.0f,
_mf.i / 60.0f, _mf.j / 60.0f, _mf.k / 60.0f);
#endif
#if IS_KINEMATIC && DISABLED(CLASSIC_JERK)
#if IS_KINEMATIC && HAS_JUNCTION_DEVIATION
#define HAS_DIST_MM_ARG 1
#endif
@@ -79,15 +101,57 @@ enum BlockFlagBit : char {
// Sync the stepper counts from the block
BLOCK_BIT_SYNC_POSITION
// Direct stepping page
#if ENABLED(DIRECT_STEPPING)
, BLOCK_BIT_IS_PAGE
#endif
// Sync the fan speeds from the block
#if ENABLED(LASER_SYNCHRONOUS_M106_M107)
, BLOCK_BIT_SYNC_FANS
#endif
};
enum BlockFlag : char {
BLOCK_FLAG_RECALCULATE = _BV(BLOCK_BIT_RECALCULATE),
BLOCK_FLAG_NOMINAL_LENGTH = _BV(BLOCK_BIT_NOMINAL_LENGTH),
BLOCK_FLAG_CONTINUED = _BV(BLOCK_BIT_CONTINUED),
BLOCK_FLAG_SYNC_POSITION = _BV(BLOCK_BIT_SYNC_POSITION)
BLOCK_FLAG_RECALCULATE = _BV(BLOCK_BIT_RECALCULATE)
, BLOCK_FLAG_NOMINAL_LENGTH = _BV(BLOCK_BIT_NOMINAL_LENGTH)
, BLOCK_FLAG_CONTINUED = _BV(BLOCK_BIT_CONTINUED)
, BLOCK_FLAG_SYNC_POSITION = _BV(BLOCK_BIT_SYNC_POSITION)
#if ENABLED(DIRECT_STEPPING)
, BLOCK_FLAG_IS_PAGE = _BV(BLOCK_BIT_IS_PAGE)
#endif
#if ENABLED(LASER_SYNCHRONOUS_M106_M107)
, BLOCK_FLAG_SYNC_FANS = _BV(BLOCK_BIT_SYNC_FANS)
#endif
};
#define BLOCK_MASK_SYNC ( BLOCK_FLAG_SYNC_POSITION | TERN0(LASER_SYNCHRONOUS_M106_M107, BLOCK_FLAG_SYNC_FANS) )
#if ENABLED(LASER_POWER_INLINE)
typedef struct {
bool isPlanned:1;
bool isEnabled:1;
bool dir:1;
bool Reserved:6;
} power_status_t;
typedef struct {
power_status_t status; // See planner settings for meaning
uint8_t power; // Ditto; When in trapezoid mode this is nominal power
#if ENABLED(LASER_POWER_INLINE_TRAPEZOID)
uint8_t power_entry; // Entry power for the laser
#if DISABLED(LASER_POWER_INLINE_TRAPEZOID_CONT)
uint8_t power_exit; // Exit power for the laser
uint32_t entry_per, // Steps per power increment (to avoid floats in stepper calcs)
exit_per; // Steps per power decrement
#endif
#endif
} block_laser_t;
#endif
/**
* struct block_t
*
@@ -114,14 +178,14 @@ typedef struct block_t {
};
uint32_t step_event_count; // The number of step events required to complete this block
#if EXTRUDERS > 1
#if HAS_MULTI_EXTRUDER
uint8_t extruder; // The extruder to move (if E move)
#else
static constexpr uint8_t extruder = 0;
#endif
#if ENABLED(MIXING_EXTRUDER)
MIXER_BLOCK_FIELD; // Normalized color for the mixing steppers
mixer_comp_t b_color[MIXING_STEPPERS]; // Normalized color for the mixing steppers
#endif
// Settings for the trapezoid generator
@@ -138,7 +202,7 @@ typedef struct block_t {
uint32_t acceleration_rate; // The acceleration rate used for acceleration calculation
#endif
uint8_t direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h)
axis_bits_t direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h)
// Advance extrusion
#if ENABLED(LIN_ADVANCE)
@@ -154,11 +218,15 @@ typedef struct block_t {
final_rate, // The minimal rate at exit
acceleration_steps_per_s2; // acceleration steps/sec^2
#if ENABLED(DIRECT_STEPPING)
page_idx_t page_idx; // Page index used for direct stepping
#endif
#if HAS_CUTTER
cutter_power_t cutter_power; // Power level for Spindle, Laser, etc.
#endif
#if FAN_COUNT > 0
#if HAS_FAN
uint8_t fan_speed[FAN_COUNT];
#endif
@@ -166,7 +234,7 @@ typedef struct block_t {
uint8_t valve_pressure, e_to_p_pressure;
#endif
#if HAS_SPI_LCD
#if HAS_WIRED_LCD
uint32_t segment_time_us;
#endif
@@ -174,17 +242,40 @@ typedef struct block_t {
uint32_t sdpos;
#endif
#if ENABLED(LASER_POWER_INLINE)
block_laser_t laser;
#endif
} block_t;
#define HAS_POSITION_FLOAT ANY(LIN_ADVANCE, SCARA_FEEDRATE_SCALING, GRADIENT_MIX, LCD_SHOW_E_TOTAL)
#if ANY(LIN_ADVANCE, SCARA_FEEDRATE_SCALING, GRADIENT_MIX, LCD_SHOW_E_TOTAL)
#define HAS_POSITION_FLOAT 1
#endif
#define BLOCK_MOD(n) ((n)&(BLOCK_BUFFER_SIZE-1))
#if ENABLED(LASER_POWER_INLINE)
typedef struct {
/**
* Laser status flags
*/
power_status_t status;
/**
* Laser power: 0 or 255 in case of PWM-less laser,
* or the OCR (oscillator count register) value;
*
* Using OCR instead of raw power, because it avoids
* floating point operations during the move loop.
*/
uint8_t power;
} laser_state_t;
#endif
typedef struct {
uint32_t max_acceleration_mm_per_s2[XYZE_N], // (mm/s^2) M201 XYZE
uint32_t max_acceleration_mm_per_s2[DISTINCT_AXES], // (mm/s^2) M201 XYZE
min_segment_time_us; // (µs) M205 B
float axis_steps_per_mm[XYZE_N]; // (steps) M92 XYZE - Steps per millimeter
feedRate_t max_feedrate_mm_s[XYZE_N]; // (mm/s) M203 XYZE - Max speeds
float axis_steps_per_mm[DISTINCT_AXES]; // (steps) M92 XYZE - Steps per millimeter
feedRate_t max_feedrate_mm_s[DISTINCT_AXES]; // (mm/s) M203 XYZE - Max speeds
float acceleration, // (mm/s^2) M204 S - Normal acceleration. DEFAULT ACCELERATION for all printing moves.
retract_acceleration, // (mm/s^2) M204 R - Retract acceleration. Filament pull-back and push-forward while standing still in the other axes
travel_acceleration; // (mm/s^2) M204 T - Travel acceleration. DEFAULT ACCELERATION for all NON printing moves.
@@ -192,6 +283,15 @@ typedef struct {
min_travel_feedrate_mm_s; // (mm/s) M205 T - Minimum travel feedrate
} planner_settings_t;
#if ENABLED(IMPROVE_HOMING_RELIABILITY)
struct motion_state_t {
TERN(DELTA, xyz_ulong_t, xy_ulong_t) acceleration;
#if HAS_CLASSIC_JERK
TERN(DELTA, xyz_float_t, xy_float_t) jerk_state;
#endif
};
#endif
#if DISABLED(SKEW_CORRECTION)
#define XY_SKEW_FACTOR 0
#define XZ_SKEW_FACTOR 0
@@ -212,6 +312,10 @@ typedef struct {
#endif
} skew_factor_t;
#if ENABLED(DISABLE_INACTIVE_EXTRUDER)
typedef IF<(BLOCK_BUFFER_SIZE > 64), uint16_t, uint8_t>::type last_move_t;
#endif
class Planner {
public:
@@ -241,7 +345,12 @@ class Planner {
static uint8_t last_extruder; // Respond to extruder change
#endif
#if EXTRUDERS
#if ENABLED(DIRECT_STEPPING)
static uint32_t last_page_step_rate; // Last page step rate given
static xyze_bool_t last_page_dir; // Last page direction given
#endif
#if HAS_EXTRUDERS
static int16_t flow_percentage[EXTRUDERS]; // Extrusion factor for each extruder
static float e_factor[EXTRUDERS]; // The flow percentage and volumetric multiplier combine to scale E movement
#endif
@@ -253,28 +362,30 @@ class Planner {
// May be auto-adjusted by a filament width sensor
#endif
#if ENABLED(VOLUMETRIC_EXTRUDER_LIMIT)
static float volumetric_extruder_limit[EXTRUDERS], // Maximum mm^3/sec the extruder can handle
volumetric_extruder_feedrate_limit[EXTRUDERS]; // Feedrate limit (mm/s) calculated from volume limit
#endif
static planner_settings_t settings;
static uint32_t max_acceleration_steps_per_s2[XYZE_N]; // (steps/s^2) Derived from mm_per_s2
static float steps_to_mm[XYZE_N]; // Millimeters per step
#if ENABLED(LASER_POWER_INLINE)
static laser_state_t laser_inline;
#endif
#if DISABLED(CLASSIC_JERK)
static float junction_deviation_mm; // (mm) M205 J
#if ENABLED(LIN_ADVANCE)
static float max_e_jerk // Calculated from junction_deviation_mm
#if ENABLED(DISTINCT_E_FACTORS)
[EXTRUDERS]
#endif
;
static uint32_t max_acceleration_steps_per_s2[DISTINCT_AXES]; // (steps/s^2) Derived from mm_per_s2
static float mm_per_step[DISTINCT_AXES]; // Millimeters per step
#if HAS_JUNCTION_DEVIATION
static float junction_deviation_mm; // (mm) M205 J
#if HAS_LINEAR_E_JERK
static float max_e_jerk[DISTINCT_E]; // Calculated from junction_deviation_mm
#endif
#endif
#if HAS_CLASSIC_JERK
#if HAS_LINEAR_E_JERK
static xyz_pos_t max_jerk; // (mm/s^2) M205 XYZ - The largest speed change requiring no acceleration.
#else
static xyze_pos_t max_jerk; // (mm/s^2) M205 XYZE - The largest speed change requiring no acceleration.
#endif
// (mm/s^2) M205 XYZ(E) - The largest speed change requiring no acceleration.
static TERN(HAS_LINEAR_E_JERK, xyz_pos_t, xyze_pos_t) max_jerk;
#endif
#if HAS_LEVELING
@@ -312,6 +423,23 @@ class Planner {
#if ENABLED(SD_ABORT_ON_ENDSTOP_HIT)
static bool abort_on_endstop_hit;
#endif
#ifdef XY_FREQUENCY_LIMIT
static int8_t xy_freq_limit_hz; // Minimum XY frequency setting
static float xy_freq_min_speed_factor; // Minimum speed factor setting
static int32_t xy_freq_min_interval_us; // Minimum segment time based on xy_freq_limit_hz
static inline void refresh_frequency_limit() {
//xy_freq_min_interval_us = xy_freq_limit_hz ?: LROUND(1000000.0f / xy_freq_limit_hz);
if (xy_freq_limit_hz)
xy_freq_min_interval_us = LROUND(1000000.0f / xy_freq_limit_hz);
}
static inline void set_min_speed_factor_u8(const uint8_t v255) {
xy_freq_min_speed_factor = float(ui8_to_percent(v255)) / 100;
}
static inline void set_frequency_limit(const uint8_t hz) {
xy_freq_limit_hz = constrain(hz, 0, 100);
refresh_frequency_limit();
}
#endif
private:
@@ -328,30 +456,19 @@ class Planner {
/**
* Limit where 64bit math is necessary for acceleration calculation
*/
static uint32_t cutoff_long;
static uint32_t acceleration_long_cutoff;
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
static float last_fade_z;
#endif
#if ENABLED(DISABLE_INACTIVE_EXTRUDER)
/**
* Counters to manage disabling inactive extruders
*/
static uint8_t g_uc_extruder_last_move[EXTRUDERS];
#endif // DISABLE_INACTIVE_EXTRUDER
#ifdef XY_FREQUENCY_LIMIT
// Used for the frequency limit
#define MAX_FREQ_TIME_US (uint32_t)(1000000.0 / XY_FREQUENCY_LIMIT)
// Old direction bits. Used for speed calculations
static unsigned char old_direction_bits;
// Segment times (in µs). Used for speed calculations
static xy_ulong_t axis_segment_time_us[3];
// Counters to manage disabling inactive extruder steppers
static last_move_t g_uc_extruder_last_move[E_STEPPERS];
#endif
#if HAS_SPI_LCD
volatile static uint32_t block_buffer_runtime_us; //Theoretical block buffer runtime in µs
#if HAS_WIRED_LCD
volatile static uint32_t block_buffer_runtime_us; // Theoretical block buffer runtime in µs
#endif
public:
@@ -368,28 +485,52 @@ class Planner {
* Static (class) Methods
*/
// Recalculate steps/s^2 accelerations based on mm/s^2 settings
static void reset_acceleration_rates();
/**
* Recalculate 'position' and 'mm_per_step'.
* Must be called whenever settings.axis_steps_per_mm changes!
*/
static void refresh_positioning();
static void set_max_acceleration(const uint8_t axis, float targetValue);
static void set_max_feedrate(const uint8_t axis, float targetValue);
static void set_max_jerk(const AxisEnum axis, float targetValue);
// For an axis set the Maximum Acceleration in mm/s^2
static void set_max_acceleration(const uint8_t axis, float inMaxAccelMMS2);
#if EXTRUDERS
// For an axis set the Maximum Feedrate in mm/s
static void set_max_feedrate(const uint8_t axis, float inMaxFeedrateMMS);
// For an axis set the Maximum Jerk (instant change) in mm/s
#if HAS_CLASSIC_JERK
static void set_max_jerk(const AxisEnum axis, float inMaxJerkMMS);
#else
static inline void set_max_jerk(const AxisEnum, const_float_t) {}
#endif
#if HAS_EXTRUDERS
FORCE_INLINE static void refresh_e_factor(const uint8_t e) {
e_factor[e] = (flow_percentage[e] * 0.01f
#if DISABLED(NO_VOLUMETRICS)
* volumetric_multiplier[e]
#endif
);
e_factor[e] = flow_percentage[e] * 0.01f * TERN(NO_VOLUMETRICS, 1.0f, volumetric_multiplier[e]);
}
static inline void set_flow(const uint8_t e, const int16_t flow) {
flow_percentage[e] = flow;
refresh_e_factor(e);
}
#endif
// Manage fans, paste pressure, etc.
static void check_axes_activity();
// Update multipliers based on new diameter measurements
static void calculate_volumetric_multipliers();
// Apply fan speeds
#if HAS_FAN
static void sync_fan_speeds(uint8_t (&fan_speed)[FAN_COUNT]);
#if FAN_KICKSTART_TIME
static void kickstart_fan(uint8_t (&fan_speed)[FAN_COUNT], const millis_t &ms, const uint8_t f);
#else
FORCE_INLINE static void kickstart_fan(uint8_t (&)[FAN_COUNT], const millis_t &, const uint8_t) {}
#endif
#endif
#if ENABLED(FILAMENT_WIDTH_SENSOR)
void apply_filament_width_sensor(const int8_t encoded_ratio);
@@ -402,10 +543,24 @@ class Planner {
}
#endif
#if ENABLED(IMPROVE_HOMING_RELIABILITY)
void enable_stall_prevention(const bool onoff);
#endif
#if DISABLED(NO_VOLUMETRICS)
FORCE_INLINE static void set_filament_size(const uint8_t e, const float &v) {
// Update multipliers based on new diameter measurements
static void calculate_volumetric_multipliers();
#if ENABLED(VOLUMETRIC_EXTRUDER_LIMIT)
// Update pre calculated extruder feedrate limits based on volumetric values
static void calculate_volumetric_extruder_limit(const uint8_t e);
static void calculate_volumetric_extruder_limits();
#endif
FORCE_INLINE static void set_filament_size(const uint8_t e, const_float_t v) {
filament_size[e] = v;
if (v > 0) volumetric_area_nominal = CIRCLE_AREA(v * 0.5); //TODO: should it be per extruder
// make sure all extruders have some sane value for the filament size
LOOP_L_N(i, COUNT(filament_size))
if (!filament_size[i]) filament_size[i] = DEFAULT_NOMINAL_FILAMENT_DIA;
@@ -413,6 +568,13 @@ class Planner {
#endif
#if ENABLED(VOLUMETRIC_EXTRUDER_LIMIT)
FORCE_INLINE static void set_volumetric_extruder_limit(const uint8_t e, const_float_t v) {
volumetric_extruder_limit[e] = v;
calculate_volumetric_extruder_limit(e);
}
#endif
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
/**
@@ -422,7 +584,7 @@ class Planner {
* Returns 1.0 if planner.z_fade_height is 0.0.
* Returns 0.0 if Z is past the specified 'Fade Height'.
*/
static inline float fade_scaling_factor_for_z(const float &rz) {
static inline float fade_scaling_factor_for_z(const_float_t rz) {
static float z_fade_factor = 1;
if (!z_fade_height) return 1;
if (rz >= z_fade_height) return 0;
@@ -435,42 +597,42 @@ class Planner {
FORCE_INLINE static void force_fade_recalc() { last_fade_z = -999.999f; }
FORCE_INLINE static void set_z_fade_height(const float &zfh) {
FORCE_INLINE static void set_z_fade_height(const_float_t zfh) {
z_fade_height = zfh > 0 ? zfh : 0;
inverse_z_fade_height = RECIPROCAL(z_fade_height);
force_fade_recalc();
}
FORCE_INLINE static bool leveling_active_at_z(const float &rz) {
FORCE_INLINE static bool leveling_active_at_z(const_float_t rz) {
return !z_fade_height || rz < z_fade_height;
}
#else
FORCE_INLINE static float fade_scaling_factor_for_z(const float&) { return 1; }
FORCE_INLINE static float fade_scaling_factor_for_z(const_float_t) { return 1; }
FORCE_INLINE static bool leveling_active_at_z(const float&) { return true; }
FORCE_INLINE static bool leveling_active_at_z(const_float_t) { return true; }
#endif
#if ENABLED(SKEW_CORRECTION)
FORCE_INLINE static void skew(float &cx, float &cy, const float &cz) {
if (WITHIN(cx, X_MIN_POS + 1, X_MAX_POS) && WITHIN(cy, Y_MIN_POS + 1, Y_MAX_POS)) {
FORCE_INLINE static void skew(float &cx, float &cy, const_float_t cz) {
if (COORDINATE_OKAY(cx, X_MIN_POS + 1, X_MAX_POS) && COORDINATE_OKAY(cy, Y_MIN_POS + 1, Y_MAX_POS)) {
const float sx = cx - cy * skew_factor.xy - cz * (skew_factor.xz - (skew_factor.xy * skew_factor.yz)),
sy = cy - cz * skew_factor.yz;
if (WITHIN(sx, X_MIN_POS, X_MAX_POS) && WITHIN(sy, Y_MIN_POS, Y_MAX_POS)) {
if (COORDINATE_OKAY(sx, X_MIN_POS, X_MAX_POS) && COORDINATE_OKAY(sy, Y_MIN_POS, Y_MAX_POS)) {
cx = sx; cy = sy;
}
}
}
FORCE_INLINE static void skew(xyz_pos_t &raw) { skew(raw.x, raw.y, raw.z); }
FORCE_INLINE static void unskew(float &cx, float &cy, const float &cz) {
if (WITHIN(cx, X_MIN_POS, X_MAX_POS) && WITHIN(cy, Y_MIN_POS, Y_MAX_POS)) {
FORCE_INLINE static void unskew(float &cx, float &cy, const_float_t cz) {
if (COORDINATE_OKAY(cx, X_MIN_POS, X_MAX_POS) && COORDINATE_OKAY(cy, Y_MIN_POS, Y_MAX_POS)) {
const float sx = cx + cy * skew_factor.xy + cz * skew_factor.xz,
sy = cy + cz * skew_factor.yz;
if (WITHIN(sx, X_MIN_POS, X_MAX_POS) && WITHIN(sy, Y_MIN_POS, Y_MAX_POS)) {
if (COORDINATE_OKAY(sx, X_MIN_POS, X_MAX_POS) && COORDINATE_OKAY(sy, Y_MIN_POS, Y_MAX_POS)) {
cx = sx; cy = sy;
}
}
@@ -491,6 +653,9 @@ class Planner {
unapply_leveling(raw);
leveling_active = false;
}
#else
FORCE_INLINE static void apply_leveling(xyz_pos_t&) {}
FORCE_INLINE static void unapply_leveling(xyz_pos_t&) {}
#endif
#if ENABLED(FWRETRACT)
@@ -501,46 +666,16 @@ class Planner {
#endif
#if HAS_POSITION_MODIFIERS
FORCE_INLINE static void apply_modifiers(xyze_pos_t &pos
#if HAS_LEVELING
, bool leveling =
#if PLANNER_LEVELING
true
#else
false
#endif
#endif
) {
#if ENABLED(SKEW_CORRECTION)
skew(pos);
#endif
#if HAS_LEVELING
if (leveling) apply_leveling(pos);
#endif
#if ENABLED(FWRETRACT)
apply_retract(pos);
#endif
FORCE_INLINE static void apply_modifiers(xyze_pos_t &pos, bool leveling=ENABLED(PLANNER_LEVELING)) {
TERN_(SKEW_CORRECTION, skew(pos));
if (leveling) apply_leveling(pos);
TERN_(FWRETRACT, apply_retract(pos));
}
FORCE_INLINE static void unapply_modifiers(xyze_pos_t &pos
#if HAS_LEVELING
, bool leveling =
#if PLANNER_LEVELING
true
#else
false
#endif
#endif
) {
#if ENABLED(FWRETRACT)
unapply_retract(pos);
#endif
#if HAS_LEVELING
if (leveling) unapply_leveling(pos);
#endif
#if ENABLED(SKEW_CORRECTION)
unskew(pos);
#endif
FORCE_INLINE static void unapply_modifiers(xyze_pos_t &pos, bool leveling=ENABLED(PLANNER_LEVELING)) {
TERN_(FWRETRACT, unapply_retract(pos));
if (leveling) unapply_leveling(pos);
TERN_(SKEW_CORRECTION, unskew(pos));
}
#endif // HAS_POSITION_MODIFIERS
@@ -589,13 +724,9 @@ class Planner {
* Returns true if movement was buffered, false otherwise
*/
static bool _buffer_steps(const xyze_long_t &target
#if HAS_POSITION_FLOAT
, const xyze_pos_t &target_float
#endif
#if HAS_DIST_MM_ARG
, const xyze_float_t &cart_dist_mm
#endif
, feedRate_t fr_mm_s, const uint8_t extruder, const float &millimeters=0.0
OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float)
OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm)
, feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters=0.0
);
/**
@@ -610,28 +741,26 @@ class Planner {
*
* Returns true is movement is acceptable, false otherwise
*/
static bool _populate_block(block_t * const block, bool split_move,
const xyze_long_t &target
#if HAS_POSITION_FLOAT
, const xyze_pos_t &target_float
#endif
#if HAS_DIST_MM_ARG
, const xyze_float_t &cart_dist_mm
#endif
, feedRate_t fr_mm_s, const uint8_t extruder, const float &millimeters=0.0
static bool _populate_block(block_t * const block, bool split_move, const xyze_long_t &target
OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float)
OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm)
, feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters=0.0
);
/**
* Planner::buffer_sync_block
* Add a block to the buffer that just updates the position
* Add a block to the buffer that just updates the position or in
* case of LASER_SYNCHRONOUS_M106_M107 the fan pwm
*/
static void buffer_sync_block();
static void buffer_sync_block(
TERN_(LASER_SYNCHRONOUS_M106_M107, uint8_t sync_flag=BLOCK_FLAG_SYNC_POSITION)
);
#if IS_KINEMATIC
private:
// Allow do_homing_move to access internal functions, such as buffer_segment.
friend void do_homing_move(const AxisEnum, const float, const feedRate_t);
friend void do_homing_move(const AxisEnum, const float, const feedRate_t, const bool);
#endif
/**
@@ -646,26 +775,11 @@ class Planner {
* extruder - target extruder
* millimeters - the length of the movement, if known
*/
static bool buffer_segment(const float &a, const float &b, const float &c, const float &e
#if HAS_DIST_MM_ARG
, const xyze_float_t &cart_dist_mm
#endif
, const feedRate_t &fr_mm_s, const uint8_t extruder, const float &millimeters=0.0
static bool buffer_segment(const abce_pos_t &abce
OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm)
, const_feedRate_t fr_mm_s, const uint8_t extruder=active_extruder, const_float_t millimeters=0.0
);
FORCE_INLINE static bool buffer_segment(abce_pos_t &abce
#if HAS_DIST_MM_ARG
, const xyze_float_t &cart_dist_mm
#endif
, const feedRate_t &fr_mm_s, const uint8_t extruder, const float &millimeters=0.0
) {
return buffer_segment(abce.a, abce.b, abce.c, abce.e
#if HAS_DIST_MM_ARG
, cart_dist_mm
#endif
, fr_mm_s, extruder, millimeters);
}
public:
/**
@@ -673,29 +787,19 @@ class Planner {
* The target is cartesian. It's translated to
* delta/scara if needed.
*
* rx,ry,rz,e - target position in mm or degrees
* cart - target position in mm or degrees
* fr_mm_s - (target) speed of the move (mm/s)
* extruder - target extruder
* millimeters - the length of the movement, if known
* inv_duration - the reciprocal if the duration of the movement, if known (kinematic only if feeedrate scaling is enabled)
*/
static bool buffer_line(const float &rx, const float &ry, const float &rz, const float &e, const feedRate_t &fr_mm_s, const uint8_t extruder, const float millimeters=0.0
#if ENABLED(SCARA_FEEDRATE_SCALING)
, const float &inv_duration=0.0
#endif
static bool buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, const uint8_t extruder=active_extruder, const float millimeters=0.0
OPTARG(SCARA_FEEDRATE_SCALING, const_float_t inv_duration=0.0)
);
FORCE_INLINE static bool buffer_line(const xyze_pos_t &cart, const feedRate_t &fr_mm_s, const uint8_t extruder, const float millimeters=0.0
#if ENABLED(SCARA_FEEDRATE_SCALING)
, const float &inv_duration=0.0
#endif
) {
return buffer_line(cart.x, cart.y, cart.z, cart.e, fr_mm_s, extruder, millimeters
#if ENABLED(SCARA_FEEDRATE_SCALING)
, inv_duration
#endif
);
}
#if ENABLED(DIRECT_STEPPING)
static void buffer_page(const page_idx_t page_idx, const uint8_t extruder, const uint16_t num_steps);
#endif
/**
* Set the planner.position and individual stepper positions.
@@ -710,9 +814,11 @@ class Planner {
*
* Clears previous speed values.
*/
static void set_position_mm(const float &rx, const float &ry, const float &rz, const float &e);
FORCE_INLINE static void set_position_mm(const xyze_pos_t &cart) { set_position_mm(cart.x, cart.y, cart.z, cart.e); }
static void set_e_position_mm(const float &e);
static void set_position_mm(const xyze_pos_t &xyze);
#if HAS_EXTRUDERS
static void set_e_position_mm(const_float_t e);
#endif
/**
* Set the planner.position and individual stepper positions.
@@ -720,8 +826,7 @@ class Planner {
* The supplied position is in machine space, and no additional
* conversions are applied.
*/
static void set_machine_position_mm(const float &a, const float &b, const float &c, const float &e);
FORCE_INLINE static void set_machine_position_mm(const abce_pos_t &abce) { set_machine_position_mm(abce.a, abce.b, abce.c, abce.e); }
static void set_machine_position_mm(const abce_pos_t &abce);
/**
* Get an axis position according to stepper position(s)
@@ -730,12 +835,11 @@ class Planner {
static float get_axis_position_mm(const AxisEnum axis);
static inline abce_pos_t get_axis_positions_mm() {
const abce_pos_t out = {
get_axis_position_mm(A_AXIS),
get_axis_position_mm(B_AXIS),
get_axis_position_mm(C_AXIS),
get_axis_position_mm(E_AXIS)
};
const abce_pos_t out = LOGICAL_AXIS_ARRAY(
get_axis_position_mm(E_AXIS),
get_axis_position_mm(A_AXIS), get_axis_position_mm(B_AXIS), get_axis_position_mm(C_AXIS),
get_axis_position_mm(I_AXIS), get_axis_position_mm(J_AXIS), get_axis_position_mm(K_AXIS)
);
return out;
}
@@ -748,7 +852,14 @@ class Planner {
// a Full Shutdown is required, or when endstops are hit)
static void quick_stop();
// Called when an endstop is triggered. Causes the machine to stop inmediately
#if ENABLED(REALTIME_REPORTING_COMMANDS)
// Force a quick pause of the machine (e.g., when a pause is required in the middle of move).
// NOTE: Hard-stops will lose steps so encoders are highly recommended if using these!
static void quick_pause();
static void quick_resume();
#endif
// Called when an endstop is triggered. Causes the machine to stop immediately
static void endstop_triggered(const AxisEnum axis);
// Triggered position of an axis in mm (not core-savvy)
@@ -760,16 +871,9 @@ class Planner {
// Wait for moves to finish and disable all steppers
static void finish_and_disable();
// Periodic tick to handle cleaning timeouts
// Periodic handler to manage the cleaning buffer counter
// Called from the Temperature ISR at ~1kHz
static void tick() {
if (cleaning_buffer_counter) {
--cleaning_buffer_counter;
#if ENABLED(SD_FINISHED_STEPPERRELEASE) && defined(SD_FINISHED_RELEASECOMMAND)
if (!cleaning_buffer_counter) queue.inject_P(PSTR(SD_FINISHED_RELEASECOMMAND));
#endif
}
}
static void isr() { if (cleaning_buffer_counter) --cleaning_buffer_counter; }
/**
* Does the buffer have any blocks queued?
@@ -787,40 +891,46 @@ class Planner {
static block_t* get_current_block();
/**
* "Discard" the block and "release" the memory.
* "Release" the current block so its slot can be reused.
* Called when the current block is no longer needed.
*/
FORCE_INLINE static void discard_current_block() {
FORCE_INLINE static void release_current_block() {
if (has_blocks_queued())
block_buffer_tail = next_block_index(block_buffer_tail);
}
#if HAS_SPI_LCD
#if HAS_WIRED_LCD
static uint16_t block_buffer_runtime();
static void clear_block_buffer_runtime();
#endif
#if ENABLED(AUTOTEMP)
static float autotemp_min, autotemp_max, autotemp_factor;
static celsius_t autotemp_min, autotemp_max;
static float autotemp_factor;
static bool autotemp_enabled;
static void getHighESpeed();
static void autotemp_update();
static void autotemp_M104_M109();
static void autotemp_task();
#endif
#if HAS_LINEAR_E_JERK
FORCE_INLINE static void recalculate_max_e_jerk() {
#define GET_MAX_E_JERK(N) SQRT(SQRT(0.5) * junction_deviation_mm * (N) * RECIPROCAL(1.0 - SQRT(0.5)))
#if ENABLED(DISTINCT_E_FACTORS)
LOOP_L_N(i, EXTRUDERS)
max_e_jerk[i] = GET_MAX_E_JERK(settings.max_acceleration_mm_per_s2[E_AXIS_N(i)]);
#else
max_e_jerk = GET_MAX_E_JERK(settings.max_acceleration_mm_per_s2[E_AXIS]);
#endif
const float prop = junction_deviation_mm * SQRT(0.5) / (1.0f - SQRT(0.5));
LOOP_L_N(i, EXTRUDERS)
max_e_jerk[E_INDEX_N(i)] = SQRT(prop * settings.max_acceleration_mm_per_s2[E_INDEX_N(i)]);
}
#endif
private:
#if ENABLED(AUTOTEMP)
#if ENABLED(AUTOTEMP_PROPORTIONAL)
static void _autotemp_update_from_hotend();
#else
static inline void _autotemp_update_from_hotend() {}
#endif
#endif
/**
* Get the index of the next / previous block in the ring buffer
*/
@@ -831,7 +941,7 @@ class Planner {
* Calculate the distance (not time) it takes to accelerate
* from initial_rate to target_rate using the given acceleration:
*/
static float estimate_acceleration_distance(const float &initial_rate, const float &target_rate, const float &accel) {
static float estimate_acceleration_distance(const_float_t initial_rate, const_float_t target_rate, const_float_t accel) {
if (accel == 0) return 0; // accel was 0, set acceleration distance to 0
return (sq(target_rate) - sq(initial_rate)) / (accel * 2);
}
@@ -844,7 +954,7 @@ class Planner {
* This is used to compute the intersection point between acceleration and deceleration
* in cases where the "trapezoid" has no plateau (i.e., never reaches maximum speed)
*/
static float intersection_distance(const float &initial_rate, const float &final_rate, const float &accel, const float &distance) {
static float intersection_distance(const_float_t initial_rate, const_float_t final_rate, const_float_t accel, const_float_t distance) {
if (accel == 0) return 0; // accel was 0, set intersection distance to 0
return (accel * 2 * distance - sq(initial_rate) + sq(final_rate)) / (accel * 4);
}
@@ -854,7 +964,7 @@ class Planner {
* to reach 'target_velocity_sqr' using 'acceleration' within a given
* 'distance'.
*/
static float max_allowable_speed_sqr(const float &accel, const float &target_velocity_sqr, const float &distance) {
static float max_allowable_speed_sqr(const_float_t accel, const_float_t target_velocity_sqr, const_float_t distance) {
return target_velocity_sqr - 2 * accel * distance;
}
@@ -862,15 +972,15 @@ class Planner {
/**
* Calculate the speed reached given initial speed, acceleration and distance
*/
static float final_speed(const float &initial_velocity, const float &accel, const float &distance) {
static float final_speed(const_float_t initial_velocity, const_float_t accel, const_float_t distance) {
return SQRT(sq(initial_velocity) + 2 * accel * distance);
}
#endif
static void calculate_trapezoid_for_block(block_t* const block, const float &entry_factor, const float &exit_factor);
static void calculate_trapezoid_for_block(block_t * const block, const_float_t entry_factor, const_float_t exit_factor);
static void reverse_pass_kernel(block_t* const current, const block_t * const next);
static void forward_pass_kernel(const block_t * const previous, block_t* const current, uint8_t block_index);
static void reverse_pass_kernel(block_t * const current, const block_t * const next);
static void forward_pass_kernel(const block_t * const previous, block_t * const current, uint8_t block_index);
static void reverse_pass();
static void forward_pass();
@@ -879,24 +989,28 @@ class Planner {
static void recalculate();
#if DISABLED(CLASSIC_JERK)
#if HAS_JUNCTION_DEVIATION
FORCE_INLINE static void normalize_junction_vector(xyze_float_t &vector) {
float magnitude_sq = 0;
LOOP_XYZE(idx) if (vector[idx]) magnitude_sq += sq(vector[idx]);
LOOP_LOGICAL_AXES(idx) if (vector[idx]) magnitude_sq += sq(vector[idx]);
vector *= RSQRT(magnitude_sq);
}
FORCE_INLINE static float limit_value_by_axis_maximum(const float &max_value, xyze_float_t &unit_vec) {
FORCE_INLINE static float limit_value_by_axis_maximum(const_float_t max_value, xyze_float_t &unit_vec) {
float limit_value = max_value;
LOOP_XYZE(idx) if (unit_vec[idx]) // Avoid divide by zero
NOMORE(limit_value, ABS(settings.max_acceleration_mm_per_s2[idx] / unit_vec[idx]));
LOOP_LOGICAL_AXES(idx) {
if (unit_vec[idx]) {
if (limit_value * ABS(unit_vec[idx]) > settings.max_acceleration_mm_per_s2[idx])
limit_value = ABS(settings.max_acceleration_mm_per_s2[idx] / unit_vec[idx]);
}
}
return limit_value;
}
#endif // !CLASSIC_JERK
};
#define PLANNER_XY_FEEDRATE() (_MIN(planner.settings.max_feedrate_mm_s[X_AXIS], planner.settings.max_feedrate_mm_s[Y_AXIS]))
#define PLANNER_XY_FEEDRATE() _MIN(planner.settings.max_feedrate_mm_s[X_AXIS], planner.settings.max_feedrate_mm_s[Y_AXIS])
extern Planner planner;

26
Marlin/src/module/planner_bezier.cpp Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
@@ -24,7 +24,6 @@
* planner_bezier.cpp
*
* Compute and buffer movement commands for bezier curves
*
*/
#include "../inc/MarlinConfig.h"
@@ -36,7 +35,6 @@
#include "temperature.h"
#include "../MarlinCore.h"
#include "../core/language.h"
#include "../gcode/queue.h"
// See the meaning in the documentation of cubic_b_spline().
@@ -45,7 +43,7 @@
#define SIGMA 0.1f
// Compute the linear interpolation between two real numbers.
static inline float interp(const float &a, const float &b, const float &t) { return (1 - t) * a + t * b; }
static inline float interp(const_float_t a, const_float_t b, const_float_t t) { return (1 - t) * a + t * b; }
/**
* Compute a Bézier curve using the De Casteljau's algorithm (see
@@ -53,7 +51,7 @@ static inline float interp(const float &a, const float &b, const float &t) { ret
* easy to code and has good numerical stability (very important,
* since Arudino works with limited precision real numbers).
*/
static inline float eval_bezier(const float &a, const float &b, const float &c, const float &d, const float &t) {
static inline float eval_bezier(const_float_t a, const_float_t b, const_float_t c, const_float_t d, const_float_t t) {
const float iab = interp(a, b, t),
ibc = interp(b, c, t),
icd = interp(c, d, t),
@@ -66,7 +64,7 @@ static inline float eval_bezier(const float &a, const float &b, const float &c,
* We approximate Euclidean distance with the sum of the coordinates
* offset (so-called "norm 1"), which is quicker to compute.
*/
static inline float dist1(const float &x1, const float &y1, const float &x2, const float &y2) { return ABS(x1 - x2) + ABS(y1 - y2); }
static inline float dist1(const_float_t x1, const_float_t y1, const_float_t x2, const_float_t y2) { return ABS(x1 - x2) + ABS(y1 - y2); }
/**
* The algorithm for computing the step is loosely based on the one in Kig
@@ -111,7 +109,7 @@ void cubic_b_spline(
const xyze_pos_t &position, // current position
const xyze_pos_t &target, // target position
const xy_pos_t (&offsets)[2], // a pair of offsets
const feedRate_t &scaled_fr_mm_s, // mm/s scaled by feedrate %
const_feedRate_t scaled_fr_mm_s, // mm/s scaled by feedrate %
const uint8_t extruder
) {
// Absolute first and second control points are recovered.
@@ -183,11 +181,15 @@ void cubic_b_spline(
t = new_t;
// Compute and send new position
xyze_pos_t new_bez = {
new_pos0, new_pos1,
interp(position.z, target.z, t), // FIXME. These two are wrong, since the parameter t is
interp(position.e, target.e, t) // not linear in the distance.
};
xyze_pos_t new_bez = LOGICAL_AXIS_ARRAY(
interp(position.e, target.e, t), // FIXME. Wrong, since t is not linear in the distance.
new_pos0,
new_pos1,
interp(position.z, target.z, t), // FIXME. Wrong, since t is not linear in the distance.
interp(position.i, target.i, t), // FIXME. Wrong, since t is not linear in the distance.
interp(position.j, target.j, t), // FIXME. Wrong, since t is not linear in the distance.
interp(position.k, target.k, t) // FIXME. Wrong, since t is not linear in the distance.
);
apply_motion_limits(new_bez);
bez_target = new_bez;

5
Marlin/src/module/planner_bezier.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -25,7 +25,6 @@
* planner_bezier.h
*
* Compute and buffer movement commands for Bézier curves
*
*/
#include "../core/types.h"
@@ -34,6 +33,6 @@ void cubic_b_spline(
const xyze_pos_t &position, // current position
const xyze_pos_t &target, // target position
const xy_pos_t (&offsets)[2], // a pair of offsets
const feedRate_t &scaled_fr_mm_s, // mm/s scaled by feedrate %
const_feedRate_t scaled_fr_mm_s, // mm/s scaled by feedrate %
const uint8_t extruder
);

View File

@@ -0,0 +1,47 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
*
*/
/**
* polargraph.cpp
*/
#include "../inc/MarlinConfig.h"
#if ENABLED(POLARGRAPH)
#include "polargraph.h"
#include "motion.h"
// For homing:
#include "planner.h"
#include "endstops.h"
#include "../lcd/marlinui.h"
#include "../MarlinCore.h"
float segments_per_second; // Initialized by settings.load()
void inverse_kinematics(const xyz_pos_t &raw) {
const float x1 = raw.x - (X_MIN_POS), x2 = (X_MAX_POS) - raw.x, y = raw.y - (Y_MAX_POS);
delta.set(HYPOT(x1, y), HYPOT(x2, y), raw.z);
}
#endif // POLARGRAPH

View File

@@ -0,0 +1,33 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* polargraph.h - Polargraph-specific functions
*/
#include "../core/types.h"
#include "../core/macros.h"
extern float segments_per_second;
void inverse_kinematics(const xyz_pos_t &raw);

113
Marlin/src/module/printcounter.cpp Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
@@ -41,6 +41,11 @@ Stopwatch print_job_timer; // Global Print Job Timer instance
#include "../libs/buzzer.h"
#endif
#if PRINTCOUNTER_SYNC
#include "../module/planner.h"
#warning "To prevent step loss, motion will pause for PRINTCOUNTER auto-save."
#endif
// Service intervals
#if HAS_SERVICE_INTERVALS
#if SERVICE_INTERVAL_1 > 0
@@ -70,19 +75,14 @@ millis_t PrintCounter::lastDuration;
bool PrintCounter::loaded = false;
millis_t PrintCounter::deltaDuration() {
#if ENABLED(DEBUG_PRINTCOUNTER)
debug(PSTR("deltaDuration"));
#endif
TERN_(DEBUG_PRINTCOUNTER, debug(PSTR("deltaDuration")));
millis_t tmp = lastDuration;
lastDuration = duration();
return lastDuration - tmp;
}
void PrintCounter::incFilamentUsed(float const &amount) {
#if ENABLED(DEBUG_PRINTCOUNTER)
debug(PSTR("incFilamentUsed"));
#endif
TERN_(DEBUG_PRINTCOUNTER, debug(PSTR("incFilamentUsed")));
// Refuses to update data if object is not loaded
if (!isLoaded()) return;
@@ -91,9 +91,7 @@ void PrintCounter::incFilamentUsed(float const &amount) {
}
void PrintCounter::initStats() {
#if ENABLED(DEBUG_PRINTCOUNTER)
debug(PSTR("initStats"));
#endif
TERN_(DEBUG_PRINTCOUNTER, debug(PSTR("initStats")));
loaded = true;
data = { 0, 0, 0, 0, 0.0
@@ -121,7 +119,7 @@ void PrintCounter::initStats() {
inline bool _service_warn(const char * const msg) {
_print_divider();
SERIAL_ECHO_START();
serialprintPGM(msg);
SERIAL_ECHOPGM_P(msg);
SERIAL_ECHOLNPGM("!");
_print_divider();
return true;
@@ -129,9 +127,7 @@ void PrintCounter::initStats() {
#endif
void PrintCounter::loadStats() {
#if ENABLED(DEBUG_PRINTCOUNTER)
debug(PSTR("loadStats"));
#endif
TERN_(DEBUG_PRINTCOUNTER, debug(PSTR("loadStats")));
// Check if the EEPROM block is initialized
uint8_t value = 0;
@@ -164,36 +160,34 @@ void PrintCounter::loadStats() {
}
void PrintCounter::saveStats() {
#if ENABLED(DEBUG_PRINTCOUNTER)
debug(PSTR("saveStats"));
#endif
TERN_(DEBUG_PRINTCOUNTER, debug(PSTR("saveStats")));
// Refuses to save data if object is not loaded
if (!isLoaded()) return;
TERN_(PRINTCOUNTER_SYNC, planner.synchronize());
// Saves the struct to EEPROM
persistentStore.access_start();
persistentStore.write_data(address + sizeof(uint8_t), (uint8_t*)&data, sizeof(printStatistics));
persistentStore.access_finish();
#if ENABLED(EXTENSIBLE_UI)
ExtUI::onConfigurationStoreWritten(true);
#endif
TERN_(EXTENSIBLE_UI, ExtUI::onConfigurationStoreWritten(true));
}
#if HAS_SERVICE_INTERVALS
inline void _service_when(char buffer[], const char * const msg, const uint32_t when) {
SERIAL_ECHOPGM(STR_STATS);
serialprintPGM(msg);
SERIAL_ECHOLNPAIR(" in ", duration_t(when).toString(buffer));
SERIAL_ECHOPGM_P(msg);
SERIAL_ECHOLNPGM(" in ", duration_t(when).toString(buffer));
}
#endif
void PrintCounter::showStats() {
char buffer[21];
char buffer[22];
SERIAL_ECHOPGM(STR_STATS);
SERIAL_ECHOLNPAIR(
SERIAL_ECHOLNPGM(
"Prints: ", data.totalPrints,
", Finished: ", data.finishedPrints,
", Failed: ", data.totalPrints - data.finishedPrints
@@ -203,21 +197,21 @@ void PrintCounter::showStats() {
SERIAL_ECHOPGM(STR_STATS);
duration_t elapsed = data.printTime;
elapsed.toString(buffer);
SERIAL_ECHOPAIR("Total time: ", buffer);
SERIAL_ECHOPGM("Total time: ", buffer);
#if ENABLED(DEBUG_PRINTCOUNTER)
SERIAL_ECHOPAIR(" (", data.printTime);
SERIAL_ECHOPGM(" (", data.printTime);
SERIAL_CHAR(')');
#endif
elapsed = data.longestPrint;
elapsed.toString(buffer);
SERIAL_ECHOPAIR(", Longest job: ", buffer);
SERIAL_ECHOPGM(", Longest job: ", buffer);
#if ENABLED(DEBUG_PRINTCOUNTER)
SERIAL_ECHOPAIR(" (", data.longestPrint);
SERIAL_ECHOPGM(" (", data.longestPrint);
SERIAL_CHAR(')');
#endif
SERIAL_ECHOPAIR("\n" STR_STATS "Filament used: ", data.filamentUsed / 1000);
SERIAL_ECHOPGM("\n" STR_STATS "Filament used: ", data.filamentUsed / 1000);
SERIAL_CHAR('m');
SERIAL_EOL();
@@ -237,11 +231,12 @@ void PrintCounter::tick() {
millis_t now = millis();
static uint32_t update_next; // = 0
static millis_t update_next; // = 0
if (ELAPSED(now, update_next)) {
#if ENABLED(DEBUG_PRINTCOUNTER)
debug(PSTR("tick"));
#endif
update_next = now + updateInterval;
TERN_(DEBUG_PRINTCOUNTER, debug(PSTR("tick")));
millis_t delta = deltaDuration();
data.printTime += delta;
@@ -254,22 +249,20 @@ void PrintCounter::tick() {
#if SERVICE_INTERVAL_3 > 0
data.nextService3 -= _MIN(delta, data.nextService3);
#endif
update_next = now + updateInterval * 1000;
}
static uint32_t eeprom_next; // = 0
if (ELAPSED(now, eeprom_next)) {
eeprom_next = now + saveInterval * 1000;
saveStats();
}
#if PRINTCOUNTER_SAVE_INTERVAL > 0
static millis_t eeprom_next; // = 0
if (ELAPSED(now, eeprom_next)) {
eeprom_next = now + saveInterval;
saveStats();
}
#endif
}
// @Override
bool PrintCounter::start() {
#if ENABLED(DEBUG_PRINTCOUNTER)
debug(PSTR("start"));
#endif
TERN_(DEBUG_PRINTCOUNTER, debug(PSTR("start")));
bool paused = isPaused();
@@ -284,30 +277,25 @@ bool PrintCounter::start() {
return false;
}
// @Override
bool PrintCounter::stop() {
#if ENABLED(DEBUG_PRINTCOUNTER)
debug(PSTR("stop"));
#endif
bool PrintCounter::_stop(const bool completed) {
TERN_(DEBUG_PRINTCOUNTER, debug(PSTR("stop")));
if (super::stop()) {
data.finishedPrints++;
const bool did_stop = super::stop();
if (did_stop) {
data.printTime += deltaDuration();
if (duration() > data.longestPrint)
data.longestPrint = duration();
saveStats();
return true;
if (completed) {
data.finishedPrints++;
if (duration() > data.longestPrint)
data.longestPrint = duration();
}
}
else return false;
saveStats();
return did_stop;
}
// @Override
void PrintCounter::reset() {
#if ENABLED(DEBUG_PRINTCOUNTER)
debug(PSTR("stop"));
#endif
TERN_(DEBUG_PRINTCOUNTER, debug(PSTR("stop")));
super::reset();
lastDuration = 0;
@@ -331,6 +319,7 @@ void PrintCounter::reset() {
}
bool PrintCounter::needsService(const int index) {
if (!loaded) loadStats();
switch (index) {
#if SERVICE_INTERVAL_1 > 0
case 1: return data.nextService1 == 0;
@@ -352,7 +341,7 @@ void PrintCounter::reset() {
void PrintCounter::debug(const char func[]) {
if (DEBUGGING(INFO)) {
SERIAL_ECHOPGM("PrintCounter::");
serialprintPGM(func);
SERIAL_ECHOPGM_P(func);
SERIAL_ECHOLNPGM("()");
}
}

38
Marlin/src/module/printcounter.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -28,12 +28,8 @@
// Print debug messages with M111 S2
//#define DEBUG_PRINTCOUNTER
#if USE_WIRED_EEPROM
// round up address to next page boundary (assuming 32 byte pages)
#define STATS_EEPROM_ADDRESS 0x40
#else
#define STATS_EEPROM_ADDRESS 0x32
#endif
// Round up I2C / SPI address to next page boundary (assuming 32 byte pages)
#define STATS_EEPROM_ADDRESS TERN(USE_WIRED_EEPROM, 0x40, 0x32)
struct printStatistics { // 16 bytes
//const uint8_t magic; // Magic header, it will always be 0x16
@@ -57,7 +53,7 @@ class PrintCounter: public Stopwatch {
private:
typedef Stopwatch super;
#if USE_WIRED_EEPROM || defined(CPU_32_BIT)
#if EITHER(USE_WIRED_EEPROM, CPU_32_BIT)
typedef uint32_t eeprom_address_t;
#else
typedef uint16_t eeprom_address_t;
@@ -75,19 +71,18 @@ class PrintCounter: public Stopwatch {
* @brief Interval in seconds between counter updates
* @details This const value defines what will be the time between each
* accumulator update. This is different from the EEPROM save interval.
*
* @note The max value for this option is 60(s), otherwise integer
* overflow will happen.
*/
static constexpr uint16_t updateInterval = 10;
static constexpr millis_t updateInterval = SEC_TO_MS(10);
/**
* @brief Interval in seconds between EEPROM saves
* @details This const value defines what will be the time between each
* EEPROM save cycle, the development team recommends to set this value
* no lower than 3600 secs (1 hour).
*/
static constexpr uint16_t saveInterval = 3600;
#if PRINTCOUNTER_SAVE_INTERVAL > 0
/**
* @brief Interval in seconds between EEPROM saves
* @details This const value defines what will be the time between each
* EEPROM save cycle, the development team recommends to set this value
* no lower than 3600 secs (1 hour).
*/
static constexpr millis_t saveInterval = MIN_TO_MS(PRINTCOUNTER_SAVE_INTERVAL);
#endif
/**
* @brief Timestamp of the last call to deltaDuration()
@@ -180,7 +175,10 @@ class PrintCounter: public Stopwatch {
* The following functions are being overridden
*/
static bool start();
static bool stop();
static bool _stop(const bool completed);
static inline bool stop() { return _stop(true); }
static inline bool abort() { return _stop(false); }
static void reset();
#if HAS_SERVICE_INTERVALS

555
Marlin/src/module/probe.cpp Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
@@ -36,9 +36,9 @@
#include "endstops.h"
#include "../gcode/gcode.h"
#include "../lcd/ultralcd.h"
#include "../lcd/marlinui.h"
#include "../MarlinCore.h" // for stop(), disable_e_steppers, wait_for_user
#include "../MarlinCore.h" // for stop(), disable_e_steppers(), wait_for_user_response()
#if HAS_LEVELING
#include "../feature/bedlevel/bedlevel.h"
@@ -48,8 +48,17 @@
#include "delta.h"
#endif
#if ENABLED(BABYSTEP_ZPROBE_OFFSET)
#include "planner.h"
#if ANY(HAS_QUIET_PROBING, USE_SENSORLESS)
#include "stepper/indirection.h"
#if BOTH(HAS_QUIET_PROBING, PROBING_ESTEPPERS_OFF)
#include "stepper.h"
#endif
#if USE_SENSORLESS
#include "../feature/tmc_util.h"
#if ENABLED(IMPROVE_HOMING_RELIABILITY)
#include "planner.h"
#endif
#endif
#endif
#if ENABLED(MEASURE_BACKLASH_WHEN_PROBING)
@@ -68,17 +77,10 @@
#include "servo.h"
#endif
#if ENABLED(SENSORLESS_PROBING)
#include "stepper.h"
#include "../feature/tmc_util.h"
#endif
#if QUIET_PROBING
#include "stepper/indirection.h"
#endif
#if ENABLED(EXTENSIBLE_UI)
#include "../lcd/extui/ui_api.h"
#elif ENABLED(DWIN_CREALITY_LCD_ENHANCED)
#include "../lcd/e3v2/enhanced/dwin.h"
#endif
#define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE)
@@ -89,7 +91,11 @@ Probe probe;
xyz_pos_t Probe::offset; // Initialized by settings.load()
#if HAS_PROBE_XY_OFFSET
const xyz_pos_t &Probe::offset_xy = Probe::offset;
const xy_pos_t &Probe::offset_xy = Probe::offset;
#endif
#if ENABLED(SENSORLESS_PROBING)
Probe::sense_bool_t Probe::test_sensitivity;
#endif
#if ENABLED(Z_PROBE_SLED)
@@ -105,7 +111,7 @@ xyz_pos_t Probe::offset; // Initialized by settings.load()
* If true, move to MAX_X and release the solenoid
*/
static void dock_sled(const bool stow) {
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("dock_sled(", stow, ")");
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("dock_sled(", stow, ")");
// Dock sled a bit closer to ensure proper capturing
do_blocking_move_to_x(X_MAX_POS + SLED_DOCKING_OFFSET - ((stow) ? 1 : 0));
@@ -134,10 +140,8 @@ xyz_pos_t Probe::offset; // Initialized by settings.load()
LCD_MESSAGEPGM(MSG_MANUAL_DEPLOY_TOUCHMI);
ui.return_to_status();
#if ENABLED(HOST_PROMPT_SUPPORT)
host_prompt_do(PROMPT_USER_CONTINUE, PSTR("Deploy TouchMI"), CONTINUE_STR);
#endif
wait_for_user_response();
TERN_(HOST_PROMPT_SUPPORT, host_prompt_do(PROMPT_USER_CONTINUE, PSTR("Deploy TouchMI"), CONTINUE_STR));
TERN_(HAS_RESUME_CONTINUE, wait_for_user_response());
ui.reset_status();
ui.goto_screen(prev_screen);
@@ -154,8 +158,8 @@ xyz_pos_t Probe::offset; // Initialized by settings.load()
inline void run_stow_moves_script() {
const xyz_pos_t oldpos = current_position;
endstops.enable_z_probe(false);
do_blocking_move_to_z(TOUCH_MI_RETRACT_Z, MMM_TO_MMS(HOMING_FEEDRATE_Z));
do_blocking_move_to(oldpos, MMM_TO_MMS(HOMING_FEEDRATE_Z));
do_blocking_move_to_z(TOUCH_MI_RETRACT_Z, homing_feedrate(Z_AXIS));
do_blocking_move_to(oldpos, homing_feedrate(Z_AXIS));
}
#elif ENABLED(Z_PROBE_ALLEN_KEY)
@@ -238,52 +242,49 @@ xyz_pos_t Probe::offset; // Initialized by settings.load()
#endif // Z_PROBE_ALLEN_KEY
#if QUIET_PROBING
#if HAS_QUIET_PROBING
void Probe::set_probing_paused(const bool p) {
#if ENABLED(PROBING_HEATERS_OFF)
thermalManager.pause(p);
#ifndef DELAY_BEFORE_PROBING
#define DELAY_BEFORE_PROBING 25
#endif
void Probe::set_probing_paused(const bool dopause) {
TERN_(PROBING_HEATERS_OFF, thermalManager.pause_heaters(dopause));
TERN_(PROBING_FANS_OFF, thermalManager.set_fans_paused(dopause));
TERN_(PROBING_ESTEPPERS_OFF, if (dopause) stepper.disable_e_steppers());
#if ENABLED(PROBING_STEPPERS_OFF) && DISABLED(DELTA)
static uint8_t old_trusted;
if (dopause) {
old_trusted = axis_trusted;
stepper.disable_axis(X_AXIS);
stepper.disable_axis(Y_AXIS);
}
else {
if (TEST(old_trusted, X_AXIS)) stepper.enable_axis(X_AXIS);
if (TEST(old_trusted, Y_AXIS)) stepper.enable_axis(Y_AXIS);
axis_trusted = old_trusted;
}
#endif
#if ENABLED(PROBING_FANS_OFF)
thermalManager.set_fans_paused(p);
#endif
#if ENABLED(PROBING_STEPPERS_OFF)
disable_e_steppers();
#if NONE(DELTA, HOME_AFTER_DEACTIVATE)
DISABLE_AXIS_X(); DISABLE_AXIS_Y();
#endif
#endif
if (p) safe_delay(
#if DELAY_BEFORE_PROBING > 25
DELAY_BEFORE_PROBING
#else
25
#endif
);
if (dopause) safe_delay(_MAX(DELAY_BEFORE_PROBING, 25));
}
#endif // QUIET_PROBING
#endif // HAS_QUIET_PROBING
/**
* Raise Z to a minimum height to make room for a probe to move
*/
void Probe::do_z_raise(const float z_raise) {
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("Probe::move_z(", z_raise, ")");
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Probe::do_z_raise(", z_raise, ")");
float z_dest = z_raise;
if (offset.z < 0) z_dest -= offset.z;
NOMORE(z_dest, Z_MAX_POS);
if (z_dest > current_position.z)
do_blocking_move_to_z(z_dest);
do_z_clearance(z_dest);
}
FORCE_INLINE void probe_specific_action(const bool deploy) {
#if ENABLED(PAUSE_BEFORE_DEPLOY_STOW)
do {
#if ENABLED(PAUSE_PROBE_DEPLOY_WHEN_TRIGGERED)
if (deploy == (READ(Z_MIN_PROBE_PIN) == Z_MIN_PROBE_ENDSTOP_INVERTING)) break;
if (deploy != PROBE_TRIGGERED()) break;
#endif
BUZZ(100, 659);
@@ -292,25 +293,15 @@ FORCE_INLINE void probe_specific_action(const bool deploy) {
PGM_P const ds_str = deploy ? GET_TEXT(MSG_MANUAL_DEPLOY) : GET_TEXT(MSG_MANUAL_STOW);
ui.return_to_status(); // To display the new status message
ui.set_status_P(ds_str, 99);
serialprintPGM(ds_str);
SERIAL_EOL();
SERIAL_ECHOLNPGM_P(ds_str);
#if ENABLED(HOST_PROMPT_SUPPORT)
host_prompt_do(PROMPT_USER_CONTINUE, PSTR("Stow Probe"), CONTINUE_STR);
#endif
#if ENABLED(EXTENSIBLE_UI)
ExtUI::onUserConfirmRequired_P(PSTR("Stow Probe"));
#endif
wait_for_user_response();
TERN_(HOST_PROMPT_SUPPORT, host_prompt_do(PROMPT_USER_CONTINUE, PSTR("Stow Probe"), CONTINUE_STR));
TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired_P(PSTR("Stow Probe")));
TERN_(DWIN_CREALITY_LCD_ENHANCED, DWIN_Popup_Confirm(ICON_BLTouch, PSTR("Stow Probe"), CONTINUE_STR));
TERN_(HAS_RESUME_CONTINUE, wait_for_user_response());
ui.reset_status();
} while(
#if ENABLED(PAUSE_PROBE_DEPLOY_WHEN_TRIGGERED)
true
#else
false
#endif
);
} while (ENABLED(PAUSE_PROBE_DEPLOY_WHEN_TRIGGERED));
#endif // PAUSE_BEFORE_DEPLOY_STOW
@@ -324,15 +315,13 @@ FORCE_INLINE void probe_specific_action(const bool deploy) {
dock_sled(!deploy);
#elif ENABLED(BLTOUCH)
deploy ? bltouch.deploy() : bltouch.stow();
#elif HAS_Z_SERVO_PROBE
#if DISABLED(BLTOUCH)
MOVE_SERVO(Z_PROBE_SERVO_NR, servo_angles[Z_PROBE_SERVO_NR][deploy ? 0 : 1]);
#elif ENABLED(BLTOUCH_HS_MODE)
// In HIGH SPEED MODE, use the normal retractable probe logic in this code
// i.e. no intermediate STOWs and DEPLOYs in between individual probe actions
if (deploy) bltouch.deploy(); else bltouch.stow();
#endif
MOVE_SERVO(Z_PROBE_SERVO_NR, servo_angles[Z_PROBE_SERVO_NR][deploy ? 0 : 1]);
#elif EITHER(TOUCH_MI_PROBE, Z_PROBE_ALLEN_KEY)
@@ -349,6 +338,59 @@ FORCE_INLINE void probe_specific_action(const bool deploy) {
#endif
}
#if EITHER(PREHEAT_BEFORE_PROBING, PREHEAT_BEFORE_LEVELING)
#if ENABLED(PREHEAT_BEFORE_PROBING)
#ifndef PROBING_NOZZLE_TEMP
#define PROBING_NOZZLE_TEMP 0
#endif
#ifndef PROBING_BED_TEMP
#define PROBING_BED_TEMP 0
#endif
#endif
/**
* Do preheating as required before leveling or probing.
* - If a preheat input is higher than the current target, raise the target temperature.
* - If a preheat input is higher than the current temperature, wait for stabilization.
*/
void Probe::preheat_for_probing(const celsius_t hotend_temp, const celsius_t bed_temp) {
#if HAS_HOTEND && (PROBING_NOZZLE_TEMP || LEVELING_NOZZLE_TEMP)
#define WAIT_FOR_NOZZLE_HEAT
#endif
#if HAS_HEATED_BED && (PROBING_BED_TEMP || LEVELING_BED_TEMP)
#define WAIT_FOR_BED_HEAT
#endif
DEBUG_ECHOPGM("Preheating ");
#if ENABLED(WAIT_FOR_NOZZLE_HEAT)
const celsius_t hotendPreheat = hotend_temp > thermalManager.degTargetHotend(0) ? hotend_temp : 0;
if (hotendPreheat) {
DEBUG_ECHOPGM("hotend (", hotendPreheat, ")");
thermalManager.setTargetHotend(hotendPreheat, 0);
}
#elif ENABLED(WAIT_FOR_BED_HEAT)
constexpr celsius_t hotendPreheat = 0;
#endif
#if ENABLED(WAIT_FOR_BED_HEAT)
const celsius_t bedPreheat = bed_temp > thermalManager.degTargetBed() ? bed_temp : 0;
if (bedPreheat) {
if (hotendPreheat) DEBUG_ECHOPGM(" and ");
DEBUG_ECHOPGM("bed (", bedPreheat, ")");
thermalManager.setTargetBed(bedPreheat);
}
#endif
DEBUG_EOL();
TERN_(WAIT_FOR_NOZZLE_HEAT, if (hotend_temp > thermalManager.wholeDegHotend(0) + (TEMP_WINDOW)) thermalManager.wait_for_hotend(0));
TERN_(WAIT_FOR_BED_HEAT, if (bed_temp > thermalManager.wholeDegBed() + (TEMP_BED_WINDOW)) thermalManager.wait_for_bed_heating());
}
#endif
/**
* Attempt to deploy or stow the probe
*
@@ -358,7 +400,7 @@ bool Probe::set_deployed(const bool deploy) {
if (DEBUGGING(LEVELING)) {
DEBUG_POS("Probe::set_deployed", current_position);
DEBUG_ECHOLNPAIR("deploy: ", deploy);
DEBUG_ECHOLNPGM("deploy: ", deploy);
}
if (endstops.z_probe_enabled == deploy) return false;
@@ -367,27 +409,16 @@ bool Probe::set_deployed(const bool deploy) {
// Fix-mounted probe should only raise for deploy
// unless PAUSE_BEFORE_DEPLOY_STOW is enabled
#if EITHER(FIX_MOUNTED_PROBE, NOZZLE_AS_PROBE) && DISABLED(PAUSE_BEFORE_DEPLOY_STOW)
const bool deploy_stow_condition = deploy;
const bool z_raise_wanted = deploy;
#else
constexpr bool deploy_stow_condition = true;
constexpr bool z_raise_wanted = true;
#endif
// For beds that fall when Z is powered off only raise for trusted Z
#if ENABLED(UNKNOWN_Z_NO_RAISE)
const bool unknown_condition = TEST(axis_known_position, Z_AXIS);
#else
constexpr float unknown_condition = true;
#endif
if (deploy_stow_condition && unknown_condition)
if (z_raise_wanted)
do_z_raise(_MAX(Z_CLEARANCE_BETWEEN_PROBES, Z_CLEARANCE_DEPLOY_PROBE));
#if EITHER(Z_PROBE_SLED, Z_PROBE_ALLEN_KEY)
if (axis_unhomed_error(
#if ENABLED(Z_PROBE_SLED)
_BV(X_AXIS)
#endif
)) {
if (homing_needed_error(TERN_(Z_PROBE_SLED, _BV(X_AXIS)))) {
SERIAL_ERROR_MSG(STR_STOP_UNHOMED);
stop();
return true;
@@ -397,23 +428,15 @@ bool Probe::set_deployed(const bool deploy) {
const xy_pos_t old_xy = current_position;
#if ENABLED(PROBE_TRIGGERED_WHEN_STOWED_TEST)
#if HAS_CUSTOM_PROBE_PIN
#define PROBE_STOWED() (READ(Z_MIN_PROBE_PIN) != Z_MIN_PROBE_ENDSTOP_INVERTING)
#else
#define PROBE_STOWED() (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING)
#endif
#endif
#ifdef PROBE_STOWED
// Only deploy/stow if needed
if (PROBE_STOWED() == deploy) {
if (PROBE_TRIGGERED() == deploy) {
if (!deploy) endstops.enable_z_probe(false); // Switch off triggered when stowed probes early
// otherwise an Allen-Key probe can't be stowed.
probe_specific_action(deploy);
}
if (PROBE_STOWED() == deploy) { // Unchanged after deploy/stow action?
if (PROBE_TRIGGERED() == deploy) { // Unchanged after deploy/stow action?
if (IsRunning()) {
SERIAL_ERROR_MSG("Z-Probe failed");
LCD_ALERTMESSAGEPGM_P(PSTR("Err: ZPROBE"));
@@ -428,21 +451,14 @@ bool Probe::set_deployed(const bool deploy) {
#endif
// If preheating is required before any probing...
TERN_(PREHEAT_BEFORE_PROBING, if (deploy) preheat_for_probing(PROBING_NOZZLE_TEMP, PROBING_BED_TEMP));
do_blocking_move_to(old_xy);
endstops.enable_z_probe(deploy);
return false;
}
#ifdef Z_AFTER_PROBING
// After probing move to a preferred Z position
void Probe::move_z_after_probing() {
if (current_position.z != Z_AFTER_PROBING) {
do_blocking_move_to_z(Z_AFTER_PROBING);
current_position.z = Z_AFTER_PROBING;
}
}
#endif
/**
* @brief Used by run_z_probe to do a single Z probe move.
*
@@ -461,67 +477,60 @@ bool Probe::set_deployed(const bool deploy) {
*
* @return TRUE if the probe failed to trigger.
*/
bool Probe::probe_down_to_z(const float z, const feedRate_t fr_mm_s) {
if (DEBUGGING(LEVELING)) DEBUG_POS(">>> Probe::probe_down_to_z", current_position);
bool Probe::probe_down_to_z(const_float_t z, const_feedRate_t fr_mm_s) {
DEBUG_SECTION(log_probe, "Probe::probe_down_to_z", DEBUGGING(LEVELING));
#if HAS_HEATED_BED && ENABLED(WAIT_FOR_BED_HEATER)
#if BOTH(HAS_HEATED_BED, WAIT_FOR_BED_HEATER)
thermalManager.wait_for_bed_heating();
#endif
#if ENABLED(BLTOUCH) && DISABLED(BLTOUCH_HS_MODE)
if (bltouch.deploy()) return true; // DEPLOY in LOW SPEED MODE on every probe action
#if BOTH(HAS_TEMP_HOTEND, WAIT_FOR_HOTEND)
thermalManager.wait_for_hotend_heating(active_extruder);
#endif
if (TERN0(BLTOUCH_SLOW_MODE, bltouch.deploy())) return true; // Deploy in LOW SPEED MODE on every probe action
// Disable stealthChop if used. Enable diag1 pin on driver.
#if ENABLED(SENSORLESS_PROBING)
sensorless_t stealth_states { false };
#if ENABLED(DELTA)
stealth_states.x = tmc_enable_stallguard(stepperX);
stealth_states.y = tmc_enable_stallguard(stepperY);
#if HAS_DELTA_SENSORLESS_PROBING
if (probe.test_sensitivity.x) stealth_states.x = tmc_enable_stallguard(stepperX); // Delta watches all DIAG pins for a stall
if (probe.test_sensitivity.y) stealth_states.y = tmc_enable_stallguard(stepperY);
#endif
stealth_states.z = tmc_enable_stallguard(stepperZ);
if (probe.test_sensitivity.z) stealth_states.z = tmc_enable_stallguard(stepperZ); // All machines will check Z-DIAG for stall
endstops.enable(true);
set_homing_current(true); // The "homing" current also applies to probing
#endif
#if QUIET_PROBING
set_probing_paused(true);
#endif
TERN_(HAS_QUIET_PROBING, set_probing_paused(true));
// Move down until the probe is triggered
do_blocking_move_to_z(z, fr_mm_s);
// Check to see if the probe was triggered
const bool probe_triggered =
#if BOTH(DELTA, SENSORLESS_PROBING)
endstops.trigger_state() & (_BV(X_MIN) | _BV(Y_MIN) | _BV(Z_MIN))
#if HAS_DELTA_SENSORLESS_PROBING
endstops.trigger_state() & (_BV(X_MAX) | _BV(Y_MAX) | _BV(Z_MAX))
#else
TEST(endstops.trigger_state(),
#if ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN)
Z_MIN
#else
Z_MIN_PROBE
#endif
)
TEST(endstops.trigger_state(), Z_MIN_PROBE)
#endif
;
#if QUIET_PROBING
set_probing_paused(false);
#endif
TERN_(HAS_QUIET_PROBING, set_probing_paused(false));
// Re-enable stealthChop if used. Disable diag1 pin on driver.
#if ENABLED(SENSORLESS_PROBING)
endstops.not_homing();
#if ENABLED(DELTA)
tmc_disable_stallguard(stepperX, stealth_states.x);
tmc_disable_stallguard(stepperY, stealth_states.y);
#if HAS_DELTA_SENSORLESS_PROBING
if (probe.test_sensitivity.x) tmc_disable_stallguard(stepperX, stealth_states.x);
if (probe.test_sensitivity.y) tmc_disable_stallguard(stepperY, stealth_states.y);
#endif
tmc_disable_stallguard(stepperZ, stealth_states.z);
if (probe.test_sensitivity.z) tmc_disable_stallguard(stepperZ, stealth_states.z);
set_homing_current(false);
#endif
#if ENABLED(BLTOUCH) && DISABLED(BLTOUCH_HS_MODE)
if (probe_triggered && bltouch.stow()) return true; // STOW in LOW SPEED MODE on trigger on every probe action
#endif
if (probe_triggered && TERN0(BLTOUCH_SLOW_MODE, bltouch.stow())) // Stow in LOW SPEED MODE on every trigger
return true;
// Clear endstop flags
endstops.hit_on_purpose();
@@ -532,11 +541,46 @@ bool Probe::probe_down_to_z(const float z, const feedRate_t fr_mm_s) {
// Tell the planner where we actually are
sync_plan_position();
if (DEBUGGING(LEVELING)) DEBUG_POS("<<< Probe::probe_down_to_z", current_position);
return !probe_triggered;
}
#if ENABLED(PROBE_TARE)
/**
* @brief Init the tare pin
*
* @details Init tare pin to ON state for a strain gauge, otherwise OFF
*/
void Probe::tare_init() {
OUT_WRITE(PROBE_TARE_PIN, !PROBE_TARE_STATE);
}
/**
* @brief Tare the Z probe
*
* @details Signal to the probe to tare itself
*
* @return TRUE if the tare cold not be completed
*/
bool Probe::tare() {
#if BOTH(PROBE_ACTIVATION_SWITCH, PROBE_TARE_ONLY_WHILE_INACTIVE)
if (endstops.probe_switch_activated()) {
SERIAL_ECHOLNPGM("Cannot tare an active probe");
return true;
}
#endif
SERIAL_ECHOLNPGM("Taring probe");
WRITE(PROBE_TARE_PIN, PROBE_TARE_STATE);
delay(PROBE_TARE_TIME);
WRITE(PROBE_TARE_PIN, !PROBE_TARE_STATE);
delay(PROBE_TARE_DELAY);
endstops.hit_on_purpose();
return false;
}
#endif
/**
* @brief Probe at the current XY (possibly more than once) to find the bed Z.
*
@@ -546,54 +590,70 @@ bool Probe::probe_down_to_z(const float z, const feedRate_t fr_mm_s) {
* @return The Z position of the bed at the current XY or NAN on error.
*/
float Probe::run_z_probe(const bool sanity_check/*=true*/) {
DEBUG_SECTION(log_probe, "Probe::run_z_probe", DEBUGGING(LEVELING));
if (DEBUGGING(LEVELING)) DEBUG_POS(">>> Probe::run_z_probe", current_position);
auto try_to_probe = [&](PGM_P const plbl, const_float_t z_probe_low_point, const feedRate_t fr_mm_s, const bool scheck, const float clearance) -> bool {
// Tare the probe, if supported
if (TERN0(PROBE_TARE, tare())) return true;
// Do a first probe at the fast speed
const bool probe_fail = probe_down_to_z(z_probe_low_point, fr_mm_s), // No probe trigger?
early_fail = (scheck && current_position.z > -offset.z + clearance); // Probe triggered too high?
#if ENABLED(DEBUG_LEVELING_FEATURE)
if (DEBUGGING(LEVELING) && (probe_fail || early_fail)) {
DEBUG_ECHOPGM_P(plbl);
DEBUG_ECHOPGM(" Probe fail! -");
if (probe_fail) DEBUG_ECHOPGM(" No trigger.");
if (early_fail) DEBUG_ECHOPGM(" Triggered early.");
DEBUG_EOL();
}
#else
UNUSED(plbl);
#endif
return probe_fail || early_fail;
};
// Stop the probe before it goes too low to prevent damage.
// If Z isn't known then probe to -10mm.
const float z_probe_low_point = TEST(axis_known_position, Z_AXIS) ? -offset.z + Z_PROBE_LOW_POINT : -10.0;
const float z_probe_low_point = axis_is_trusted(Z_AXIS) ? -offset.z + Z_PROBE_LOW_POINT : -10.0;
// Double-probing does a fast probe followed by a slow probe
#if TOTAL_PROBING == 2
// Attempt to tare the probe
if (TERN0(PROBE_TARE, tare())) return NAN;
// Do a first probe at the fast speed
if (probe_down_to_z(z_probe_low_point, MMM_TO_MMS(Z_PROBE_SPEED_FAST)) // No probe trigger?
|| (sanity_check && current_position.z > -offset.z + _MAX(Z_CLEARANCE_BETWEEN_PROBES, 4) / 2) // Probe triggered too high?
) {
if (DEBUGGING(LEVELING)) {
DEBUG_ECHOLNPGM("FAST Probe fail!");
DEBUG_POS("<<< run_z_probe", current_position);
}
return NAN;
}
if (try_to_probe(PSTR("FAST"), z_probe_low_point, z_probe_fast_mm_s,
sanity_check, Z_CLEARANCE_BETWEEN_PROBES) ) return NAN;
const float first_probe_z = current_position.z;
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("1st Probe Z:", first_probe_z);
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("1st Probe Z:", first_probe_z);
// Raise to give the probe clearance
do_blocking_move_to_z(current_position.z + Z_CLEARANCE_MULTI_PROBE, MMM_TO_MMS(Z_PROBE_SPEED_FAST));
do_blocking_move_to_z(current_position.z + Z_CLEARANCE_MULTI_PROBE, z_probe_fast_mm_s);
#elif Z_PROBE_SPEED_FAST != Z_PROBE_SPEED_SLOW
#elif Z_PROBE_FEEDRATE_FAST != Z_PROBE_FEEDRATE_SLOW
// If the nozzle is well over the travel height then
// move down quickly before doing the slow probe
const float z = Z_CLEARANCE_DEPLOY_PROBE + 5.0 + (offset.z < 0 ? -offset.z : 0);
if (current_position.z > z) {
// Probe down fast. If the probe never triggered, raise for probe clearance
if (!probe_down_to_z(z, MMM_TO_MMS(Z_PROBE_SPEED_FAST)))
do_blocking_move_to_z(current_position.z + Z_CLEARANCE_BETWEEN_PROBES, MMM_TO_MMS(Z_PROBE_SPEED_FAST));
if (!probe_down_to_z(z, z_probe_fast_mm_s))
do_blocking_move_to_z(current_position.z + Z_CLEARANCE_BETWEEN_PROBES, z_probe_fast_mm_s);
}
#endif
#ifdef EXTRA_PROBING
#if EXTRA_PROBING > 0
float probes[TOTAL_PROBING];
#endif
#if TOTAL_PROBING > 2
float probes_z_sum = 0;
for (
#if EXTRA_PROBING
#if EXTRA_PROBING > 0
uint8_t p = 0; p < TOTAL_PROBING; p++
#else
uint8_t p = TOTAL_PROBING; p--;
@@ -601,24 +661,18 @@ float Probe::run_z_probe(const bool sanity_check/*=true*/) {
)
#endif
{
// Probe downward slowly to find the bed
if (probe_down_to_z(z_probe_low_point, MMM_TO_MMS(Z_PROBE_SPEED_SLOW)) // No probe trigger?
|| (sanity_check && current_position.z > -offset.z + _MAX(Z_CLEARANCE_MULTI_PROBE, 4) / 2) // Probe triggered too high?
) {
if (DEBUGGING(LEVELING)) {
DEBUG_ECHOLNPGM("SLOW Probe fail!");
DEBUG_POS("<<< run_z_probe", current_position);
}
return NAN;
}
// If the probe won't tare, return
if (TERN0(PROBE_TARE, tare())) return true;
#if ENABLED(MEASURE_BACKLASH_WHEN_PROBING)
backlash.measure_with_probe();
#endif
// Probe downward slowly to find the bed
if (try_to_probe(PSTR("SLOW"), z_probe_low_point, MMM_TO_MMS(Z_PROBE_FEEDRATE_SLOW),
sanity_check, Z_CLEARANCE_MULTI_PROBE) ) return NAN;
TERN_(MEASURE_BACKLASH_WHEN_PROBING, backlash.measure_with_probe());
const float z = current_position.z;
#if EXTRA_PROBING
#if EXTRA_PROBING > 0
// Insert Z measurement into probes[]. Keep it sorted ascending.
LOOP_LE_N(i, p) { // Iterate the saved Zs to insert the new Z
if (i == p || probes[i] > z) { // Last index or new Z is smaller than this Z
@@ -636,16 +690,16 @@ float Probe::run_z_probe(const bool sanity_check/*=true*/) {
#if TOTAL_PROBING > 2
// Small Z raise after all but the last probe
if (p
#if EXTRA_PROBING
#if EXTRA_PROBING > 0
< TOTAL_PROBING - 1
#endif
) do_blocking_move_to_z(z + Z_CLEARANCE_MULTI_PROBE, MMM_TO_MMS(Z_PROBE_SPEED_FAST));
) do_blocking_move_to_z(z + Z_CLEARANCE_MULTI_PROBE, z_probe_fast_mm_s);
#endif
}
#if TOTAL_PROBING > 2
#if EXTRA_PROBING
#if EXTRA_PROBING > 0
// Take the center value (or average the two middle values) as the median
static constexpr int PHALF = (TOTAL_PROBING - 1) / 2;
const float middle = probes[PHALF],
@@ -669,7 +723,7 @@ float Probe::run_z_probe(const bool sanity_check/*=true*/) {
const float z2 = current_position.z;
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("2nd Probe Z:", z2, " Discrepancy:", first_probe_z - z2);
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("2nd Probe Z:", z2, " Discrepancy:", first_probe_z - z2);
// Return a weighted average of the fast and slow probes
const float measured_z = (z2 * 3.0 + first_probe_z * 2.0) * 0.2;
@@ -681,8 +735,6 @@ float Probe::run_z_probe(const bool sanity_check/*=true*/) {
#endif
if (DEBUGGING(LEVELING)) DEBUG_POS("<<< run_z_probe", current_position);
return measured_z;
}
@@ -695,12 +747,14 @@ float Probe::run_z_probe(const bool sanity_check/*=true*/) {
* - Raise to the BETWEEN height
* - Return the probed Z position
*/
float Probe::probe_at_point(const float &rx, const float &ry, const ProbePtRaise raise_after/*=PROBE_PT_NONE*/, const uint8_t verbose_level/*=0*/, const bool probe_relative/*=true*/, const bool sanity_check/*=true*/) {
float Probe::probe_at_point(const_float_t rx, const_float_t ry, const ProbePtRaise raise_after/*=PROBE_PT_NONE*/, const uint8_t verbose_level/*=0*/, const bool probe_relative/*=true*/, const bool sanity_check/*=true*/) {
DEBUG_SECTION(log_probe, "Probe::probe_at_point", DEBUGGING(LEVELING));
if (DEBUGGING(LEVELING)) {
DEBUG_ECHOLNPAIR(
">>> Probe::probe_at_point(", LOGICAL_X_POSITION(rx), ", ", LOGICAL_Y_POSITION(ry),
", ", raise_after == PROBE_PT_RAISE ? "raise" : raise_after == PROBE_PT_STOW ? "stow" : "none",
", ", int(verbose_level),
DEBUG_ECHOLNPGM(
"...(", LOGICAL_X_POSITION(rx), ", ", LOGICAL_Y_POSITION(ry),
", ", raise_after == PROBE_PT_RAISE ? "raise" : raise_after == PROBE_PT_LAST_STOW ? "stow (last)" : raise_after == PROBE_PT_STOW ? "stow" : "none",
", ", verbose_level,
", ", probe_relative ? "probe" : "nozzle", "_relative)"
);
DEBUG_POS("", current_position);
@@ -710,8 +764,8 @@ float Probe::probe_at_point(const float &rx, const float &ry, const ProbePtRaise
if (bltouch.triggered()) bltouch._reset();
#endif
// TODO: Adapt for SCARA, where the offset rotates
xyz_pos_t npos = { rx, ry };
// On delta keep Z below clip height or do_blocking_move_to will abort
xyz_pos_t npos = { rx, ry, TERN(DELTA, _MIN(delta_clip_start_height, current_position.z), current_position.z) };
if (probe_relative) { // The given position is in terms of the probe
if (!can_reach(npos)) {
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Position Not Reachable");
@@ -721,47 +775,30 @@ float Probe::probe_at_point(const float &rx, const float &ry, const ProbePtRaise
}
else if (!position_is_reachable(npos)) return NAN; // The given position is in terms of the nozzle
npos.z =
#if ENABLED(DELTA)
// Move below clip height or xy move will be aborted by do_blocking_move_to
_MIN(current_position.z, delta_clip_start_height)
#else
current_position.z
#endif
;
const float old_feedrate_mm_s = feedrate_mm_s;
feedrate_mm_s = XY_PROBE_FEEDRATE_MM_S;
// Move the probe to the starting XYZ
do_blocking_move_to(npos);
do_blocking_move_to(npos, feedRate_t(XY_PROBE_FEEDRATE_MM_S));
float measured_z = NAN;
if (!deploy()) measured_z = run_z_probe(sanity_check) + offset.z;
if (!isnan(measured_z)) {
const bool big_raise = raise_after == PROBE_PT_BIG_RAISE;
if (big_raise || raise_after == PROBE_PT_RAISE)
do_blocking_move_to_z(current_position.z + (big_raise ? 25 : Z_CLEARANCE_BETWEEN_PROBES), MMM_TO_MMS(Z_PROBE_SPEED_FAST));
else if (raise_after == PROBE_PT_STOW)
do_blocking_move_to_z(current_position.z + (big_raise ? 25 : Z_CLEARANCE_BETWEEN_PROBES), z_probe_fast_mm_s);
else if (raise_after == PROBE_PT_STOW || raise_after == PROBE_PT_LAST_STOW)
if (stow()) measured_z = NAN; // Error on stow?
if (verbose_level > 2) {
SERIAL_ECHOPAIR_F("Bed X: ", LOGICAL_X_POSITION(rx), 3);
SERIAL_ECHOPAIR_F( " Y: ", LOGICAL_Y_POSITION(ry), 3);
SERIAL_ECHOLNPAIR_F( " Z: ", measured_z, 3);
}
if (verbose_level > 2)
SERIAL_ECHOLNPGM("Bed X: ", LOGICAL_X_POSITION(rx), " Y: ", LOGICAL_Y_POSITION(ry), " Z: ", measured_z);
}
feedrate_mm_s = old_feedrate_mm_s;
if (isnan(measured_z)) {
stow();
LCD_MESSAGEPGM(MSG_LCD_PROBING_FAILED);
SERIAL_ERROR_MSG(STR_ERR_PROBING_FAILED);
#if DISABLED(G29_RETRY_AND_RECOVER)
SERIAL_ERROR_MSG(STR_ERR_PROBING_FAILED);
#endif
}
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("<<< Probe::probe_at_point");
return measured_z;
}
@@ -775,11 +812,101 @@ float Probe::probe_at_point(const float &rx, const float &ry, const ProbePtRaise
* when starting up the machine or rebooting the board.
* There's no way to know where the nozzle is positioned until
* homing has been done - no homing with z-probe without init!
*
*/
STOW_Z_SERVO();
}
#endif // HAS_Z_SERVO_PROBE
#if USE_SENSORLESS
sensorless_t stealth_states { false };
/**
* Disable stealthChop if used. Enable diag1 pin on driver.
*/
void Probe::enable_stallguard_diag1() {
#if ENABLED(SENSORLESS_PROBING)
#if HAS_DELTA_SENSORLESS_PROBING
stealth_states.x = tmc_enable_stallguard(stepperX);
stealth_states.y = tmc_enable_stallguard(stepperY);
#endif
stealth_states.z = tmc_enable_stallguard(stepperZ);
endstops.enable(true);
#endif
}
/**
* Re-enable stealthChop if used. Disable diag1 pin on driver.
*/
void Probe::disable_stallguard_diag1() {
#if ENABLED(SENSORLESS_PROBING)
endstops.not_homing();
#if HAS_DELTA_SENSORLESS_PROBING
tmc_disable_stallguard(stepperX, stealth_states.x);
tmc_disable_stallguard(stepperY, stealth_states.y);
#endif
tmc_disable_stallguard(stepperZ, stealth_states.z);
#endif
}
/**
* Change the current in the TMC drivers to N##_CURRENT_HOME. And we save the current configuration of each TMC driver.
*/
void Probe::set_homing_current(const bool onoff) {
#define HAS_CURRENT_HOME(N) (defined(N##_CURRENT_HOME) && N##_CURRENT_HOME != N##_CURRENT)
#if HAS_CURRENT_HOME(X) || HAS_CURRENT_HOME(Y) || HAS_CURRENT_HOME(Z)
#if ENABLED(DELTA)
static int16_t saved_current_X, saved_current_Y;
#endif
#if HAS_CURRENT_HOME(Z)
static int16_t saved_current_Z;
#endif
#if ((ENABLED(DELTA) && (HAS_CURRENT_HOME(X) || HAS_CURRENT_HOME(Y))) || HAS_CURRENT_HOME(Z))
auto debug_current_on = [](PGM_P const s, const int16_t a, const int16_t b) {
if (DEBUGGING(LEVELING)) { DEBUG_ECHOPGM_P(s); DEBUG_ECHOLNPGM(" current: ", a, " -> ", b); }
};
#endif
if (onoff) {
#if ENABLED(DELTA)
#if HAS_CURRENT_HOME(X)
saved_current_X = stepperX.getMilliamps();
stepperX.rms_current(X_CURRENT_HOME);
debug_current_on(PSTR("X"), saved_current_X, X_CURRENT_HOME);
#endif
#if HAS_CURRENT_HOME(Y)
saved_current_Y = stepperY.getMilliamps();
stepperY.rms_current(Y_CURRENT_HOME);
debug_current_on(PSTR("Y"), saved_current_Y, Y_CURRENT_HOME);
#endif
#endif
#if HAS_CURRENT_HOME(Z)
saved_current_Z = stepperZ.getMilliamps();
stepperZ.rms_current(Z_CURRENT_HOME);
debug_current_on(PSTR("Z"), saved_current_Z, Z_CURRENT_HOME);
#endif
TERN_(IMPROVE_HOMING_RELIABILITY, planner.enable_stall_prevention(true));
}
else {
#if ENABLED(DELTA)
#if HAS_CURRENT_HOME(X)
stepperX.rms_current(saved_current_X);
debug_current_on(PSTR("X"), X_CURRENT_HOME, saved_current_X);
#endif
#if HAS_CURRENT_HOME(Y)
stepperY.rms_current(saved_current_Y);
debug_current_on(PSTR("Y"), Y_CURRENT_HOME, saved_current_Y);
#endif
#endif
#if HAS_CURRENT_HOME(Z)
stepperZ.rms_current(saved_current_Z);
debug_current_on(PSTR("Z"), Z_CURRENT_HOME, saved_current_Z);
#endif
TERN_(IMPROVE_HOMING_RELIABILITY, planner.enable_stall_prevention(false));
}
#endif
}
#endif // SENSORLESS_PROBING || SENSORLESS_HOMING
#endif // HAS_BED_PROBE

204
Marlin/src/module/probe.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -33,33 +33,57 @@
enum ProbePtRaise : uint8_t {
PROBE_PT_NONE, // No raise or stow after run_z_probe
PROBE_PT_STOW, // Do a complete stow after run_z_probe
PROBE_PT_LAST_STOW, // Stow for sure, even in BLTouch HS mode
PROBE_PT_RAISE, // Raise to "between" clearance after run_z_probe
PROBE_PT_BIG_RAISE // Raise to big clearance after run_z_probe
};
#endif
#if USES_Z_MIN_PROBE_PIN
#define PROBE_TRIGGERED() (READ(Z_MIN_PROBE_PIN) != Z_MIN_PROBE_ENDSTOP_INVERTING)
#else
#define PROBE_TRIGGERED() (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING)
#endif
#if ENABLED(PREHEAT_BEFORE_LEVELING)
#ifndef LEVELING_NOZZLE_TEMP
#define LEVELING_NOZZLE_TEMP 0
#endif
#ifndef LEVELING_BED_TEMP
#define LEVELING_BED_TEMP 0
#endif
#endif
class Probe {
public:
#if ENABLED(SENSORLESS_PROBING)
typedef struct { bool x:1, y:1, z:1; } sense_bool_t;
static sense_bool_t test_sensitivity;
#endif
#if HAS_BED_PROBE
static xyz_pos_t offset;
static bool set_deployed(const bool deploy);
#if EITHER(PREHEAT_BEFORE_PROBING, PREHEAT_BEFORE_LEVELING)
static void preheat_for_probing(const celsius_t hotend_temp, const celsius_t bed_temp);
#endif
static bool set_deployed(const bool deploy);
#if IS_KINEMATIC
#if HAS_PROBE_XY_OFFSET
// Return true if the both nozzle and the probe can reach the given point.
// Note: This won't work on SCARA since the probe offset rotates with the arm.
static inline bool can_reach(const float &rx, const float &ry) {
static bool can_reach(const_float_t rx, const_float_t ry) {
return position_is_reachable(rx - offset_xy.x, ry - offset_xy.y) // The nozzle can go where it needs to go?
&& position_is_reachable(rx, ry, ABS(MIN_PROBE_EDGE)); // Can the nozzle also go near there?
&& position_is_reachable(rx, ry, ABS(PROBING_MARGIN)); // Can the nozzle also go near there?
}
#else
FORCE_INLINE static bool can_reach(const float &rx, const float &ry) {
return position_is_reachable(rx, ry, MIN_PROBE_EDGE);
static bool can_reach(const_float_t rx, const_float_t ry) {
return position_is_reachable(rx, ry, PROBING_MARGIN);
}
#endif
@@ -72,40 +96,50 @@ public:
* Example: For a probe offset of -10,+10, then for the probe to reach 0,0 the
* nozzle must be be able to reach +10,-10.
*/
static inline bool can_reach(const float &rx, const float &ry) {
static bool can_reach(const_float_t rx, const_float_t ry) {
return position_is_reachable(rx - offset_xy.x, ry - offset_xy.y)
&& WITHIN(rx, min_x() - fslop, max_x() + fslop)
&& WITHIN(ry, min_y() - fslop, max_y() + fslop);
&& COORDINATE_OKAY(rx, min_x() - fslop, max_x() + fslop)
&& COORDINATE_OKAY(ry, min_y() - fslop, max_y() + fslop);
}
#endif
#ifdef Z_AFTER_PROBING
static void move_z_after_probing();
#endif
static float probe_at_point(const float &rx, const float &ry, const ProbePtRaise raise_after=PROBE_PT_NONE, const uint8_t verbose_level=0, const bool probe_relative=true, const bool sanity_check=true);
static inline float probe_at_point(const xy_pos_t &pos, const ProbePtRaise raise_after=PROBE_PT_NONE, const uint8_t verbose_level=0, const bool probe_relative=true, const bool sanity_check=true) {
static void move_z_after_probing() {
#ifdef Z_AFTER_PROBING
do_z_clearance(Z_AFTER_PROBING, true); // Move down still permitted
#endif
}
static float probe_at_point(const_float_t rx, const_float_t ry, const ProbePtRaise raise_after=PROBE_PT_NONE, const uint8_t verbose_level=0, const bool probe_relative=true, const bool sanity_check=true);
static float probe_at_point(const xy_pos_t &pos, const ProbePtRaise raise_after=PROBE_PT_NONE, const uint8_t verbose_level=0, const bool probe_relative=true, const bool sanity_check=true) {
return probe_at_point(pos.x, pos.y, raise_after, verbose_level, probe_relative, sanity_check);
}
#else
static constexpr xyz_pos_t offset = xyz_pos_t({ 0, 0, 0 }); // See #16767
static constexpr xyz_pos_t offset = xyz_pos_t(LINEAR_AXIS_ARRAY(0, 0, 0, 0, 0, 0)); // See #16767
static bool set_deployed(const bool) { return false; }
FORCE_INLINE static bool can_reach(const float &rx, const float &ry) { return position_is_reachable(rx, ry); }
static bool can_reach(const_float_t rx, const_float_t ry) { return position_is_reachable(rx, ry); }
#endif
FORCE_INLINE static bool can_reach(const xy_pos_t &pos) { return can_reach(pos.x, pos.y); }
static void move_z_after_homing() {
#ifdef Z_AFTER_HOMING
do_z_clearance(Z_AFTER_HOMING, true);
#elif BOTH(Z_AFTER_PROBING, HAS_BED_PROBE)
move_z_after_probing();
#endif
}
FORCE_INLINE static bool good_bounds(const xy_pos_t &lf, const xy_pos_t &rb) {
static bool can_reach(const xy_pos_t &pos) { return can_reach(pos.x, pos.y); }
static bool good_bounds(const xy_pos_t &lf, const xy_pos_t &rb) {
return (
#if IS_KINEMATIC
can_reach(lf.x, 0) && can_reach(rb.x, 0) && can_reach(0, lf.y) && can_reach(0, rb.y)
can_reach(lf.x, 0) && can_reach(rb.x, 0) && can_reach(0, lf.y) && can_reach(0, rb.y)
#else
can_reach(lf) && can_reach(rb)
can_reach(lf) && can_reach(rb)
#endif
);
}
@@ -113,85 +147,101 @@ public:
// Use offset_xy for read only access
// More optimal the XY offset is known to always be zero.
#if HAS_PROBE_XY_OFFSET
static const xyz_pos_t &offset_xy;
static const xy_pos_t &offset_xy;
#else
static constexpr xy_pos_t offset_xy = xy_pos_t({ 0, 0 }); // See #16767
#endif
static inline bool deploy() { return set_deployed(true); }
static inline bool stow() { return set_deployed(false); }
static bool deploy() { return set_deployed(true); }
static bool stow() { return set_deployed(false); }
#if HAS_BED_PROBE || HAS_LEVELING
#if IS_KINEMATIC
static constexpr float printable_radius = (
#if ENABLED(DELTA)
DELTA_PRINTABLE_RADIUS
#elif IS_SCARA
SCARA_PRINTABLE_RADIUS
#endif
TERN_(DELTA, DELTA_PRINTABLE_RADIUS)
TERN_(IS_SCARA, SCARA_PRINTABLE_RADIUS)
);
static inline float probe_radius() {
return printable_radius - _MAX(MIN_PROBE_EDGE, HYPOT(offset_xy.x, offset_xy.y));
static constexpr float probe_radius(const xy_pos_t &probe_offset_xy = offset_xy) {
return printable_radius - _MAX(PROBING_MARGIN, HYPOT(probe_offset_xy.x, probe_offset_xy.y));
}
#endif
static inline float min_x() {
return (
#if IS_KINEMATIC
(X_CENTER) - probe_radius()
#else
_MAX((X_MIN_BED) + (MIN_PROBE_EDGE_LEFT), (X_MIN_POS) + offset_xy.x)
#endif
static constexpr float _min_x(const xy_pos_t &probe_offset_xy = offset_xy) {
return TERN(IS_KINEMATIC,
(X_CENTER) - probe_radius(probe_offset_xy),
_MAX((X_MIN_BED) + (PROBING_MARGIN_LEFT), (X_MIN_POS) + probe_offset_xy.x)
);
}
static inline float max_x() {
return (
#if IS_KINEMATIC
(X_CENTER) + probe_radius()
#else
_MIN((X_MAX_BED) - (MIN_PROBE_EDGE_RIGHT), (X_MAX_POS) + offset_xy.x)
#endif
static constexpr float _max_x(const xy_pos_t &probe_offset_xy = offset_xy) {
return TERN(IS_KINEMATIC,
(X_CENTER) + probe_radius(probe_offset_xy),
_MIN((X_MAX_BED) - (PROBING_MARGIN_RIGHT), (X_MAX_POS) + probe_offset_xy.x)
);
}
static inline float min_y() {
return (
#if IS_KINEMATIC
(Y_CENTER) - probe_radius()
#else
_MAX((Y_MIN_BED) + (MIN_PROBE_EDGE_FRONT), (Y_MIN_POS) + offset_xy.y)
#endif
static constexpr float _min_y(const xy_pos_t &probe_offset_xy = offset_xy) {
return TERN(IS_KINEMATIC,
(Y_CENTER) - probe_radius(probe_offset_xy),
_MAX((Y_MIN_BED) + (PROBING_MARGIN_FRONT), (Y_MIN_POS) + probe_offset_xy.y)
);
}
static inline float max_y() {
return (
#if IS_KINEMATIC
(Y_CENTER) + probe_radius()
#else
_MIN((Y_MAX_BED) - (MIN_PROBE_EDGE_BACK), (Y_MAX_POS) + offset_xy.y)
#endif
static constexpr float _max_y(const xy_pos_t &probe_offset_xy = offset_xy) {
return TERN(IS_KINEMATIC,
(Y_CENTER) + probe_radius(probe_offset_xy),
_MIN((Y_MAX_BED) - (PROBING_MARGIN_BACK), (Y_MAX_POS) + probe_offset_xy.y)
);
}
static float min_x() { return _min_x() TERN_(NOZZLE_AS_PROBE, TERN_(HAS_HOME_OFFSET, - home_offset.x)); }
static float max_x() { return _max_x() TERN_(NOZZLE_AS_PROBE, TERN_(HAS_HOME_OFFSET, - home_offset.x)); }
static float min_y() { return _min_y() TERN_(NOZZLE_AS_PROBE, TERN_(HAS_HOME_OFFSET, - home_offset.y)); }
static float max_y() { return _max_y() TERN_(NOZZLE_AS_PROBE, TERN_(HAS_HOME_OFFSET, - home_offset.y)); }
// constexpr helpers used in build-time static_asserts, relying on default probe offsets.
class build_time {
static constexpr xyz_pos_t default_probe_xyz_offset =
#if HAS_BED_PROBE
NOZZLE_TO_PROBE_OFFSET
#else
{ 0 }
#endif
;
static constexpr xy_pos_t default_probe_xy_offset = { default_probe_xyz_offset.x, default_probe_xyz_offset.y };
public:
static constexpr bool can_reach(float x, float y) {
#if IS_KINEMATIC
return HYPOT2(x, y) <= sq(probe_radius(default_probe_xy_offset));
#else
return COORDINATE_OKAY(x, _min_x(default_probe_xy_offset) - fslop, _max_x(default_probe_xy_offset) + fslop)
&& COORDINATE_OKAY(y, _min_y(default_probe_xy_offset) - fslop, _max_y(default_probe_xy_offset) + fslop);
#endif
}
static constexpr bool can_reach(const xy_pos_t &point) { return can_reach(point.x, point.y); }
};
#if NEEDS_THREE_PROBE_POINTS
// Retrieve three points to probe the bed. Any type exposing set(X,Y) may be used.
template <typename T>
static inline void get_three_points(T points[3]) {
static void get_three_points(T points[3]) {
#if HAS_FIXED_3POINT
points[0].set(PROBE_PT_1_X, PROBE_PT_1_Y);
points[1].set(PROBE_PT_2_X, PROBE_PT_2_Y);
points[2].set(PROBE_PT_3_X, PROBE_PT_3_Y);
#define VALIDATE_PROBE_PT(N) static_assert(Probe::build_time::can_reach(xy_pos_t{PROBE_PT_##N##_X, PROBE_PT_##N##_Y}), \
"PROBE_PT_" STRINGIFY(N) "_(X|Y) is unreachable using default NOZZLE_TO_PROBE_OFFSET and PROBING_MARGIN");
VALIDATE_PROBE_PT(1); VALIDATE_PROBE_PT(2); VALIDATE_PROBE_PT(3);
points[0] = xy_float_t({ PROBE_PT_1_X, PROBE_PT_1_Y });
points[1] = xy_float_t({ PROBE_PT_2_X, PROBE_PT_2_Y });
points[2] = xy_float_t({ PROBE_PT_3_X, PROBE_PT_3_Y });
#else
#if IS_KINEMATIC
constexpr float SIN0 = 0.0, SIN120 = 0.866025, SIN240 = -0.866025,
COS0 = 1.0, COS120 = -0.5 , COS240 = -0.5;
points[0].set((X_CENTER) + probe_radius() * COS0, (Y_CENTER) + probe_radius() * SIN0);
points[1].set((X_CENTER) + probe_radius() * COS120, (Y_CENTER) + probe_radius() * SIN120);
points[2].set((X_CENTER) + probe_radius() * COS240, (Y_CENTER) + probe_radius() * SIN240);
points[0] = xy_float_t({ (X_CENTER) + probe_radius() * COS0, (Y_CENTER) + probe_radius() * SIN0 });
points[1] = xy_float_t({ (X_CENTER) + probe_radius() * COS120, (Y_CENTER) + probe_radius() * SIN120 });
points[2] = xy_float_t({ (X_CENTER) + probe_radius() * COS240, (Y_CENTER) + probe_radius() * SIN240 });
#else
points[0].set(min_x(), min_y());
points[1].set(max_x(), min_y());
points[2].set((max_x() - min_x()) / 2, max_y());
points[0] = xy_float_t({ min_x(), min_y() });
points[1] = xy_float_t({ max_x(), min_y() });
points[2] = xy_float_t({ (min_x() + max_x()) / 2, max_y() });
#endif
#endif
}
@@ -203,12 +253,24 @@ public:
static void servo_probe_init();
#endif
#if QUIET_PROBING
#if HAS_QUIET_PROBING
static void set_probing_paused(const bool p);
#endif
#if ENABLED(PROBE_TARE)
static void tare_init();
static bool tare();
#endif
// Basic functions for Sensorless Homing and Probing
#if USE_SENSORLESS
static void enable_stallguard_diag1();
static void disable_stallguard_diag1();
static void set_homing_current(const bool onoff);
#endif
private:
static bool probe_down_to_z(const float z, const feedRate_t fr_mm_s);
static bool probe_down_to_z(const_float_t z, const_feedRate_t fr_mm_s);
static void do_z_raise(const float z_raise);
static float run_z_probe(const bool sanity_check=true);
};

285
Marlin/src/module/scara.cpp Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
@@ -32,79 +32,74 @@
#include "motion.h"
#include "planner.h"
float delta_segments_per_second = SCARA_SEGMENTS_PER_SECOND;
#if ENABLED(AXEL_TPARA)
#include "endstops.h"
#include "../MarlinCore.h"
#endif
void scara_set_axis_is_at_home(const AxisEnum axis) {
if (axis == Z_AXIS)
current_position.z = Z_HOME_POS;
else {
float segments_per_second = TERN(AXEL_TPARA, TPARA_SEGMENTS_PER_SECOND, SCARA_SEGMENTS_PER_SECOND);
/**
* SCARA homes XY at the same time
*/
xyz_pos_t homeposition;
LOOP_XYZ(i) homeposition[i] = base_home_pos((AxisEnum)i);
#if EITHER(MORGAN_SCARA, MP_SCARA)
#if ENABLED(MORGAN_SCARA)
// MORGAN_SCARA uses arm angles for AB home position
// SERIAL_ECHOLNPAIR("homeposition A:", homeposition.a, " B:", homeposition.b);
inverse_kinematics(homeposition);
forward_kinematics_SCARA(delta.a, delta.b);
current_position[axis] = cartes[axis];
#else
// MP_SCARA uses a Cartesian XY home position
// SERIAL_ECHOPGM("homeposition");
// SERIAL_ECHOLNPAIR_P(SP_X_LBL, homeposition.x, SP_Y_LBL, homeposition.y);
current_position[axis] = homeposition[axis];
#endif
static constexpr xy_pos_t scara_offset = { SCARA_OFFSET_X, SCARA_OFFSET_Y };
// SERIAL_ECHOPGM("Cartesian");
// SERIAL_ECHOLNPAIR_P(SP_X_LBL, current_position.x, SP_Y_LBL, current_position.y);
update_software_endstops(axis);
/**
* Morgan SCARA Forward Kinematics. Results in 'cartes'.
* Maths and first version by QHARLEY.
* Integrated into Marlin and slightly restructured by Joachim Cerny.
*/
void forward_kinematics(const_float_t a, const_float_t b) {
const float a_sin = sin(RADIANS(a)) * L1,
a_cos = cos(RADIANS(a)) * L1,
b_sin = sin(RADIANS(SUM_TERN(MP_SCARA, b, a))) * L2,
b_cos = cos(RADIANS(SUM_TERN(MP_SCARA, b, a))) * L2;
cartes.x = a_cos + b_cos + scara_offset.x; // theta
cartes.y = a_sin + b_sin + scara_offset.y; // phi
/*
DEBUG_ECHOLNPGM(
"SCARA FK Angle a=", a,
" b=", b,
" a_sin=", a_sin,
" a_cos=", a_cos,
" b_sin=", b_sin,
" b_cos=", b_cos
);
DEBUG_ECHOLNPGM(" cartes (X,Y) = "(cartes.x, ", ", cartes.y, ")");
//*/
}
}
static constexpr xy_pos_t scara_offset = { SCARA_OFFSET_X, SCARA_OFFSET_Y };
#endif
/**
* Morgan SCARA Forward Kinematics. Results in 'cartes'.
* Maths and first version by QHARLEY.
* Integrated into Marlin and slightly restructured by Joachim Cerny.
*/
void forward_kinematics_SCARA(const float &a, const float &b) {
#if ENABLED(MORGAN_SCARA)
const float a_sin = sin(RADIANS(a)) * L1,
a_cos = cos(RADIANS(a)) * L1,
b_sin = sin(RADIANS(b)) * L2,
b_cos = cos(RADIANS(b)) * L2;
void scara_set_axis_is_at_home(const AxisEnum axis) {
if (axis == Z_AXIS)
current_position.z = Z_HOME_POS;
else {
// MORGAN_SCARA uses a Cartesian XY home position
xyz_pos_t homeposition = { X_HOME_POS, Y_HOME_POS, Z_HOME_POS };
//DEBUG_ECHOLNPGM_P(PSTR("homeposition X"), homeposition.x, SP_Y_LBL, homeposition.y);
cartes.set(a_cos + b_cos + scara_offset.x, // theta
a_sin + b_sin + scara_offset.y); // theta+phi
delta = homeposition;
forward_kinematics(delta.a, delta.b);
current_position[axis] = cartes[axis];
/*
SERIAL_ECHOLNPAIR(
"SCARA FK Angle a=", a,
" b=", b,
" a_sin=", a_sin,
" a_cos=", a_cos,
" b_sin=", b_sin,
" b_cos=", b_cos
);
SERIAL_ECHOLNPAIR(" cartes (X,Y) = "(cartes.x, ", ", cartes.y, ")");
//*/
}
//DEBUG_ECHOLNPGM_P(PSTR("Cartesian X"), current_position.x, SP_Y_LBL, current_position.y);
update_software_endstops(axis);
}
}
void inverse_kinematics(const xyz_pos_t &raw) {
#if ENABLED(MORGAN_SCARA)
/**
* Morgan SCARA Inverse Kinematics. Results in 'delta'.
*
* See http://forums.reprap.org/read.php?185,283327
*
* Maths and first version by QHARLEY.
* Integrated into Marlin and slightly restructured by Joachim Cerny.
*/
/**
* Morgan SCARA Inverse Kinematics. Results are stored in 'delta'.
*
* See https://reprap.org/forum/read.php?185,283327
*
* Maths and first version by QHARLEY.
* Integrated into Marlin and slightly restructured by Joachim Cerny.
*/
void inverse_kinematics(const xyz_pos_t &raw) {
float C2, S2, SK1, SK2, THETA, PSI;
// Translate SCARA to standard XY with scaling factor
@@ -116,6 +111,8 @@ void inverse_kinematics(const xyz_pos_t &raw) {
else
C2 = (H2 - (L1_2 + L2_2)) / (2.0f * L1 * L2);
LIMIT(C2, -1, 1);
S2 = SQRT(1.0f - sq(C2));
// Unrotated Arm1 plus rotated Arm2 gives the distance from Center to End
@@ -130,16 +127,41 @@ void inverse_kinematics(const xyz_pos_t &raw) {
// Angle of Arm2
PSI = ATAN2(S2, C2);
delta.set(DEGREES(THETA), DEGREES(THETA + PSI), raw.z);
delta.set(DEGREES(THETA), DEGREES(SUM_TERN(MORGAN_SCARA, PSI, THETA)), raw.z);
/*
DEBUG_POS("SCARA IK", raw);
DEBUG_POS("SCARA IK", delta);
SERIAL_ECHOLNPAIR(" SCARA (x,y) ", sx, ",", sy, " C2=", C2, " S2=", S2, " Theta=", THETA, " Phi=", PHI);
DEBUG_ECHOLNPGM(" SCARA (x,y) ", sx, ",", sy, " C2=", C2, " S2=", S2, " Theta=", THETA, " Psi=", PSI);
//*/
}
#else // MP_SCARA
#elif ENABLED(MP_SCARA)
void scara_set_axis_is_at_home(const AxisEnum axis) {
if (axis == Z_AXIS)
current_position.z = Z_HOME_POS;
else {
// MP_SCARA uses arm angles for AB home position
#ifndef SCARA_OFFSET_THETA1
#define SCARA_OFFSET_THETA1 12 // degrees
#endif
#ifndef SCARA_OFFSET_THETA2
#define SCARA_OFFSET_THETA2 131 // degrees
#endif
ab_float_t homeposition = { SCARA_OFFSET_THETA1, SCARA_OFFSET_THETA2 };
//DEBUG_ECHOLNPGM("homeposition A:", homeposition.a, " B:", homeposition.b);
inverse_kinematics(homeposition);
forward_kinematics(delta.a, delta.b);
current_position[axis] = cartes[axis];
//DEBUG_ECHOLNPGM_P(PSTR("Cartesian X"), current_position.x, SP_Y_LBL, current_position.y);
update_software_endstops(axis);
}
}
void inverse_kinematics(const xyz_pos_t &raw) {
const float x = raw.x, y = raw.y, c = HYPOT(x, y),
THETA3 = ATAN2(y, x),
THETA1 = THETA3 + ACOS((sq(c) + sq(L1) - sq(L2)) / (2.0f * c * L1)),
@@ -150,14 +172,137 @@ void inverse_kinematics(const xyz_pos_t &raw) {
/*
DEBUG_POS("SCARA IK", raw);
DEBUG_POS("SCARA IK", delta);
SERIAL_ECHOLNPAIR(" SCARA (x,y) ", x, ",", y," Theta1=", THETA1, " Theta2=", THETA2);
SERIAL_ECHOLNPGM(" SCARA (x,y) ", x, ",", y," Theta1=", THETA1, " Theta2=", THETA2);
//*/
}
#endif // MP_SCARA
}
#elif ENABLED(AXEL_TPARA)
static constexpr xyz_pos_t robot_offset = { TPARA_OFFSET_X, TPARA_OFFSET_Y, TPARA_OFFSET_Z };
void scara_set_axis_is_at_home(const AxisEnum axis) {
if (axis == Z_AXIS)
current_position.z = Z_HOME_POS;
else {
xyz_pos_t homeposition = { X_HOME_POS, Y_HOME_POS, Z_HOME_POS };
//DEBUG_ECHOLNPGM_P(PSTR("homeposition X"), homeposition.x, SP_Y_LBL, homeposition.y, SP_Z_LBL, homeposition.z);
inverse_kinematics(homeposition);
forward_kinematics(delta.a, delta.b, delta.c);
current_position[axis] = cartes[axis];
//DEBUG_ECHOLNPGM_P(PSTR("Cartesian X"), current_position.x, SP_Y_LBL, current_position.y);
update_software_endstops(axis);
}
}
// Convert ABC inputs in degrees to XYZ outputs in mm
void forward_kinematics(const_float_t a, const_float_t b, const_float_t c) {
const float w = c - b,
r = L1 * cos(RADIANS(b)) + L2 * sin(RADIANS(w - (90 - b))),
x = r * cos(RADIANS(a)),
y = r * sin(RADIANS(a)),
rho2 = L1_2 + L2_2 - 2.0f * L1 * L2 * cos(RADIANS(w));
cartes = robot_offset + xyz_pos_t({ x, y, SQRT(rho2 - sq(x) - sq(y)) });
}
// Home YZ together, then X (or all at once). Based on quick_home_xy & home_delta
void home_TPARA() {
// Init the current position of all carriages to 0,0,0
current_position.reset();
destination.reset();
sync_plan_position();
// Disable stealthChop if used. Enable diag1 pin on driver.
#if ENABLED(SENSORLESS_HOMING)
TERN_(X_SENSORLESS, sensorless_t stealth_states_x = start_sensorless_homing_per_axis(X_AXIS));
TERN_(Y_SENSORLESS, sensorless_t stealth_states_y = start_sensorless_homing_per_axis(Y_AXIS));
TERN_(Z_SENSORLESS, sensorless_t stealth_states_z = start_sensorless_homing_per_axis(Z_AXIS));
#endif
//const int x_axis_home_dir = TOOL_X_HOME_DIR(active_extruder);
//const xy_pos_t pos { max_length(X_AXIS) , max_length(Y_AXIS) };
//const float mlz = max_length(X_AXIS),
// Move all carriages together linearly until an endstop is hit.
//do_blocking_move_to_xy_z(pos, mlz, homing_feedrate(Z_AXIS));
current_position.x = 0 ;
current_position.y = 0 ;
current_position.z = max_length(Z_AXIS) ;
line_to_current_position(homing_feedrate(Z_AXIS));
planner.synchronize();
// Re-enable stealthChop if used. Disable diag1 pin on driver.
#if ENABLED(SENSORLESS_HOMING)
TERN_(X_SENSORLESS, end_sensorless_homing_per_axis(X_AXIS, stealth_states_x));
TERN_(Y_SENSORLESS, end_sensorless_homing_per_axis(Y_AXIS, stealth_states_y));
TERN_(Z_SENSORLESS, end_sensorless_homing_per_axis(Z_AXIS, stealth_states_z));
#endif
endstops.validate_homing_move();
// At least one motor has reached its endstop.
// Now re-home each motor separately.
homeaxis(A_AXIS);
homeaxis(C_AXIS);
homeaxis(B_AXIS);
// Set all carriages to their home positions
// Do this here all at once for Delta, because
// XYZ isn't ABC. Applying this per-tower would
// give the impression that they are the same.
LOOP_LINEAR_AXES(i) set_axis_is_at_home((AxisEnum)i);
sync_plan_position();
}
void inverse_kinematics(const xyz_pos_t &raw) {
const xyz_pos_t spos = raw - robot_offset;
const float RXY = SQRT(HYPOT2(spos.x, spos.y)),
RHO2 = NORMSQ(spos.x, spos.y, spos.z),
//RHO = SQRT(RHO2),
LSS = L1_2 + L2_2,
LM = 2.0f * L1 * L2,
CG = (LSS - RHO2) / LM,
SG = SQRT(1 - POW(CG, 2)), // Method 2
K1 = L1 - L2 * CG,
K2 = L2 * SG,
// Angle of Body Joint
THETA = ATAN2(spos.y, spos.x),
// Angle of Elbow Joint
//GAMMA = ACOS(CG),
GAMMA = ATAN2(SG, CG), // Method 2
// Angle of Shoulder Joint, elevation angle measured from horizontal (r+)
//PHI = asin(spos.z/RHO) + asin(L2 * sin(GAMMA) / RHO),
PHI = ATAN2(spos.z, RXY) + ATAN2(K2, K1), // Method 2
// Elbow motor angle measured from horizontal, same frame as shoulder (r+)
PSI = PHI + GAMMA;
delta.set(DEGREES(THETA), DEGREES(PHI), DEGREES(PSI));
//SERIAL_ECHOLNPGM(" SCARA (x,y,z) ", spos.x , ",", spos.y, ",", spos.z, " Rho=", RHO, " Rho2=", RHO2, " Theta=", THETA, " Phi=", PHI, " Psi=", PSI, " Gamma=", GAMMA);
}
#endif
void scara_report_positions() {
SERIAL_ECHOLNPAIR("SCARA Theta:", planner.get_axis_position_degrees(A_AXIS), " Psi+Theta:", planner.get_axis_position_degrees(B_AXIS));
SERIAL_ECHOLNPGM("SCARA Theta:", planner.get_axis_position_degrees(A_AXIS)
#if ENABLED(AXEL_TPARA)
, " Phi:", planner.get_axis_position_degrees(B_AXIS)
, " Psi:", planner.get_axis_position_degrees(C_AXIS)
#else
, " Psi" TERN_(MORGAN_SCARA, "+Theta") ":", planner.get_axis_position_degrees(B_AXIS)
#endif
);
SERIAL_EOL();
}

29
Marlin/src/module/scara.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -27,16 +27,27 @@
#include "../core/macros.h"
extern float delta_segments_per_second;
extern float segments_per_second;
// Float constants for SCARA calculations
float constexpr L1 = SCARA_LINKAGE_1, L2 = SCARA_LINKAGE_2,
L1_2 = sq(float(L1)), L1_2_2 = 2.0 * L1_2,
L2_2 = sq(float(L2));
#if ENABLED(AXEL_TPARA)
void scara_set_axis_is_at_home(const AxisEnum axis);
float constexpr L1 = TPARA_LINKAGE_1, L2 = TPARA_LINKAGE_2, // Float constants for Robot arm calculations
L1_2 = sq(float(L1)), L1_2_2 = 2.0 * L1_2,
L2_2 = sq(float(L2));
void forward_kinematics(const_float_t a, const_float_t b, const_float_t c);
void home_TPARA();
#else
float constexpr L1 = SCARA_LINKAGE_1, L2 = SCARA_LINKAGE_2, // Float constants for SCARA calculations
L1_2 = sq(float(L1)), L1_2_2 = 2.0 * L1_2,
L2_2 = sq(float(L2));
void forward_kinematics(const_float_t a, const_float_t b);
#endif
void inverse_kinematics(const xyz_pos_t &raw);
void forward_kinematics_SCARA(const float &a, const float &b);
void scara_set_axis_is_at_home(const AxisEnum axis);
void scara_report_positions();

10
Marlin/src/module/servo.cpp Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
@@ -39,19 +39,19 @@ HAL_SERVO_LIB servo[NUM_SERVOS];
void servo_init() {
#if NUM_SERVOS >= 1 && HAS_SERVO_0
servo[0].attach(SERVO0_PIN);
servo[0].detach(); // Just set up the pin. We don't have a position yet. Don't move to a random position.
DETACH_SERVO(0); // Just set up the pin. We don't have a position yet. Don't move to a random position.
#endif
#if NUM_SERVOS >= 2 && HAS_SERVO_1
servo[1].attach(SERVO1_PIN);
servo[1].detach();
DETACH_SERVO(1);
#endif
#if NUM_SERVOS >= 3 && HAS_SERVO_2
servo[2].attach(SERVO2_PIN);
servo[2].detach();
DETACH_SERVO(2);
#endif
#if NUM_SERVOS >= 4 && HAS_SERVO_3
servo[3].attach(SERVO3_PIN);
servo[3].detach();
DETACH_SERVO(3);
#endif
}

5
Marlin/src/module/servo.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -110,6 +110,7 @@
#endif // HAS_SERVO_ANGLES
#define MOVE_SERVO(I, P) servo[I].move(P)
#define DETACH_SERVO(I) servo[I].detach()
extern HAL_SERVO_LIB servo[NUM_SERVOS];
extern void servo_init();
void servo_init();

File diff suppressed because it is too large Load Diff

View File

@@ -16,25 +16,30 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
//
// settings.cpp - Settings and EEPROM storage
//
#include "../inc/MarlinConfig.h"
#if ENABLED(EEPROM_SETTINGS)
#include "../HAL/shared/eeprom_api.h"
#endif
// PATCH START: Knutwurst
#ifdef POWER_OUTAGE_TEST
static bool RestartFlag = false;
void OutageSave();
void OutageRead();
extern float last_position[4];
extern long last_sd_position[1];
static bool RestartFlag = false;
void OutageSave();
void OutageRead();
extern float last_position[4];
extern long last_sd_position[1];
#endif
// PATCH END: Knutwurst
class MarlinSettings {
public:
@@ -47,9 +52,7 @@ class MarlinSettings {
reset();
#if ENABLED(EEPROM_SETTINGS)
const bool success = save();
#if ENABLED(EEPROM_CHITCHAT)
if (success) report();
#endif
if (TERN0(EEPROM_CHITCHAT, success)) report();
return success;
#else
return true;
@@ -83,12 +86,15 @@ class MarlinSettings {
//static void delete_mesh(); // necessary if we have a MAT
//static void defrag_meshes(); // "
#endif
#else
#else // !EEPROM_SETTINGS
FORCE_INLINE
static bool load() { reset(); report(); return true; }
FORCE_INLINE
static void first_load() { (void)load(); }
#endif
#endif // !EEPROM_SETTINGS
#if DISABLED(DISABLE_M503)
static void report(const bool forReplay=false);
@@ -112,7 +118,42 @@ class MarlinSettings {
static bool _load();
static bool size_error(const uint16_t size);
#endif
static int eeprom_index;
static uint16_t working_crc;
static bool EEPROM_START(int eeprom_offset) {
if (!persistentStore.access_start()) { SERIAL_ECHO_MSG("No EEPROM."); return false; }
eeprom_index = eeprom_offset;
working_crc = 0;
return true;
}
static void EEPROM_FINISH(void) { persistentStore.access_finish(); }
template<typename T>
static void EEPROM_SKIP(const T &VAR) { eeprom_index += sizeof(VAR); }
template<typename T>
static void EEPROM_WRITE(const T &VAR) {
persistentStore.write_data(eeprom_index, (const uint8_t *) &VAR, sizeof(VAR), &working_crc);
}
template<typename T>
static void EEPROM_READ(T &VAR) {
persistentStore.read_data(eeprom_index, (uint8_t *) &VAR, sizeof(VAR), &working_crc, !validating);
}
static void EEPROM_READ(uint8_t *VAR, size_t sizeof_VAR) {
persistentStore.read_data(eeprom_index, VAR, sizeof_VAR, &working_crc, !validating);
}
template<typename T>
static void EEPROM_READ_ALWAYS(T &VAR) {
persistentStore.read_data(eeprom_index, (uint8_t *) &VAR, sizeof(VAR), &working_crc);
}
#endif // EEPROM_SETTINGS
};
extern MarlinSettings settings;

2
Marlin/src/module/speed_lookuptable.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once

1490
Marlin/src/module/stepper.cpp Executable file → Normal file

File diff suppressed because it is too large Load Diff

293
Marlin/src/module/stepper.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -38,7 +38,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Grbl. If not, see <http://www.gnu.org/licenses/>.
* along with Grbl. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../inc/MarlinConfig.h"
@@ -133,27 +133,6 @@
#endif
// Add time for each stepper
#if HAS_X_STEP
#define ISR_X_STEPPER_CYCLES ISR_STEPPER_CYCLES
#else
#define ISR_X_STEPPER_CYCLES 0UL
#endif
#if HAS_Y_STEP
#define ISR_Y_STEPPER_CYCLES ISR_STEPPER_CYCLES
#else
#define ISR_START_Y_STEPPER_CYCLES 0UL
#define ISR_Y_STEPPER_CYCLES 0UL
#endif
#if HAS_Z_STEP
#define ISR_Z_STEPPER_CYCLES ISR_STEPPER_CYCLES
#else
#define ISR_Z_STEPPER_CYCLES 0UL
#endif
// E is always interpolated, even for mixing extruders
#define ISR_E_STEPPER_CYCLES ISR_STEPPER_CYCLES
// If linear advance is disabled, the loop also handles them
#if DISABLED(LIN_ADVANCE) && ENABLED(MIXING_EXTRUDER)
#define ISR_MIXING_STEPPER_CYCLES ((MIXING_STEPPERS) * (ISR_STEPPER_CYCLES))
@@ -161,8 +140,31 @@
#define ISR_MIXING_STEPPER_CYCLES 0UL
#endif
// Add time for each stepper
#if HAS_X_STEP
#define ISR_X_STEPPER_CYCLES ISR_STEPPER_CYCLES
#endif
#if HAS_Y_STEP
#define ISR_Y_STEPPER_CYCLES ISR_STEPPER_CYCLES
#endif
#if HAS_Z_STEP
#define ISR_Z_STEPPER_CYCLES ISR_STEPPER_CYCLES
#endif
#if HAS_I_STEP
#define ISR_I_STEPPER_CYCLES ISR_STEPPER_CYCLES
#endif
#if HAS_J_STEP
#define ISR_J_STEPPER_CYCLES ISR_STEPPER_CYCLES
#endif
#if HAS_K_STEP
#define ISR_K_STEPPER_CYCLES ISR_STEPPER_CYCLES
#endif
#if HAS_EXTRUDERS
#define ISR_E_STEPPER_CYCLES ISR_STEPPER_CYCLES // E is always interpolated, even for mixing extruders
#endif
// And the total minimum loop time, not including the base
#define MIN_ISR_LOOP_CYCLES (ISR_X_STEPPER_CYCLES + ISR_Y_STEPPER_CYCLES + ISR_Z_STEPPER_CYCLES + ISR_E_STEPPER_CYCLES + ISR_MIXING_STEPPER_CYCLES)
#define MIN_ISR_LOOP_CYCLES (ISR_MIXING_STEPPER_CYCLES LOGICAL_AXIS_GANG(+ ISR_E_STEPPER_CYCLES, + ISR_X_STEPPER_CYCLES, + ISR_Y_STEPPER_CYCLES, + ISR_Z_STEPPER_CYCLES, + ISR_I_STEPPER_CYCLES, + ISR_J_STEPPER_CYCLES, + ISR_K_STEPPER_CYCLES))
// Calculate the minimum MPU cycles needed per pulse to enforce, limited to the max stepper rate
#define _MIN_STEPPER_PULSE_CYCLES(N) _MAX(uint32_t((F_CPU) / (MAXIMUM_STEPPER_RATE)), ((F_CPU) / 500000UL) * (N))
@@ -191,7 +193,6 @@
#error "Expected at least one of MINIMUM_STEPPER_PULSE or MAXIMUM_STEPPER_RATE to be defined"
#endif
// But the user could be enforcing a minimum time, so the loop time is
#define ISR_LOOP_CYCLES (ISR_LOOP_BASE_CYCLES + _MAX(MIN_STEPPER_PULSE_CYCLES, MIN_ISR_LOOP_CYCLES))
@@ -230,8 +231,75 @@
#define MAX_STEP_ISR_FREQUENCY_2X ((F_CPU) / ISR_EXECUTION_CYCLES(2))
#define MAX_STEP_ISR_FREQUENCY_1X ((F_CPU) / ISR_EXECUTION_CYCLES(1))
// The minimum allowable frequency for step smoothing will be 1/10 of the maximum nominal frequency (in Hz)
#define MIN_STEP_ISR_FREQUENCY MAX_STEP_ISR_FREQUENCY_1X
// The minimum step ISR rate used by ADAPTIVE_STEP_SMOOTHING to target 50% CPU usage
// This does not account for the possibility of multi-stepping.
// Perhaps DISABLE_MULTI_STEPPING should be required with ADAPTIVE_STEP_SMOOTHING.
#define MIN_STEP_ISR_FREQUENCY (MAX_STEP_ISR_FREQUENCY_1X / 2)
#define ENABLE_COUNT (LINEAR_AXES + E_STEPPERS)
typedef IF<(ENABLE_COUNT > 8), uint16_t, uint8_t>::type ena_mask_t;
// Axis flags type, for enabled state or other simple state
typedef struct {
union {
ena_mask_t bits;
struct {
bool LINEAR_AXIS_LIST(X:1, Y:1, Z:1, I:1, J:1, K:1);
#if HAS_EXTRUDERS
bool LIST_N(EXTRUDERS, E0:1, E1:1, E2:1, E3:1, E4:1, E5:1, E6:1, E7:1);
#endif
};
};
constexpr ena_mask_t linear_bits() { return _BV(LINEAR_AXES) - 1; }
constexpr ena_mask_t e_bits() { return (_BV(EXTRUDERS) - 1) << LINEAR_AXES; }
} axis_flags_t;
// All the stepper enable pins
constexpr pin_t ena_pins[] = {
LINEAR_AXIS_LIST(X_ENABLE_PIN, Y_ENABLE_PIN, Z_ENABLE_PIN, I_ENABLE_PIN, J_ENABLE_PIN, K_ENABLE_PIN),
LIST_N(E_STEPPERS, E0_ENABLE_PIN, E1_ENABLE_PIN, E2_ENABLE_PIN, E3_ENABLE_PIN, E4_ENABLE_PIN, E5_ENABLE_PIN, E6_ENABLE_PIN, E7_ENABLE_PIN)
};
// Index of the axis or extruder element in a combined array
constexpr uint8_t index_of_axis(const AxisEnum axis E_OPTARG(const uint8_t eindex=0)) {
return uint8_t(axis) + (E_TERN0(axis < LINEAR_AXES ? 0 : eindex));
}
//#define __IAX_N(N,V...) _IAX_##N(V)
//#define _IAX_N(N,V...) __IAX_N(N,V)
//#define _IAX_1(A) index_of_axis(A)
//#define _IAX_2(A,B) index_of_axis(A E_OPTARG(B))
//#define INDEX_OF_AXIS(V...) _IAX_N(TWO_ARGS(V),V)
#define INDEX_OF_AXIS(A,V...) index_of_axis(A E_OPTARG(V+0))
// Bit mask for a matching enable pin, or 0
constexpr ena_mask_t ena_same(const uint8_t a, const uint8_t b) {
return ena_pins[a] == ena_pins[b] ? _BV(b) : 0;
}
// Recursively get the enable overlaps mask for a given linear axis or extruder
constexpr ena_mask_t ena_overlap(const uint8_t a=0, const uint8_t b=0) {
return b >= ENABLE_COUNT ? 0 : (a == b ? 0 : ena_same(a, b)) | ena_overlap(a, b + 1);
}
// Recursively get whether there's any overlap at all
constexpr bool any_enable_overlap(const uint8_t a=0) {
return a >= ENABLE_COUNT ? false : ena_overlap(a) || any_enable_overlap(a + 1);
}
// Array of axes that overlap with each
// TODO: Consider cases where >=2 steppers are used by a linear axis or extruder
// (e.g., CoreXY, Dual XYZ, or E with multiple steppers, etc.).
constexpr ena_mask_t enable_overlap[] = {
#define _OVERLAP(N) ena_overlap(INDEX_OF_AXIS(AxisEnum(N))),
REPEAT(LINEAR_AXES, _OVERLAP)
#if HAS_EXTRUDERS
#define _E_OVERLAP(N) ena_overlap(INDEX_OF_AXIS(E_AXIS, N)),
REPEAT(E_STEPPERS, _E_OVERLAP)
#endif
};
//static_assert(!any_enable_overlap(), "There is some overlap.");
//
// Stepper class definition
@@ -240,34 +308,44 @@ class Stepper {
public:
#if HAS_EXTRA_ENDSTOPS || ENABLED(Z_STEPPER_AUTO_ALIGN)
#if EITHER(HAS_EXTRA_ENDSTOPS, Z_STEPPER_AUTO_ALIGN)
static bool separate_multi_axis;
#endif
#if HAS_MOTOR_CURRENT_PWM
#ifndef PWM_MOTOR_CURRENT
#define PWM_MOTOR_CURRENT DEFAULT_PWM_MOTOR_CURRENT
#if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM
#if HAS_MOTOR_CURRENT_PWM
#ifndef PWM_MOTOR_CURRENT
#define PWM_MOTOR_CURRENT DEFAULT_PWM_MOTOR_CURRENT
#endif
#define MOTOR_CURRENT_COUNT LINEAR_AXES
#elif HAS_MOTOR_CURRENT_SPI
static constexpr uint32_t digipot_count[] = DIGIPOT_MOTOR_CURRENT;
#define MOTOR_CURRENT_COUNT COUNT(Stepper::digipot_count)
#endif
static uint32_t motor_current_setting[3];
static bool initialized;
static uint32_t motor_current_setting[MOTOR_CURRENT_COUNT]; // Initialized by settings.load()
#endif
// Last-moved extruder, as set when the last movement was fetched from planner
#if HAS_MULTI_EXTRUDER
static uint8_t last_moved_extruder;
#else
static constexpr uint8_t last_moved_extruder = 0;
#endif
#if HAS_FREEZE_PIN
static bool frozen; // Set this flag to instantly freeze motion
#endif
private:
static block_t* current_block; // A pointer to the block currently being traced
static uint8_t last_direction_bits, // The next stepping-bits to be output
axis_did_move; // Last Movement in the given direction is not null, as computed when the last movement was fetched from planner
static axis_bits_t last_direction_bits, // The next stepping-bits to be output
axis_did_move; // Last Movement in the given direction is not null, as computed when the last movement was fetched from planner
static bool abort_current_block; // Signals to the stepper that current block should be aborted
// Last-moved extruder, as set when the last movement was fetched from planner
#if EXTRUDERS < 2
static constexpr uint8_t last_moved_extruder = 0;
#elif DISABLED(MIXING_EXTRUDER)
static uint8_t last_moved_extruder;
#endif
#if ENABLED(X_DUAL_ENDSTOPS)
static bool locked_X_motor, locked_X2_motor;
#endif
@@ -303,7 +381,7 @@ class Stepper {
decelerate_after, // The point from where we need to start decelerating
step_event_count; // The total event count for the current block
#if EXTRUDERS > 1 || ENABLED(MIXING_EXTRUDER)
#if EITHER(HAS_MULTI_EXTRUDER, MIXING_EXTRUDER)
static uint8_t stepper_extruder;
#else
static constexpr uint8_t stepper_extruder = 0;
@@ -334,28 +412,44 @@ class Stepper {
static uint32_t nextBabystepISR;
#endif
#if ENABLED(DIRECT_STEPPING)
static page_step_state_t page_step_state;
#endif
static int32_t ticks_nominal;
#if DISABLED(S_CURVE_ACCELERATION)
static uint32_t acc_step_rate; // needed for deceleration start point
#endif
//
// Exact steps at which an endstop was triggered
//
static xyz_long_t endstops_trigsteps;
//
// Positions of stepper motors, in step units
//
static xyze_long_t count_position;
//
// Current direction of stepper motors (+1 or -1)
//
// Current stepper motor directions (+1 or -1)
static xyze_int8_t count_direction;
public:
#if ENABLED(LASER_POWER_INLINE_TRAPEZOID)
typedef struct {
bool enabled; // Trapezoid needed flag (i.e., laser on, planner in control)
uint8_t cur_power; // Current laser power
bool cruise_set; // Power set up for cruising?
#if ENABLED(LASER_POWER_INLINE_TRAPEZOID_CONT)
uint16_t till_update; // Countdown to the next update
#else
uint32_t last_step_count, // Step count from the last update
acc_step_count; // Bresenham counter for laser accel/decel
#endif
} stepper_laser_t;
static stepper_laser_t laser_trap;
#endif
public:
// Initialize stepper hardware
static void init();
@@ -400,20 +494,30 @@ class Stepper {
#endif
// Check if the given block is busy or not - Must not be called from ISR contexts
static bool is_block_busy(const block_t* const block);
static bool is_block_busy(const block_t * const block);
// Get the position of a stepper, in steps
static int32_t position(const AxisEnum axis);
// Set the current position in steps
static void set_position(const int32_t &a, const int32_t &b, const int32_t &c, const int32_t &e);
static inline void set_position(const xyze_long_t &abce) { set_position(abce.a, abce.b, abce.c, abce.e); }
static void set_position(const xyze_long_t &spos);
static void set_axis_position(const AxisEnum a, const int32_t &v);
// Report the positions of the steppers, in steps
static void report_a_position(const xyz_long_t &pos);
static void report_positions();
// Discard current block and free any resources
FORCE_INLINE static void discard_current_block() {
#if ENABLED(DIRECT_STEPPING)
if (IS_PAGE(current_block))
page_manager.free_page(current_block->page_idx);
#endif
current_block = nullptr;
axis_did_move = 0;
planner.release_current_block();
}
// Quickly stop all steppers
FORCE_INLINE static void quick_stop() { abort_current_block = true; }
@@ -423,24 +527,15 @@ class Stepper {
// The last movement direction was not null on the specified axis. Note that motor direction is not necessarily the same.
FORCE_INLINE static bool axis_is_moving(const AxisEnum axis) { return TEST(axis_did_move, axis); }
// The extruder associated to the last movement
FORCE_INLINE static uint8_t movement_extruder() {
return (0
#if EXTRUDERS > 1 && DISABLED(MIXING_EXTRUDER)
+ last_moved_extruder
#endif
);
}
// Handle a triggered endstop
static void endstop_triggered(const AxisEnum axis);
// Triggered position of an axis in steps
static int32_t triggered_position(const AxisEnum axis);
#if HAS_DIGIPOTSS || HAS_MOTOR_CURRENT_PWM
static void digitalPotWrite(const int16_t address, const int16_t value);
static void digipot_current(const uint8_t driver, const int16_t current);
#if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM
static void set_digipot_value_spi(const int16_t address, const int16_t value);
static void set_digipot_current(const uint8_t driver, const int16_t current);
#endif
#if HAS_MICROSTEPS
@@ -449,7 +544,7 @@ class Stepper {
static void microstep_readings();
#endif
#if HAS_EXTRA_ENDSTOPS || ENABLED(Z_STEPPER_AUTO_ALIGN)
#if EITHER(HAS_EXTRA_ENDSTOPS, Z_STEPPER_AUTO_ALIGN)
FORCE_INLINE static void set_separate_multi_axis(const bool state) { separate_multi_axis = state; }
#endif
#if ENABLED(X_DUAL_ENDSTOPS)
@@ -461,7 +556,7 @@ class Stepper {
FORCE_INLINE static void set_y2_lock(const bool state) { locked_Y2_motor = state; }
#endif
#if EITHER(Z_MULTI_ENDSTOPS, Z_STEPPER_AUTO_ALIGN)
FORCE_INLINE static void set_z_lock(const bool state) { locked_Z_motor = state; }
FORCE_INLINE static void set_z1_lock(const bool state) { locked_Z_motor = state; }
FORCE_INLINE static void set_z2_lock(const bool state) { locked_Z2_motor = state; }
#if NUM_Z_STEPPER_DRIVERS >= 3
FORCE_INLINE static void set_z3_lock(const bool state) { locked_Z3_motor = state; }
@@ -469,6 +564,16 @@ class Stepper {
FORCE_INLINE static void set_z4_lock(const bool state) { locked_Z4_motor = state; }
#endif
#endif
static inline void set_all_z_lock(const bool lock, const int8_t except=-1) {
set_z1_lock(lock ^ (except == 0));
set_z2_lock(lock ^ (except == 1));
#if NUM_Z_STEPPER_DRIVERS >= 3
set_z3_lock(lock ^ (except == 2));
#if NUM_Z_STEPPER_DRIVERS >= 4
set_z4_lock(lock ^ (except == 3));
#endif
#endif
}
#endif
#if ENABLED(BABYSTEPPING)
@@ -479,16 +584,58 @@ class Stepper {
static void refresh_motor_power();
#endif
// Set direction bits for all steppers
static axis_flags_t axis_enabled; // Axis stepper(s) ENABLED states
static inline bool axis_is_enabled(const AxisEnum axis E_OPTARG(const uint8_t eindex=0)) {
return TEST(axis_enabled.bits, INDEX_OF_AXIS(axis, eindex));
}
static inline void mark_axis_enabled(const AxisEnum axis E_OPTARG(const uint8_t eindex=0)) {
SBI(axis_enabled.bits, INDEX_OF_AXIS(axis, eindex));
}
static inline void mark_axis_disabled(const AxisEnum axis E_OPTARG(const uint8_t eindex=0)) {
CBI(axis_enabled.bits, INDEX_OF_AXIS(axis, eindex));
}
static inline bool can_axis_disable(const AxisEnum axis E_OPTARG(const uint8_t eindex=0)) {
return !any_enable_overlap() || !(axis_enabled.bits & enable_overlap[INDEX_OF_AXIS(axis, eindex)]);
}
static void enable_axis(const AxisEnum axis);
static bool disable_axis(const AxisEnum axis);
#if HAS_EXTRUDERS
static void enable_extruder(E_TERN_(const uint8_t eindex=0));
static bool disable_extruder(E_TERN_(const uint8_t eindex=0));
static void enable_e_steppers();
static void disable_e_steppers();
#else
static inline void enable_extruder() {}
static inline bool disable_extruder() {}
static inline void enable_e_steppers() {}
static inline void disable_e_steppers() {}
#endif
#define ENABLE_EXTRUDER(N) enable_extruder(E_TERN_(N))
#define DISABLE_EXTRUDER(N) disable_extruder(E_TERN_(N))
#define AXIS_IS_ENABLED(N,V...) axis_is_enabled(N E_OPTARG(#V))
static void enable_all_steppers();
static void disable_all_steppers();
// Update direction states for all steppers
static void set_directions();
// Set direction bits and update all stepper DIR states
static void set_directions(const axis_bits_t bits) {
last_direction_bits = bits;
set_directions();
}
private:
// Set the current position in steps
static void _set_position(const int32_t &a, const int32_t &b, const int32_t &c, const int32_t &e);
FORCE_INLINE static void _set_position(const abce_long_t &spos) { _set_position(spos.a, spos.b, spos.c, spos.e); }
static void _set_position(const abce_long_t &spos);
FORCE_INLINE static uint32_t calc_timer_interval(uint32_t step_rate, uint8_t* loops) {
FORCE_INLINE static uint32_t calc_timer_interval(uint32_t step_rate, uint8_t *loops) {
uint32_t timer;
// Scale the frequency, as requested by the caller
@@ -525,7 +672,7 @@ class Stepper {
// In case of high-performance processor, it is able to calculate in real-time
timer = uint32_t(STEPPER_TIMER_RATE) / step_rate;
#else
constexpr uint32_t min_step_rate = F_CPU / 500000U;
constexpr uint32_t min_step_rate = (F_CPU) / 500000U;
NOLESS(step_rate, min_step_rate);
step_rate -= min_step_rate; // Correct for minimal speed
if (step_rate >= (8 * 256)) { // higher step rate
@@ -553,7 +700,7 @@ class Stepper {
static int32_t _eval_bezier_curve(const uint32_t curr_step);
#endif
#if HAS_DIGIPOTSS || HAS_MOTOR_CURRENT_PWM
#if HAS_MOTOR_CURRENT_SPI || HAS_MOTOR_CURRENT_PWM
static void digipot_init();
#endif

23
Marlin/src/module/stepper/L64xx.cpp Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
@@ -55,6 +55,15 @@
#if AXIS_IS_L64XX(Z4)
L64XX_CLASS(Z4) stepperZ4(L6470_CHAIN_SS_PIN);
#endif
#if AXIS_IS_L64XX(I)
L64XX_CLASS(I) stepperI(L6470_CHAIN_SS_PIN);
#endif
#if AXIS_IS_L64XX(J)
L64XX_CLASS(J) stepperJ(L6470_CHAIN_SS_PIN);
#endif
#if AXIS_IS_L64XX(K)
L64XX_CLASS(K) stepperK(L6470_CHAIN_SS_PIN);
#endif
#if AXIS_IS_L64XX(E0)
L64XX_CLASS(E0) stepperE0(L6470_CHAIN_SS_PIN);
#endif
@@ -196,6 +205,18 @@ void L64XX_Marlin::init_to_defaults() {
#if AXIS_IS_L64XX(Z3)
L6470_INIT_CHIP(Z3);
#endif
#if AXIS_IS_L64XX(Z4)
L6470_INIT_CHIP(Z4);
#endif
#if AXIS_IS_L64XX(I)
L6470_INIT_CHIP(I);
#endif
#if AXIS_IS_L64XX(J)
L6470_INIT_CHIP(J);
#endif
#if AXIS_IS_L64XX(K)
L6470_INIT_CHIP(K);
#endif
#if AXIS_IS_L64XX(E0)
L6470_INIT_CHIP(E0);
#endif

108
Marlin/src/module/stepper/L64xx.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -45,7 +45,7 @@
#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_WRITE(STATE) (STATE ? stepperX.hardStop() : 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)
@@ -65,7 +65,7 @@
#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_WRITE(STATE) (STATE ? stepperY.hardStop() : 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)
@@ -85,7 +85,7 @@
#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_WRITE(STATE) (STATE ? stepperZ.hardStop() : 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)
@@ -105,7 +105,7 @@
#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_WRITE(STATE) (STATE ? stepperX2.hardStop() : 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)
@@ -126,7 +126,7 @@
#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_WRITE(STATE) (STATE ? stepperY2.hardStop() : 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)
@@ -147,7 +147,7 @@
#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_WRITE(STATE) (STATE ? stepperZ2.hardStop() : 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)
@@ -168,7 +168,7 @@
#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_WRITE(STATE) (STATE ? stepperZ3.hardStop() : 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)
@@ -189,7 +189,7 @@
#if HAS_Z4_ENABLE && AXIS_IS_L64XX(Z4)
extern L64XX_CLASS(Z4) stepperZ4;
#define Z4_ENABLE_INIT() NOOP
#define Z4_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperZ4.free())
#define Z4_ENABLE_WRITE(STATE) (STATE ? stepperZ4.hardStop() : stepperZ4.free())
#define Z4_ENABLE_READ() (stepperZ4.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_Z4(L6474)
#define Z4_DIR_INIT() SET_OUTPUT(Z4_DIR_PIN)
@@ -206,11 +206,71 @@
#define DISABLE_STEPPER_Z4() stepperZ4.free()
#endif
// I Stepper
#if AXIS_IS_L64XX(I)
extern L64XX_CLASS(I) stepperI;
#define I_ENABLE_INIT() NOOP
#define I_ENABLE_WRITE(STATE) (STATE ? stepperI.hardStop() : stepperI.free())
#define I_ENABLE_READ() (stepperI.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_I(L6474)
#define I_DIR_INIT() SET_OUTPUT(I_DIR_PIN)
#define I_DIR_WRITE(STATE) L6474_DIR_WRITE(I, STATE)
#define I_DIR_READ() READ(I_DIR_PIN)
#else
#define I_DIR_INIT() NOOP
#define I_DIR_WRITE(STATE) L64XX_DIR_WRITE(I, STATE)
#define I_DIR_READ() (stepper##I.getStatus() & STATUS_DIR);
#if AXIS_DRIVER_TYPE_I(L6470)
#define DISABLE_STEPPER_I() stepperI.free()
#endif
#endif
#endif
// J Stepper
#if AXIS_IS_L64XX(J)
extern L64XX_CLASS(J) stepperJ;
#define J_ENABLE_INIT() NOOP
#define J_ENABLE_WRITE(STATE) (STATE ? stepperJ.hardStop() : stepperJ.free())
#define J_ENABLE_READ() (stepperJ.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_J(L6474)
#define J_DIR_INIT() SET_OUTPUT(J_DIR_PIN)
#define J_DIR_WRITE(STATE) L6474_DIR_WRITE(J, STATE)
#define J_DIR_READ() READ(J_DIR_PIN)
#else
#define J_DIR_INIT() NOOP
#define J_DIR_WRITE(STATE) L64XX_DIR_WRITE(J, STATE)
#define J_DIR_READ() (stepper##J.getStatus() & STATUS_DIR);
#if AXIS_DRIVER_TYPE_J(L6470)
#define DISABLE_STEPPER_J() stepperJ.free()
#endif
#endif
#endif
// K Stepper
#if AXIS_IS_L64XX(K)
extern L64XX_CLASS(K) stepperK;
#define K_ENABLE_INIT() NOOP
#define K_ENABLE_WRITE(STATE) (STATE ? stepperK.hardStop() : stepperK.free())
#define K_ENABLE_READ() (stepperK.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_K(L6474)
#define K_DIR_INIT() SET_OUTPUT(K_DIR_PIN)
#define K_DIR_WRITE(STATE) L6474_DIR_WRITE(K, STATE)
#define K_DIR_READ() READ(K_DIR_PIN)
#else
#define K_DIR_INIT() NOOP
#define K_DIR_WRITE(STATE) L64XX_DIR_WRITE(K, STATE)
#define K_DIR_READ() (stepper##K.getStatus() & STATUS_DIR);
#if AXIS_DRIVER_TYPE_K(L6470)
#define DISABLE_STEPPER_K() stepperK.free()
#endif
#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_WRITE(STATE) (STATE ? stepperE0.hardStop() : 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)
@@ -221,7 +281,7 @@
#define E0_DIR_WRITE(STATE) L64XX_DIR_WRITE(E0, STATE)
#define E0_DIR_READ() (stepper##E0.getStatus() & STATUS_DIR);
#if AXIS_DRIVER_TYPE_E0(L6470)
#define DISABLE_STEPPER_E0() do{ stepperE0.free(); CBI(axis_known_position, E_AXIS); }while(0)
#define DISABLE_STEPPER_E0() do{ stepperE0.free(); }while(0)
#endif
#endif
#endif
@@ -230,7 +290,7 @@
#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_WRITE(STATE) (STATE ? stepperE1.hardStop() : 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)
@@ -241,7 +301,7 @@
#define E1_DIR_WRITE(STATE) L64XX_DIR_WRITE(E1, STATE)
#define E1_DIR_READ() (stepper##E1.getStatus() & STATUS_DIR);
#if AXIS_DRIVER_TYPE_E1(L6470)
#define DISABLE_STEPPER_E1() do{ stepperE1.free(); CBI(axis_known_position, E_AXIS); }while(0)
#define DISABLE_STEPPER_E1() do{ stepperE1.free(); }while(0)
#endif
#endif
#endif
@@ -250,7 +310,7 @@
#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_WRITE(STATE) (STATE ? stepperE2.hardStop() : 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)
@@ -261,7 +321,7 @@
#define E2_DIR_WRITE(STATE) L64XX_DIR_WRITE(E2, STATE)
#define E2_DIR_READ() (stepper##E2.getStatus() & STATUS_DIR);
#if AXIS_DRIVER_TYPE_E2(L6470)
#define DISABLE_STEPPER_E2() do{ stepperE2.free(); CBI(axis_known_position, E_AXIS); }while(0)
#define DISABLE_STEPPER_E2() do{ stepperE2.free(); }while(0)
#endif
#endif
#endif
@@ -270,7 +330,7 @@
#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_WRITE(STATE) (STATE ? stepperE3.hardStop() : 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)
@@ -287,7 +347,7 @@
#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_WRITE(STATE) (STATE ? stepperE4.hardStop() : 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)
@@ -298,7 +358,7 @@
#define E4_DIR_WRITE(STATE) L64XX_DIR_WRITE(E4, STATE)
#define E4_DIR_READ() (stepper##E4.getStatus() & STATUS_DIR);
#if AXIS_DRIVER_TYPE_E4(L6470)
#define DISABLE_STEPPER_E4() do{ stepperE4.free(); CBI(axis_known_position, E_AXIS); }while(0)
#define DISABLE_STEPPER_E4() do{ stepperE4.free(); }while(0)
#endif
#endif
#endif
@@ -307,7 +367,7 @@
#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_WRITE(STATE) (STATE ? stepperE5.hardStop() : 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)
@@ -318,7 +378,7 @@
#define E5_DIR_WRITE(STATE) L64XX_DIR_WRITE(E5, STATE)
#define E5_DIR_READ() (stepper##E5.getStatus() & STATUS_DIR);
#if AXIS_DRIVER_TYPE_E5(L6470)
#define DISABLE_STEPPER_E5() do{ stepperE5.free(); CBI(axis_known_position, E_AXIS); }while(0)
#define DISABLE_STEPPER_E5() do{ stepperE5.free(); }while(0)
#endif
#endif
#endif
@@ -327,7 +387,7 @@
#if AXIS_IS_L64XX(E6)
extern L64XX_CLASS(E6) stepperE6;
#define E6_ENABLE_INIT() NOOP
#define E6_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperE6.free())
#define E6_ENABLE_WRITE(STATE) (STATE ? stepperE6.hardStop() : stepperE6.free())
#define E6_ENABLE_READ() (stepperE6.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_E6(L6474)
#define E6_DIR_INIT() SET_OUTPUT(E6_DIR_PIN)
@@ -338,7 +398,7 @@
#define E6_DIR_WRITE(STATE) L64XX_DIR_WRITE(E6, STATE)
#define E6_DIR_READ() (stepper##E6.getStatus() & STATUS_DIR);
#if AXIS_DRIVER_TYPE_E6(L6470)
#define DISABLE_STEPPER_E6() do{ stepperE6.free(); CBI(axis_known_position, E_AXIS); }while(0)
#define DISABLE_STEPPER_E6() do{ stepperE6.free(); }while(0)
#endif
#endif
#endif
@@ -347,7 +407,7 @@
#if AXIS_IS_L64XX(E7)
extern L64XX_CLASS(E7) stepperE7;
#define E7_ENABLE_INIT() NOOP
#define E7_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperE7.free())
#define E7_ENABLE_WRITE(STATE) (STATE ? stepperE7.hardStop() : stepperE7.free())
#define E7_ENABLE_READ() (stepperE7.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_E7(L6474)
#define E7_DIR_INIT() SET_OUTPUT(E7_DIR_PIN)
@@ -358,7 +418,7 @@
#define E7_DIR_WRITE(STATE) L64XX_DIR_WRITE(E7, STATE)
#define E7_DIR_READ() (stepper##E7.getStatus() & STATUS_DIR);
#if AXIS_DRIVER_TYPE_E7(L6470)
#define DISABLE_STEPPER_E7() do{ stepperE7.free(); CBI(axis_known_position, E_AXIS); }while(0)
#define DISABLE_STEPPER_E7() do{ stepperE7.free(); }while(0)
#endif
#endif
#endif

24
Marlin/src/module/stepper/TMC26X.cpp Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
@@ -30,7 +30,7 @@
//
// TMC26X Driver objects and inits
//
#if HAS_DRIVER(TMC26X)
#if HAS_TMC26X
#include "TMC26X.h"
@@ -60,6 +60,15 @@
#if AXIS_DRIVER_TYPE_Z4(TMC26X)
_TMC26X_DEFINE(Z4);
#endif
#if AXIS_DRIVER_TYPE_I(TMC26X)
_TMC26X_DEFINE(I);
#endif
#if AXIS_DRIVER_TYPE_J(TMC26X)
_TMC26X_DEFINE(J);
#endif
#if AXIS_DRIVER_TYPE_K(TMC26X)
_TMC26X_DEFINE(K);
#endif
#if AXIS_DRIVER_TYPE_E0(TMC26X)
_TMC26X_DEFINE(E0);
#endif
@@ -115,6 +124,15 @@ void tmc26x_init_to_defaults() {
#if AXIS_DRIVER_TYPE_Z4(TMC26X)
_TMC26X_INIT(Z4);
#endif
#if AXIS_DRIVER_TYPE_I(TMC26X)
_TMC26X_INIT(I);
#endif
#if AXIS_DRIVER_TYPE_J(TMC26X)
_TMC26X_INIT(J);
#endif
#if AXIS_DRIVER_TYPE_K(TMC26X)
_TMC26X_INIT(K);
#endif
#if AXIS_DRIVER_TYPE_E0(TMC26X)
_TMC26X_INIT(E0);
#endif
@@ -141,4 +159,4 @@ void tmc26x_init_to_defaults() {
#endif
}
#endif // TMC26X
#endif // HAS_TMC26X

32
Marlin/src/module/stepper/TMC26X.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -31,11 +31,7 @@
// TMC26X drivers have STEP/DIR on normal pins, but ENABLE via SPI
#include <SPI.h>
#if defined(STM32GENERIC) && defined(STM32F7)
#include "../../HAL/STM32_F4_F7/STM32F7/TMC2660.h"
#else
#include <TMC26XStepper.h>
#endif
#include <TMC26XStepper.h>
void tmc26x_init_to_defaults();
@@ -103,6 +99,30 @@ void tmc26x_init_to_defaults();
#define Z4_ENABLE_READ() stepperZ4.isEnabled()
#endif
// I Stepper
#if HAS_I_ENABLE && AXIS_DRIVER_TYPE_I(TMC26X)
extern TMC26XStepper stepperI;
#define I_ENABLE_INIT() NOOP
#define I_ENABLE_WRITE(STATE) stepperI.setEnabled(STATE)
#define I_ENABLE_READ() stepperI.isEnabled()
#endif
// J Stepper
#if HAS_J_ENABLE && AXIS_DRIVER_TYPE_J(TMC26X)
extern TMC26XStepper stepperJ;
#define J_ENABLE_INIT() NOOP
#define J_ENABLE_WRITE(STATE) stepperJ.setEnabled(STATE)
#define J_ENABLE_READ() stepperJ.isEnabled()
#endif
// K Stepper
#if HAS_K_ENABLE && AXIS_DRIVER_TYPE_K(TMC26X)
extern TMC26XStepper stepperK;
#define K_ENABLE_INIT() NOOP
#define K_ENABLE_WRITE(STATE) stepperK.setEnabled(STATE)
#define K_ENABLE_READ() stepperK.isEnabled()
#endif
// E0 Stepper
#if AXIS_DRIVER_TYPE_E0(TMC26X)
extern TMC26XStepper stepperE0;

25
Marlin/src/module/stepper/indirection.cpp Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
@@ -33,21 +33,16 @@
#include "indirection.h"
void restore_stepper_drivers() {
#if HAS_TRINAMIC_CONFIG
restore_trinamic_drivers();
#endif
TERN_(HAS_TRINAMIC_CONFIG, restore_trinamic_drivers());
}
void reset_stepper_drivers() {
#if HAS_DRIVER(TMC26X)
tmc26x_init_to_defaults();
#endif
#if HAS_L64XX
L64xxManager.init_to_defaults();
#endif
#if HAS_TRINAMIC_CONFIG
reset_trinamic_drivers();
#endif
TERN_(HAS_TMC26X, tmc26x_init_to_defaults());
TERN_(HAS_L64XX, L64xxManager.init_to_defaults());
TERN_(HAS_TRINAMIC_CONFIG, reset_trinamic_drivers());
}
#if ENABLED(SOFTWARE_DRIVER_ENABLE)
// Flags to optimize XYZ Enabled state
xyz_bool_t axis_sw_enabled; // = { false, false, false }
#endif

336
Marlin/src/module/stepper/indirection.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -36,7 +36,7 @@
#include "L64xx.h"
#endif
#if HAS_DRIVER(TMC26X)
#if HAS_TMC26X
#include "TMC26X.h"
#endif
@@ -44,7 +44,7 @@
#include "trinamic.h"
#endif
void restore_stepper_drivers(); // Called by PSU_ON
void restore_stepper_drivers(); // Called by powerManager.power_on()
void reset_stepper_drivers(); // Called by settings.load / settings.reset
// X Stepper
@@ -65,38 +65,42 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset
#define X_STEP_READ() bool(READ(X_STEP_PIN))
// Y Stepper
#ifndef Y_ENABLE_INIT
#define Y_ENABLE_INIT() SET_OUTPUT(Y_ENABLE_PIN)
#define Y_ENABLE_WRITE(STATE) WRITE(Y_ENABLE_PIN,STATE)
#define Y_ENABLE_READ() bool(READ(Y_ENABLE_PIN))
#if HAS_Y_AXIS
#ifndef Y_ENABLE_INIT
#define Y_ENABLE_INIT() SET_OUTPUT(Y_ENABLE_PIN)
#define Y_ENABLE_WRITE(STATE) WRITE(Y_ENABLE_PIN,STATE)
#define Y_ENABLE_READ() bool(READ(Y_ENABLE_PIN))
#endif
#ifndef Y_DIR_INIT
#define Y_DIR_INIT() SET_OUTPUT(Y_DIR_PIN)
#define Y_DIR_WRITE(STATE) WRITE(Y_DIR_PIN,STATE)
#define Y_DIR_READ() bool(READ(Y_DIR_PIN))
#endif
#define Y_STEP_INIT() SET_OUTPUT(Y_STEP_PIN)
#ifndef Y_STEP_WRITE
#define Y_STEP_WRITE(STATE) WRITE(Y_STEP_PIN,STATE)
#endif
#define Y_STEP_READ() bool(READ(Y_STEP_PIN))
#endif
#ifndef Y_DIR_INIT
#define Y_DIR_INIT() SET_OUTPUT(Y_DIR_PIN)
#define Y_DIR_WRITE(STATE) WRITE(Y_DIR_PIN,STATE)
#define Y_DIR_READ() bool(READ(Y_DIR_PIN))
#endif
#define Y_STEP_INIT() SET_OUTPUT(Y_STEP_PIN)
#ifndef Y_STEP_WRITE
#define Y_STEP_WRITE(STATE) WRITE(Y_STEP_PIN,STATE)
#endif
#define Y_STEP_READ() bool(READ(Y_STEP_PIN))
// Z Stepper
#ifndef Z_ENABLE_INIT
#define Z_ENABLE_INIT() SET_OUTPUT(Z_ENABLE_PIN)
#define Z_ENABLE_WRITE(STATE) WRITE(Z_ENABLE_PIN,STATE)
#define Z_ENABLE_READ() bool(READ(Z_ENABLE_PIN))
#if HAS_Z_AXIS
#ifndef Z_ENABLE_INIT
#define Z_ENABLE_INIT() SET_OUTPUT(Z_ENABLE_PIN)
#define Z_ENABLE_WRITE(STATE) WRITE(Z_ENABLE_PIN,STATE)
#define Z_ENABLE_READ() bool(READ(Z_ENABLE_PIN))
#endif
#ifndef Z_DIR_INIT
#define Z_DIR_INIT() SET_OUTPUT(Z_DIR_PIN)
#define Z_DIR_WRITE(STATE) WRITE(Z_DIR_PIN,STATE)
#define Z_DIR_READ() bool(READ(Z_DIR_PIN))
#endif
#define Z_STEP_INIT() SET_OUTPUT(Z_STEP_PIN)
#ifndef Z_STEP_WRITE
#define Z_STEP_WRITE(STATE) WRITE(Z_STEP_PIN,STATE)
#endif
#define Z_STEP_READ() bool(READ(Z_STEP_PIN))
#endif
#ifndef Z_DIR_INIT
#define Z_DIR_INIT() SET_OUTPUT(Z_DIR_PIN)
#define Z_DIR_WRITE(STATE) WRITE(Z_DIR_PIN,STATE)
#define Z_DIR_READ() bool(READ(Z_DIR_PIN))
#endif
#define Z_STEP_INIT() SET_OUTPUT(Z_STEP_PIN)
#ifndef Z_STEP_WRITE
#define Z_STEP_WRITE(STATE) WRITE(Z_STEP_PIN,STATE)
#endif
#define Z_STEP_READ() bool(READ(Z_STEP_PIN))
// X2 Stepper
#if HAS_X2_ENABLE
@@ -201,6 +205,63 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset
#define Z4_DIR_WRITE(STATE) NOOP
#endif
// I Stepper
#if LINEAR_AXES >= 4
#ifndef I_ENABLE_INIT
#define I_ENABLE_INIT() SET_OUTPUT(I_ENABLE_PIN)
#define I_ENABLE_WRITE(STATE) WRITE(I_ENABLE_PIN,STATE)
#define I_ENABLE_READ() bool(READ(I_ENABLE_PIN))
#endif
#ifndef I_DIR_INIT
#define I_DIR_INIT() SET_OUTPUT(I_DIR_PIN)
#define I_DIR_WRITE(STATE) WRITE(I_DIR_PIN,STATE)
#define I_DIR_READ() bool(READ(I_DIR_PIN))
#endif
#define I_STEP_INIT() SET_OUTPUT(I_STEP_PIN)
#ifndef I_STEP_WRITE
#define I_STEP_WRITE(STATE) WRITE(I_STEP_PIN,STATE)
#endif
#define I_STEP_READ() bool(READ(I_STEP_PIN))
#endif
// J Stepper
#if LINEAR_AXES >= 5
#ifndef J_ENABLE_INIT
#define J_ENABLE_INIT() SET_OUTPUT(J_ENABLE_PIN)
#define J_ENABLE_WRITE(STATE) WRITE(J_ENABLE_PIN,STATE)
#define J_ENABLE_READ() bool(READ(J_ENABLE_PIN))
#endif
#ifndef J_DIR_INIT
#define J_DIR_INIT() SET_OUTPUT(J_DIR_PIN)
#define J_DIR_WRITE(STATE) WRITE(J_DIR_PIN,STATE)
#define J_DIR_READ() bool(READ(J_DIR_PIN))
#endif
#define J_STEP_INIT() SET_OUTPUT(J_STEP_PIN)
#ifndef J_STEP_WRITE
#define J_STEP_WRITE(STATE) WRITE(J_STEP_PIN,STATE)
#endif
#define J_STEP_READ() bool(READ(J_STEP_PIN))
#endif
// K Stepper
#if LINEAR_AXES >= 6
#ifndef K_ENABLE_INIT
#define K_ENABLE_INIT() SET_OUTPUT(K_ENABLE_PIN)
#define K_ENABLE_WRITE(STATE) WRITE(K_ENABLE_PIN,STATE)
#define K_ENABLE_READ() bool(READ(K_ENABLE_PIN))
#endif
#ifndef K_DIR_INIT
#define K_DIR_INIT() SET_OUTPUT(K_DIR_PIN)
#define K_DIR_WRITE(STATE) WRITE(K_DIR_PIN,STATE)
#define K_DIR_READ() bool(READ(K_DIR_PIN))
#endif
#define K_STEP_INIT() SET_OUTPUT(K_STEP_PIN)
#ifndef K_STEP_WRITE
#define K_STEP_WRITE(STATE) WRITE(K_STEP_PIN,STATE)
#endif
#define K_STEP_READ() bool(READ(K_STEP_PIN))
#endif
// E0 Stepper
#ifndef E0_ENABLE_INIT
#define E0_ENABLE_INIT() SET_OUTPUT(E0_ENABLE_PIN)
@@ -417,12 +478,15 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset
#define NORM_E_DIR(E) do{ E0_DIR_WRITE(E ? INVERT_E0_DIR : !INVERT_E0_DIR); }while(0)
#define REV_E_DIR(E) do{ E0_DIR_WRITE(E ? !INVERT_E0_DIR : INVERT_E0_DIR); }while(0)
#endif
#elif ENABLED(PRUSA_MMU2)
#elif HAS_PRUSA_MMU2 // One multiplexed stepper driver
#define E_STEP_WRITE(E,V) E0_STEP_WRITE(V)
#define NORM_E_DIR(E) E0_DIR_WRITE(!INVERT_E0_DIR)
#define REV_E_DIR(E) E0_DIR_WRITE( INVERT_E0_DIR)
#elif ENABLED(MK2_MULTIPLEXER) // One multiplexed stepper driver, reversed on odd index
#elif HAS_PRUSA_MMU1 // One multiplexed stepper driver, reversed on odd index
#define E_STEP_WRITE(E,V) E0_STEP_WRITE(V)
#define NORM_E_DIR(E) do{ E0_DIR_WRITE(TEST(E, 0) ? !INVERT_E0_DIR: INVERT_E0_DIR); }while(0)
#define REV_E_DIR(E) do{ E0_DIR_WRITE(TEST(E, 0) ? INVERT_E0_DIR: !INVERT_E0_DIR); }while(0)
@@ -581,6 +645,11 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset
#endif
#elif ENABLED(E_DUAL_STEPPER_DRIVERS)
#define E_STEP_WRITE(E,V) do{ E0_STEP_WRITE(V); E1_STEP_WRITE(V); }while(0)
#define NORM_E_DIR(E) do{ E0_DIR_WRITE(!INVERT_E0_DIR); E1_DIR_WRITE(!INVERT_E0_DIR ^ ENABLED(INVERT_E1_VS_E0_DIR)); }while(0)
#define REV_E_DIR(E) do{ E0_DIR_WRITE( INVERT_E0_DIR); E1_DIR_WRITE( INVERT_E0_DIR ^ ENABLED(INVERT_E1_VS_E0_DIR)); }while(0)
#elif E_STEPPERS
#define E_STEP_WRITE(E,V) E0_STEP_WRITE(V)
#define NORM_E_DIR(E) E0_DIR_WRITE(!INVERT_E0_DIR)
@@ -598,138 +667,87 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset
//
#ifndef ENABLE_STEPPER_X
#if HAS_X_ENABLE
#define ENABLE_STEPPER_X() X_ENABLE_WRITE( X_ENABLE_ON)
#else
#define ENABLE_STEPPER_X() NOOP
#endif
#define ENABLE_STEPPER_X() TERN(HAS_X_ENABLE, X_ENABLE_WRITE( X_ENABLE_ON), NOOP)
#endif
#ifndef DISABLE_STEPPER_X
#if HAS_X_ENABLE
#define DISABLE_STEPPER_X() X_ENABLE_WRITE(!X_ENABLE_ON)
#else
#define DISABLE_STEPPER_X() NOOP
#endif
#define DISABLE_STEPPER_X() TERN(HAS_X_ENABLE, X_ENABLE_WRITE(!X_ENABLE_ON), NOOP)
#endif
#ifndef ENABLE_STEPPER_X2
#if HAS_X2_ENABLE
#define ENABLE_STEPPER_X2() X2_ENABLE_WRITE( X_ENABLE_ON)
#else
#define ENABLE_STEPPER_X2() NOOP
#endif
#define ENABLE_STEPPER_X2() TERN(HAS_X2_ENABLE, X2_ENABLE_WRITE( X_ENABLE_ON), NOOP)
#endif
#ifndef DISABLE_STEPPER_X2
#if HAS_X2_ENABLE
#define DISABLE_STEPPER_X2() X2_ENABLE_WRITE(!X_ENABLE_ON)
#else
#define DISABLE_STEPPER_X2() NOOP
#endif
#define DISABLE_STEPPER_X2() TERN(HAS_X2_ENABLE, X2_ENABLE_WRITE(!X_ENABLE_ON), NOOP)
#endif
#ifndef ENABLE_STEPPER_Y
#if HAS_Y_ENABLE
#define ENABLE_STEPPER_Y() Y_ENABLE_WRITE( Y_ENABLE_ON)
#else
#define ENABLE_STEPPER_Y() NOOP
#endif
#define ENABLE_STEPPER_Y() TERN(HAS_Y_ENABLE, Y_ENABLE_WRITE( Y_ENABLE_ON), NOOP)
#endif
#ifndef DISABLE_STEPPER_Y
#if HAS_Y_ENABLE
#define DISABLE_STEPPER_Y() Y_ENABLE_WRITE(!Y_ENABLE_ON)
#else
#define DISABLE_STEPPER_Y() NOOP
#endif
#define DISABLE_STEPPER_Y() TERN(HAS_Y_ENABLE, Y_ENABLE_WRITE(!Y_ENABLE_ON), NOOP)
#endif
#ifndef ENABLE_STEPPER_Y2
#if HAS_Y2_ENABLE
#define ENABLE_STEPPER_Y2() Y2_ENABLE_WRITE( Y_ENABLE_ON)
#else
#define ENABLE_STEPPER_Y2() NOOP
#endif
#define ENABLE_STEPPER_Y2() TERN(HAS_Y2_ENABLE, Y2_ENABLE_WRITE( Y_ENABLE_ON), NOOP)
#endif
#ifndef DISABLE_STEPPER_Y2
#if HAS_Y2_ENABLE
#define DISABLE_STEPPER_Y2() Y2_ENABLE_WRITE(!Y_ENABLE_ON)
#else
#define DISABLE_STEPPER_Y2() NOOP
#endif
#define DISABLE_STEPPER_Y2() TERN(HAS_Y2_ENABLE, Y2_ENABLE_WRITE(!Y_ENABLE_ON), NOOP)
#endif
#ifndef ENABLE_STEPPER_Z
#if HAS_Z_ENABLE
#define ENABLE_STEPPER_Z() Z_ENABLE_WRITE( Z_ENABLE_ON)
#else
#define ENABLE_STEPPER_Z() NOOP
#endif
#define ENABLE_STEPPER_Z() TERN(HAS_Z_ENABLE, Z_ENABLE_WRITE( Z_ENABLE_ON), NOOP)
#endif
#ifndef DISABLE_STEPPER_Z
#if HAS_Z_ENABLE
#define DISABLE_STEPPER_Z() Z_ENABLE_WRITE(!Z_ENABLE_ON)
#else
#define DISABLE_STEPPER_Z() NOOP
#endif
#define DISABLE_STEPPER_Z() TERN(HAS_Z_ENABLE, Z_ENABLE_WRITE(!Z_ENABLE_ON), NOOP)
#endif
#ifndef ENABLE_STEPPER_Z2
#if HAS_Z2_ENABLE
#define ENABLE_STEPPER_Z2() Z2_ENABLE_WRITE( Z_ENABLE_ON)
#else
#define ENABLE_STEPPER_Z2() NOOP
#endif
#define ENABLE_STEPPER_Z2() TERN(HAS_Z2_ENABLE, Z2_ENABLE_WRITE( Z_ENABLE_ON), NOOP)
#endif
#ifndef DISABLE_STEPPER_Z2
#if HAS_Z2_ENABLE
#define DISABLE_STEPPER_Z2() Z2_ENABLE_WRITE(!Z_ENABLE_ON)
#else
#define DISABLE_STEPPER_Z2() NOOP
#endif
#define DISABLE_STEPPER_Z2() TERN(HAS_Z2_ENABLE, Z2_ENABLE_WRITE(!Z_ENABLE_ON), NOOP)
#endif
#ifndef ENABLE_STEPPER_Z3
#if HAS_Z3_ENABLE
#define ENABLE_STEPPER_Z3() Z3_ENABLE_WRITE( Z_ENABLE_ON)
#else
#define ENABLE_STEPPER_Z3() NOOP
#endif
#define ENABLE_STEPPER_Z3() TERN(HAS_Z3_ENABLE, Z3_ENABLE_WRITE( Z_ENABLE_ON), NOOP)
#endif
#ifndef DISABLE_STEPPER_Z3
#if HAS_Z3_ENABLE
#define DISABLE_STEPPER_Z3() Z3_ENABLE_WRITE(!Z_ENABLE_ON)
#else
#define DISABLE_STEPPER_Z3() NOOP
#endif
#define DISABLE_STEPPER_Z3() TERN(HAS_Z3_ENABLE, Z3_ENABLE_WRITE(!Z_ENABLE_ON), NOOP)
#endif
#ifndef ENABLE_STEPPER_Z4
#if HAS_Z4_ENABLE
#define ENABLE_STEPPER_Z4() Z4_ENABLE_WRITE( Z_ENABLE_ON)
#else
#define ENABLE_STEPPER_Z4() NOOP
#endif
#define ENABLE_STEPPER_Z4() TERN(HAS_Z4_ENABLE, Z4_ENABLE_WRITE( Z_ENABLE_ON), NOOP)
#endif
#ifndef DISABLE_STEPPER_Z4
#if HAS_Z4_ENABLE
#define DISABLE_STEPPER_Z4() Z4_ENABLE_WRITE(!Z_ENABLE_ON)
#else
#define DISABLE_STEPPER_Z4() NOOP
#endif
#define DISABLE_STEPPER_Z4() TERN(HAS_Z4_ENABLE, Z4_ENABLE_WRITE(!Z_ENABLE_ON), NOOP)
#endif
#ifndef ENABLE_STEPPER_I
#define ENABLE_STEPPER_I() TERN(HAS_I_ENABLE, I_ENABLE_WRITE( I_ENABLE_ON), NOOP)
#endif
#ifndef DISABLE_STEPPER_I
#define DISABLE_STEPPER_I() TERN(HAS_I_ENABLE, I_ENABLE_WRITE(!I_ENABLE_ON), NOOP)
#endif
#ifndef ENABLE_STEPPER_J
#define ENABLE_STEPPER_J() TERN(HAS_J_ENABLE, J_ENABLE_WRITE( J_ENABLE_ON), NOOP)
#endif
#ifndef DISABLE_STEPPER_J
#define DISABLE_STEPPER_J() TERN(HAS_J_ENABLE, J_ENABLE_WRITE(!J_ENABLE_ON), NOOP)
#endif
#ifndef ENABLE_STEPPER_K
#define ENABLE_STEPPER_K() TERN(HAS_K_ENABLE, K_ENABLE_WRITE( K_ENABLE_ON), NOOP)
#endif
#ifndef DISABLE_STEPPER_K
#define DISABLE_STEPPER_K() TERN(HAS_K_ENABLE, K_ENABLE_WRITE(!K_ENABLE_ON), NOOP)
#endif
#ifndef ENABLE_STEPPER_E0
#if HAS_E0_ENABLE
#define ENABLE_STEPPER_E0() E0_ENABLE_WRITE( E_ENABLE_ON)
#else
#define ENABLE_STEPPER_E0() NOOP
#endif
#define ENABLE_STEPPER_E0() TERN(HAS_E0_ENABLE, E0_ENABLE_WRITE( E_ENABLE_ON), NOOP)
#endif
#ifndef DISABLE_STEPPER_E0
#if HAS_E0_ENABLE
#define DISABLE_STEPPER_E0() E0_ENABLE_WRITE(!E_ENABLE_ON)
#else
#define DISABLE_STEPPER_E0() NOOP
#endif
#define DISABLE_STEPPER_E0() TERN(HAS_E0_ENABLE, E0_ENABLE_WRITE(!E_ENABLE_ON), NOOP)
#endif
#ifndef ENABLE_STEPPER_E1
@@ -840,21 +858,71 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset
//
// Axis steppers enable / disable macros
//
#if ENABLED(SOFTWARE_DRIVER_ENABLE)
// Avoid expensive calls to enable / disable steppers
extern xyz_bool_t axis_sw_enabled;
#define SHOULD_ENABLE(N) !axis_sw_enabled.N
#define SHOULD_DISABLE(N) axis_sw_enabled.N
#define AFTER_CHANGE(N,TF) axis_sw_enabled.N = TF
#else
#define SHOULD_ENABLE(N) true
#define SHOULD_DISABLE(N) true
#define AFTER_CHANGE(N,TF) NOOP
#endif
#define ENABLE_AXIS_X() do{ ENABLE_STEPPER_X(); ENABLE_STEPPER_X2(); }while(0)
#define DISABLE_AXIS_X() do{ DISABLE_STEPPER_X(); DISABLE_STEPPER_X2(); CBI(axis_known_position, X_AXIS); }while(0)
#define ENABLE_AXIS_X() if (SHOULD_ENABLE(x)) { ENABLE_STEPPER_X(); ENABLE_STEPPER_X2(); AFTER_CHANGE(x, true); }
#define DISABLE_AXIS_X() if (SHOULD_DISABLE(x)) { DISABLE_STEPPER_X(); DISABLE_STEPPER_X2(); AFTER_CHANGE(x, false); set_axis_untrusted(X_AXIS); }
#define ENABLE_AXIS_Y() do{ ENABLE_STEPPER_Y(); ENABLE_STEPPER_Y2(); }while(0)
#define DISABLE_AXIS_Y() do{ DISABLE_STEPPER_Y(); DISABLE_STEPPER_Y2(); CBI(axis_known_position, Y_AXIS); }while(0)
#if HAS_Y_AXIS
#define ENABLE_AXIS_Y() if (SHOULD_ENABLE(y)) { ENABLE_STEPPER_Y(); ENABLE_STEPPER_Y2(); AFTER_CHANGE(y, true); }
#define DISABLE_AXIS_Y() if (SHOULD_DISABLE(y)) { DISABLE_STEPPER_Y(); DISABLE_STEPPER_Y2(); AFTER_CHANGE(y, false); set_axis_untrusted(Y_AXIS); }
#else
#define ENABLE_AXIS_Y() NOOP
#define DISABLE_AXIS_Y() NOOP
#endif
#define ENABLE_AXIS_Z() do{ ENABLE_STEPPER_Z(); ENABLE_STEPPER_Z2(); ENABLE_STEPPER_Z3(); ENABLE_STEPPER_Z4(); }while(0)
#define DISABLE_AXIS_Z() do{ DISABLE_STEPPER_Z(); DISABLE_STEPPER_Z2(); DISABLE_STEPPER_Z3(); DISABLE_STEPPER_Z4(); CBI(axis_known_position, Z_AXIS); }while(0)
#if HAS_Z_AXIS
#define ENABLE_AXIS_Z() if (SHOULD_ENABLE(z)) { ENABLE_STEPPER_Z(); ENABLE_STEPPER_Z2(); ENABLE_STEPPER_Z3(); ENABLE_STEPPER_Z4(); AFTER_CHANGE(z, true); }
#define DISABLE_AXIS_Z() if (SHOULD_DISABLE(z)) { DISABLE_STEPPER_Z(); DISABLE_STEPPER_Z2(); DISABLE_STEPPER_Z3(); DISABLE_STEPPER_Z4(); AFTER_CHANGE(z, false); set_axis_untrusted(Z_AXIS); Z_RESET(); }
#else
#define ENABLE_AXIS_Z() NOOP
#define DISABLE_AXIS_Z() NOOP
#endif
#ifdef Z_IDLE_HEIGHT
#define Z_RESET() do{ current_position.z = Z_IDLE_HEIGHT; sync_plan_position(); }while(0)
#else
#define Z_RESET()
#endif
#if LINEAR_AXES >= 4
#define ENABLE_AXIS_I() if (SHOULD_ENABLE(i)) { ENABLE_STEPPER_I(); AFTER_CHANGE(i, true); }
#define DISABLE_AXIS_I() if (SHOULD_DISABLE(i)) { DISABLE_STEPPER_I(); AFTER_CHANGE(i, false); set_axis_untrusted(I_AXIS); }
#else
#define ENABLE_AXIS_I() NOOP
#define DISABLE_AXIS_I() NOOP
#endif
#if LINEAR_AXES >= 5
#define ENABLE_AXIS_J() if (SHOULD_ENABLE(j)) { ENABLE_STEPPER_J(); AFTER_CHANGE(j, true); }
#define DISABLE_AXIS_J() if (SHOULD_DISABLE(j)) { DISABLE_STEPPER_J(); AFTER_CHANGE(j, false); set_axis_untrusted(J_AXIS); }
#else
#define ENABLE_AXIS_J() NOOP
#define DISABLE_AXIS_J() NOOP
#endif
#if LINEAR_AXES >= 6
#define ENABLE_AXIS_K() if (SHOULD_ENABLE(k)) { ENABLE_STEPPER_K(); AFTER_CHANGE(k, true); }
#define DISABLE_AXIS_K() if (SHOULD_DISABLE(k)) { DISABLE_STEPPER_K(); AFTER_CHANGE(k, false); set_axis_untrusted(K_AXIS); }
#else
#define ENABLE_AXIS_K() NOOP
#define DISABLE_AXIS_K() NOOP
#endif
//
// Extruder steppers enable / disable macros
//
#if ENABLED(MIXING_EXTRUDER)
/**
* Mixing steppers keep all their enable (and direction) states synchronized
*/
@@ -862,17 +930,23 @@ void reset_stepper_drivers(); // Called by settings.load / settings.reset
#define _CALL_DIS_E(N) DISABLE_STEPPER_E##N () ;
#define ENABLE_AXIS_E0() { RREPEAT(MIXING_STEPPERS, _CALL_ENA_E) }
#define DISABLE_AXIS_E0() { RREPEAT(MIXING_STEPPERS, _CALL_DIS_E) }
#elif ENABLED(E_DUAL_STEPPER_DRIVERS)
#define ENABLE_AXIS_E0() do{ ENABLE_STEPPER_E0(); ENABLE_STEPPER_E1(); }while(0)
#define DISABLE_AXIS_E0() do{ DISABLE_STEPPER_E0(); DISABLE_STEPPER_E1(); }while(0)
#endif
#ifndef ENABLE_AXIS_E0
#if E_STEPPERS > 0 && HAS_E0_ENABLE
#if E_STEPPERS && HAS_E0_ENABLE
#define ENABLE_AXIS_E0() ENABLE_STEPPER_E0()
#else
#define ENABLE_AXIS_E0() NOOP
#endif
#endif
#ifndef DISABLE_AXIS_E0
#if E_STEPPERS > 0 && HAS_E0_ENABLE
#if E_STEPPERS && HAS_E0_ENABLE
#define DISABLE_AXIS_E0() DISABLE_STEPPER_E0()
#else
#define DISABLE_AXIS_E0() NOOP

554
Marlin/src/module/stepper/trinamic.cpp Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
@@ -35,8 +35,10 @@
#include <HardwareSerial.h>
#include <SPI.h>
enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
#define TMC_INIT(ST, STEALTH_INDEX) tmc_init(stepper##ST, ST##_CURRENT, ST##_MICROSTEPS, ST##_HYBRID_THRESHOLD, stealthchop_by_axis[STEALTH_INDEX])
enum StealthIndex : uint8_t {
LOGICAL_AXIS_LIST(STEALTH_AXIS_E, STEALTH_AXIS_X, STEALTH_AXIS_Y, STEALTH_AXIS_Z, STEALTH_AXIS_I, STEALTH_AXIS_J, STEALTH_AXIS_K)
};
#define TMC_INIT(ST, STEALTH_INDEX) tmc_init(stepper##ST, ST##_CURRENT, ST##_MICROSTEPS, ST##_HYBRID_THRESHOLD, stealthchop_by_axis[STEALTH_INDEX], chopper_timing_##ST, ST##_INTERPOLATE)
// IC = TMC model number
// ST = Stepper object letter
@@ -49,8 +51,12 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
#define __TMC_SPI_DEFINE(IC, ST, L, AI) TMCMarlin<IC##Stepper, L, AI> stepper##ST(ST##_CS_PIN, float(ST##_RSENSE), ST##_CHAIN_POS)
#endif
#define TMC_UART_HW_DEFINE(IC, ST, L, AI) TMCMarlin<IC##Stepper, L, AI> stepper##ST(&ST##_HARDWARE_SERIAL, float(ST##_RSENSE), ST##_SLAVE_ADDRESS)
#define TMC_UART_SW_DEFINE(IC, ST, L, AI) TMCMarlin<IC##Stepper, L, AI> stepper##ST(ST##_SERIAL_RX_PIN, ST##_SERIAL_TX_PIN, float(ST##_RSENSE), ST##_SLAVE_ADDRESS, ST##_SERIAL_RX_PIN > -1)
#if ENABLED(TMC_SERIAL_MULTIPLEXER)
#define TMC_UART_HW_DEFINE(IC, ST, L, AI) TMCMarlin<IC##Stepper, L, AI> stepper##ST(&ST##_HARDWARE_SERIAL, float(ST##_RSENSE), ST##_SLAVE_ADDRESS, SERIAL_MUL_PIN1, SERIAL_MUL_PIN2)
#else
#define TMC_UART_HW_DEFINE(IC, ST, L, AI) TMCMarlin<IC##Stepper, L, AI> stepper##ST(&ST##_HARDWARE_SERIAL, float(ST##_RSENSE), ST##_SLAVE_ADDRESS)
#endif
#define TMC_UART_SW_DEFINE(IC, ST, L, AI) TMCMarlin<IC##Stepper, L, AI> stepper##ST(ST##_SERIAL_RX_PIN, ST##_SERIAL_TX_PIN, float(ST##_RSENSE), ST##_SLAVE_ADDRESS)
#define _TMC_SPI_DEFINE(IC, ST, AI) __TMC_SPI_DEFINE(IC, ST, TMC_##ST##_LABEL, AI)
#define TMC_SPI_DEFINE(ST, AI) _TMC_SPI_DEFINE(ST##_DRIVER_TYPE, ST, AI##_AXIS)
@@ -58,7 +64,7 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
#define _TMC_UART_DEFINE(SWHW, IC, ST, AI) TMC_UART_##SWHW##_DEFINE(IC, ST, TMC_##ST##_LABEL, AI)
#define TMC_UART_DEFINE(SWHW, ST, AI) _TMC_UART_DEFINE(SWHW, ST##_DRIVER_TYPE, ST, AI##_AXIS)
#if ENABLED(DISTINCT_E_FACTORS) && E_STEPPERS > 1
#if ENABLED(DISTINCT_E_FACTORS)
#define TMC_SPI_DEFINE_E(AI) TMC_SPI_DEFINE(E##AI, E##AI)
#define TMC_UART_DEFINE_E(SWHW, AI) TMC_UART_DEFINE(SWHW, E##AI, E##AI)
#else
@@ -91,6 +97,15 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
#if AXIS_HAS_SPI(Z4)
TMC_SPI_DEFINE(Z4, Z);
#endif
#if AXIS_HAS_SPI(I)
TMC_SPI_DEFINE(I, I);
#endif
#if AXIS_HAS_SPI(J)
TMC_SPI_DEFINE(J, J);
#endif
#if AXIS_HAS_SPI(K)
TMC_SPI_DEFINE(K, K);
#endif
#if AXIS_HAS_SPI(E0)
TMC_SPI_DEFINE_E(0);
#endif
@@ -117,32 +132,84 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
#endif
#ifndef TMC_BAUD_RATE
#if HAS_TMC_SW_SERIAL
// Reduce baud rate for boards not already overriding TMC_BAUD_RATE for software serial.
// Testing has shown that 115200 is not 100% reliable on AVR platforms, occasionally
// failing to read status properly. 32-bit platforms typically define an even lower
// TMC_BAUD_RATE, due to differences in how SoftwareSerial libraries work on different
// platforms.
#define TMC_BAUD_RATE 57600
#else
#define TMC_BAUD_RATE 115200
#endif
// Reduce baud rate for boards not already overriding TMC_BAUD_RATE for software serial.
// Testing has shown that 115200 is not 100% reliable on AVR platforms, occasionally
// failing to read status properly. 32-bit platforms typically define an even lower
// TMC_BAUD_RATE, due to differences in how SoftwareSerial libraries work on different
// platforms.
#define TMC_BAUD_RATE TERN(HAS_TMC_SW_SERIAL, 57600, 115200)
#endif
#ifndef TMC_X_BAUD_RATE
#define TMC_X_BAUD_RATE TMC_BAUD_RATE
#endif
#ifndef TMC_X2_BAUD_RATE
#define TMC_X2_BAUD_RATE TMC_BAUD_RATE
#endif
#ifndef TMC_Y_BAUD_RATE
#define TMC_Y_BAUD_RATE TMC_BAUD_RATE
#endif
#ifndef TMC_Y2_BAUD_RATE
#define TMC_Y2_BAUD_RATE TMC_BAUD_RATE
#endif
#ifndef TMC_Z_BAUD_RATE
#define TMC_Z_BAUD_RATE TMC_BAUD_RATE
#endif
#ifndef TMC_Z2_BAUD_RATE
#define TMC_Z2_BAUD_RATE TMC_BAUD_RATE
#endif
#ifndef TMC_Z3_BAUD_RATE
#define TMC_Z3_BAUD_RATE TMC_BAUD_RATE
#endif
#ifndef TMC_Z4_BAUD_RATE
#define TMC_Z4_BAUD_RATE TMC_BAUD_RATE
#endif
#ifndef TMC_I_BAUD_RATE
#define TMC_I_BAUD_RATE TMC_BAUD_RATE
#endif
#ifndef TMC_J_BAUD_RATE
#define TMC_J_BAUD_RATE TMC_BAUD_RATE
#endif
#ifndef TMC_K_BAUD_RATE
#define TMC_K_BAUD_RATE TMC_BAUD_RATE
#endif
#ifndef TMC_E0_BAUD_RATE
#define TMC_E0_BAUD_RATE TMC_BAUD_RATE
#endif
#ifndef TMC_E1_BAUD_RATE
#define TMC_E1_BAUD_RATE TMC_BAUD_RATE
#endif
#ifndef TMC_E2_BAUD_RATE
#define TMC_E2_BAUD_RATE TMC_BAUD_RATE
#endif
#ifndef TMC_E3_BAUD_RATE
#define TMC_E3_BAUD_RATE TMC_BAUD_RATE
#endif
#ifndef TMC_E4_BAUD_RATE
#define TMC_E4_BAUD_RATE TMC_BAUD_RATE
#endif
#ifndef TMC_E5_BAUD_RATE
#define TMC_E5_BAUD_RATE TMC_BAUD_RATE
#endif
#ifndef TMC_E6_BAUD_RATE
#define TMC_E6_BAUD_RATE TMC_BAUD_RATE
#endif
#ifndef TMC_E7_BAUD_RATE
#define TMC_E7_BAUD_RATE TMC_BAUD_RATE
#endif
#if HAS_DRIVER(TMC2130)
template<char AXIS_LETTER, char DRIVER_ID, AxisEnum AXIS_ID>
void tmc_init(TMCMarlin<TMC2130Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth) {
void tmc_init(TMCMarlin<TMC2130Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, const chopper_timing_t &chop_init, const bool interpolate) {
st.begin();
CHOPCONF_t chopconf{0};
chopconf.tbl = 1;
chopconf.toff = chopper_timing.toff;
chopconf.intpol = INTERPOLATE;
chopconf.hend = chopper_timing.hend + 3;
chopconf.hstrt = chopper_timing.hstrt - 1;
#if ENABLED(SQUARE_WAVE_STEPPING)
chopconf.dedge = true;
#endif
chopconf.tbl = 0b01;
chopconf.toff = chop_init.toff;
chopconf.intpol = interpolate;
chopconf.hend = chop_init.hend + 3;
chopconf.hstrt = chop_init.hstrt - 1;
TERN_(SQUARE_WAVE_STEPPING, chopconf.dedge = true);
st.CHOPCONF(chopconf.sr);
st.rms_current(mA, HOLD_MULTIPLIER);
@@ -160,11 +227,7 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
pwmconf.pwm_ampl = 180;
st.PWMCONF(pwmconf.sr);
#if ENABLED(HYBRID_THRESHOLD)
st.set_pwm_thrs(hyb_thrs);
#else
UNUSED(hyb_thrs);
#endif
TERN(HYBRID_THRESHOLD, st.set_pwm_thrs(hyb_thrs), UNUSED(hyb_thrs));
st.GSTAT(); // Clear GSTAT
}
@@ -172,18 +235,16 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
#if HAS_DRIVER(TMC2160)
template<char AXIS_LETTER, char DRIVER_ID, AxisEnum AXIS_ID>
void tmc_init(TMCMarlin<TMC2160Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth) {
void tmc_init(TMCMarlin<TMC2160Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, const chopper_timing_t &chop_init, const bool interpolate) {
st.begin();
CHOPCONF_t chopconf{0};
chopconf.tbl = 1;
chopconf.toff = chopper_timing.toff;
chopconf.intpol = INTERPOLATE;
chopconf.hend = chopper_timing.hend + 3;
chopconf.hstrt = chopper_timing.hstrt - 1;
#if ENABLED(SQUARE_WAVE_STEPPING)
chopconf.dedge = true;
#endif
chopconf.tbl = 0b01;
chopconf.toff = chop_init.toff;
chopconf.intpol = interpolate;
chopconf.hend = chop_init.hend + 3;
chopconf.hstrt = chop_init.hstrt - 1;
TERN_(SQUARE_WAVE_STEPPING, chopconf.dedge = true);
st.CHOPCONF(chopconf.sr);
st.rms_current(mA, HOLD_MULTIPLIER);
@@ -204,11 +265,7 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
pwmconf.pwm_ofs = 36;
st.PWMCONF(pwmconf.sr);
#if ENABLED(HYBRID_THRESHOLD)
st.set_pwm_thrs(hyb_thrs);
#else
UNUSED(hyb_thrs);
#endif
TERN(HYBRID_THRESHOLD, st.set_pwm_thrs(hyb_thrs), UNUSED(hyb_thrs));
st.GSTAT(); // Clear GSTAT
}
@@ -221,225 +278,323 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
#if AXIS_HAS_UART(X)
#ifdef X_HARDWARE_SERIAL
TMC_UART_DEFINE(HW, X, X);
#define X_HAS_HW_SERIAL 1
#else
TMC_UART_DEFINE(SW, X, X);
#define X_HAS_SW_SERIAL 1
#endif
#endif
#if AXIS_HAS_UART(X2)
#ifdef X2_HARDWARE_SERIAL
TMC_UART_DEFINE(HW, X2, X);
#define X2_HAS_HW_SERIAL 1
#else
TMC_UART_DEFINE(SW, X2, X);
#define X2_HAS_SW_SERIAL 1
#endif
#endif
#if AXIS_HAS_UART(Y)
#ifdef Y_HARDWARE_SERIAL
TMC_UART_DEFINE(HW, Y, Y);
#define Y_HAS_HW_SERIAL 1
#else
TMC_UART_DEFINE(SW, Y, Y);
#define Y_HAS_SW_SERIAL 1
#endif
#endif
#if AXIS_HAS_UART(Y2)
#ifdef Y2_HARDWARE_SERIAL
TMC_UART_DEFINE(HW, Y2, Y);
#define Y2_HAS_HW_SERIAL 1
#else
TMC_UART_DEFINE(SW, Y2, Y);
#define Y2_HAS_SW_SERIAL 1
#endif
#endif
#if AXIS_HAS_UART(Z)
#ifdef Z_HARDWARE_SERIAL
TMC_UART_DEFINE(HW, Z, Z);
#define Z_HAS_HW_SERIAL 1
#else
TMC_UART_DEFINE(SW, Z, Z);
#define Z_HAS_SW_SERIAL 1
#endif
#endif
#if AXIS_HAS_UART(Z2)
#ifdef Z2_HARDWARE_SERIAL
TMC_UART_DEFINE(HW, Z2, Z);
#define Z2_HAS_HW_SERIAL 1
#else
TMC_UART_DEFINE(SW, Z2, Z);
#define Z2_HAS_SW_SERIAL 1
#endif
#endif
#if AXIS_HAS_UART(Z3)
#ifdef Z3_HARDWARE_SERIAL
TMC_UART_DEFINE(HW, Z3, Z);
#define Z3_HAS_HW_SERIAL 1
#else
TMC_UART_DEFINE(SW, Z3, Z);
#define Z3_HAS_SW_SERIAL 1
#endif
#endif
#if AXIS_HAS_UART(Z4)
#ifdef Z4_HARDWARE_SERIAL
TMC_UART_DEFINE(HW, Z4, Z);
#define Z4_HAS_HW_SERIAL 1
#else
TMC_UART_DEFINE(SW, Z4, Z);
#define Z4_HAS_SW_SERIAL 1
#endif
#endif
#if AXIS_HAS_UART(I)
#ifdef I_HARDWARE_SERIAL
TMC_UART_DEFINE(HW, I, I);
#define I_HAS_HW_SERIAL 1
#else
TMC_UART_DEFINE(SW, I, I);
#define I_HAS_SW_SERIAL 1
#endif
#endif
#if AXIS_HAS_UART(J)
#ifdef J_HARDWARE_SERIAL
TMC_UART_DEFINE(HW, J, J);
#define J_HAS_HW_SERIAL 1
#else
TMC_UART_DEFINE(SW, J, J);
#define J_HAS_SW_SERIAL 1
#endif
#endif
#if AXIS_HAS_UART(K)
#ifdef K_HARDWARE_SERIAL
TMC_UART_DEFINE(HW, K, K);
#define K_HAS_HW_SERIAL 1
#else
TMC_UART_DEFINE(SW, K, K);
#define K_HAS_SW_SERIAL 1
#endif
#endif
#if AXIS_HAS_UART(E0)
#ifdef E0_HARDWARE_SERIAL
TMC_UART_DEFINE_E(HW, 0);
#define E0_HAS_HW_SERIAL 1
#else
TMC_UART_DEFINE_E(SW, 0);
#define E0_HAS_SW_SERIAL 1
#endif
#endif
#if AXIS_HAS_UART(E1)
#ifdef E1_HARDWARE_SERIAL
TMC_UART_DEFINE_E(HW, 1);
#define E1_HAS_HW_SERIAL 1
#else
TMC_UART_DEFINE_E(SW, 1);
#define E1_HAS_SW_SERIAL 1
#endif
#endif
#if AXIS_HAS_UART(E2)
#ifdef E2_HARDWARE_SERIAL
TMC_UART_DEFINE_E(HW, 2);
#define E2_HAS_HW_SERIAL 1
#else
TMC_UART_DEFINE_E(SW, 2);
#define E2_HAS_SW_SERIAL 1
#endif
#endif
#if AXIS_HAS_UART(E3)
#ifdef E3_HARDWARE_SERIAL
TMC_UART_DEFINE_E(HW, 3);
#define E3_HAS_HW_SERIAL 1
#else
TMC_UART_DEFINE_E(SW, 3);
#define E3_HAS_SW_SERIAL 1
#endif
#endif
#if AXIS_HAS_UART(E4)
#ifdef E4_HARDWARE_SERIAL
TMC_UART_DEFINE_E(HW, 4);
#define E4_HAS_HW_SERIAL 1
#else
TMC_UART_DEFINE_E(SW, 4);
#define E4_HAS_SW_SERIAL 1
#endif
#endif
#if AXIS_HAS_UART(E5)
#ifdef E5_HARDWARE_SERIAL
TMC_UART_DEFINE_E(HW, 5);
#define E5_HAS_HW_SERIAL 1
#else
TMC_UART_DEFINE_E(SW, 5);
#define E5_HAS_SW_SERIAL 1
#endif
#endif
#if AXIS_HAS_UART(E6)
#ifdef E6_HARDWARE_SERIAL
TMC_UART_DEFINE_E(HW, 6);
#define E6_HAS_HW_SERIAL 1
#else
TMC_UART_DEFINE_E(SW, 6);
#define E6_HAS_SW_SERIAL 1
#endif
#endif
#if AXIS_HAS_UART(E7)
#ifdef E7_HARDWARE_SERIAL
TMC_UART_DEFINE_E(HW, 7);
#define E7_HAS_HW_SERIAL 1
#else
TMC_UART_DEFINE_E(SW, 7);
#define E7_HAS_SW_SERIAL 1
#endif
#endif
#define _EN_ITEM(N) , E##N
enum TMCAxis : uint8_t { LINEAR_AXIS_LIST(X, Y, Z, I, J, K), X2, Y2, Z2, Z3, Z4 REPEAT(EXTRUDERS, _EN_ITEM), TOTAL };
#undef _EN_ITEM
void tmc_serial_begin() {
#if HAS_TMC_HW_SERIAL
struct {
const void *ptr[TMCAxis::TOTAL];
bool began(const TMCAxis a, const void * const p) {
LOOP_L_N(i, a) if (p == ptr[i]) return true;
ptr[a] = p; return false;
};
} sp_helper;
#define HW_SERIAL_BEGIN(A) do{ if (!sp_helper.began(TMCAxis::A, &A##_HARDWARE_SERIAL)) \
A##_HARDWARE_SERIAL.begin(TMC_##A##_BAUD_RATE); }while(0)
#endif
#if AXIS_HAS_UART(X)
#ifdef X_HARDWARE_SERIAL
X_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
HW_SERIAL_BEGIN(X);
#else
stepperX.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(X2)
#ifdef X2_HARDWARE_SERIAL
X2_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
HW_SERIAL_BEGIN(X2);
#else
stepperX2.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(Y)
#ifdef Y_HARDWARE_SERIAL
Y_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
HW_SERIAL_BEGIN(Y);
#else
stepperY.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(Y2)
#ifdef Y2_HARDWARE_SERIAL
Y2_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
HW_SERIAL_BEGIN(Y2);
#else
stepperY2.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(Z)
#ifdef Z_HARDWARE_SERIAL
Z_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
HW_SERIAL_BEGIN(Z);
#else
stepperZ.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(Z2)
#ifdef Z2_HARDWARE_SERIAL
Z2_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
HW_SERIAL_BEGIN(Z2);
#else
stepperZ2.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(Z3)
#ifdef Z3_HARDWARE_SERIAL
Z3_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
HW_SERIAL_BEGIN(Z3);
#else
stepperZ3.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(Z4)
#ifdef Z4_HARDWARE_SERIAL
Z4_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
HW_SERIAL_BEGIN(Z4);
#else
stepperZ4.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(I)
#ifdef I_HARDWARE_SERIAL
HW_SERIAL_BEGIN(I);
#else
stepperI.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(J)
#ifdef J_HARDWARE_SERIAL
HW_SERIAL_BEGIN(J);
#else
stepperJ.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(K)
#ifdef K_HARDWARE_SERIAL
HW_SERIAL_BEGIN(K);
#else
stepperK.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(E0)
#ifdef E0_HARDWARE_SERIAL
E0_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
HW_SERIAL_BEGIN(E0);
#else
stepperE0.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(E1)
#ifdef E1_HARDWARE_SERIAL
E1_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
HW_SERIAL_BEGIN(E1);
#else
stepperE1.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(E2)
#ifdef E2_HARDWARE_SERIAL
E2_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
HW_SERIAL_BEGIN(E2);
#else
stepperE2.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(E3)
#ifdef E3_HARDWARE_SERIAL
E3_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
HW_SERIAL_BEGIN(E3);
#else
stepperE3.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(E4)
#ifdef E4_HARDWARE_SERIAL
E4_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
HW_SERIAL_BEGIN(E4);
#else
stepperE4.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(E5)
#ifdef E5_HARDWARE_SERIAL
E5_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
HW_SERIAL_BEGIN(E5);
#else
stepperE5.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(E6)
#ifdef E6_HARDWARE_SERIAL
E6_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
HW_SERIAL_BEGIN(E6);
#else
stepperE6.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(E7)
#ifdef E7_HARDWARE_SERIAL
E7_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
HW_SERIAL_BEGIN(E7);
#else
stepperE7.beginSerial(TMC_BAUD_RATE);
#endif
@@ -449,7 +604,7 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
#if HAS_DRIVER(TMC2208)
template<char AXIS_LETTER, char DRIVER_ID, AxisEnum AXIS_ID>
void tmc_init(TMCMarlin<TMC2208Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth) {
void tmc_init(TMCMarlin<TMC2208Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, const chopper_timing_t &chop_init, const bool interpolate) {
TMC2208_n::GCONF_t gconf{0};
gconf.pdn_disable = true; // Use UART
gconf.mstep_reg_select = true; // Select microsteps with UART
@@ -460,13 +615,11 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
TMC2208_n::CHOPCONF_t chopconf{0};
chopconf.tbl = 0b01; // blank_time = 24
chopconf.toff = chopper_timing.toff;
chopconf.intpol = INTERPOLATE;
chopconf.hend = chopper_timing.hend + 3;
chopconf.hstrt = chopper_timing.hstrt - 1;
#if ENABLED(SQUARE_WAVE_STEPPING)
chopconf.dedge = true;
#endif
chopconf.toff = chop_init.toff;
chopconf.intpol = interpolate;
chopconf.hend = chop_init.hend + 3;
chopconf.hstrt = chop_init.hstrt - 1;
TERN_(SQUARE_WAVE_STEPPING, chopconf.dedge = true);
st.CHOPCONF(chopconf.sr);
st.rms_current(mA, HOLD_MULTIPLIER);
@@ -484,11 +637,7 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
pwmconf.pwm_ofs = 36;
st.PWMCONF(pwmconf.sr);
#if ENABLED(HYBRID_THRESHOLD)
st.set_pwm_thrs(hyb_thrs);
#else
UNUSED(hyb_thrs);
#endif
TERN(HYBRID_THRESHOLD, st.set_pwm_thrs(hyb_thrs), UNUSED(hyb_thrs));
st.GSTAT(0b111); // Clear
delay(200);
@@ -497,7 +646,7 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
#if HAS_DRIVER(TMC2209)
template<char AXIS_LETTER, char DRIVER_ID, AxisEnum AXIS_ID>
void tmc_init(TMCMarlin<TMC2209Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth) {
void tmc_init(TMCMarlin<TMC2209Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, const chopper_timing_t &chop_init, const bool interpolate) {
TMC2208_n::GCONF_t gconf{0};
gconf.pdn_disable = true; // Use UART
gconf.mstep_reg_select = true; // Select microsteps with UART
@@ -508,13 +657,11 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
TMC2208_n::CHOPCONF_t chopconf{0};
chopconf.tbl = 0b01; // blank_time = 24
chopconf.toff = chopper_timing.toff;
chopconf.intpol = INTERPOLATE;
chopconf.hend = chopper_timing.hend + 3;
chopconf.hstrt = chopper_timing.hstrt - 1;
#if ENABLED(SQUARE_WAVE_STEPPING)
chopconf.dedge = true;
#endif
chopconf.toff = chop_init.toff;
chopconf.intpol = interpolate;
chopconf.hend = chop_init.hend + 3;
chopconf.hstrt = chop_init.hstrt - 1;
TERN_(SQUARE_WAVE_STEPPING, chopconf.dedge = true);
st.CHOPCONF(chopconf.sr);
st.rms_current(mA, HOLD_MULTIPLIER);
@@ -532,11 +679,7 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
pwmconf.pwm_ofs = 36;
st.PWMCONF(pwmconf.sr);
#if ENABLED(HYBRID_THRESHOLD)
st.set_pwm_thrs(hyb_thrs);
#else
UNUSED(hyb_thrs);
#endif
TERN(HYBRID_THRESHOLD, st.set_pwm_thrs(hyb_thrs), UNUSED(hyb_thrs));
st.GSTAT(0b111); // Clear
delay(200);
@@ -545,45 +688,38 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
#if HAS_DRIVER(TMC2660)
template<char AXIS_LETTER, char DRIVER_ID, AxisEnum AXIS_ID>
void tmc_init(TMCMarlin<TMC2660Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t, const bool) {
void tmc_init(TMCMarlin<TMC2660Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t, const bool, const chopper_timing_t &chop_init, const bool interpolate) {
st.begin();
TMC2660_n::CHOPCONF_t chopconf{0};
chopconf.tbl = 1;
chopconf.toff = chopper_timing.toff;
chopconf.hend = chopper_timing.hend + 3;
chopconf.hstrt = chopper_timing.hstrt - 1;
chopconf.tbl = 0b01;
chopconf.toff = chop_init.toff;
chopconf.hend = chop_init.hend + 3;
chopconf.hstrt = chop_init.hstrt - 1;
st.CHOPCONF(chopconf.sr);
st.sdoff(0);
st.rms_current(mA);
st.microsteps(microsteps);
#if ENABLED(SQUARE_WAVE_STEPPING)
st.dedge(true);
#endif
st.intpol(INTERPOLATE);
TERN_(SQUARE_WAVE_STEPPING, st.dedge(true));
st.intpol(interpolate);
st.diss2g(true); // Disable short to ground protection. Too many false readings?
#if ENABLED(TMC_DEBUG)
st.rdsel(0b01);
#endif
TERN_(TMC_DEBUG, st.rdsel(0b01));
}
#endif // TMC2660
#if HAS_DRIVER(TMC5130)
template<char AXIS_LETTER, char DRIVER_ID, AxisEnum AXIS_ID>
void tmc_init(TMCMarlin<TMC5130Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth) {
void tmc_init(TMCMarlin<TMC5130Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, const chopper_timing_t &chop_init, const bool interpolate) {
st.begin();
CHOPCONF_t chopconf{0};
chopconf.tbl = 1;
chopconf.toff = chopper_timing.toff;
chopconf.intpol = INTERPOLATE;
chopconf.hend = chopper_timing.hend + 3;
chopconf.hstrt = chopper_timing.hstrt - 1;
#if ENABLED(SQUARE_WAVE_STEPPING)
chopconf.dedge = true;
#endif
chopconf.tbl = 0b01;
chopconf.toff = chop_init.toff;
chopconf.intpol = interpolate;
chopconf.hend = chop_init.hend + 3;
chopconf.hstrt = chop_init.hstrt - 1;
TERN_(SQUARE_WAVE_STEPPING, chopconf.dedge = true);
st.CHOPCONF(chopconf.sr);
st.rms_current(mA, HOLD_MULTIPLIER);
@@ -601,11 +737,7 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
pwmconf.pwm_ampl = 180;
st.PWMCONF(pwmconf.sr);
#if ENABLED(HYBRID_THRESHOLD)
st.set_pwm_thrs(hyb_thrs);
#else
UNUSED(hyb_thrs);
#endif
TERN(HYBRID_THRESHOLD, st.set_pwm_thrs(hyb_thrs), UNUSED(hyb_thrs));
st.GSTAT(); // Clear GSTAT
}
@@ -613,18 +745,16 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
#if HAS_DRIVER(TMC5160)
template<char AXIS_LETTER, char DRIVER_ID, AxisEnum AXIS_ID>
void tmc_init(TMCMarlin<TMC5160Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth) {
void tmc_init(TMCMarlin<TMC5160Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t hyb_thrs, const bool stealth, const chopper_timing_t &chop_init, const bool interpolate) {
st.begin();
CHOPCONF_t chopconf{0};
chopconf.tbl = 1;
chopconf.toff = chopper_timing.toff;
chopconf.intpol = INTERPOLATE;
chopconf.hend = chopper_timing.hend + 3;
chopconf.hstrt = chopper_timing.hstrt - 1;
#if ENABLED(SQUARE_WAVE_STEPPING)
chopconf.dedge = true;
#endif
chopconf.tbl = 0b01;
chopconf.toff = chop_init.toff;
chopconf.intpol = interpolate;
chopconf.hend = chop_init.hend + 3;
chopconf.hstrt = chop_init.hstrt - 1;
TERN_(SQUARE_WAVE_STEPPING, chopconf.dedge = true);
st.CHOPCONF(chopconf.sr);
st.rms_current(mA, HOLD_MULTIPLIER);
@@ -645,11 +775,7 @@ enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };
pwmconf.pwm_ofs = 36;
st.PWMCONF(pwmconf.sr);
#if ENABLED(HYBRID_THRESHOLD)
st.set_pwm_thrs(hyb_thrs);
#else
UNUSED(hyb_thrs);
#endif
TERN(HYBRID_THRESHOLD, st.set_pwm_thrs(hyb_thrs), UNUSED(hyb_thrs));
st.GSTAT(); // Clear GSTAT
}
#endif // TMC5160
@@ -679,6 +805,15 @@ void restore_trinamic_drivers() {
#if AXIS_IS_TMC(Z4)
stepperZ4.push();
#endif
#if AXIS_IS_TMC(I)
stepperI.push();
#endif
#if AXIS_IS_TMC(J)
stepperJ.push();
#endif
#if AXIS_IS_TMC(K)
stepperK.push();
#endif
#if AXIS_IS_TMC(E0)
stepperE0.push();
#endif
@@ -706,37 +841,23 @@ void restore_trinamic_drivers() {
}
void reset_trinamic_drivers() {
static constexpr bool stealthchop_by_axis[] = {
#if ENABLED(STEALTHCHOP_XY)
true
#else
false
#endif
,
#if ENABLED(STEALTHCHOP_Z)
true
#else
false
#endif
,
#if ENABLED(STEALTHCHOP_E)
true
#else
false
#endif
};
static constexpr bool stealthchop_by_axis[] = LOGICAL_AXIS_ARRAY(
ENABLED(STEALTHCHOP_E),
ENABLED(STEALTHCHOP_XY), ENABLED(STEALTHCHOP_XY), ENABLED(STEALTHCHOP_Z),
ENABLED(STEALTHCHOP_I), ENABLED(STEALTHCHOP_J), ENABLED(STEALTHCHOP_K)
);
#if AXIS_IS_TMC(X)
TMC_INIT(X, STEALTH_AXIS_XY);
TMC_INIT(X, STEALTH_AXIS_X);
#endif
#if AXIS_IS_TMC(X2)
TMC_INIT(X2, STEALTH_AXIS_XY);
TMC_INIT(X2, STEALTH_AXIS_X);
#endif
#if AXIS_IS_TMC(Y)
TMC_INIT(Y, STEALTH_AXIS_XY);
TMC_INIT(Y, STEALTH_AXIS_Y);
#endif
#if AXIS_IS_TMC(Y2)
TMC_INIT(Y2, STEALTH_AXIS_XY);
TMC_INIT(Y2, STEALTH_AXIS_Y);
#endif
#if AXIS_IS_TMC(Z)
TMC_INIT(Z, STEALTH_AXIS_Z);
@@ -750,6 +871,15 @@ void reset_trinamic_drivers() {
#if AXIS_IS_TMC(Z4)
TMC_INIT(Z4, STEALTH_AXIS_Z);
#endif
#if AXIS_IS_TMC(I)
TMC_INIT(I, STEALTH_AXIS_I);
#endif
#if AXIS_IS_TMC(J)
TMC_INIT(J, STEALTH_AXIS_J);
#endif
#if AXIS_IS_TMC(K)
TMC_INIT(K, STEALTH_AXIS_K);
#endif
#if AXIS_IS_TMC(E0)
TMC_INIT(E0, STEALTH_AXIS_E);
#endif
@@ -777,39 +907,48 @@ void reset_trinamic_drivers() {
#if USE_SENSORLESS
#if X_SENSORLESS
#if AXIS_HAS_STALLGUARD(X)
stepperX.homing_threshold(X_STALL_SENSITIVITY);
stepperX.homing_threshold(X_STALL_SENSITIVITY);
#if AXIS_HAS_STALLGUARD(X2)
stepperX2.homing_threshold(CAT(TERN(X2_SENSORLESS, X2, X), _STALL_SENSITIVITY));
#endif
#if AXIS_HAS_STALLGUARD(X2) && !X2_SENSORLESS
stepperX2.homing_threshold(X_STALL_SENSITIVITY);
#endif
#endif
#if X2_SENSORLESS
stepperX2.homing_threshold(X2_STALL_SENSITIVITY);
#endif
#if Y_SENSORLESS
#if AXIS_HAS_STALLGUARD(Y)
stepperY.homing_threshold(Y_STALL_SENSITIVITY);
#endif
stepperY.homing_threshold(Y_STALL_SENSITIVITY);
#if AXIS_HAS_STALLGUARD(Y2)
stepperY2.homing_threshold(Y_STALL_SENSITIVITY);
stepperY2.homing_threshold(CAT(TERN(Y2_SENSORLESS, Y2, Y), _STALL_SENSITIVITY));
#endif
#endif
#if Z_SENSORLESS
#if AXIS_HAS_STALLGUARD(Z)
stepperZ.homing_threshold(Z_STALL_SENSITIVITY);
#endif
stepperZ.homing_threshold(Z_STALL_SENSITIVITY);
#if AXIS_HAS_STALLGUARD(Z2)
stepperZ2.homing_threshold(Z_STALL_SENSITIVITY);
stepperZ2.homing_threshold(CAT(TERN(Z2_SENSORLESS, Z2, Z), _STALL_SENSITIVITY));
#endif
#if AXIS_HAS_STALLGUARD(Z3)
stepperZ3.homing_threshold(Z_STALL_SENSITIVITY);
stepperZ3.homing_threshold(CAT(TERN(Z3_SENSORLESS, Z3, Z), _STALL_SENSITIVITY));
#endif
#if AXIS_HAS_STALLGUARD(Z4)
stepperZ4.homing_threshold(Z_STALL_SENSITIVITY);
stepperZ4.homing_threshold(CAT(TERN(Z4_SENSORLESS, Z4, Z), _STALL_SENSITIVITY));
#endif
#endif
#endif
#if I_SENSORLESS
stepperI.homing_threshold(I_STALL_SENSITIVITY);
#if AXIS_HAS_STALLGUARD(I)
stepperI.homing_threshold(CAT(TERN(I_SENSORLESS, I, I), _STALL_SENSITIVITY));
#endif
#endif
#if J_SENSORLESS
stepperJ.homing_threshold(J_STALL_SENSITIVITY);
#if AXIS_HAS_STALLGUARD(J)
stepperJ.homing_threshold(CAT(TERN(J_SENSORLESS, J, J), _STALL_SENSITIVITY));
#endif
#endif
#if K_SENSORLESS
stepperK.homing_threshold(K_STALL_SENSITIVITY);
#if AXIS_HAS_STALLGUARD(K)
stepperK.homing_threshold(CAT(TERN(K_SENSORLESS, K, K), _STALL_SENSITIVITY));
#endif
#endif
#endif // USE SENSORLESS
#ifdef TMC_ADV
TMC_ADV()
@@ -818,4 +957,81 @@ void reset_trinamic_drivers() {
stepper.set_directions();
}
// TMC Slave Address Conflict Detection
//
// Conflict detection is performed in the following way. Similar methods are used for
// hardware and software serial, but the implementations are independent.
//
// 1. Populate a data structure with UART parameters and addresses for all possible axis.
// If an axis is not in use, populate it with recognizable placeholder data.
// 2. For each axis in use, static_assert using a constexpr function, which counts the
// number of matching/conflicting axis. If the value is not exactly 1, fail.
#if ANY_AXIS_HAS(HW_SERIAL)
// Hardware serial names are compared as strings, since actually resolving them cannot occur in a constexpr.
// Using a fixed-length character array for the port name allows this to be constexpr compatible.
struct SanityHwSerialDetails { const char port[20]; uint32_t address; };
#define TMC_HW_DETAIL_ARGS(A) TERN(A##_HAS_HW_SERIAL, STRINGIFY(A##_HARDWARE_SERIAL), ""), TERN0(A##_HAS_HW_SERIAL, A##_SLAVE_ADDRESS)
#define TMC_HW_DETAIL(A) { TMC_HW_DETAIL_ARGS(A) }
constexpr SanityHwSerialDetails sanity_tmc_hw_details[] = {
TMC_HW_DETAIL(X), TMC_HW_DETAIL(X2),
TMC_HW_DETAIL(Y), TMC_HW_DETAIL(Y2),
TMC_HW_DETAIL(Z), TMC_HW_DETAIL(Z2), TMC_HW_DETAIL(Z3), TMC_HW_DETAIL(Z4),
TMC_HW_DETAIL(I), TMC_HW_DETAIL(J), TMC_HW_DETAIL(K),
TMC_HW_DETAIL(E0), TMC_HW_DETAIL(E1), TMC_HW_DETAIL(E2), TMC_HW_DETAIL(E3), TMC_HW_DETAIL(E4), TMC_HW_DETAIL(E5), TMC_HW_DETAIL(E6), TMC_HW_DETAIL(E7)
};
// constexpr compatible string comparison
constexpr bool str_eq_ce(const char * a, const char * b) {
return *a == *b && (*a == '\0' || str_eq_ce(a+1,b+1));
}
constexpr bool sc_hw_done(size_t start, size_t end) { return start == end; }
constexpr bool sc_hw_skip(const char *port_name) { return !(*port_name); }
constexpr bool sc_hw_match(const char *port_name, uint32_t address, size_t start, size_t end) {
return !sc_hw_done(start, end) && !sc_hw_skip(port_name) && (address == sanity_tmc_hw_details[start].address && str_eq_ce(port_name, sanity_tmc_hw_details[start].port));
}
constexpr int count_tmc_hw_serial_matches(const char *port_name, uint32_t address, size_t start, size_t end) {
return sc_hw_done(start, end) ? 0 : ((sc_hw_skip(port_name) ? 0 : (sc_hw_match(port_name, address, start, end) ? 1 : 0)) + count_tmc_hw_serial_matches(port_name, address, start + 1, end));
}
#define TMC_HWSERIAL_CONFLICT_MSG(A) STRINGIFY(A) "_SLAVE_ADDRESS conflicts with another driver using the same " STRINGIFY(A) "_HARDWARE_SERIAL"
#define SA_NO_TMC_HW_C(A) static_assert(1 >= count_tmc_hw_serial_matches(TMC_HW_DETAIL_ARGS(A), 0, COUNT(sanity_tmc_hw_details)), TMC_HWSERIAL_CONFLICT_MSG(A));
SA_NO_TMC_HW_C(X); SA_NO_TMC_HW_C(X2);
SA_NO_TMC_HW_C(Y); SA_NO_TMC_HW_C(Y2);
SA_NO_TMC_HW_C(Z); SA_NO_TMC_HW_C(Z2); SA_NO_TMC_HW_C(Z3); SA_NO_TMC_HW_C(Z4);
SA_NO_TMC_HW_C(I); SA_NO_TMC_HW_C(J); SA_NO_TMC_HW_C(K);
SA_NO_TMC_HW_C(E0); SA_NO_TMC_HW_C(E1); SA_NO_TMC_HW_C(E2); SA_NO_TMC_HW_C(E3); SA_NO_TMC_HW_C(E4); SA_NO_TMC_HW_C(E5); SA_NO_TMC_HW_C(E6); SA_NO_TMC_HW_C(E7);
#endif
#if ANY_AXIS_HAS(SW_SERIAL)
struct SanitySwSerialDetails { int32_t txpin; int32_t rxpin; uint32_t address; };
#define TMC_SW_DETAIL_ARGS(A) TERN(A##_HAS_SW_SERIAL, A##_SERIAL_TX_PIN, -1), TERN(A##_HAS_SW_SERIAL, A##_SERIAL_RX_PIN, -1), TERN0(A##_HAS_SW_SERIAL, A##_SLAVE_ADDRESS)
#define TMC_SW_DETAIL(A) TMC_SW_DETAIL_ARGS(A)
constexpr SanitySwSerialDetails sanity_tmc_sw_details[] = {
TMC_SW_DETAIL(X), TMC_SW_DETAIL(X2),
TMC_SW_DETAIL(Y), TMC_SW_DETAIL(Y2),
TMC_SW_DETAIL(Z), TMC_SW_DETAIL(Z2), TMC_SW_DETAIL(Z3), TMC_SW_DETAIL(Z4),
TMC_SW_DETAIL(I), TMC_SW_DETAIL(J), TMC_SW_DETAIL(K),
TMC_SW_DETAIL(E0), TMC_SW_DETAIL(E1), TMC_SW_DETAIL(E2), TMC_SW_DETAIL(E3), TMC_SW_DETAIL(E4), TMC_SW_DETAIL(E5), TMC_SW_DETAIL(E6), TMC_SW_DETAIL(E7)
};
constexpr bool sc_sw_done(size_t start, size_t end) { return start == end; }
constexpr bool sc_sw_skip(int32_t txpin) { return txpin < 0; }
constexpr bool sc_sw_match(int32_t txpin, int32_t rxpin, uint32_t address, size_t start, size_t end) {
return !sc_sw_done(start, end) && !sc_sw_skip(txpin) && (txpin == sanity_tmc_sw_details[start].txpin || rxpin == sanity_tmc_sw_details[start].rxpin) && (address == sanity_tmc_sw_details[start].address);
}
constexpr int count_tmc_sw_serial_matches(int32_t txpin, int32_t rxpin, uint32_t address, size_t start, size_t end) {
return sc_sw_done(start, end) ? 0 : ((sc_sw_skip(txpin) ? 0 : (sc_sw_match(txpin, rxpin, address, start, end) ? 1 : 0)) + count_tmc_sw_serial_matches(txpin, rxpin, address, start + 1, end));
}
#define TMC_SWSERIAL_CONFLICT_MSG(A) STRINGIFY(A) "_SLAVE_ADDRESS conflicts with another driver using the same " STRINGIFY(A) "_SERIAL_RX_PIN or " STRINGIFY(A) "_SERIAL_TX_PIN"
#define SA_NO_TMC_SW_C(A) static_assert(1 >= count_tmc_sw_serial_matches(TMC_SW_DETAIL_ARGS(A), 0, COUNT(sanity_tmc_sw_details)), TMC_SWSERIAL_CONFLICT_MSG(A));
SA_NO_TMC_SW_C(X); SA_NO_TMC_SW_C(X2);
SA_NO_TMC_SW_C(Y); SA_NO_TMC_SW_C(Y2);
SA_NO_TMC_SW_C(Z); SA_NO_TMC_SW_C(Z2); SA_NO_TMC_SW_C(Z3); SA_NO_TMC_SW_C(Z4);
SA_NO_TMC_SW_C(I); SA_NO_TMC_SW_C(J); SA_NO_TMC_SW_C(K);
SA_NO_TMC_SW_C(E0); SA_NO_TMC_SW_C(E1); SA_NO_TMC_SW_C(E2); SA_NO_TMC_SW_C(E3); SA_NO_TMC_SW_C(E4); SA_NO_TMC_SW_C(E5); SA_NO_TMC_SW_C(E6); SA_NO_TMC_SW_C(E7);
#endif
#endif // HAS_TRINAMIC_CONFIG

205
Marlin/src/module/stepper/trinamic.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -46,6 +46,10 @@
#define TMC_Y_LABEL 'Y', '0'
#define TMC_Z_LABEL 'Z', '0'
#define TMC_I_LABEL 'I', '0'
#define TMC_J_LABEL 'J', '0'
#define TMC_K_LABEL 'K', '0'
#define TMC_X2_LABEL 'X', '2'
#define TMC_Y2_LABEL 'Y', '2'
#define TMC_Z2_LABEL 'Z', '2'
@@ -76,7 +80,27 @@ typedef struct {
uint8_t hstrt;
} chopper_timing_t;
static constexpr chopper_timing_t chopper_timing = CHOPPER_TIMING;
#ifndef CHOPPER_TIMING_X
#define CHOPPER_TIMING_X CHOPPER_TIMING
#endif
#if HAS_Y_AXIS && !defined(CHOPPER_TIMING_Y)
#define CHOPPER_TIMING_Y CHOPPER_TIMING
#endif
#if HAS_Z_AXIS && !defined(CHOPPER_TIMING_Z)
#define CHOPPER_TIMING_Z CHOPPER_TIMING
#endif
#if LINEAR_AXES >= 4 && !defined(CHOPPER_TIMING_I)
#define CHOPPER_TIMING_I CHOPPER_TIMING
#endif
#if LINEAR_AXES >= 5 && !defined(CHOPPER_TIMING_J)
#define CHOPPER_TIMING_J CHOPPER_TIMING
#endif
#if LINEAR_AXES >= 6 && !defined(CHOPPER_TIMING_K)
#define CHOPPER_TIMING_K CHOPPER_TIMING
#endif
#if HAS_EXTRUDERS && !defined(CHOPPER_TIMING_E)
#define CHOPPER_TIMING_E CHOPPER_TIMING
#endif
#if HAS_TMC220x
void tmc_serial_begin();
@@ -90,22 +114,24 @@ void reset_trinamic_drivers();
// X Stepper
#if AXIS_IS_TMC(X)
extern TMC_CLASS(X, X) stepperX;
static constexpr chopper_timing_t chopper_timing_X = CHOPPER_TIMING_X;
#if ENABLED(SOFTWARE_DRIVER_ENABLE)
#define X_ENABLE_INIT() NOOP
#define X_ENABLE_WRITE(STATE) stepperX.toff((STATE)==X_ENABLE_ON ? chopper_timing.toff : 0)
#define X_ENABLE_WRITE(STATE) stepperX.toff((STATE)==X_ENABLE_ON ? chopper_timing_X.toff : 0)
#define X_ENABLE_READ() stepperX.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(X)
#define X_STEP_WRITE(STATE) do{ if(STATE) TOGGLE(X_STEP_PIN); }while(0)
#define X_STEP_WRITE(STATE) do{ if (STATE) TOGGLE(X_STEP_PIN); }while(0)
#endif
#endif
// Y Stepper
#if AXIS_IS_TMC(Y)
extern TMC_CLASS(Y, Y) stepperY;
static constexpr chopper_timing_t chopper_timing_Y = CHOPPER_TIMING_Y;
#if ENABLED(SOFTWARE_DRIVER_ENABLE)
#define Y_ENABLE_INIT() NOOP
#define Y_ENABLE_WRITE(STATE) stepperY.toff((STATE)==Y_ENABLE_ON ? chopper_timing.toff : 0)
#define Y_ENABLE_WRITE(STATE) stepperY.toff((STATE)==Y_ENABLE_ON ? chopper_timing_Y.toff : 0)
#define Y_ENABLE_READ() stepperY.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(Y)
@@ -116,181 +142,276 @@ void reset_trinamic_drivers();
// Z Stepper
#if AXIS_IS_TMC(Z)
extern TMC_CLASS(Z, Z) stepperZ;
static constexpr chopper_timing_t chopper_timing_Z = CHOPPER_TIMING_Z;
#if ENABLED(SOFTWARE_DRIVER_ENABLE)
#define Z_ENABLE_INIT() NOOP
#define Z_ENABLE_WRITE(STATE) stepperZ.toff((STATE)==Z_ENABLE_ON ? chopper_timing.toff : 0)
#define Z_ENABLE_WRITE(STATE) stepperZ.toff((STATE)==Z_ENABLE_ON ? chopper_timing_Z.toff : 0)
#define Z_ENABLE_READ() stepperZ.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(Z)
#define Z_STEP_WRITE(STATE) do{ if(STATE) TOGGLE(Z_STEP_PIN); }while(0)
#define Z_STEP_WRITE(STATE) do{ if (STATE) TOGGLE(Z_STEP_PIN); }while(0)
#endif
#endif
// X2 Stepper
#if HAS_X2_ENABLE && AXIS_IS_TMC(X2)
extern TMC_CLASS(X2, X) stepperX2;
#ifndef CHOPPER_TIMING_X2
#define CHOPPER_TIMING_X2 CHOPPER_TIMING_X
#endif
static constexpr chopper_timing_t chopper_timing_X2 = CHOPPER_TIMING_X2;
#if ENABLED(SOFTWARE_DRIVER_ENABLE)
#define X2_ENABLE_INIT() NOOP
#define X2_ENABLE_WRITE(STATE) stepperX2.toff((STATE)==X_ENABLE_ON ? chopper_timing.toff : 0)
#define X2_ENABLE_WRITE(STATE) stepperX2.toff((STATE)==X_ENABLE_ON ? chopper_timing_X2.toff : 0)
#define X2_ENABLE_READ() stepperX2.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(X2)
#define X2_STEP_WRITE(STATE) do{ if(STATE) TOGGLE(X2_STEP_PIN); }while(0)
#define X2_STEP_WRITE(STATE) do{ if (STATE) TOGGLE(X2_STEP_PIN); }while(0)
#endif
#endif
// Y2 Stepper
#if HAS_Y2_ENABLE && AXIS_IS_TMC(Y2)
extern TMC_CLASS(Y2, Y) stepperY2;
#ifndef CHOPPER_TIMING_Y2
#define CHOPPER_TIMING_Y2 CHOPPER_TIMING_Y
#endif
static constexpr chopper_timing_t chopper_timing_Y2 = CHOPPER_TIMING_Y2;
#if ENABLED(SOFTWARE_DRIVER_ENABLE)
#define Y2_ENABLE_INIT() NOOP
#define Y2_ENABLE_WRITE(STATE) stepperY2.toff((STATE)==Y_ENABLE_ON ? chopper_timing.toff : 0)
#define Y2_ENABLE_WRITE(STATE) stepperY2.toff((STATE)==Y_ENABLE_ON ? chopper_timing_Y2.toff : 0)
#define Y2_ENABLE_READ() stepperY2.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(Y2)
#define Y2_STEP_WRITE(STATE) do{ if(STATE) TOGGLE(Y2_STEP_PIN); }while(0)
#define Y2_STEP_WRITE(STATE) do{ if (STATE) TOGGLE(Y2_STEP_PIN); }while(0)
#endif
#endif
// Z2 Stepper
#if HAS_Z2_ENABLE && AXIS_IS_TMC(Z2)
extern TMC_CLASS(Z2, Z) stepperZ2;
#if ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(Z2)
#ifndef CHOPPER_TIMING_Z2
#define CHOPPER_TIMING_Z2 CHOPPER_TIMING_Z
#endif
static constexpr chopper_timing_t chopper_timing_Z2 = CHOPPER_TIMING_Z2;
#if ENABLED(SOFTWARE_DRIVER_ENABLE)
#define Z2_ENABLE_INIT() NOOP
#define Z2_ENABLE_WRITE(STATE) stepperZ2.toff((STATE)==Z_ENABLE_ON ? chopper_timing.toff : 0)
#define Z2_ENABLE_WRITE(STATE) stepperZ2.toff((STATE)==Z_ENABLE_ON ? chopper_timing_Z2.toff : 0)
#define Z2_ENABLE_READ() stepperZ2.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(Z2)
#define Z2_STEP_WRITE(STATE) do{ if(STATE) TOGGLE(Z2_STEP_PIN); }while(0)
#define Z2_STEP_WRITE(STATE) do{ if (STATE) TOGGLE(Z2_STEP_PIN); }while(0)
#endif
#endif
// Z3 Stepper
#if HAS_Z3_ENABLE && AXIS_IS_TMC(Z3)
extern TMC_CLASS(Z3, Z) stepperZ3;
#ifndef CHOPPER_TIMING_Z3
#define CHOPPER_TIMING_Z3 CHOPPER_TIMING_Z
#endif
static constexpr chopper_timing_t chopper_timing_Z3 = CHOPPER_TIMING_Z3;
#if ENABLED(SOFTWARE_DRIVER_ENABLE)
#define Z3_ENABLE_INIT() NOOP
#define Z3_ENABLE_WRITE(STATE) stepperZ3.toff((STATE)==Z_ENABLE_ON ? chopper_timing.toff : 0)
#define Z3_ENABLE_WRITE(STATE) stepperZ3.toff((STATE)==Z_ENABLE_ON ? chopper_timing_Z3.toff : 0)
#define Z3_ENABLE_READ() stepperZ3.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(Z3)
#define Z3_STEP_WRITE(STATE) do{ if(STATE) TOGGLE(Z3_STEP_PIN); }while(0)
#define Z3_STEP_WRITE(STATE) do{ if (STATE) TOGGLE(Z3_STEP_PIN); }while(0)
#endif
#endif
// Z4 Stepper
#if HAS_Z4_ENABLE && AXIS_IS_TMC(Z4)
extern TMC_CLASS(Z4, Z) stepperZ4;
#ifndef CHOPPER_TIMING_Z4
#define CHOPPER_TIMING_Z4 CHOPPER_TIMING_Z
#endif
static constexpr chopper_timing_t chopper_timing_Z4 = CHOPPER_TIMING_Z4;
#if ENABLED(SOFTWARE_DRIVER_ENABLE)
#define Z4_ENABLE_INIT() NOOP
#define Z4_ENABLE_WRITE(STATE) stepperZ4.toff((STATE)==Z_ENABLE_ON ? chopper_timing.toff : 0)
#define Z4_ENABLE_WRITE(STATE) stepperZ4.toff((STATE)==Z_ENABLE_ON ? chopper_timing_Z4.toff : 0)
#define Z4_ENABLE_READ() stepperZ4.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(Z4)
#define Z4_STEP_WRITE(STATE) do{ if(STATE) TOGGLE(Z4_STEP_PIN); }while(0)
#define Z4_STEP_WRITE(STATE) do{ if (STATE) TOGGLE(Z4_STEP_PIN); }while(0)
#endif
#endif
// I Stepper
#if AXIS_IS_TMC(I)
extern TMC_CLASS(I, I) stepperI;
static constexpr chopper_timing_t chopper_timing_I = CHOPPER_TIMING_I;
#if ENABLED(SOFTWARE_DRIVER_ENABLE)
#define I_ENABLE_INIT() NOOP
#define I_ENABLE_WRITE(STATE) stepperI.toff((STATE)==I_ENABLE_ON ? chopper_timing.toff : 0)
#define I_ENABLE_READ() stepperI.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(I)
#define I_STEP_WRITE(STATE) do{ if (STATE) TOGGLE(I_STEP_PIN); }while(0)
#endif
#endif
// J Stepper
#if AXIS_IS_TMC(J)
extern TMC_CLASS(J, J) stepperJ;
static constexpr chopper_timing_t chopper_timing_J = CHOPPER_TIMING_J;
#if ENABLED(SOFTWARE_DRIVER_ENABLE)
#define J_ENABLE_INIT() NOOP
#define J_ENABLE_WRITE(STATE) stepperJ.toff((STATE)==J_ENABLE_ON ? chopper_timing.toff : 0)
#define J_ENABLE_READ() stepperJ.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(J)
#define J_STEP_WRITE(STATE) do{ if (STATE) TOGGLE(J_STEP_PIN); }while(0)
#endif
#endif
// K Stepper
#if AXIS_IS_TMC(K)
extern TMC_CLASS(K, K) stepperK;
static constexpr chopper_timing_t chopper_timing_K = CHOPPER_TIMING_K;
#if ENABLED(SOFTWARE_DRIVER_ENABLE)
#define K_ENABLE_INIT() NOOP
#define K_ENABLE_WRITE(STATE) stepperK.toff((STATE)==K_ENABLE_ON ? chopper_timing.toff : 0)
#define K_ENABLE_READ() stepperK.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(K)
#define K_STEP_WRITE(STATE) do{ if (STATE) TOGGLE(K_STEP_PIN); }while(0)
#endif
#endif
// E0 Stepper
#if AXIS_IS_TMC(E0)
extern TMC_CLASS_E(0) stepperE0;
#if ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E0)
#ifndef CHOPPER_TIMING_E0
#define CHOPPER_TIMING_E0 CHOPPER_TIMING_E
#endif
static constexpr chopper_timing_t chopper_timing_E0 = CHOPPER_TIMING_E0;
#if ENABLED(SOFTWARE_DRIVER_ENABLE)
#define E0_ENABLE_INIT() NOOP
#define E0_ENABLE_WRITE(STATE) stepperE0.toff((STATE)==E_ENABLE_ON ? chopper_timing.toff : 0)
#define E0_ENABLE_WRITE(STATE) stepperE0.toff((STATE)==E_ENABLE_ON ? chopper_timing_E0.toff : 0)
#define E0_ENABLE_READ() stepperE0.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(E0)
#define E0_STEP_WRITE(STATE) do{ if(STATE) TOGGLE(E0_STEP_PIN); }while(0)
#define E0_STEP_WRITE(STATE) do{ if (STATE) TOGGLE(E0_STEP_PIN); }while(0)
#endif
#endif
// E1 Stepper
#if AXIS_IS_TMC(E1)
extern TMC_CLASS_E(1) stepperE1;
#if ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E1)
#ifndef CHOPPER_TIMING_E1
#define CHOPPER_TIMING_E1 CHOPPER_TIMING_E
#endif
static constexpr chopper_timing_t chopper_timing_E1 = CHOPPER_TIMING_E1;
#if ENABLED(SOFTWARE_DRIVER_ENABLE)
#define E1_ENABLE_INIT() NOOP
#define E1_ENABLE_WRITE(STATE) stepperE1.toff((STATE)==E_ENABLE_ON ? chopper_timing.toff : 0)
#define E1_ENABLE_WRITE(STATE) stepperE1.toff((STATE)==E_ENABLE_ON ? chopper_timing_E1.toff : 0)
#define E1_ENABLE_READ() stepperE1.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(E1)
#define E1_STEP_WRITE(STATE) do{ if(STATE) TOGGLE(E1_STEP_PIN); }while(0)
#define E1_STEP_WRITE(STATE) do{ if (STATE) TOGGLE(E1_STEP_PIN); }while(0)
#endif
#endif
// E2 Stepper
#if AXIS_IS_TMC(E2)
extern TMC_CLASS_E(2) stepperE2;
#if ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E2)
#ifndef CHOPPER_TIMING_E2
#define CHOPPER_TIMING_E2 CHOPPER_TIMING_E
#endif
static constexpr chopper_timing_t chopper_timing_E2 = CHOPPER_TIMING_E2;
#if ENABLED(SOFTWARE_DRIVER_ENABLE)
#define E2_ENABLE_INIT() NOOP
#define E2_ENABLE_WRITE(STATE) stepperE2.toff((STATE)==E_ENABLE_ON ? chopper_timing.toff : 0)
#define E2_ENABLE_WRITE(STATE) stepperE2.toff((STATE)==E_ENABLE_ON ? chopper_timing_E2.toff : 0)
#define E2_ENABLE_READ() stepperE2.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(E2)
#define E2_STEP_WRITE(STATE) do{ if(STATE) TOGGLE(E2_STEP_PIN); }while(0)
#define E2_STEP_WRITE(STATE) do{ if (STATE) TOGGLE(E2_STEP_PIN); }while(0)
#endif
#endif
// E3 Stepper
#if AXIS_IS_TMC(E3)
extern TMC_CLASS_E(3) stepperE3;
#if ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E3)
#ifndef CHOPPER_TIMING_E3
#define CHOPPER_TIMING_E3 CHOPPER_TIMING_E
#endif
static constexpr chopper_timing_t chopper_timing_E3 = CHOPPER_TIMING_E3;
#if ENABLED(SOFTWARE_DRIVER_ENABLE)
#define E3_ENABLE_INIT() NOOP
#define E3_ENABLE_WRITE(STATE) stepperE3.toff((STATE)==E_ENABLE_ON ? chopper_timing.toff : 0)
#define E3_ENABLE_WRITE(STATE) stepperE3.toff((STATE)==E_ENABLE_ON ? chopper_timing_E3.toff : 0)
#define E3_ENABLE_READ() stepperE3.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(E3)
#define E3_STEP_WRITE(STATE) do{ if(STATE) TOGGLE(E3_STEP_PIN); }while(0)
#define E3_STEP_WRITE(STATE) do{ if (STATE) TOGGLE(E3_STEP_PIN); }while(0)
#endif
#endif
// E4 Stepper
#if AXIS_IS_TMC(E4)
extern TMC_CLASS_E(4) stepperE4;
#if ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E4)
#ifndef CHOPPER_TIMING_E4
#define CHOPPER_TIMING_E4 CHOPPER_TIMING_E
#endif
static constexpr chopper_timing_t chopper_timing_E4 = CHOPPER_TIMING_E4;
#if ENABLED(SOFTWARE_DRIVER_ENABLE)
#define E4_ENABLE_INIT() NOOP
#define E4_ENABLE_WRITE(STATE) stepperE4.toff((STATE)==E_ENABLE_ON ? chopper_timing.toff : 0)
#define E4_ENABLE_WRITE(STATE) stepperE4.toff((STATE)==E_ENABLE_ON ? chopper_timing_E4.toff : 0)
#define E4_ENABLE_READ() stepperE4.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(E4)
#define E4_STEP_WRITE(STATE) do{ if(STATE) TOGGLE(E4_STEP_PIN); }while(0)
#define E4_STEP_WRITE(STATE) do{ if (STATE) TOGGLE(E4_STEP_PIN); }while(0)
#endif
#endif
// E5 Stepper
#if AXIS_IS_TMC(E5)
extern TMC_CLASS_E(5) stepperE5;
#if ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E5)
#ifndef CHOPPER_TIMING_E5
#define CHOPPER_TIMING_E5 CHOPPER_TIMING_E
#endif
static constexpr chopper_timing_t chopper_timing_E5 = CHOPPER_TIMING_E5;
#if ENABLED(SOFTWARE_DRIVER_ENABLE)
#define E5_ENABLE_INIT() NOOP
#define E5_ENABLE_WRITE(STATE) stepperE5.toff((STATE)==E_ENABLE_ON ? chopper_timing.toff : 0)
#define E5_ENABLE_WRITE(STATE) stepperE5.toff((STATE)==E_ENABLE_ON ? chopper_timing_E5.toff : 0)
#define E5_ENABLE_READ() stepperE5.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(E5)
#define E5_STEP_WRITE(STATE) do{ if(STATE) TOGGLE(E5_STEP_PIN); }while(0)
#define E5_STEP_WRITE(STATE) do{ if (STATE) TOGGLE(E5_STEP_PIN); }while(0)
#endif
#endif
// E6 Stepper
#if AXIS_IS_TMC(E6)
extern TMC_CLASS_E(6) stepperE6;
#if ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E6)
#ifndef CHOPPER_TIMING_E6
#define CHOPPER_TIMING_E6 CHOPPER_TIMING_E
#endif
static constexpr chopper_timing_t chopper_timing_E6 = CHOPPER_TIMING_E6;
#if ENABLED(SOFTWARE_DRIVER_ENABLE)
#define E6_ENABLE_INIT() NOOP
#define E6_ENABLE_WRITE(STATE) stepperE6.toff((STATE)==E_ENABLE_ON ? chopper_timing.toff : 0)
#define E6_ENABLE_WRITE(STATE) stepperE6.toff((STATE)==E_ENABLE_ON ? chopper_timing_E6.toff : 0)
#define E6_ENABLE_READ() stepperE6.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(E6)
#define E6_STEP_WRITE(STATE) do{ if(STATE) TOGGLE(E6_STEP_PIN); }while(0)
#define E6_STEP_WRITE(STATE) do{ if (STATE) TOGGLE(E6_STEP_PIN); }while(0)
#endif
#endif
// E7 Stepper
#if AXIS_IS_TMC(E7)
extern TMC_CLASS_E(7) stepperE7;
#if ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E7)
#ifndef CHOPPER_TIMING_E7
#define CHOPPER_TIMING_E7 CHOPPER_TIMING_E
#endif
static constexpr chopper_timing_t chopper_timing_E7 = CHOPPER_TIMING_E7;
#if ENABLED(SOFTWARE_DRIVER_ENABLE)
#define E7_ENABLE_INIT() NOOP
#define E7_ENABLE_WRITE(STATE) stepperE7.toff((STATE)==E_ENABLE_ON ? chopper_timing.toff : 0)
#define E7_ENABLE_WRITE(STATE) stepperE7.toff((STATE)==E_ENABLE_ON ? chopper_timing_E7.toff : 0)
#define E7_ENABLE_READ() stepperE7.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(E7)
#define E7_STEP_WRITE(STATE) do{ if(STATE) TOGGLE(E7_STEP_PIN); }while(0)
#define E7_STEP_WRITE(STATE) do{ if (STATE) TOGGLE(E7_STEP_PIN); }while(0)
#endif
#endif

3423
Marlin/src/module/temperature.cpp Executable file → Normal file

File diff suppressed because it is too large Load Diff

747
Marlin/src/module/temperature.h Executable file → Normal file

File diff suppressed because it is too large Load Diff

4
Marlin/src/module/thermistor/thermistor_1.h Executable file → Normal file
View File

@@ -16,13 +16,13 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 100 kOhm, beta25 = 4092 K, 4.7 kOhm pull-up, bed thermistor
const short temptable_1[][2] PROGMEM = {
constexpr temp_entry_t temptable_1[] PROGMEM = {
{ OV( 23), 300 },
{ OV( 25), 295 },
{ OV( 27), 290 },

4
Marlin/src/module/thermistor/thermistor_10.h Executable file → Normal file
View File

@@ -16,13 +16,13 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 100 kOhm, beta25 = 3960 K, 4.7 kOhm pull-up, RS thermistor 198-961
const short temptable_10[][2] PROGMEM = {
constexpr temp_entry_t temptable_10[] PROGMEM = {
{ OV( 1), 929 },
{ OV( 36), 299 },
{ OV( 71), 246 },

6
Marlin/src/module/thermistor/thermistor_1010.h Executable file → Normal file
View File

@@ -16,13 +16,15 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#define REVERSE_TEMP_SENSOR_RANGE_1010 1
// Pt1000 with 1k0 pullup
const short temptable_1010[][2] PROGMEM = {
constexpr temp_entry_t temptable_1010[] PROGMEM = {
PtLine( 0, 1000, 1000),
PtLine( 25, 1000, 1000),
PtLine( 50, 1000, 1000),

12
Marlin/src/module/thermistor/thermistor_1047.h Executable file → Normal file
View File

@@ -16,13 +16,15 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#define REVERSE_TEMP_SENSOR_RANGE_1047 1
// Pt1000 with 4k7 pullup
const short temptable_1047[][2] PROGMEM = {
constexpr temp_entry_t temptable_1047[] PROGMEM = {
// only a few values are needed as the curve is very flat
PtLine( 0, 1000, 4700),
PtLine( 50, 1000, 4700),
@@ -30,5 +32,9 @@ const short temptable_1047[][2] PROGMEM = {
PtLine(150, 1000, 4700),
PtLine(200, 1000, 4700),
PtLine(250, 1000, 4700),
PtLine(300, 1000, 4700)
PtLine(300, 1000, 4700),
PtLine(350, 1000, 4700),
PtLine(400, 1000, 4700),
PtLine(450, 1000, 4700),
PtLine(500, 1000, 4700)
};

4
Marlin/src/module/thermistor/thermistor_11.h Executable file → Normal file
View File

@@ -16,13 +16,13 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 100 kOhm, beta25 = 3950 K, 4.7 kOhm pull-up, QU-BD silicone bed QWG-104F-3950 thermistor
const short temptable_11[][2] PROGMEM = {
constexpr temp_entry_t temptable_11[] PROGMEM = {
{ OV( 1), 938 },
{ OV( 31), 314 },
{ OV( 41), 290 },

6
Marlin/src/module/thermistor/thermistor_110.h Executable file → Normal file
View File

@@ -16,13 +16,15 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#define REVERSE_TEMP_SENSOR_RANGE_110 1
// Pt100 with 1k0 pullup
const short temptable_110[][2] PROGMEM = {
constexpr temp_entry_t temptable_110[] PROGMEM = {
// only a few values are needed as the curve is very flat
PtLine( 0, 100, 1000),
PtLine( 50, 100, 1000),

4
Marlin/src/module/thermistor/thermistor_12.h Executable file → Normal file
View File

@@ -16,13 +16,13 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 100 kOhm, beta25 = 4700 K, 4.7 kOhm pull-up, (personal calibration for Makibox hot bed)
const short temptable_12[][2] PROGMEM = {
constexpr temp_entry_t temptable_12[] PROGMEM = {
{ OV( 35), 180 }, // top rating 180C
{ OV( 211), 140 },
{ OV( 233), 135 },

4
Marlin/src/module/thermistor/thermistor_13.h Executable file → Normal file
View File

@@ -16,13 +16,13 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 100 kOhm, beta25 = 4100 K, 4.7 kOhm pull-up, Hisens thermistor
const short temptable_13[][2] PROGMEM = {
constexpr temp_entry_t temptable_13[] PROGMEM = {
{ OV( 20.04), 300 },
{ OV( 23.19), 290 },
{ OV( 26.71), 280 },

6
Marlin/src/module/thermistor/thermistor_147.h Executable file → Normal file
View File

@@ -16,13 +16,15 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#define REVERSE_TEMP_SENSOR_RANGE_147 1
// Pt100 with 4k7 pullup
const short temptable_147[][2] PROGMEM = {
constexpr temp_entry_t temptable_147[] PROGMEM = {
// only a few values are needed as the curve is very flat
PtLine( 0, 100, 4700),
PtLine( 50, 100, 4700),

4
Marlin/src/module/thermistor/thermistor_15.h Executable file → Normal file
View File

@@ -16,13 +16,13 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// 100k bed thermistor in JGAurora A5. Calibrated by Sam Pinches 21st Jan 2018 using cheap k-type thermocouple inserted into heater block, using TM-902C meter.
const short temptable_15[][2] PROGMEM = {
constexpr temp_entry_t temptable_15[] PROGMEM = {
{ OV( 31), 275 },
{ OV( 33), 270 },
{ OV( 35), 260 },

View File

@@ -0,0 +1,78 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// Dagoma NTC 100k white thermistor
constexpr temp_entry_t temptable_17[] PROGMEM = {
{ OV( 16), 309 },
{ OV( 18), 307 },
{ OV( 20), 300 },
{ OV( 22), 293 },
{ OV( 26), 284 },
{ OV( 29), 272 },
{ OV( 33), 266 },
{ OV( 36), 260 },
{ OV( 42), 252 },
{ OV( 46), 247 },
{ OV( 48), 244 },
{ OV( 51), 241 },
{ OV( 62), 231 },
{ OV( 73), 222 },
{ OV( 78), 219 },
{ OV( 87), 212 },
{ OV( 98), 207 },
{ OV( 109), 201 },
{ OV( 118), 197 },
{ OV( 131), 191 },
{ OV( 145), 186 },
{ OV( 160), 181 },
{ OV( 177), 175 },
{ OV( 203), 169 },
{ OV( 222), 164 },
{ OV( 256), 156 },
{ OV( 283), 151 },
{ OV( 312), 145 },
{ OV( 343), 140 },
{ OV( 377), 131 },
{ OV( 413), 125 },
{ OV( 454), 119 },
{ OV( 496), 113 },
{ OV( 537), 108 },
{ OV( 578), 102 },
{ OV( 619), 97 },
{ OV( 658), 92 },
{ OV( 695), 87 },
{ OV( 735), 81 },
{ OV( 773), 75 },
{ OV( 808), 70 },
{ OV( 844), 64 },
{ OV( 868), 59 },
{ OV( 892), 54 },
{ OV( 914), 49 },
{ OV( 935), 42 },
{ OV( 951), 38 },
{ OV( 967), 32 },
{ OV( 975), 28 },
{ OV(1000), 20 },
{ OV(1010), 10 },
{ OV(1024), -273 } // for safety
};

4
Marlin/src/module/thermistor/thermistor_18.h Executable file → Normal file
View File

@@ -16,13 +16,13 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// ATC Semitec 204GT-2 (4.7k pullup) Dagoma.Fr - MKS_Base_DKU001327 - version (measured/tested/approved)
const short temptable_18[][2] PROGMEM = {
constexpr temp_entry_t temptable_18[] PROGMEM = {
{ OV( 1), 713 },
{ OV( 17), 284 },
{ OV( 20), 275 },

6
Marlin/src/module/thermistor/thermistor_2.h Executable file → Normal file
View File

@@ -16,17 +16,17 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
//
// R25 = 200 kOhm, beta25 = 4338 K, 4.7 kOhm pull-up, ATC Semitec 204GT-2
// Verified by linagee. Source: http://shop.arcol.hu/static/datasheets/thermistors.pdf
// Verified by linagee. Source: https://www.mouser.com/datasheet/2/362/semitec%20usa%20corporation_gtthermistor-1202937.pdf
// Calculated using 4.7kohm pullup, voltage divider math, and manufacturer provided temp/resistance
//
const short temptable_2[][2] PROGMEM = {
constexpr temp_entry_t temptable_2[] PROGMEM = {
{ OV( 1), 848 },
{ OV( 30), 300 }, // top rating 300C
{ OV( 34), 290 },

6
Marlin/src/module/thermistor/thermistor_20.h Executable file → Normal file
View File

@@ -16,15 +16,15 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#define REVERSE_TEMP_SENSOR_RANGE
#define REVERSE_TEMP_SENSOR_RANGE_20 1
// Pt100 with INA826 amp on Ultimaker v2.0 electronics
const short temptable_20[][2] PROGMEM = {
constexpr temp_entry_t temptable_20[] PROGMEM = {
{ OV( 0), 0 },
{ OV(227), 1 },
{ OV(236), 10 },

View File

@@ -0,0 +1,60 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 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 <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 100 KOhm, beta25 = 4550 K, 4.7 kOhm pull-up, TDK NTCG104LH104KT1 https://product.tdk.com/en/search/sensor/ntc/chip-ntc-thermistor/info?part_no=NTCG104LH104KT1
constexpr temp_entry_t temptable_2000[] PROGMEM = {
{ OV(313), 125 },
{ OV(347), 120 },
{ OV(383), 115 },
{ OV(422), 110 },
{ OV(463), 105 },
{ OV(506), 100 },
{ OV(549), 95 },
{ OV(594), 90 },
{ OV(638), 85 },
{ OV(681), 80 },
{ OV(722), 75 },
{ OV(762), 70 },
{ OV(799), 65 },
{ OV(833), 60 },
{ OV(863), 55 },
{ OV(890), 50 },
{ OV(914), 45 },
{ OV(934), 40 },
{ OV(951), 35 },
{ OV(966), 30 },
{ OV(978), 25 },
{ OV(988), 20 },
{ OV(996), 15 },
{ OV(1002), 10 },
{ OV(1007), 5 },
{ OV(1012), 0 },
{ OV(1015), -5 },
{ OV(1017), -10 },
{ OV(1019), -15 },
{ OV(1020), -20 },
{ OV(1021), -25 },
{ OV(1022), -30 },
{ OV(1023), -35 },
{ OV(1023), -40 }
};

6
Marlin/src/module/thermistor/thermistor_201.h Executable file → Normal file
View File

@@ -16,15 +16,15 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#define REVERSE_TEMP_SENSOR_RANGE
#define REVERSE_TEMP_SENSOR_RANGE_201 1
// Pt100 with LMV324 amp on Overlord v1.1 electronics
const short temptable_201[][2] PROGMEM = {
constexpr temp_entry_t temptable_201[] PROGMEM = {
{ OV( 0), 0 },
{ OV( 8), 1 },
{ OV( 23), 6 },

2
Marlin/src/module/thermistor/thermistor_202.h Executable file → Normal file
View File

@@ -3,7 +3,7 @@
// Temptable sent from dealer technologyoutlet.co.uk
//
const short temptable_202[][2] PROGMEM = {
constexpr temp_entry_t temptable_202[] PROGMEM = {
{ OV( 1), 864 },
{ OV( 35), 300 },
{ OV( 38), 295 },

9
Marlin/src/module/thermistor/thermistor_21.h Executable file → Normal file
View File

@@ -16,18 +16,19 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#define REVERSE_TEMP_SENSOR_RANGE
#define REVERSE_TEMP_SENSOR_RANGE_21 1
#undef OV_SCALE
#define OV_SCALE(N) (float((N) * 5) / 3.3f)
// Pt100 with INA826 amp with 3.3v excitation based on "Pt100 with INA826 amp on Ultimaker v2.0 electronics"
const short temptable_21[][2] PROGMEM = {
// Pt100 with INA826 amplifier board with 5v supply based on Thermistor 20, with 3v3 ADC reference on the mainboard.
// If the ADC reference and INA826 board supply voltage are identical, Thermistor 20 instead.
constexpr temp_entry_t temptable_21[] PROGMEM = {
{ OV( 0), 0 },
{ OV(227), 1 },
{ OV(236), 10 },

View File

@@ -0,0 +1,72 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
*
*/
// 100k hotend thermistor with 4.7k pull up to 3.3v and 220R to analog input as in GTM32 Pro vB
constexpr temp_entry_t temptable_22[] PROGMEM = {
{ OV( 1), 352 },
{ OV( 6), 341 },
{ OV( 11), 330 },
{ OV( 16), 319 },
{ OV( 20), 307 },
{ OV( 26), 296 },
{ OV( 31), 285 },
{ OV( 40), 274 },
{ OV( 51), 263 },
{ OV( 61), 251 },
{ OV( 72), 245 },
{ OV( 77), 240 },
{ OV( 82), 237 },
{ OV( 87), 232 },
{ OV( 91), 229 },
{ OV( 94), 227 },
{ OV( 97), 225 },
{ OV( 100), 223 },
{ OV( 104), 221 },
{ OV( 108), 219 },
{ OV( 115), 214 },
{ OV( 126), 209 },
{ OV( 137), 204 },
{ OV( 147), 200 },
{ OV( 158), 193 },
{ OV( 167), 192 },
{ OV( 177), 189 },
{ OV( 197), 163 },
{ OV( 230), 174 },
{ OV( 267), 165 },
{ OV( 310), 158 },
{ OV( 336), 151 },
{ OV( 379), 143 },
{ OV( 413), 138 },
{ OV( 480), 127 },
{ OV( 580), 110 },
{ OV( 646), 100 },
{ OV( 731), 88 },
{ OV( 768), 84 },
{ OV( 861), 69 },
{ OV( 935), 50 },
{ OV( 975), 38 },
{ OV(1001), 27 },
{ OV(1011), 22 },
{ OV(1015), 13 },
{ OV(1020), 6 },
{ OV(1023), 0 }
};

View File

@@ -0,0 +1,128 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
*
*/
// 100k hotbed thermistor with 4.7k pull up to 3.3v and 220R to analog input as in GTM32 Pro vB
constexpr temp_entry_t temptable_23[] PROGMEM = {
{ OV( 1), 938 },
{ OV( 11), 423 },
{ OV( 21), 351 },
{ OV( 31), 314 },
{ OV( 41), 290 },
{ OV( 51), 272 },
{ OV( 61), 258 },
{ OV( 71), 247 },
{ OV( 81), 237 },
{ OV( 91), 229 },
{ OV( 101), 221 },
{ OV( 111), 215 },
{ OV( 121), 209 },
{ OV( 131), 204 },
{ OV( 141), 199 },
{ OV( 151), 195 },
{ OV( 161), 190 },
{ OV( 171), 187 },
{ OV( 181), 183 },
{ OV( 191), 179 },
{ OV( 201), 176 },
{ OV( 211), 173 },
{ OV( 221), 170 },
{ OV( 231), 167 },
{ OV( 241), 165 },
{ OV( 251), 162 },
{ OV( 261), 160 },
{ OV( 271), 157 },
{ OV( 281), 155 },
{ OV( 291), 153 },
{ OV( 301), 150 },
{ OV( 311), 148 },
{ OV( 321), 146 },
{ OV( 331), 144 },
{ OV( 341), 142 },
{ OV( 351), 140 },
{ OV( 361), 139 },
{ OV( 371), 137 },
{ OV( 381), 135 },
{ OV( 391), 133 },
{ OV( 401), 131 },
{ OV( 411), 130 },
{ OV( 421), 128 },
{ OV( 431), 126 },
{ OV( 441), 125 },
{ OV( 451), 123 },
{ OV( 461), 122 },
{ OV( 471), 120 },
{ OV( 481), 119 },
{ OV( 491), 117 },
{ OV( 501), 116 },
{ OV( 511), 114 },
{ OV( 521), 113 },
{ OV( 531), 111 },
{ OV( 541), 110 },
{ OV( 551), 108 },
{ OV( 561), 107 },
{ OV( 571), 105 },
{ OV( 581), 104 },
{ OV( 591), 102 },
{ OV( 601), 101 },
{ OV( 611), 100 },
{ OV( 621), 98 },
{ OV( 631), 97 },
{ OV( 641), 95 },
{ OV( 651), 94 },
{ OV( 661), 92 },
{ OV( 671), 91 },
{ OV( 681), 90 },
{ OV( 691), 88 },
{ OV( 701), 87 },
{ OV( 711), 85 },
{ OV( 721), 84 },
{ OV( 731), 82 },
{ OV( 741), 81 },
{ OV( 751), 79 },
{ OV( 761), 77 },
{ OV( 771), 76 },
{ OV( 781), 74 },
{ OV( 791), 72 },
{ OV( 801), 71 },
{ OV( 811), 69 },
{ OV( 821), 67 },
{ OV( 831), 65 },
{ OV( 841), 63 },
{ OV( 851), 62 },
{ OV( 861), 60 },
{ OV( 871), 57 },
{ OV( 881), 55 },
{ OV( 891), 53 },
{ OV( 901), 51 },
{ OV( 911), 48 },
{ OV( 921), 45 },
{ OV( 931), 42 },
{ OV( 941), 39 },
{ OV( 951), 36 },
{ OV( 961), 32 },
{ OV( 971), 28 },
{ OV( 981), 25 },
{ OV( 991), 23 },
{ OV(1001), 21 },
{ OV(1011), 19 },
{ OV(1021), 5 }
};

4
Marlin/src/module/thermistor/thermistor_3.h Executable file → Normal file
View File

@@ -16,13 +16,13 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 100 kOhm, beta25 = 4120 K, 4.7 kOhm pull-up, mendel-parts
const short temptable_3[][2] PROGMEM = {
constexpr temp_entry_t temptable_3[] PROGMEM = {
{ OV( 1), 864 },
{ OV( 21), 300 },
{ OV( 25), 290 },

View File

@@ -0,0 +1,66 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 100 kOhm, beta25 = 3950 K, 4.7 kOhm pull-up
// Resistance 100k Ohms at 25deg. C
// Resistance Tolerance + / -1%
// B Value 3950K at 25/50 deg. C
// B Value Tolerance + / - 1%
// Kis3d Silicone Heater 24V 200W/300W with 6mm Precision cast plate (EN AW 5083)
// Temperature setting time 10 min to determine the 12Bit ADC value on the surface. (le3tspeak)
constexpr temp_entry_t temptable_30[] PROGMEM = {
{ OV( 1), 938 },
{ OV( 298), 125 }, // 1193 - 125°
{ OV( 321), 121 }, // 1285 - 121°
{ OV( 348), 117 }, // 1392 - 117°
{ OV( 387), 113 }, // 1550 - 113°
{ OV( 411), 110 }, // 1644 - 110°
{ OV( 445), 106 }, // 1780 - 106°
{ OV( 480), 101 }, // 1920 - 101°
{ OV( 516), 97 }, // 2064 - 97°
{ OV( 553), 92 }, // 2212 - 92°
{ OV( 591), 88 }, // 2364 - 88°
{ OV( 628), 84 }, // 2512 - 84°
{ OV( 665), 79 }, // 2660 - 79°
{ OV( 702), 75 }, // 2808 - 75°
{ OV( 736), 71 }, // 2945 - 71°
{ OV( 770), 67 }, // 3080 - 67°
{ OV( 801), 63 }, // 3204 - 63°
{ OV( 830), 59 }, // 3320 - 59°
{ OV( 857), 55 }, // 3428 - 55°
{ OV( 881), 51 }, // 3524 - 51°
{ OV( 902), 47 }, // 3611 - 47°
{ OV( 922), 42 }, // 3688 - 42°
{ OV( 938), 38 }, // 3754 - 38°
{ OV( 952), 34 }, // 3811 - 34°
{ OV( 964), 29 }, // 3857 - 29°
{ OV( 975), 25 }, // 3900 - 25°
{ OV( 980), 23 }, // 3920 - 23°
{ OV( 991), 17 }, // 3964 - 17°
{ OV(1001), 9 }, // Calculated
{ OV(1004), 5 }, // Calculated
{ OV(1008), 0 }, // Calculated
{ OV(1012), -5 }, // Calculated
{ OV(1016), -10 }, // Calculated
{ OV(1020), -15 } // Calculated
};

4
Marlin/src/module/thermistor/thermistor_331.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -24,7 +24,7 @@
#define OVM(V) OV((V)*(0.327/0.5))
// R25 = 100 kOhm, beta25 = 4092 K, 4.7 kOhm pull-up, bed thermistor
const short temptable_331[][2] PROGMEM = {
constexpr temp_entry_t temptable_331[] PROGMEM = {
{ OVM( 23), 300 },
{ OVM( 25), 295 },
{ OVM( 27), 290 },

4
Marlin/src/module/thermistor/thermistor_332.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -24,7 +24,7 @@
#define OVM(V) OV((V)*(0.327/0.327))
// R25 = 100 kOhm, beta25 = 4092 K, 4.7 kOhm pull-up, bed thermistor
const short temptable_332[][2] PROGMEM = {
constexpr temp_entry_t temptable_332[] PROGMEM = {
{ OVM( 268), 150 },
{ OVM( 293), 145 },
{ OVM( 320), 141 },

4
Marlin/src/module/thermistor/thermistor_4.h Executable file → Normal file
View File

@@ -16,13 +16,13 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 10 kOhm, beta25 = 3950 K, 4.7 kOhm pull-up, Generic 10k thermistor
const short temptable_4[][2] PROGMEM = {
constexpr temp_entry_t temptable_4[] PROGMEM = {
{ OV( 1), 430 },
{ OV( 54), 137 },
{ OV( 107), 107 },

6
Marlin/src/module/thermistor/thermistor_5.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -24,9 +24,9 @@
// R25 = 100 kOhm, beta25 = 4267 K, 4.7 kOhm pull-up
// 100k ParCan thermistor (104GT-2)
// ATC Semitec 104GT-2/104NT-4-R025H42G (Used in ParCan)
// Verified by linagee. Source: http://shop.arcol.hu/static/datasheets/thermistors.pdf
// Verified by linagee. Source: https://www.mouser.com/datasheet/2/362/semitec%20usa%20corporation_gtthermistor-1202937.pdf
// Calculated using 4.7kohm pullup, voltage divider math, and manufacturer provided temp/resistance
const short temptable_5[][2] PROGMEM = {
constexpr temp_entry_t temptable_5[] PROGMEM = {
{ OV( 1), 713 },
{ OV( 17), 300 }, // top rating 300C
{ OV( 20), 290 },

4
Marlin/src/module/thermistor/thermistor_501.h Executable file → Normal file
View File

@@ -16,13 +16,13 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// 100k Zonestar thermistor. Adjusted By Hally
const short temptable_501[][2] PROGMEM = {
constexpr temp_entry_t temptable_501[] PROGMEM = {
{ OV( 1), 713 },
{ OV( 14), 300 }, // Top rating 300C
{ OV( 16), 290 },

View File

@@ -0,0 +1,60 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// Unknown thermistor for the Zonestar P802M hot bed. Adjusted By Nerseth
// These were the shipped settings from Zonestar in original firmware: P802M_8_Repetier_V1.6_Zonestar.zip
constexpr temp_entry_t temptable_502[] PROGMEM = {
{ OV( 56.0 / 4), 300 },
{ OV( 187.0 / 4), 250 },
{ OV( 615.0 / 4), 190 },
{ OV( 690.0 / 4), 185 },
{ OV( 750.0 / 4), 180 },
{ OV( 830.0 / 4), 175 },
{ OV( 920.0 / 4), 170 },
{ OV(1010.0 / 4), 165 },
{ OV(1118.0 / 4), 160 },
{ OV(1215.0 / 4), 155 },
{ OV(1330.0 / 4), 145 },
{ OV(1460.0 / 4), 140 },
{ OV(1594.0 / 4), 135 },
{ OV(1752.0 / 4), 130 },
{ OV(1900.0 / 4), 125 },
{ OV(2040.0 / 4), 120 },
{ OV(2200.0 / 4), 115 },
{ OV(2350.0 / 4), 110 },
{ OV(2516.0 / 4), 105 },
{ OV(2671.0 / 4), 98 },
{ OV(2831.0 / 4), 92 },
{ OV(2975.0 / 4), 85 },
{ OV(3115.0 / 4), 76 },
{ OV(3251.0 / 4), 72 },
{ OV(3480.0 / 4), 62 },
{ OV(3580.0 / 4), 52 },
{ OV(3660.0 / 4), 46 },
{ OV(3740.0 / 4), 40 },
{ OV(3869.0 / 4), 30 },
{ OV(3912.0 / 4), 25 },
{ OV(3948.0 / 4), 20 },
{ OV(4077.0 / 4), -20 },
{ OV(4094.0 / 4), -55 }
};

View File

@@ -0,0 +1,57 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// Zonestar (Z8XM2) Heated Bed thermistor. Added By AvanOsch
// These are taken from the Zonestar settings in original Repetier firmware: Z8XM2_ZRIB_LCD12864_V51.zip
constexpr temp_entry_t temptable_503[] PROGMEM = {
{ OV( 12), 300 },
{ OV( 27), 270 },
{ OV( 47), 250 },
{ OV( 68), 230 },
{ OV( 99), 210 },
{ OV( 120), 200 },
{ OV( 141), 190 },
{ OV( 171), 180 },
{ OV( 201), 170 },
{ OV( 261), 160 },
{ OV( 321), 150 },
{ OV( 401), 140 },
{ OV( 451), 130 },
{ OV( 551), 120 },
{ OV( 596), 110 },
{ OV( 626), 105 },
{ OV( 666), 100 },
{ OV( 697), 90 },
{ OV( 717), 85 },
{ OV( 798), 69 },
{ OV( 819), 65 },
{ OV( 870), 55 },
{ OV( 891), 51 },
{ OV( 922), 39 },
{ OV( 968), 28 },
{ OV( 980), 23 },
{ OV( 991), 17 },
{ OV( 1001), 9 },
{ OV(1021), -27 },
{ OV(1023), -200}
};

4
Marlin/src/module/thermistor/thermistor_51.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -26,7 +26,7 @@
// Verified by linagee.
// Calculated using 1kohm pullup, voltage divider math, and manufacturer provided temp/resistance
// Advantage: Twice the resolution and better linearity from 150C to 200C
const short temptable_51[][2] PROGMEM = {
constexpr temp_entry_t temptable_51[] PROGMEM = {
{ OV( 1), 350 },
{ OV( 190), 250 }, // top rating 250C
{ OV( 203), 245 },

4
Marlin/src/module/thermistor/thermistor_512.h Executable file → Normal file
View File

@@ -16,13 +16,13 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
// 100k thermistor supplied with RPW-Ultra hotend, 4.7k pullup
const short temptable_512[][2] PROGMEM = {
constexpr temp_entry_t temptable_512[] PROGMEM = {
{ OV(26), 300 },
{ OV(28), 295 },
{ OV(30), 290 },

6
Marlin/src/module/thermistor/thermistor_52.h Executable file → Normal file
View File

@@ -16,17 +16,17 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 200 kOhm, beta25 = 4338 K, 1 kOhm pull-up,
// 200k ATC Semitec 204GT-2 (WITH 1kohm RESISTOR FOR PULLUP, R9 ON SANGUINOLOLU! NOT FOR 4.7kohm PULLUP! THIS IS NOT NORMAL!)
// Verified by linagee. Source: http://shop.arcol.hu/static/datasheets/thermistors.pdf
// Verified by linagee. Source: https://www.mouser.com/datasheet/2/362/semitec%20usa%20corporation_gtthermistor-1202937.pdf
// Calculated using 1kohm pullup, voltage divider math, and manufacturer provided temp/resistance
// Advantage: More resolution and better linearity from 150C to 200C
const short temptable_52[][2] PROGMEM = {
constexpr temp_entry_t temptable_52[] PROGMEM = {
{ OV( 1), 500 },
{ OV( 125), 300 }, // top rating 300C
{ OV( 142), 290 },

6
Marlin/src/module/thermistor/thermistor_55.h Executable file → Normal file
View File

@@ -16,17 +16,17 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 100 kOhm, beta25 = 4267 K, 1 kOhm pull-up,
// 100k ATC Semitec 104GT-2 (Used on ParCan) (WITH 1kohm RESISTOR FOR PULLUP, R9 ON SANGUINOLOLU! NOT FOR 4.7kohm PULLUP! THIS IS NOT NORMAL!)
// Verified by linagee. Source: http://shop.arcol.hu/static/datasheets/thermistors.pdf
// Verified by linagee. Source: https://www.mouser.com/datasheet/2/362/semitec%20usa%20corporation_gtthermistor-1202937.pdf
// Calculated using 1kohm pullup, voltage divider math, and manufacturer provided temp/resistance
// Advantage: More resolution and better linearity from 150C to 200C
const short temptable_55[][2] PROGMEM = {
constexpr temp_entry_t temptable_55[] PROGMEM = {
{ OV( 1), 500 },
{ OV( 76), 300 },
{ OV( 87), 290 },

4
Marlin/src/module/thermistor/thermistor_6.h Executable file → Normal file
View File

@@ -16,13 +16,13 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 100 kOhm, beta25 = 4092 K, 8.2 kOhm pull-up, 100k Epcos (?) thermistor
const short temptable_6[][2] PROGMEM = {
constexpr temp_entry_t temptable_6[] PROGMEM = {
{ OV( 1), 350 },
{ OV( 28), 250 }, // top rating 250C
{ OV( 31), 245 },

4
Marlin/src/module/thermistor/thermistor_60.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -31,7 +31,7 @@
// beta: 3950
// min adc: 1 at 0.0048828125 V
// max adc: 1023 at 4.9951171875 V
const short temptable_60[][2] PROGMEM = {
constexpr temp_entry_t temptable_60[] PROGMEM = {
{ OV( 51), 272 },
{ OV( 61), 258 },
{ OV( 71), 247 },

6
Marlin/src/module/thermistor/thermistor_61.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -30,8 +30,8 @@
// Resistance Tolerance + / -1%
// B Value 3950K at 25/50 deg. C
// B Value Tolerance + / - 1%
const short temptable_61[][2] PROGMEM = {
{ OV( 2.00), 420 }, // Guestimate to ensure we dont lose a reading and drop temps to -50 when over
constexpr temp_entry_t temptable_61[] PROGMEM = {
{ OV( 2.00), 420 }, // Guestimate to ensure we don't lose a reading and drop temps to -50 when over
{ OV( 12.07), 350 },
{ OV( 12.79), 345 },
{ OV( 13.59), 340 },

4
Marlin/src/module/thermistor/thermistor_66.h Executable file → Normal file
View File

@@ -16,13 +16,13 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 2.5 MOhm, beta25 = 4500 K, 4.7 kOhm pull-up, DyzeDesign 500 °C Thermistor
const short temptable_66[][2] PROGMEM = {
constexpr temp_entry_t temptable_66[] PROGMEM = {
{ OV( 17.5), 850 },
{ OV( 17.9), 500 },
{ OV( 21.7), 480 },

5
Marlin/src/module/thermistor/thermistor_666.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -33,8 +33,7 @@
* B: 0.00031362
* C: -2.03978e-07
*/
#define NUMTEMPS 61
const short temptable_666[NUMTEMPS][2] PROGMEM = {
constexpr temp_entry_t temptable_666[] PROGMEM = {
{ OV( 1), 794 },
{ OV( 18), 288 },
{ OV( 35), 234 },

4
Marlin/src/module/thermistor/thermistor_67.h Executable file → Normal file
View File

@@ -16,13 +16,13 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 500 KOhm, beta25 = 3800 K, 4.7 kOhm pull-up, SliceEngineering 450 °C Thermistor
const short temptable_67[][2] PROGMEM = {
constexpr temp_entry_t temptable_67[] PROGMEM = {
{ OV( 22 ), 500 },
{ OV( 23 ), 490 },
{ OV( 25 ), 480 },

4
Marlin/src/module/thermistor/thermistor_7.h Executable file → Normal file
View File

@@ -16,13 +16,13 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 100 kOhm, beta25 = 3974 K, 4.7 kOhm pull-up, Honeywell 135-104LAG-J01
const short temptable_7[][2] PROGMEM = {
constexpr temp_entry_t temptable_7[] PROGMEM = {
{ OV( 1), 941 },
{ OV( 19), 362 },
{ OV( 37), 299 }, // top rating 300C

4
Marlin/src/module/thermistor/thermistor_70.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -26,7 +26,7 @@
// ANENG AN8009 DMM with a K-type probe used for measurements.
// R25 = 100 kOhm, beta25 = 4100 K, 4.7 kOhm pull-up, bqh2 stock thermistor
const short temptable_70[][2] PROGMEM = {
constexpr temp_entry_t temptable_70[] PROGMEM = {
{ OV( 18), 270 },
{ OV( 27), 248 },
{ OV( 34), 234 },

4
Marlin/src/module/thermistor/thermistor_71.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -27,7 +27,7 @@
// Beta = 3974
// R1 = 0 Ohm
// R2 = 4700 Ohm
const short temptable_71[][2] PROGMEM = {
constexpr temp_entry_t temptable_71[] PROGMEM = {
{ OV( 35), 300 },
{ OV( 51), 269 },
{ OV( 59), 258 },

4
Marlin/src/module/thermistor/thermistor_75.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -34,7 +34,7 @@
//#define HIGH_TEMP_RANGE_75
const short temptable_75[][2] PROGMEM = { // Generic Silicon Heat Pad with NTC 100K MGB18-104F39050L32 thermistor
constexpr temp_entry_t temptable_75[] PROGMEM = { // Generic Silicon Heat Pad with NTC 100K MGB18-104F39050L32 thermistor
{ OV(111.06), 200 }, // v=0.542 r=571.747 res=0.501 degC/count
#ifdef HIGH_TEMP_RANGE_75

4
Marlin/src/module/thermistor/thermistor_8.h Executable file → Normal file
View File

@@ -16,13 +16,13 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 100 kOhm, beta25 = 3950 K, 10 kOhm pull-up, NTCS0603E3104FHT
const short temptable_8[][2] PROGMEM = {
constexpr temp_entry_t temptable_8[] PROGMEM = {
{ OV( 1), 704 },
{ OV( 54), 216 },
{ OV( 107), 175 },

4
Marlin/src/module/thermistor/thermistor_9.h Executable file → Normal file
View File

@@ -16,13 +16,13 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 100 kOhm, beta25 = 3960 K, 4.7 kOhm pull-up, GE Sensing AL03006-58.2K-97-G1
const short temptable_9[][2] PROGMEM = {
constexpr temp_entry_t temptable_9[] PROGMEM = {
{ OV( 1), 936 },
{ OV( 36), 300 },
{ OV( 71), 246 },

5
Marlin/src/module/thermistor/thermistor_99.h Executable file → Normal file
View File

@@ -16,15 +16,14 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// 100k bed thermistor with a 10K pull-up resistor - made by $ buildroot/share/scripts/createTemperatureLookupMarlin.py --rp=10000
const short temptable_99[][2] PROGMEM = {
constexpr temp_entry_t temptable_99[] PROGMEM = {
{ OV( 5.81), 350 }, // v=0.028 r= 57.081 res=13.433 degC/count
{ OV( 6.54), 340 }, // v=0.032 r= 64.248 res=11.711 degC/count
{ OV( 7.38), 330 }, // v=0.036 r= 72.588 res=10.161 degC/count

4
Marlin/src/module/thermistor/thermistor_998.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -27,7 +27,7 @@
#define DUMMY_THERMISTOR_998_VALUE 25
#endif
const short temptable_998[][2] PROGMEM = {
constexpr temp_entry_t temptable_998[] PROGMEM = {
{ OV( 1), DUMMY_THERMISTOR_998_VALUE },
{ OV(1023), DUMMY_THERMISTOR_998_VALUE }
};

4
Marlin/src/module/thermistor/thermistor_999.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -27,7 +27,7 @@
#define DUMMY_THERMISTOR_999_VALUE 25
#endif
const short temptable_999[][2] PROGMEM = {
constexpr temp_entry_t temptable_999[] PROGMEM = {
{ OV( 1), DUMMY_THERMISTOR_999_VALUE },
{ OV(1023), DUMMY_THERMISTOR_999_VALUE }
};

461
Marlin/src/module/thermistor/thermistors.h Executable file → Normal file
View File

@@ -16,17 +16,19 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "../../inc/MarlinConfig.h"
#define THERMISTOR_TABLE_ADC_RESOLUTION 1024
#define THERMISTOR_TABLE_SCALE (HAL_ADC_RANGE / (THERMISTOR_TABLE_ADC_RESOLUTION))
#define THERMISTOR_TABLE_ADC_RESOLUTION 10
#define THERMISTOR_TABLE_SCALE (HAL_ADC_RANGE / _BV(THERMISTOR_TABLE_ADC_RESOLUTION))
#if ENABLED(HAL_ADC_FILTERED)
#define OVERSAMPLENR 1
#elif HAL_ADC_RESOLUTION > 10
#define OVERSAMPLENR (20 - HAL_ADC_RESOLUTION)
#else
#define OVERSAMPLENR 16
#endif
@@ -40,7 +42,19 @@
#define OV_SCALE(N) (N)
#define OV(N) int16_t(OV_SCALE(N) * (OVERSAMPLENR) * (THERMISTOR_TABLE_SCALE))
#define ANY_THERMISTOR_IS(n) (THERMISTOR_HEATER_0 == n || THERMISTOR_HEATER_1 == n || THERMISTOR_HEATER_2 == n || THERMISTOR_HEATER_3 == n || THERMISTOR_HEATER_4 == n || THERMISTOR_HEATER_5 == n || THERMISTOR_HEATER_6 == n || THERMISTOR_HEATER_7 == n || THERMISTORBED == n || THERMISTORCHAMBER == n || THERMISTORPROBE == n)
#define TEMP_SENSOR_IS(n,H) (n == TEMP_SENSOR_##H)
#define ANY_THERMISTOR_IS(n) ( TEMP_SENSOR_IS(n, 0) || TEMP_SENSOR_IS(n, 1) \
|| TEMP_SENSOR_IS(n, 2) || TEMP_SENSOR_IS(n, 3) \
|| TEMP_SENSOR_IS(n, 4) || TEMP_SENSOR_IS(n, 5) \
|| TEMP_SENSOR_IS(n, 6) || TEMP_SENSOR_IS(n, 7) \
|| TEMP_SENSOR_IS(n, BED) \
|| TEMP_SENSOR_IS(n, CHAMBER) \
|| TEMP_SENSOR_IS(n, COOLER) \
|| TEMP_SENSOR_IS(n, PROBE) \
|| TEMP_SENSOR_IS(n, BOARD) \
|| TEMP_SENSOR_IS(n, REDUNDANT) )
typedef struct { int16_t value; celsius_t celsius; } temp_entry_t;
// Pt1000 and Pt100 handling
//
@@ -70,6 +84,12 @@
#if ANY_THERMISTOR_IS(501) // 100K Zonestar thermistor
#include "thermistor_501.h"
#endif
#if ANY_THERMISTOR_IS(502) // Unknown thermistor used by the Zonestar Průša P802M hot bed
#include "thermistor_502.h"
#endif
#if ANY_THERMISTOR_IS(503) // Zonestar (Z8XM2) Heated Bed thermistor
#include "thermistor_503.h"
#endif
#if ANY_THERMISTOR_IS(512) // 100k thermistor in RPW-Ultra hotend, Pull-up = 4.7 kOhm, "unknown model"
#include "thermistor_512.h"
#endif
@@ -100,6 +120,9 @@
#if ANY_THERMISTOR_IS(15) // JGAurora A5 thermistor calibration
#include "thermistor_15.h"
#endif
#if ANY_THERMISTOR_IS(17) // Dagoma NTC 100k white thermistor
#include "thermistor_17.h"
#endif
#if ANY_THERMISTOR_IS(18) // ATC Semitec 204GT-2 (4.7k pullup) Dagoma.Fr - MKS_Base_DKU001327
#include "thermistor_18.h"
#endif
@@ -109,6 +132,15 @@
#if ANY_THERMISTOR_IS(21) // Pt100 with INA826 amp with 3.3v excitation based on "Pt100 with INA826 amp on Ultimaker v2.0 electronics"
#include "thermistor_21.h"
#endif
#if ANY_THERMISTOR_IS(22) // Thermistor in a Rostock 301 hot end, calibrated with a multimeter
#include "thermistor_22.h"
#endif
#if ANY_THERMISTOR_IS(23) // By AluOne #12622. Formerly 22 above. May need calibration/checking.
#include "thermistor_23.h"
#endif
#if ANY_THERMISTOR_IS(30) // Kis3d Silicone mat 24V 200W/300W with 6mm Precision cast plate (EN AW 5083)
#include "thermistor_30.h"
#endif
#if ANY_THERMISTOR_IS(51) // beta25 = 4092 K, R25 = 100 kOhm, Pull-up = 1 kOhm, "EPCOS"
#include "thermistor_51.h"
#endif
@@ -169,6 +201,9 @@
#if ANY_THERMISTOR_IS(1047) // Pt1000 with 4k7 pullup
#include "thermistor_1047.h"
#endif
#if ANY_THERMISTOR_IS(2000) // "Ultimachine Rambo TDK NTCG104LH104KT1 NTC100K motherboard Thermistor" https://product.tdk.com/en/search/sensor/ntc/chip-ntc-thermistor/info?part_no=NTCG104LH104KT1
#include "thermistor_2000.h"
#endif
#if ANY_THERMISTOR_IS(998) // User-defined table 1
#include "thermistor_998.h"
#endif
@@ -176,219 +211,341 @@
#include "thermistor_999.h"
#endif
#if ANY_THERMISTOR_IS(1000) // Custom
const short temptable_1000[][2] PROGMEM = { { 0, 0 } };
constexpr temp_entry_t temptable_1000[] PROGMEM = { { 0, 0 } };
#endif
#define _TT_NAME(_N) temptable_ ## _N
#define TT_NAME(_N) _TT_NAME(_N)
#if THERMISTOR_HEATER_0
#define HEATER_0_TEMPTABLE TT_NAME(THERMISTOR_HEATER_0)
#define HEATER_0_TEMPTABLE_LEN COUNT(HEATER_0_TEMPTABLE)
#elif defined(HEATER_0_USES_THERMISTOR)
#error "No heater 0 thermistor table specified"
#if TEMP_SENSOR_0 > 0
#define TEMPTABLE_0 TT_NAME(TEMP_SENSOR_0)
#define TEMPTABLE_0_LEN COUNT(TEMPTABLE_0)
#else
#define HEATER_0_TEMPTABLE nullptr
#define HEATER_0_TEMPTABLE_LEN 0
#define TEMPTABLE_0 nullptr
#define TEMPTABLE_0_LEN 0
#endif
#if THERMISTOR_HEATER_1
#define HEATER_1_TEMPTABLE TT_NAME(THERMISTOR_HEATER_1)
#define HEATER_1_TEMPTABLE_LEN COUNT(HEATER_1_TEMPTABLE)
#elif defined(HEATER_1_USES_THERMISTOR)
#error "No heater 1 thermistor table specified"
#if TEMP_SENSOR_1 > 0
#define TEMPTABLE_1 TT_NAME(TEMP_SENSOR_1)
#define TEMPTABLE_1_LEN COUNT(TEMPTABLE_1)
#else
#define HEATER_1_TEMPTABLE nullptr
#define HEATER_1_TEMPTABLE_LEN 0
#define TEMPTABLE_1 nullptr
#define TEMPTABLE_1_LEN 0
#endif
#if THERMISTOR_HEATER_2
#define HEATER_2_TEMPTABLE TT_NAME(THERMISTOR_HEATER_2)
#define HEATER_2_TEMPTABLE_LEN COUNT(HEATER_2_TEMPTABLE)
#elif defined(HEATER_2_USES_THERMISTOR)
#error "No heater 2 thermistor table specified"
#if TEMP_SENSOR_2 > 0
#define TEMPTABLE_2 TT_NAME(TEMP_SENSOR_2)
#define TEMPTABLE_2_LEN COUNT(TEMPTABLE_2)
#else
#define HEATER_2_TEMPTABLE nullptr
#define HEATER_2_TEMPTABLE_LEN 0
#define TEMPTABLE_2 nullptr
#define TEMPTABLE_2_LEN 0
#endif
#if THERMISTOR_HEATER_3
#define HEATER_3_TEMPTABLE TT_NAME(THERMISTOR_HEATER_3)
#define HEATER_3_TEMPTABLE_LEN COUNT(HEATER_3_TEMPTABLE)
#elif defined(HEATER_3_USES_THERMISTOR)
#error "No heater 3 thermistor table specified"
#if TEMP_SENSOR_3 > 0
#define TEMPTABLE_3 TT_NAME(TEMP_SENSOR_3)
#define TEMPTABLE_3_LEN COUNT(TEMPTABLE_3)
#else
#define HEATER_3_TEMPTABLE nullptr
#define HEATER_3_TEMPTABLE_LEN 0
#define TEMPTABLE_3 nullptr
#define TEMPTABLE_3_LEN 0
#endif
#if THERMISTOR_HEATER_4
#define HEATER_4_TEMPTABLE TT_NAME(THERMISTOR_HEATER_4)
#define HEATER_4_TEMPTABLE_LEN COUNT(HEATER_4_TEMPTABLE)
#elif defined(HEATER_4_USES_THERMISTOR)
#error "No heater 4 thermistor table specified"
#if TEMP_SENSOR_4 > 0
#define TEMPTABLE_4 TT_NAME(TEMP_SENSOR_4)
#define TEMPTABLE_4_LEN COUNT(TEMPTABLE_4)
#else
#define HEATER_4_TEMPTABLE nullptr
#define HEATER_4_TEMPTABLE_LEN 0
#define TEMPTABLE_4 nullptr
#define TEMPTABLE_4_LEN 0
#endif
#if THERMISTOR_HEATER_5
#define HEATER_5_TEMPTABLE TT_NAME(THERMISTOR_HEATER_5)
#define HEATER_5_TEMPTABLE_LEN COUNT(HEATER_5_TEMPTABLE)
#elif defined(HEATER_5_USES_THERMISTOR)
#error "No heater 5 thermistor table specified"
#if TEMP_SENSOR_5 > 0
#define TEMPTABLE_5 TT_NAME(TEMP_SENSOR_5)
#define TEMPTABLE_5_LEN COUNT(TEMPTABLE_5)
#else
#define HEATER_5_TEMPTABLE nullptr
#define HEATER_5_TEMPTABLE_LEN 0
#define TEMPTABLE_5 nullptr
#define TEMPTABLE_5_LEN 0
#endif
#if THERMISTOR_HEATER_6
#define HEATER_6_TEMPTABLE TT_NAME(THERMISTOR_HEATER_6)
#define HEATER_6_TEMPTABLE_LEN COUNT(HEATER_6_TEMPTABLE)
#elif defined(HEATER_6_USES_THERMISTOR)
#error "No heater 6 thermistor table specified"
#if TEMP_SENSOR_6 > 0
#define TEMPTABLE_6 TT_NAME(TEMP_SENSOR_6)
#define TEMPTABLE_6_LEN COUNT(TEMPTABLE_6)
#else
#define HEATER_6_TEMPTABLE nullptr
#define HEATER_6_TEMPTABLE_LEN 0
#define TEMPTABLE_6 nullptr
#define TEMPTABLE_6_LEN 0
#endif
#if THERMISTOR_HEATER_7
#define HEATER_7_TEMPTABLE TT_NAME(THERMISTOR_HEATER_7)
#define HEATER_7_TEMPTABLE_LEN COUNT(HEATER_7_TEMPTABLE)
#elif defined(HEATER_7_USES_THERMISTOR)
#error "No heater 7 thermistor table specified"
#if TEMP_SENSOR_7 > 0
#define TEMPTABLE_7 TT_NAME(TEMP_SENSOR_7)
#define TEMPTABLE_7_LEN COUNT(TEMPTABLE_7)
#else
#define HEATER_7_TEMPTABLE nullptr
#define HEATER_7_TEMPTABLE_LEN 0
#define TEMPTABLE_7 nullptr
#define TEMPTABLE_7_LEN 0
#endif
#ifdef THERMISTORBED
#define BED_TEMPTABLE TT_NAME(THERMISTORBED)
#define BED_TEMPTABLE_LEN COUNT(BED_TEMPTABLE)
#elif defined(HEATER_BED_USES_THERMISTOR)
#error "No bed thermistor table specified"
#if TEMP_SENSOR_BED > 0
#define TEMPTABLE_BED TT_NAME(TEMP_SENSOR_BED)
#define TEMPTABLE_BED_LEN COUNT(TEMPTABLE_BED)
#else
#define BED_TEMPTABLE_LEN 0
#define TEMPTABLE_BED_LEN 0
#endif
#ifdef THERMISTORCHAMBER
#define CHAMBER_TEMPTABLE TT_NAME(THERMISTORCHAMBER)
#define CHAMBER_TEMPTABLE_LEN COUNT(CHAMBER_TEMPTABLE)
#elif defined(HEATER_CHAMBER_USES_THERMISTOR)
#error "No chamber thermistor table specified"
#if TEMP_SENSOR_CHAMBER > 0
#define TEMPTABLE_CHAMBER TT_NAME(TEMP_SENSOR_CHAMBER)
#define TEMPTABLE_CHAMBER_LEN COUNT(TEMPTABLE_CHAMBER)
#else
#define CHAMBER_TEMPTABLE_LEN 0
#define TEMPTABLE_CHAMBER_LEN 0
#endif
#ifdef THERMISTORPROBE
#define PROBE_TEMPTABLE TT_NAME(THERMISTORPROBE)
#define PROBE_TEMPTABLE_LEN COUNT(PROBE_TEMPTABLE)
#if TEMP_SENSOR_COOLER > 0
#define TEMPTABLE_COOLER TT_NAME(TEMP_SENSOR_COOLER)
#define TEMPTABLE_COOLER_LEN COUNT(TEMPTABLE_COOLER)
#else
#define PROBE_TEMPTABLE_LEN 0
#define TEMPTABLE_COOLER_LEN 0
#endif
#if TEMP_SENSOR_PROBE > 0
#define TEMPTABLE_PROBE TT_NAME(TEMP_SENSOR_PROBE)
#define TEMPTABLE_PROBE_LEN COUNT(TEMPTABLE_PROBE)
#else
#define TEMPTABLE_PROBE_LEN 0
#endif
#if TEMP_SENSOR_BOARD > 0
#define TEMPTABLE_BOARD TT_NAME(TEMP_SENSOR_BOARD)
#define TEMPTABLE_BOARD_LEN COUNT(TEMPTABLE_BOARD)
#else
#define TEMPTABLE_BOARD_LEN 0
#endif
#if TEMP_SENSOR_REDUNDANT > 0
#define TEMPTABLE_REDUNDANT TT_NAME(TEMP_SENSOR_REDUNDANT)
#define TEMPTABLE_REDUNDANT_LEN COUNT(TEMPTABLE_REDUNDANT)
#else
#define TEMPTABLE_REDUNDANT_LEN 0
#endif
// The SCAN_THERMISTOR_TABLE macro needs alteration?
static_assert(
HEATER_0_TEMPTABLE_LEN < 256 && HEATER_1_TEMPTABLE_LEN < 256
&& HEATER_2_TEMPTABLE_LEN < 256 && HEATER_3_TEMPTABLE_LEN < 256
&& HEATER_4_TEMPTABLE_LEN < 256 && HEATER_5_TEMPTABLE_LEN < 256
&& HEATER_6_TEMPTABLE_LEN < 258 && HEATER_7_TEMPTABLE_LEN < 258
&& BED_TEMPTABLE_LEN < 256 && CHAMBER_TEMPTABLE_LEN < 256
&& PROBE_TEMPTABLE_LEN < 256,
"Temperature conversion tables over 255 entries need special consideration."
static_assert(255 > TEMPTABLE_0_LEN || 255 > TEMPTABLE_1_LEN || 255 > TEMPTABLE_2_LEN || 255 > TEMPTABLE_3_LEN
|| 255 > TEMPTABLE_4_LEN || 255 > TEMPTABLE_5_LEN || 255 > TEMPTABLE_6_LEN || 255 > TEMPTABLE_7_LEN
|| 255 > TEMPTABLE_BED_LEN
|| 255 > TEMPTABLE_CHAMBER_LEN
|| 255 > TEMPTABLE_COOLER_LEN
|| 255 > TEMPTABLE_PROBE_LEN
|| 255 > TEMPTABLE_BOARD_LEN
|| 255 > TEMPTABLE_REDUNDANT_LEN
, "Temperature conversion tables over 255 entries need special consideration."
);
// Set the high and low raw values for the heaters
// For thermistors the highest temperature results in the lowest ADC value
// For thermocouples the highest temperature results in the highest ADC value
#ifndef HEATER_0_RAW_HI_TEMP
#if defined(REVERSE_TEMP_SENSOR_RANGE) || !defined(HEATER_0_USES_THERMISTOR)
#define HEATER_0_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define HEATER_0_RAW_LO_TEMP 0
#define _TT_REV(N) REVERSE_TEMP_SENSOR_RANGE_##N
#define TT_REV(N) TERN0(TEMP_SENSOR_##N##_IS_THERMISTOR, DEFER4(_TT_REV)(TEMP_SENSOR_##N))
#define _TT_REVRAW(N) !TEMP_SENSOR_##N##_IS_THERMISTOR
#define TT_REVRAW(N) (TT_REV(N) || _TT_REVRAW(N))
#ifdef TEMPTABLE_0
#if TT_REV(0)
#define TEMP_SENSOR_0_MINTEMP_IND 0
#define TEMP_SENSOR_0_MAXTEMP_IND TEMPTABLE_0_LEN - 1
#else
#define HEATER_0_RAW_HI_TEMP 0
#define HEATER_0_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_0_MINTEMP_IND TEMPTABLE_0_LEN - 1
#define TEMP_SENSOR_0_MAXTEMP_IND 0
#endif
#endif
#ifndef HEATER_1_RAW_HI_TEMP
#if defined(REVERSE_TEMP_SENSOR_RANGE) || !defined(HEATER_1_USES_THERMISTOR)
#define HEATER_1_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define HEATER_1_RAW_LO_TEMP 0
#ifdef TEMPTABLE_1
#if TT_REV(1)
#define TEMP_SENSOR_1_MINTEMP_IND 0
#define TEMP_SENSOR_1_MAXTEMP_IND TEMPTABLE_1_LEN - 1
#else
#define HEATER_1_RAW_HI_TEMP 0
#define HEATER_1_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_1_MINTEMP_IND TEMPTABLE_1_LEN - 1
#define TEMP_SENSOR_1_MAXTEMP_IND 0
#endif
#endif
#ifndef HEATER_2_RAW_HI_TEMP
#if defined(REVERSE_TEMP_SENSOR_RANGE) || !defined(HEATER_2_USES_THERMISTOR)
#define HEATER_2_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define HEATER_2_RAW_LO_TEMP 0
#ifdef TEMPTABLE_2
#if TT_REV(2)
#define TEMP_SENSOR_2_MINTEMP_IND 0
#define TEMP_SENSOR_2_MAXTEMP_IND TEMPTABLE_2_LEN - 1
#else
#define HEATER_2_RAW_HI_TEMP 0
#define HEATER_2_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_2_MINTEMP_IND TEMPTABLE_2_LEN - 1
#define TEMP_SENSOR_2_MAXTEMP_IND 0
#endif
#endif
#ifndef HEATER_3_RAW_HI_TEMP
#if defined(REVERSE_TEMP_SENSOR_RANGE) || !defined(HEATER_3_USES_THERMISTOR)
#define HEATER_3_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define HEATER_3_RAW_LO_TEMP 0
#ifdef TEMPTABLE_3
#if TT_REV(3)
#define TEMP_SENSOR_3_MINTEMP_IND 0
#define TEMP_SENSOR_3_MAXTEMP_IND TEMPTABLE_3_LEN - 1
#else
#define HEATER_3_RAW_HI_TEMP 0
#define HEATER_3_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_3_MINTEMP_IND TEMPTABLE_3_LEN - 1
#define TEMP_SENSOR_3_MAXTEMP_IND 0
#endif
#endif
#ifndef HEATER_4_RAW_HI_TEMP
#if defined(REVERSE_TEMP_SENSOR_RANGE) || !defined(HEATER_4_USES_THERMISTOR)
#define HEATER_4_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define HEATER_4_RAW_LO_TEMP 0
#ifdef TEMPTABLE_4
#if TT_REV(4)
#define TEMP_SENSOR_4_MINTEMP_IND 0
#define TEMP_SENSOR_4_MAXTEMP_IND TEMPTABLE_4_LEN - 1
#else
#define HEATER_4_RAW_HI_TEMP 0
#define HEATER_4_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_4_MINTEMP_IND TEMPTABLE_4_LEN - 1
#define TEMP_SENSOR_4_MAXTEMP_IND 0
#endif
#endif
#ifndef HEATER_5_RAW_HI_TEMP
#if defined(REVERSE_TEMP_SENSOR_RANGE) || !defined(HEATER_5_USES_THERMISTOR)
#define HEATER_5_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define HEATER_5_RAW_LO_TEMP 0
#ifdef TEMPTABLE_5
#if TT_REV(5)
#define TEMP_SENSOR_5_MINTEMP_IND 0
#define TEMP_SENSOR_5_MAXTEMP_IND TEMPTABLE_5_LEN - 1
#else
#define HEATER_5_RAW_HI_TEMP 0
#define HEATER_5_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_5_MINTEMP_IND TEMPTABLE_5_LEN - 1
#define TEMP_SENSOR_5_MAXTEMP_IND 0
#endif
#endif
#ifndef HEATER_6_RAW_HI_TEMP
#if defined(REVERSE_TEMP_SENSOR_RANGE) || !defined(HEATER_6_USES_THERMISTOR)
#define HEATER_6_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define HEATER_6_RAW_LO_TEMP 0
#ifdef TEMPTABLE_6
#if TT_REV(6)
#define TEMP_SENSOR_6_MINTEMP_IND 0
#define TEMP_SENSOR_6_MAXTEMP_IND TEMPTABLE_6_LEN - 1
#else
#define HEATER_6_RAW_HI_TEMP 0
#define HEATER_6_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_6_MINTEMP_IND TEMPTABLE_6_LEN - 1
#define TEMP_SENSOR_6_MAXTEMP_IND 0
#endif
#endif
#ifndef HEATER_7_RAW_HI_TEMP
#if defined(REVERSE_TEMP_SENSOR_RANGE) || !defined(HEATER_7_USES_THERMISTOR)
#define HEATER_7_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define HEATER_7_RAW_LO_TEMP 0
#ifdef TEMPTABLE_7
#if TT_REV(7)
#define TEMP_SENSOR_7_MINTEMP_IND 0
#define TEMP_SENSOR_7_MAXTEMP_IND TEMPTABLE_7_LEN - 1
#else
#define HEATER_7_RAW_HI_TEMP 0
#define HEATER_7_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#endif
#endif
#ifndef HEATER_BED_RAW_HI_TEMP
#if defined(REVERSE_TEMP_SENSOR_RANGE) || !defined(HEATER_BED_USES_THERMISTOR)
#define HEATER_BED_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define HEATER_BED_RAW_LO_TEMP 0
#else
#define HEATER_BED_RAW_HI_TEMP 0
#define HEATER_BED_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#endif
#endif
#ifndef HEATER_CHAMBER_RAW_HI_TEMP
#if defined(REVERSE_TEMP_SENSOR_RANGE) || !defined(HEATER_CHAMBER_USES_THERMISTOR)
#define HEATER_CHAMBER_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define HEATER_CHAMBER_RAW_LO_TEMP 0
#else
#define HEATER_CHAMBER_RAW_HI_TEMP 0
#define HEATER_CHAMBER_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_7_MINTEMP_IND TEMPTABLE_7_LEN - 1
#define TEMP_SENSOR_7_MAXTEMP_IND 0
#endif
#endif
#undef REVERSE_TEMP_SENSOR_RANGE
#ifndef TEMP_SENSOR_0_RAW_HI_TEMP
#if TT_REVRAW(0)
#define TEMP_SENSOR_0_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_0_RAW_LO_TEMP 0
#else
#define TEMP_SENSOR_0_RAW_HI_TEMP 0
#define TEMP_SENSOR_0_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#endif
#endif
#ifndef TEMP_SENSOR_1_RAW_HI_TEMP
#if TT_REVRAW(1)
#define TEMP_SENSOR_1_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_1_RAW_LO_TEMP 0
#else
#define TEMP_SENSOR_1_RAW_HI_TEMP 0
#define TEMP_SENSOR_1_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#endif
#endif
#ifndef TEMP_SENSOR_2_RAW_HI_TEMP
#if TT_REVRAW(2)
#define TEMP_SENSOR_2_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_2_RAW_LO_TEMP 0
#else
#define TEMP_SENSOR_2_RAW_HI_TEMP 0
#define TEMP_SENSOR_2_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#endif
#endif
#ifndef TEMP_SENSOR_3_RAW_HI_TEMP
#if TT_REVRAW(3)
#define TEMP_SENSOR_3_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_3_RAW_LO_TEMP 0
#else
#define TEMP_SENSOR_3_RAW_HI_TEMP 0
#define TEMP_SENSOR_3_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#endif
#endif
#ifndef TEMP_SENSOR_4_RAW_HI_TEMP
#if TT_REVRAW(4)
#define TEMP_SENSOR_4_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_4_RAW_LO_TEMP 0
#else
#define TEMP_SENSOR_4_RAW_HI_TEMP 0
#define TEMP_SENSOR_4_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#endif
#endif
#ifndef TEMP_SENSOR_5_RAW_HI_TEMP
#if TT_REVRAW(5)
#define TEMP_SENSOR_5_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_5_RAW_LO_TEMP 0
#else
#define TEMP_SENSOR_5_RAW_HI_TEMP 0
#define TEMP_SENSOR_5_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#endif
#endif
#ifndef TEMP_SENSOR_6_RAW_HI_TEMP
#if TT_REVRAW(6)
#define TEMP_SENSOR_6_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_6_RAW_LO_TEMP 0
#else
#define TEMP_SENSOR_6_RAW_HI_TEMP 0
#define TEMP_SENSOR_6_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#endif
#endif
#ifndef TEMP_SENSOR_7_RAW_HI_TEMP
#if TT_REVRAW(7)
#define TEMP_SENSOR_7_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_7_RAW_LO_TEMP 0
#else
#define TEMP_SENSOR_7_RAW_HI_TEMP 0
#define TEMP_SENSOR_7_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#endif
#endif
#ifndef TEMP_SENSOR_BED_RAW_HI_TEMP
#if TT_REVRAW(BED)
#define TEMP_SENSOR_BED_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_BED_RAW_LO_TEMP 0
#else
#define TEMP_SENSOR_BED_RAW_HI_TEMP 0
#define TEMP_SENSOR_BED_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#endif
#endif
#ifndef TEMP_SENSOR_CHAMBER_RAW_HI_TEMP
#if TT_REVRAW(CHAMBER)
#define TEMP_SENSOR_CHAMBER_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_CHAMBER_RAW_LO_TEMP 0
#else
#define TEMP_SENSOR_CHAMBER_RAW_HI_TEMP 0
#define TEMP_SENSOR_CHAMBER_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#endif
#endif
#ifndef TEMP_SENSOR_COOLER_RAW_HI_TEMP
#if TT_REVRAW(COOLER)
#define TEMP_SENSOR_COOLER_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_COOLER_RAW_LO_TEMP 0
#else
#define TEMP_SENSOR_COOLER_RAW_HI_TEMP 0
#define TEMP_SENSOR_COOLER_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#endif
#endif
#ifndef TEMP_SENSOR_PROBE_RAW_HI_TEMP
#if TT_REVRAW(PROBE)
#define TEMP_SENSOR_PROBE_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_PROBE_RAW_LO_TEMP 0
#else
#define TEMP_SENSOR_PROBE_RAW_HI_TEMP 0
#define TEMP_SENSOR_PROBE_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#endif
#endif
#ifndef TEMP_SENSOR_BOARD_RAW_HI_TEMP
#if TT_REVRAW(BOARD)
#define TEMP_SENSOR_BOARD_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_BOARD_RAW_LO_TEMP 0
#else
#define TEMP_SENSOR_BOARD_RAW_HI_TEMP 0
#define TEMP_SENSOR_BOARD_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#endif
#endif
#ifndef TEMP_SENSOR_REDUNDANT_RAW_HI_TEMP
#if TT_REVRAW(REDUNDANT)
#define TEMP_SENSOR_REDUNDANT_RAW_HI_TEMP MAX_RAW_THERMISTOR_VALUE
#define TEMP_SENSOR_REDUNDANT_RAW_LO_TEMP 0
#else
#define TEMP_SENSOR_REDUNDANT_RAW_HI_TEMP 0
#define TEMP_SENSOR_REDUNDANT_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#endif
#endif
#undef __TT_REV
#undef _TT_REV
#undef TT_REV
#undef _TT_REVRAW
#undef TT_REVRAW

1047
Marlin/src/module/tool_change.cpp Executable file → Normal file

File diff suppressed because it is too large Load Diff

67
Marlin/src/module/tool_change.h Executable file → Normal file
View File

@@ -16,22 +16,24 @@
* 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/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "../inc/MarlinConfigPre.h"
#include "../core/types.h"
#include "../inc/MarlinConfig.h"
#if EXTRUDERS > 1
//#define DEBUG_TOOLCHANGE_MIGRATION_FEATURE
#if HAS_MULTI_EXTRUDER
typedef struct {
#if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
float swap_length, extra_prime;
int16_t prime_speed, retract_speed;
float swap_length, extra_prime, extra_resume;
int16_t prime_speed, retract_speed, unretract_speed, fan, fan_speed, fan_time;
#endif
#if ENABLED(TOOLCHANGE_PARK)
bool enable_park;
xy_pos_t change_point;
#endif
float z_raise;
@@ -39,6 +41,27 @@
extern toolchange_settings_t toolchange_settings;
#if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
void tool_change_prime();
#endif
#if ENABLED(TOOLCHANGE_FS_PRIME_FIRST_USED)
extern bool enable_first_prime;
#endif
#if ENABLED(TOOLCHANGE_FS_INIT_BEFORE_SWAP)
extern bool toolchange_extruder_ready[EXTRUDERS];
#endif
#if ENABLED(TOOLCHANGE_MIGRATION_FEATURE)
typedef struct {
uint8_t target, last;
bool automode, in_progress;
} migration_settings_t;
constexpr migration_settings_t migration_defaults = { 0, 0, false, false };
extern migration_settings_t migration;
bool extruder_migration();
#endif
#endif
#if DO_SWITCH_EXTRUDER
@@ -56,19 +79,18 @@
#if ENABLED(PARKING_EXTRUDER)
#if ENABLED(PARKING_EXTRUDER_SOLENOIDS_INVERT)
#define PE_MAGNET_ON_STATE !PARKING_EXTRUDER_SOLENOIDS_PINS_ACTIVE
#else
#define PE_MAGNET_ON_STATE PARKING_EXTRUDER_SOLENOIDS_PINS_ACTIVE
#endif
void pe_solenoid_set_pin_state(const uint8_t extruder_num, const uint8_t state);
void pe_set_solenoid(const uint8_t extruder_num, const uint8_t state);
inline void pe_activate_solenoid(const uint8_t extruder_num) { pe_set_solenoid(extruder_num, PE_MAGNET_ON_STATE); }
inline void pe_deactivate_solenoid(const uint8_t extruder_num) { pe_set_solenoid(extruder_num, !PE_MAGNET_ON_STATE); }
#define PE_MAGNET_ON_STATE TERN_(PARKING_EXTRUDER_SOLENOIDS_INVERT, !)PARKING_EXTRUDER_SOLENOIDS_PINS_ACTIVE
inline void pe_solenoid_magnet_on(const uint8_t extruder_num) { pe_solenoid_set_pin_state(extruder_num, PE_MAGNET_ON_STATE); }
inline void pe_solenoid_magnet_off(const uint8_t extruder_num) { pe_solenoid_set_pin_state(extruder_num, !PE_MAGNET_ON_STATE); }
void pe_solenoid_init();
extern bool extruder_parked;
inline void parking_extruder_set_parked(const bool parked) { extruder_parked = parked; }
bool parking_extruder_unpark_after_homing(const uint8_t final_tool, bool homed_towards_final_tool);
#elif ENABLED(MAGNETIC_PARKING_EXTRUDER)
typedef struct MPESettings {
@@ -86,19 +108,16 @@
#endif
#if ENABLED(SINGLENOZZLE)
extern uint16_t singlenozzle_temp[EXTRUDERS];
#if FAN_COUNT > 0
extern uint8_t singlenozzle_fan_speed[EXTRUDERS];
#endif
#endif
#if ENABLED(ELECTROMAGNETIC_SWITCHING_TOOLHEAD)
void est_init();
#elif ENABLED(SWITCHING_TOOLHEAD)
void swt_init();
#endif
#if ENABLED(SWITCHING_TOOLHEAD)
void swt_init();
#if ENABLED(TOOL_SENSOR)
uint8_t check_tool_sensor_stats(const uint8_t active_tool, const bool kill_on_error=false, const bool disable=false);
#else
inline uint8_t check_tool_sensor_stats(const uint8_t, const bool=false, const bool=false) { return 0; }
#endif
/**